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

Re: [PATCH] vpci: Add resizable bar support



On Mon, Nov 18, 2024 at 06:06:03AM +0000, Chen, Jiqian wrote:
> On 2024/11/15 19:42, Roger Pau Monné wrote:
> > On Fri, Nov 15, 2024 at 03:04:22AM +0000, Chen, Jiqian wrote:
> >> On 2024/11/15 01:36, Roger Pau Monné wrote:
> >>> On Thu, Nov 14, 2024 at 04:52:18PM +0100, Roger Pau Monné wrote:
> >>>> On Thu, Nov 14, 2024 at 06:11:46AM +0000, Chen, Jiqian wrote:
> >>>>> On 2024/11/13 18:30, Roger Pau Monné wrote:
> >>>>>> On Wed, Nov 13, 2024 at 10:00:33AM +0000, Chen, Jiqian wrote:
> >>>>>>> On 2024/11/13 17:30, Roger Pau Monné wrote:
> >>>>>>>> On Wed, Nov 13, 2024 at 04:00:27PM +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 support resizing has two 
> >>>>>>>>> registers,
> >>>>>>>>> PCI_REBAR_CAP and PCI_REBAR_CTRL, so add these two registers and 
> >>>>>>>>> their
> >>>>>>>>> corresponding handler into vpci.
> >>>>>>>>>
> >>>>>>>>> PCI_REBAR_CAP is RO, only provide reading.
> >>>>>>>>>
> >>>>>>>>> PCI_REBAR_CTRL only has bar size is RW, so add write function to 
> >>>>>>>>> support
> >>>>>>>>> setting the new size.
> >>>>>>>>
> >>>>>>>> I think the logic to handle resizable BAR could be much simpler.  
> >>>>>>>> Some
> >>>>>>>> time ago I've made a patch to add support for it, but due to lack of
> >>>>>>>> hardware on my side to test it I've never submitted it.
> >>>>>>>>
> >>>>>>>> My approach would be to detect the presence of the
> >>>>>>>> PCI_EXT_CAP_ID_REBAR capability in init_header(), and if the
> >>>>>>>> capability is present force the sizing of BARs each time they are
> >>>>>>>> mapped in modify_bars().  I don't think we need to trap accesses to
> >>>>>>>> the capability itself, as resizing can only happen when memory
> >>>>>>>> decoding is not enabled for the device.  It's enough to fetch the 
> >>>>>>>> size
> >>>>>>>> of the BARs ahead of each enabling of memory decoding.
> >>>>>>>>
> >>>>>>>> Note that memory decoding implies mapping the BARs into the p2m, 
> >>>>>>>> which
> >>>>>>>> is already an expensive operation, the extra sizing is unlikely to
> >>>>>>>> make much of a difference performance wise.
> >>>>>>>>
> >>>>>>>> I've found the following on my git tree and rebased on top of 
> >>>>>>>> staging:
> >>>>>>> OK.
> >>>>>>> Do you need me to validate your patch in my environment?
> >>>>>>
> >>>>>> Yes please, I have no way to test it.  Let's see what others think
> >>>>>> about the different approaches.
> >>>>> There are some errors with your method.
> >>>>> I attached the dmesg and xl dmesg logs.
> >>>>> From the dmesg logs, it seems that 0000:03:00.0 has addresse overlap 
> >>>>> with 0000:03:00.1
> >>>>
> >>>> Do you have the output of lspci with the BAR sizes/positions before
> >>>> and after the resizing?
> >>>>
> >>>>>
> >>>>> I think there is a place that needs to be modified regarding your 
> >>>>> method,
> >>>>> although this modification does not help with the above-mentioned 
> >>>>> errors,
> >>>>> it is that whether to support resizing is specific to which bar, rather 
> >>>>> than just determining whether there is a Rebar capability.
> >>>>
> >>>> Do we really need such fine-grained information?  It should be
> >>>> harmless (even if not strictly necessary) to size all BARs on the
> >>>> device before enabling memory decoding, even if some of them do not
> >>>> support resizing.
> >>>>
> >>>> I might have to provide a patch with additional messages to see what's
> >>>> going on.
> >>>
> >>> One nit that I've noticed with the patch I gave you previously is that
> >>> the check for a size change in modify_bars() should be done ahead of
> >>> pci_check_bar(), otherwise the check is possibly using an outdated
> >>> size.
> >>>
> >>> I've also added a debug message to notify when a BAR register is
> >>> written and report the new address.  This is done unconditionally, but
> >>> if you think it's too chatty you can limit to only printing for the
> >>> device that has the ReBAR capability.
> >> Errors are the same.
> >> Attached the dmesg, xl dmesg, patch and lspci output.
> >> I will also continue to debug your method on my side to try to get some 
> >> findings.
> > 
> > Hello,
> > 
> > I've been looking at the output, and it all seems fine, except the
> > 03:00.0 device that becomes broken at some point, note the lspci
> > output lists [virtual] next to the resource sizes.  This means reading
> > for the registers returned 0, so the position and sizes are provided
> > from the internal OS information.
> > 
> > I'm assuming the patch you sent to the list doesn't lead to such errors,
> Yes, the method of my patch doesn't lead to any errors.
> I attached the dmesg, xl dmesg and lspci logs of my method.
> 
> > in which case I can only guess that fetching the size of the
> > BARs in modify_bars() causes issues with the device.
> > 
> > To confirm this, can you try the following patch on top of your original 
> > change?  
> I tried below patch with my original patch, it didn't cause any errors.
> And the lspci showed without the "[virtual]".
> So, unfortunately, it is not related to the fetching size of Bars in 
> modify_bars().

I see, I'm at a loss as to what's wrong with my patch.  Do you have
any additional patches on Xen when testing your or my approach?

I sadly don't have any box with a PCI device that exposes the
resizable BAR capability, so I'm not able to test or debug this.

I would like to understand why my approach doesn't work, as otherwise
I feel like I'm missing how ReBAR is supposed to work.  Anyway, if you
can give a try to the diff below, it's the same patch, but with yet
even more debug messages added.

Thanks, and sorry for keeping you testing it.

Regards, Roger.

diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
index ef6c965c081c..dda42ef0b7ff 100644
--- a/xen/drivers/vpci/header.c
+++ b/xen/drivers/vpci/header.c
@@ -316,6 +316,9 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t 
cmd, bool rom_only)
 
     ASSERT(rw_is_write_locked(&pdev->domain->pci_lock));
 
+    printk("%pp: modify bars cmd: %x rom_only: %d\n",
+           &pdev->sbdf, cmd, rom_only);
+
     /*
      * Create a rangeset per BAR that represents the current device memory
      * region and compare it against all the currently active BAR memory
@@ -346,6 +349,33 @@ static int modify_bars(const struct pci_dev *pdev, 
uint16_t cmd, bool rom_only)
              bar->enabled == !!(cmd & PCI_COMMAND_MEMORY) )
             continue;
 
+        if ( bar->type != VPCI_BAR_ROM && header->bars_resizable &&
+             (cmd & PCI_COMMAND_MEMORY) )
+        {
+            uint64_t addr, size;
+
+            pci_size_mem_bar(pdev->sbdf, PCI_BASE_ADDRESS_0 + i * 4,
+                             &addr, &size, 0);
+
+            printk("%pp: BAR%u ReBAR supported addr %#lx -> %#lx size %#lx -> 
%#lx\n",
+                    &pdev->sbdf, i, bar->addr, addr, bar->size, size);
+
+            if ( bar->addr != addr )
+                printk(XENLOG_G_ERR
+                       "%pp: BAR#%u address mismatch %#lx vs %#lx\n",
+                       &pdev->sbdf, i, bar->addr, addr);
+
+            if ( bar->size != size )
+            {
+                printk(XENLOG_G_DEBUG
+                       "%pp: detected BAR#%u size change (%#lx -> %#lx)\n",
+                       &pdev->sbdf, i, bar->size, size);
+                bar->size = size;
+                end = PFN_DOWN(bar->addr + size - 1);
+                end_guest = PFN_DOWN(bar->guest_addr + size - 1);
+            }
+        }
+
         if ( !pci_check_bar(pdev, _mfn(start), _mfn(end)) )
         {
             printk(XENLOG_G_WARNING
@@ -583,8 +613,6 @@ static void cf_check bar_write(
      */
     if ( bar->enabled )
     {
-        /* If the value written is the current one avoid printing a warning. */
-        if ( val != (uint32_t)(bar->addr >> (hi ? 32 : 0)) )
             gprintk(XENLOG_WARNING,
                     "%pp: ignored BAR %zu write while mapped\n",
                     &pdev->sbdf, bar - pdev->vpci->header.bars + hi);
@@ -601,6 +629,10 @@ static void cf_check bar_write(
     /* Update guest address, so hardware domain BAR is identity mapped. */
     bar->guest_addr = bar->addr;
 
+    printk("%pp: write BAR%zu val: %#x BAR%zu address: %#lx\n",
+           &pdev->sbdf, bar - pdev->vpci->header.bars, val,
+           bar - pdev->vpci->header.bars + hi, bar->addr);
+
     /* Make sure Xen writes back the same value for the BAR RO bits. */
     if ( !hi )
     {
@@ -870,6 +902,9 @@ static int cf_check init_header(struct pci_dev *pdev)
     if ( pdev->ignore_bars )
         return 0;
 
+    header->bars_resizable = pci_find_ext_capability(pdev->sbdf,
+                                                     PCI_EXT_CAP_ID_REBAR);
+
     cmd = pci_conf_read16(pdev->sbdf, PCI_COMMAND);
 
     /*
diff --git a/xen/include/xen/pci_regs.h b/xen/include/xen/pci_regs.h
index 250ba106dbd3..c543a2b86778 100644
--- 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
 
 /* Advanced Error Reporting */
 #define PCI_ERR_UNCOR_STATUS   4       /* Uncorrectable Error Status */
diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h
index 41e7c3bc2791..45ebc1bb3356 100644
--- a/xen/include/xen/vpci.h
+++ b/xen/include/xen/vpci.h
@@ -129,6 +129,8 @@ struct vpci {
          * upon to know whether BARs are mapped into the guest p2m.
          */
         bool bars_mapped      : 1;
+        /* Device has the Resizable BARs capability. */
+        bool bars_resizable   : 1;
         /* FIXME: currently there's no support for SR-IOV. */
     } header;
 



 


Rackspace

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