[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v4] vpci: Add resizable bar support


  • To: Jan Beulich <jbeulich@xxxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>
  • From: "Chen, Jiqian" <Jiqian.Chen@xxxxxxx>
  • Date: Fri, 10 Jan 2025 07:10:20 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=amd.com; dmarc=pass action=none header.from=amd.com; dkim=pass header.d=amd.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=c1V2XdQodbknOaVFFS21dJUm31ycTGpj/1JY2ZLwAy8=; b=eR6utBJJCoYOfIgN67h4dTl9gMOKPSLcgLjxw8S3fH6jOz7PjKO0xI+754guug9Bs6TtNEN3UnU7yvcRyw46xTBkyDyk/+jGo0YOMotNK4bWO5b0NtXmg4HJKetZHItsxwKDkjobRjO5OUNsbAONAOpVAffYv94mZg3XLko9EXYUv36QIihL9Dx3T+UZUvLZZoFhrbLOCKS7OmoF9IAIgXi2xM431XEJdHnfselFHbpJyLW6eQQSnfbQQLOnQGxcKA9h5QxbPehqXcT30VF8fITYWn1HzVzpSCRdubTQbUn0Bmm+/WeQexZn0603AnW2VY4xFuFutF76ux8pvvy7Yg==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=U94gknPmAEq7HvszIJhRv4pvp9xt+mZuJYygWjSMXzu+OopoOFcJEdfUEyC0IzrQieLm0aL46NfWD+QVRegpweU7f51mdaEsxeEsUSFUUyVSxX02Gk6Mwb30zs2j0zDQxFyKqq11SA0WCrw7XRs9leI+rUupIjYn1UDqSdRlN3SJ2wcWv4HIx0T2AyESiPyEqfL1WUtZyIt42Hurz8zt3T5crnm/1RbuIpA1ubxicgYWhcb49rUbzD11YLW3VUNkeZr2N+jd+9U0F7II9iNuLHrU6l2haVlOZRjgQwMrKL6GMkLZpEbgJ3ybUOOrPrsfXLUaWYGdjQ1JP/EWZ24Vhw==
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=amd.com;
  • Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, "Huang, Ray" <Ray.Huang@xxxxxxx>, "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, "Chen, Jiqian" <Jiqian.Chen@xxxxxxx>
  • Delivery-date: Fri, 10 Jan 2025 07:10:44 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHbUdYKjT75oVKG00CoBVtVLX93obMLM/yAgAUH7YA=
  • Thread-topic: [PATCH v4] vpci: Add resizable bar support

On 2025/1/7 18:06, Jan Beulich wrote:
> On 19.12.2024 06:21, Jiqian Chen wrote:
>> --- /dev/null
>> +++ b/xen/drivers/vpci/rebar.c
>> @@ -0,0 +1,131 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (C) 2024 Advanced Micro Devices, Inc. All Rights Reserved.
>> + *
>> + * Author: Jiqian Chen <Jiqian.Chen@xxxxxxx>
>> + */
>> +
>> +#include <xen/sched.h>
>> +#include <xen/vpci.h>
>> +
>> +static void cf_check rebar_ctrl_write(const struct pci_dev *pdev,
>> +                                      unsigned int reg,
>> +                                      uint32_t val,
>> +                                      void *data)
>> +{
>> +    struct vpci_bar *bar = data;
>> +    uint64_t size = PCI_REBAR_CTRL_SIZE(val);
>> +
>> +    if ( bar->enabled )
>> +    {
>> +        /*
>> +         * Refuse to resize a BAR while memory decoding is enabled, as
>> +         * otherwise the size of the mapped region in the p2m would become
>> +         * stale with the newly set BAR size, and the position of the BAR
>> +         * would be reset to undefined.  Note the PCIe specification also
>> +         * forbids resizing a BAR with memory decoding enabled.
>> +         */
>> +        if ( size != bar->size )
>> +            gprintk(XENLOG_ERR,
>> +                    "%pp: refuse to resize BAR with memory decoding 
>> enabled\n",
>> +                    &pdev->sbdf);
>> +        return;
>> +    }
>> +
>> +    if ( !((size >> PCI_REBAR_SIZE_BIAS) & bar->resizable_sizes) )
>> +        gprintk(XENLOG_WARNING,
>> +                "%pp: new size %#lx is not supported by hardware\n",
>> +                &pdev->sbdf, size);
>> +
>> +    bar->size = size;
> 
> Shouldn't at least this be in an "else" to the if() above?
After reading your discussion with Roger., here..

> 
>> +    bar->addr = 0;
> 
> For maximum compatibility with the behavior on bare metal, would we
> perhaps better ...
> 
>> +    bar->guest_addr = 0;
>> +    pci_conf_write32(pdev->sbdf, reg, val);
> 
> ... re-read the BAR from hardware after this write?
> 
> Similar consideration may apply to ->guest_addr: Driver writers knowing
> how their hardware behaves may expect that merely some of the bits of
> the address get cleared (if the size increases).
and here, I need to use pci_size_mem_bar to re-obtain addr and size, then set 
guest_addr to be addr.
    pci_size_mem_bar(pdev->sbdf, reg, &bar->addr, &bar->size, );
    bar->guest_addr = bar->addr;


> 
>> +static int cf_check init_rebar(struct pci_dev *pdev)
>> +{
>> +    uint32_t ctrl;
>> +    unsigned int nbars;
>> +    unsigned int rebar_offset = pci_find_ext_capability(pdev->sbdf,
>> +                                                        
>> PCI_EXT_CAP_ID_REBAR);
>> +
>> +    if ( !rebar_offset )
>> +        return 0;
>> +
>> +    if ( !is_hardware_domain(pdev->domain) )
>> +    {
>> +        printk(XENLOG_ERR "%pp: resizable BARs unsupported for unpriv 
>> %pd\n",
>> +               &pdev->sbdf, pdev->domain);
>> +        return -EOPNOTSUPP;
>> +    }
>> +
>> +    ctrl = pci_conf_read32(pdev->sbdf, rebar_offset + PCI_REBAR_CTRL(0));
>> +    nbars = MASK_EXTR(ctrl, PCI_REBAR_CTRL_NBAR_MASK);
>> +
>> +    for ( unsigned int i = 0; i < nbars; i++ )
>> +    {
>> +        int rc;
>> +        struct vpci_bar *bar;
>> +        unsigned int index;
>> +
>> +        ctrl = pci_conf_read32(pdev->sbdf, rebar_offset + 
>> PCI_REBAR_CTRL(i));
>> +        index = ctrl & PCI_REBAR_CTRL_BAR_IDX;;
> 
> Nit: No double semicolons please.
> 
>> +        if ( index >= PCI_HEADER_NORMAL_NR_BARS )
>> +        {
>> +            /*
>> +             * TODO: for failed pathes, need to hide ReBar capability
>> +             * from hardware domain instead of returning an error.
>> +             */
>> +            printk(XENLOG_ERR "%pd %pp: too big BAR number %u in 
>> REBAR_CTRL\n",
>> +                   pdev->domain, &pdev->sbdf, index);
>> +            return -EINVAL;
> 
> With the TODO unaddressed, is it actually appropriate to return an error
> here? Shouldn't we continue in a best effort manner? (Question also to
> Roger as the maintainer.)
> 
>> +        }
>> +
>> +        bar = &pdev->vpci->header.bars[index];
>> +        if ( bar->type != VPCI_BAR_MEM64_LO && bar->type != VPCI_BAR_MEM32 )
>> +        {
>> +            printk(XENLOG_ERR "%pd %pp: BAR%u is not in memory space\n",
>> +                   pdev->domain, &pdev->sbdf, index);
>> +            return -EINVAL;
> 
> Same question here then.
After reading your discussion with Roger. I will change to "continue" here and 
above.

> 
>> +        }
>> +
>> +        rc = vpci_add_register(pdev->vpci, vpci_hw_read32, vpci_hw_write32,
>> +                               rebar_offset + PCI_REBAR_CAP(i), 4, NULL);
>> +        if ( rc )
>> +        {
>> +            printk(XENLOG_ERR "%pd %pp: fail to add reg of REBAR_CAP 
>> rc=%d\n",
>> +                   pdev->domain, &pdev->sbdf, rc);
>> +            return rc;
>> +        }
>> +
>> +        rc = vpci_add_register(pdev->vpci, vpci_hw_read32, rebar_ctrl_write,
>> +                               rebar_offset + PCI_REBAR_CTRL(i), 4, bar);
>> +        if ( rc )
>> +        {
>> +            printk(XENLOG_ERR "%pd %pp: fail to add reg of REBAR_CTRL 
>> rc=%d\n",
>> +                   pdev->domain, &pdev->sbdf, rc);
>> +            return rc;
>> +        }
>> +
>> +        bar->resizable_sizes |=
>> +            (pci_conf_read32(pdev->sbdf, rebar_offset + PCI_REBAR_CAP(i)) >>
>> +             PCI_REBAR_CAP_SHIFT);
> 
> Imo this would better use = in place of |= and (see also below) would also
> better use MASK_EXTR() just like ...
> 
>> +        bar->resizable_sizes |=
>> +            ((uint64_t)MASK_EXTR(ctrl, PCI_REBAR_CTRL_SIZES) <<
>> +             (32 - PCI_REBAR_CAP_SHIFT));
> 
> ... this one does.
Combine with your below comments about the macro " PCI_REBAR_CAP_SHIFT" and 
"PCI_REBAR_CTRL_SIZES ",
I will change "PCI_REBAR_CAP_SHIFT 4" to "PCI_REBAR_CAP_SIZES_MASK 0xFFFFFFF0U",
change "PCI_REBAR_CTRL_SIZES 0xFFFF0000U" to "PCI_REBAR_CTRL_SIZES_MASK 
0xFFFF0000U"
Then, here will be:
        bar->resizable_sizes =
            MASK_EXTR(pci_conf_read32(pdev->sbdf,
                                      rebar_offset + PCI_REBAR_CAP(i)),
                      PCI_REBAR_CAP_SIZES_MASK);
        bar->resizable_sizes |=
            (((uint64_t)MASK_EXTR(ctrl, PCI_REBAR_CTRL_SIZES_MASK) << 32) /
             ISOLATE_LSB(PCI_REBAR_CAP_SIZES_MASK));

> 
> Further I think you want to truncate the value for 32-bit BARs, such that
> rebar_ctrl_write() would properly reject attempts to set sizes of 4G and
> above for them.
After reading your discussion with Roger, since I will change to re-obtain from 
hardware, so I can do nothing with this comment.

> 
>> --- a/xen/drivers/vpci/vpci.c
>> +++ b/xen/drivers/vpci/vpci.c
>> @@ -232,6 +232,12 @@ void cf_check vpci_hw_write16(
>>      pci_conf_write16(pdev->sbdf, reg, val);
>>  }
>>  
>> +void cf_check vpci_hw_write32(
>> +    const struct pci_dev *pdev, unsigned int reg, uint32_t val, void *data)
>> +{
>> +    pci_conf_write32(pdev->sbdf, reg, val);
>> +}
> 
> This function is being added just to handle writing of a r/o register.
> Can't you better re-use vpci_ignored_write()?
> 
>> --- a/xen/include/xen/pci_regs.h
>> +++ b/xen/include/xen/pci_regs.h
>> @@ -459,6 +459,7 @@
>>  #define PCI_EXT_CAP_ID_ARI  14
>>  #define PCI_EXT_CAP_ID_ATS  15
>>  #define PCI_EXT_CAP_ID_SRIOV        16
>> +#define PCI_EXT_CAP_ID_REBAR        21      /* Resizable BAR */
>>  
>>  /* Advanced Error Reporting */
>>  #define PCI_ERR_UNCOR_STATUS        4       /* Uncorrectable Error Status */
>> @@ -541,6 +542,19 @@
>>  #define  PCI_VNDR_HEADER_REV(x)     (((x) >> 16) & 0xf)
>>  #define  PCI_VNDR_HEADER_LEN(x)     (((x) >> 20) & 0xfff)
>>  
>> +/* Resizable BARs */
>> +#define PCI_REBAR_SIZE_BIAS 20
> 
> I think it would be best if all register definitions came first, and
> auxiliary ones followed afterwards (maybe even separated by a brief
> comment for clarity).
> 
>> +#define PCI_REBAR_CAP(n)            (4 + 8 * (n))   /* capability register 
>> */
>> +#define  PCI_REBAR_CAP_SHIFT                4               /* shift for 
>> supported BAR sizes */
>> +#define PCI_REBAR_CTRL(n)           (8 + 8 * (n))   /* control register */
> 
> Something's odd with the padding here. Please be consistent with the use
> of whitespace (ought to be only hard tabs here afaict).
Sorry, I don't understand how to modify it specifically.

> 
>> +#define  PCI_REBAR_CTRL_BAR_IDX     0x00000007      /* BAR index */
>> +#define  PCI_REBAR_CTRL_NBAR_MASK   0x000000E0      /* # of resizable BARs 
>> */
>> +#define  PCI_REBAR_CTRL_BAR_SIZE    0x00001F00      /* BAR size */
> 
> This field is 6 bits wide in the spec I'm looking at. Or else BAR sizes
> 2^^52 and up can't be encoded.
> 
>> +#define  PCI_REBAR_CTRL_SIZE(v) \
>> +            (1UL << (MASK_EXTR(v, PCI_REBAR_CTRL_BAR_SIZE) \
>> +                     + PCI_REBAR_SIZE_BIAS))
>> +#define  PCI_REBAR_CTRL_SIZES               0xFFFF0000U     /* supported 
>> BAR sizes */
> 
> PCI_REBAR_CAP_SHIFT and PCI_REBAR_CTRL_SIZES don't fit together very well.
> Imo both want representing as masks.
> 
> Jan

-- 
Best regards,
Jiqian Chen.

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.