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

Re: [RFC PATCH 07/10] xen: pci: add per-device locking



On Wed, 31 Aug 2022, Volodymyr Babchuk wrote:
> Spinlock in struct pci_device will be used to protect access to device
> itself. Right now it is used mostly by MSI code.
> 
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>

There are 2 instances of:

    BUG_ON(list_empty(&dev->msi_list));

in xen/arch/x86/msi.c:__pci_disable_msi and
xen/arch/x86/msi.c:__pci_disable_msix which are not protected by
pcidev_lock. However list_empty needs to be protected. (pci_disable_msi
can also be called from xen/arch/x86/irq.c where it is not surrounded by
pcidev_lock.)

Given that they are BUG_ON, I wonder if we could remove them instead of
adding locks there. It would make things simpler.


> ---
>  xen/arch/x86/hvm/vmsi.c       |  6 +++++-
>  xen/arch/x86/msi.c            | 16 ++++++++++++++++
>  xen/drivers/passthrough/msi.c |  8 +++++++-
>  xen/drivers/passthrough/pci.c |  2 ++
>  xen/include/xen/pci.h         | 12 ++++++++++++
>  5 files changed, 42 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c
> index 7fb1075673..c9e5f279c5 100644
> --- a/xen/arch/x86/hvm/vmsi.c
> +++ b/xen/arch/x86/hvm/vmsi.c
> @@ -203,10 +203,14 @@ static struct msi_desc *msixtbl_addr_to_desc(
>  
>      nr_entry = (addr - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
>  
> +    pcidev_lock(entry->pdev);
>      list_for_each_entry( desc, &entry->pdev->msi_list, list )
>          if ( desc->msi_attrib.type == PCI_CAP_ID_MSIX &&
> -             desc->msi_attrib.entry_nr == nr_entry )
> +             desc->msi_attrib.entry_nr == nr_entry ) {
> +         pcidev_unlock(entry->pdev);

code style


>              return desc;
> +     }
> +    pcidev_unlock(entry->pdev);
>  
>      return NULL;
>  }
> diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c
> index bccaccb98b..6b62c4f452 100644
> --- a/xen/arch/x86/msi.c
> +++ b/xen/arch/x86/msi.c
> @@ -389,6 +389,7 @@ static bool msi_set_mask_bit(struct irq_desc *desc, bool 
> host, bool guest)
>      default:
>          return 0;
>      }
> +

spurious change


>      entry->msi_attrib.host_masked = host;
>      entry->msi_attrib.guest_masked = guest;
>  
> @@ -585,12 +586,17 @@ static struct msi_desc *find_msi_entry(struct pci_dev 
> *dev,
>  {
>      struct msi_desc *entry;
>  
> +    pcidev_lock(dev);
>      list_for_each_entry( entry, &dev->msi_list, list )
>      {
>          if ( entry->msi_attrib.type == cap_id &&
>               (irq == -1 || entry->irq == irq) )
> +     {
> +         pcidev_unlock(dev);
>              return entry;
> +     }
>      }
> +    pcidev_unlock(dev);
>  
>      return NULL;
>  }
> @@ -661,7 +667,9 @@ static int msi_capability_init(struct pci_dev *dev,
>          maskbits |= ~(uint32_t)0 >> (32 - dev->msi_maxvec);
>          pci_conf_write32(dev->sbdf, mpos, maskbits);
>      }
> +    pcidev_lock(dev);
>      list_add_tail(&entry->list, &dev->msi_list);
> +    pcidev_unlock(dev);
>  
>      *desc = entry;
>      /* Restore the original MSI enabled bits  */
> @@ -946,7 +954,9 @@ static int msix_capability_init(struct pci_dev *dev,
>  
>       pcidev_get(dev);
>  
> +     pcidev_lock(dev);
>          list_add_tail(&entry->list, &dev->msi_list);
> +     pcidev_unlock(dev);
>          *desc = entry;
>      }
>  
> @@ -1231,11 +1241,13 @@ static void msi_free_irqs(struct pci_dev* dev)
>  {
>      struct msi_desc *entry, *tmp;
>  
> +    pcidev_lock(dev);
>      list_for_each_entry_safe( entry, tmp, &dev->msi_list, list )
>      {
>          pci_disable_msi(entry);
>          msi_free_irq(entry);
>      }
> +    pcidev_unlock(dev);
>  }
>  
>  void pci_cleanup_msi(struct pci_dev *pdev)
> @@ -1354,6 +1366,7 @@ int pci_restore_msi_state(struct pci_dev *pdev)
>      if ( ret )
>          return ret;
>  
> +    pcidev_lock(pdev);
>      list_for_each_entry_safe( entry, tmp, &pdev->msi_list, list )
>      {
>          unsigned int i = 0, nr = 1;
> @@ -1371,6 +1384,7 @@ int pci_restore_msi_state(struct pci_dev *pdev)
>              dprintk(XENLOG_ERR, "Restore MSI for %pp entry %u not set?\n",
>                      &pdev->sbdf, i);
>              spin_unlock_irqrestore(&desc->lock, flags);
> +         pcidev_unlock(pdev);
>              if ( type == PCI_CAP_ID_MSIX )
>                  pci_conf_write16(pdev->sbdf, msix_control_reg(pos),
>                                   control & ~PCI_MSIX_FLAGS_ENABLE);
> @@ -1393,6 +1407,7 @@ int pci_restore_msi_state(struct pci_dev *pdev)
>              if ( unlikely(!memory_decoded(pdev)) )
>              {
>                  spin_unlock_irqrestore(&desc->lock, flags);
> +             pcidev_unlock(pdev);
>                  pci_conf_write16(pdev->sbdf, msix_control_reg(pos),
>                                   control & ~PCI_MSIX_FLAGS_ENABLE);
>                  return -ENXIO;
> @@ -1438,6 +1453,7 @@ int pci_restore_msi_state(struct pci_dev *pdev)
>          pci_conf_write16(pdev->sbdf, msix_control_reg(pos),
>                           control | PCI_MSIX_FLAGS_ENABLE);
>  
> +    pcidev_unlock(pdev);
>      return 0;
>  }
>  
> diff --git a/xen/drivers/passthrough/msi.c b/xen/drivers/passthrough/msi.c
> index ce1a450f6f..98f4d2721a 100644
> --- a/xen/drivers/passthrough/msi.c
> +++ b/xen/drivers/passthrough/msi.c
> @@ -22,6 +22,7 @@ int pdev_msi_init(struct pci_dev *pdev)
>  {
>      unsigned int pos;
>  
> +    pcidev_lock(pdev);
>      INIT_LIST_HEAD(&pdev->msi_list);
>  
>      pos = pci_find_cap_offset(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
> @@ -41,7 +42,10 @@ int pdev_msi_init(struct pci_dev *pdev)
>          uint16_t ctrl;
>  
>          if ( !msix )
> -            return -ENOMEM;
> +        {
> +             pcidev_unlock(pdev);
> +             return -ENOMEM;
> +        }
>  
>          spin_lock_init(&msix->table_lock);
>  
> @@ -51,6 +55,8 @@ int pdev_msi_init(struct pci_dev *pdev)
>          pdev->msix = msix;
>      }
>  
> +    pcidev_unlock(pdev);
> +
>      return 0;
>  }
>  
> diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
> index c8da80b981..c83397211b 100644
> --- a/xen/drivers/passthrough/pci.c
> +++ b/xen/drivers/passthrough/pci.c
> @@ -1383,7 +1383,9 @@ static int cf_check _dump_pci_devices(struct pci_seg 
> *pseg, void *arg)
>              printk("%pd", pdev->domain);
>          printk(" - node %-3d refcnt %d", (pdev->node != NUMA_NO_NODE) ? 
> pdev->node : -1,
>                 atomic_read(&pdev->refcnt));
> +        pcidev_lock(pdev);
>          pdev_dump_msi(pdev);
> +        pcidev_unlock(pdev);
>          printk("\n");
>      }
>      spin_unlock(&pseg->alldevs_lock);
> diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
> index e71a180ef3..d0a7339d84 100644
> --- a/xen/include/xen/pci.h
> +++ b/xen/include/xen/pci.h
> @@ -106,6 +106,8 @@ struct pci_dev {
>      uint8_t msi_maxvec;
>      uint8_t phantom_stride;
>  
> +    /* Device lock */
> +    spinlock_t lock;
>      nodeid_t node; /* NUMA node */
>  
>      /* Device to be quarantined, don't automatically re-assign to dom0 */
> @@ -235,6 +237,16 @@ int msixtbl_pt_register(struct domain *, struct pirq *, 
> uint64_t gtable);
>  void msixtbl_pt_unregister(struct domain *, struct pirq *);
>  void msixtbl_pt_cleanup(struct domain *d);
>  
> +static inline void pcidev_lock(struct pci_dev *pdev)
> +{
> +    spin_lock(&pdev->lock);
> +}
> +
> +static inline void pcidev_unlock(struct pci_dev *pdev)
> +{
> +    spin_unlock(&pdev->lock);
> +}
> +
>  #ifdef CONFIG_HVM
>  int arch_pci_clean_pirqs(struct domain *d);
>  #else
> -- 
> 2.36.1
> 



 


Rackspace

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