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

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


  • To: Roger Pau Monné <roger.pau@xxxxxxxxxx>
  • From: "Chen, Jiqian" <Jiqian.Chen@xxxxxxx>
  • Date: Tue, 17 Dec 2024 08:20:21 +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=qJx8eTxv7F/NiWwUFXPBLNcFqpJE/1gAiI4qYypjeW4=; b=ZJgs+uGrI+ZtLQxsYIp4EjkBXlxpxWqfuUsSv7aR8Di+BzxdId6lnAFyntrp8LDw9rIjWyHYprFb8dGGQKqkcM/Xera+j2GsPgOpKDgLVQLXO8QYXWRRYHVeR1N6JPpXR/34y8m14ZdD7pPcXR5H7F57toX46MBszOhz0bf84zgkfFnQou1U2QOuLbL2qtIBIQJFy/BIKvQZo4Km9VkXUuADXSIqLwNkHoXC6QAFL+Scp8T+jXONg7bFbB95ohA7ISjSOql1MwAlupKMvsOHtuLloJ2gKPQ81VVL1cmUQfOpBiZw6fjEqURhdb4xJ9k7WQ2BbvefFl9A1tPLEyiGdA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Ml2U7Ql8V06RJLAlRB3KQchl/aFzGXqGavzjOApLAhHio9bqEeTo9/YCGkKvi86p/rGlhtGIIsSVwGhnq2Ds4H9c0gA6YcW28Np281U+peOr/1LWJxYK+vDh0YNKZkgeTWSJ7AF2M/0WbWs3qMM8kVtXRwf32ge0UaG6TMT1oQgWkbHeFu+drzoJwCe3q8svsCyrSxT8Vdaw9xh+dsHY5fkitPl7KMeyIyV0nU+JKBB9xWf/8gGLthnO9/rfhb2gFnbZu5p9zptAMM28rBkM7CRnnL2FMdLzLM6OKd28olEI/saao11yuVRq5rtzudqkbXmIuF0P81ItajXtN8tfBw==
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=amd.com;
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Julien Grall <julien@xxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, "Huang, Ray" <Ray.Huang@xxxxxxx>, "Chen, Jiqian" <Jiqian.Chen@xxxxxxx>
  • Delivery-date: Tue, 17 Dec 2024 08:20:48 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHbTSHk/+a4JH45i0iSPkOFUem08bLor0CAgAHzfgA=
  • Thread-topic: [PATCH v3] vpci: Add resizable bar support

On 2024/12/16 18:24, Roger Pau Monné wrote:
> On Fri, Dec 13, 2024 at 01:42:32PM +0800, Jiqian Chen wrote:
>> Some devices, like discrete GPU of amd, support resizable bar
>> capability, but vpci of Xen doesn't support this feature, so
>> they fail to resize bars and then cause probing failure.
>>
>> According to PCIe spec, each bar that supports resizing has
>> two registers, PCI_REBAR_CAP and PCI_REBAR_CTRL. So, add
>> handlers for them to support resizing the size of BARs.
>>
>> Signed-off-by: Jiqian Chen <Jiqian.Chen@xxxxxxx>
>> ---
>> Hi all,
>> v2->v3 changes:
>> * Used "bar->enabled" to replace "pci_conf_read16(pdev->sbdf, PCI_COMMAND) & 
>> PCI_COMMAND_MEMORY",
>>   and added comments why it needs this check.
>> * Added "!is_hardware_domain(pdev->domain)" check in init_rebar() to return 
>> EOPNOTSUPP for domUs.
>> * Moved BAR type and index check into init_rebar(), then only need to check 
>> once.
>> * Added 'U' suffix for macro PCI_REBAR_CAP_SIZES.
>> * Added macro PCI_REBAR_SIZE_BIAS to represent 20.
>>
>> TODO: need to hide ReBar capability from hardware domain when init_rebar() 
>> fails.
>>
>> Best regards,
>> Jiqian Chen.
>>
>> v1->v2 changes:
>> * In rebar_ctrl_write, to check if memory decoding is enabled, and added
>>   some checks for the type of Bar.
>> * Added vpci_hw_write32 to handle PCI_REBAR_CAP's write, since there is
>>   no write limitation of dom0.
>> * And has many other minor modifications as well.
>> ---
>>  xen/drivers/vpci/Makefile  |   2 +-
>>  xen/drivers/vpci/rebar.c   | 130 +++++++++++++++++++++++++++++++++++++
>>  xen/drivers/vpci/vpci.c    |   6 ++
>>  xen/include/xen/pci_regs.h |  13 ++++
>>  xen/include/xen/vpci.h     |   2 +
>>  5 files changed, 152 insertions(+), 1 deletion(-)
>>  create mode 100644 xen/drivers/vpci/rebar.c
>>
>> diff --git a/xen/drivers/vpci/Makefile b/xen/drivers/vpci/Makefile
>> index 1a1413b93e76..a7c8a30a8956 100644
>> --- a/xen/drivers/vpci/Makefile
>> +++ b/xen/drivers/vpci/Makefile
>> @@ -1,2 +1,2 @@
>> -obj-y += vpci.o header.o
>> +obj-y += vpci.o header.o rebar.o
>>  obj-$(CONFIG_HAS_PCI_MSI) += msi.o msix.o
>> diff --git a/xen/drivers/vpci/rebar.c b/xen/drivers/vpci/rebar.c
>> new file mode 100644
>> index 000000000000..39432c3271a4
>> --- /dev/null
>> +++ b/xen/drivers/vpci/rebar.c
>> @@ -0,0 +1,130 @@
>> +/* 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/hypercall.h>
> 
> Do you really need the hypercall header?
I will change to <xen/sched.h> since is_hardware_domain() needs.

> 
>> +#include <xen/vpci.h>
>> +
>> +static void cf_check rebar_ctrl_write(const struct pci_dev *pdev,
>> +                                      unsigned int reg,
>> +                                      uint32_t val,
>> +                                      void *data)
>> +{
>> +    uint64_t size;
>> +    struct vpci_bar *bar = data;
>> +
>> +    size = PCI_REBAR_CTRL_SIZE(val);
>> +    if ( bar->enabled )
>> +    {
>> +        if ( size == bar->size )
>> +            return;
>> +
>> +        /*
> 
> Indentation
> 
>> +        * 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.
>> +        */
>> +        gprintk(XENLOG_ERR,
>> +                "%pp: refuse to resize BAR with memory decoding enabled\n",
>> +                &pdev->sbdf);
>> +        return;
>> +    }
> 
> Nit: just realized this could be made shorter:
> 
> 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) &
>> +           MASK_EXTR(pci_conf_read32(pdev->sbdf,
>> +                                     reg - PCI_REBAR_CTRL + PCI_REBAR_CAP),
>> +                                     PCI_REBAR_CAP_SIZES)) )
> 
> Would it be possible to cache this information.  It's my understand
> the supported sizes won't change, and hence Xen could read and cache
> them in init_rebar() to avoid repeated reads to the register on every
> access?
Thanks, I will change in next version.
Then I think I need to add a parameter to struct vpci_bar.
Maybe I can name it "resizable_sizes" ?

> 
>> +        gprintk(XENLOG_WARNING,
>> +                "%pp: new size %#lx is not supported by hardware\n",
>> +                &pdev->sbdf, size);
>> +
>> +    bar->size = size;
>> +    bar->addr = 0;
>> +    bar->guest_addr = 0;
>> +    pci_conf_write32(pdev->sbdf, reg, val);
>> +}
>> +
>> +static int cf_check init_rebar(struct pci_dev *pdev)
>> +{
>> +    uint32_t ctrl;
>> +    unsigned int rebar_offset, nbars;
>> +
>> +    rebar_offset = pci_find_ext_capability(pdev->sbdf, 
>> PCI_EXT_CAP_ID_REBAR);
> 
> You can do the init at definition:
> 
>     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("ReBar is not supported for domUs\n");
> 
> This needs a bit more information IMO:
> 
> printk(XENLOG_ERR
>        "%pd %pp: resizable BAR capability not supported for unprivileged 
> domains\n",
>        pdev->domain, &pdev->sbdf);
OK, will change.
If the length of code of printing more than 80 characters in one line, is it 
fine?

> 
> I wonder if this should instead be an XSM check, but that would
> require a new XSM hook to process permissions for PCI capabilities.
> 
>> +        return -EOPNOTSUPP;
>> +    }
>> +
>> +    ctrl = pci_conf_read32(pdev->sbdf, rebar_offset + PCI_REBAR_CTRL);
>> +    nbars = MASK_EXTR(ctrl, PCI_REBAR_CTRL_NBAR_MASK);
>> +
>> +    for ( unsigned int i = 0; i < nbars; i++, rebar_offset += 
>> PCI_REBAR_CTRL )
>> +    {
>> +        int rc;
>> +        unsigned int index;
>> +        struct vpci_bar *bars = pdev->vpci->header.bars;
>> +
>> +        index = pci_conf_read32(pdev->sbdf, rebar_offset + PCI_REBAR_CTRL) &
>> +                PCI_REBAR_CTRL_BAR_IDX;
> 
> You could initialize index at definition.
> 
>> +
>> +        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("%pp: BAR number %u in REBAR_CTRL register is too big\n",
>> +                   &pdev->sdf, index);
> 
> XENLOG_ERR, plus we could print the domain the device was assigned to
> (pdev->domain).
> 
>> +            return -EINVAL;
>> +        }
>> +
>> +        if ( bars[index].type != VPCI_BAR_MEM64_LO &&
>> +             bars[index].type != VPCI_BAR_MEM32 )
>> +        {
>> +            printk("%pp: BAR%u is not in memory space\n", &pdev->sbdf, 
>> index);
>> +            return -EINVAL;
>> +        }
>> +
>> +        rc = vpci_add_register(pdev->vpci, vpci_hw_read32, vpci_hw_write32,
>> +                               rebar_offset + PCI_REBAR_CAP, 4, NULL);
>> +        if ( rc )
>> +        {
>> +            printk("%pp: add register for PCI_REBAR_CAP failed (rc=%d)\n",
>> +                   &pdev->sbdf, rc);
>> +            return rc;
>> +        }
>> +
>> +        rc = vpci_add_register(pdev->vpci, vpci_hw_read32, rebar_ctrl_write,
>> +                               rebar_offset + PCI_REBAR_CTRL, 4,
>> +                               &bars[index]);
>> +        if ( rc )
>> +        {
>> +            printk("%pp: add register for PCI_REBAR_CTRL failed %d\n",
>> +                   &pdev->sbdf, rc);
>> +            return rc;
>> +        }
> 
> All the log messages above need the XENLOG_ERR prefix, plus possibly
> printing the assigned domain.
Will change according to your all comments, thank you!

> 
> Thanks, Roger.

-- 
Best regards,
Jiqian Chen.

 


Rackspace

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