|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [RFC PATCH 03/10] xen: pci: introduce ats_list_lock
On Wed, 31 Aug 2022, Volodymyr Babchuk wrote:
> ATS subsystem has own list of PCI devices. As we are going to remove
> global pcidevs_lock() in favor to more granular locking, we need to
> ensure that this list is protected somehow. To do this, we need to add
> additional lock for each IOMMU, as list to be protected is also part
> of IOMMU.
>
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
> ---
> xen/drivers/passthrough/amd/iommu.h | 1 +
> xen/drivers/passthrough/amd/iommu_detect.c | 1 +
> xen/drivers/passthrough/amd/pci_amd_iommu.c | 8 ++++++++
> xen/drivers/passthrough/pci.c | 1 +
> xen/drivers/passthrough/vtd/iommu.c | 11 +++++++++++
> xen/drivers/passthrough/vtd/iommu.h | 1 +
> xen/drivers/passthrough/vtd/qinval.c | 3 +++
> xen/drivers/passthrough/vtd/x86/ats.c | 3 +++
> 8 files changed, 29 insertions(+)
>
> diff --git a/xen/drivers/passthrough/amd/iommu.h
> b/xen/drivers/passthrough/amd/iommu.h
> index 8bc3c35b1b..edd6eb52b3 100644
> --- a/xen/drivers/passthrough/amd/iommu.h
> +++ b/xen/drivers/passthrough/amd/iommu.h
> @@ -106,6 +106,7 @@ struct amd_iommu {
> int enabled;
>
> struct list_head ats_devices;
> + spinlock_t ats_list_lock;
> };
>
> struct ivrs_unity_map {
> diff --git a/xen/drivers/passthrough/amd/iommu_detect.c
> b/xen/drivers/passthrough/amd/iommu_detect.c
> index 2317fa6a7d..1d6f4f2168 100644
> --- a/xen/drivers/passthrough/amd/iommu_detect.c
> +++ b/xen/drivers/passthrough/amd/iommu_detect.c
> @@ -160,6 +160,7 @@ int __init amd_iommu_detect_one_acpi(
> }
>
> spin_lock_init(&iommu->lock);
> + spin_lock_init(&iommu->ats_list_lock);
> INIT_LIST_HEAD(&iommu->ats_devices);
>
> iommu->seg = ivhd_block->pci_segment_group;
> diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c
> b/xen/drivers/passthrough/amd/pci_amd_iommu.c
> index 64c016491d..955f3af57a 100644
> --- a/xen/drivers/passthrough/amd/pci_amd_iommu.c
> +++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c
> @@ -276,7 +276,11 @@ static int __must_check amd_iommu_setup_domain_device(
> !pci_ats_enabled(iommu->seg, bus, pdev->devfn) )
> {
> if ( devfn == pdev->devfn )
> + {
> + spin_lock(&iommu->ats_list_lock);
> enable_ats_device(pdev, &iommu->ats_devices);
> + spin_unlock(&iommu->ats_list_lock);
code style
> + }
>
> amd_iommu_flush_iotlb(devfn, pdev, INV_IOMMU_ALL_PAGES_ADDRESS, 0);
> }
> @@ -416,7 +420,11 @@ static void amd_iommu_disable_domain_device(const struct
> domain *domain,
>
> if ( pci_ats_device(iommu->seg, bus, pdev->devfn) &&
> pci_ats_enabled(iommu->seg, bus, pdev->devfn) )
> + {
> + spin_lock(&iommu->ats_list_lock);
> disable_ats_device(pdev);
> + spin_unlock(&iommu->ats_list_lock);
code style
> + }
>
> BUG_ON ( iommu->dev_table.buffer == NULL );
> req_id = get_dma_requestor_id(iommu->seg, PCI_BDF(bus, devfn));
> diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
> index 2dfa1c2875..b5db5498a1 100644
> --- a/xen/drivers/passthrough/pci.c
> +++ b/xen/drivers/passthrough/pci.c
> @@ -1641,6 +1641,7 @@ void iommu_dev_iotlb_flush_timeout(struct domain *d,
> struct pci_dev *pdev)
> {
> pcidevs_lock();
>
> + /* iommu->ats_list_lock is taken by the caller of this function */
This is a locking inversion. In all other places we take pcidevs_lock
first, then ats_list_lock lock. For instance look at
xen/drivers/passthrough/pci.c:deassign_device that is called with
pcidevs_locked and then calls iommu_call(... reassign_device ...) which
ends up taking ats_list_lock.
This is the only exception. I think we need to move the
spin_lock(ats_list_lock) from qinval.c to here.
> disable_ats_device(pdev);
>
> ASSERT(pdev->domain);
> diff --git a/xen/drivers/passthrough/vtd/iommu.c
> b/xen/drivers/passthrough/vtd/iommu.c
> index fff1442265..42661f22f4 100644
> --- a/xen/drivers/passthrough/vtd/iommu.c
> +++ b/xen/drivers/passthrough/vtd/iommu.c
> @@ -1281,6 +1281,7 @@ int __init iommu_alloc(struct acpi_drhd_unit *drhd)
> spin_lock_init(&iommu->lock);
> spin_lock_init(&iommu->register_lock);
> spin_lock_init(&iommu->intremap.lock);
> + spin_lock_init(&iommu->ats_list_lock);
>
> iommu->drhd = drhd;
> drhd->iommu = iommu;
> @@ -1769,7 +1770,11 @@ static int domain_context_mapping(struct domain
> *domain, u8 devfn,
> if ( ret > 0 )
> ret = 0;
> if ( !ret && devfn == pdev->devfn && ats_device(pdev, drhd) > 0 )
> + {
> + spin_lock(&drhd->iommu->ats_list_lock);
> enable_ats_device(pdev, &drhd->iommu->ats_devices);
> + spin_unlock(&drhd->iommu->ats_list_lock);
> + }
>
> break;
>
> @@ -1977,7 +1982,11 @@ static const struct acpi_drhd_unit
> *domain_context_unmap(
> domain, &PCI_SBDF(seg, bus, devfn));
> ret = domain_context_unmap_one(domain, iommu, bus, devfn);
> if ( !ret && devfn == pdev->devfn && ats_device(pdev, drhd) > 0 )
> + {
> + spin_lock(&iommu->ats_list_lock);
> disable_ats_device(pdev);
> + spin_unlock(&iommu->ats_list_lock);
> + }
>
> break;
>
> @@ -2374,7 +2383,9 @@ static int cf_check intel_iommu_enable_device(struct
> pci_dev *pdev)
> if ( ret <= 0 )
> return ret;
>
> + spin_lock(&drhd->iommu->ats_list_lock);
> ret = enable_ats_device(pdev, &drhd->iommu->ats_devices);
> + spin_unlock(&drhd->iommu->ats_list_lock);
>
> return ret >= 0 ? 0 : ret;
> }
> diff --git a/xen/drivers/passthrough/vtd/iommu.h
> b/xen/drivers/passthrough/vtd/iommu.h
> index 78aa8a96f5..2a7a4c1b58 100644
> --- a/xen/drivers/passthrough/vtd/iommu.h
> +++ b/xen/drivers/passthrough/vtd/iommu.h
> @@ -506,6 +506,7 @@ struct vtd_iommu {
> } flush;
>
> struct list_head ats_devices;
> + spinlock_t ats_list_lock;
> unsigned long *pseudo_domid_map; /* "pseudo" domain id bitmap */
> unsigned long *domid_bitmap; /* domain id bitmap */
> domid_t *domid_map; /* domain id mapping array */
> diff --git a/xen/drivers/passthrough/vtd/qinval.c
> b/xen/drivers/passthrough/vtd/qinval.c
> index 4f9ad136b9..6e876348db 100644
> --- a/xen/drivers/passthrough/vtd/qinval.c
> +++ b/xen/drivers/passthrough/vtd/qinval.c
> @@ -238,7 +238,10 @@ static int __must_check dev_invalidate_sync(struct
> vtd_iommu *iommu,
> if ( d == NULL )
> return rc;
>
> + spin_lock(&iommu->ats_list_lock);
> iommu_dev_iotlb_flush_timeout(d, pdev);
> + spin_unlock(&iommu->ats_list_lock);
code style
> rcu_unlock_domain(d);
> }
> else if ( rc == -ETIMEDOUT )
> diff --git a/xen/drivers/passthrough/vtd/x86/ats.c
> b/xen/drivers/passthrough/vtd/x86/ats.c
> index 04d702b1d6..55e991183b 100644
> --- a/xen/drivers/passthrough/vtd/x86/ats.c
> +++ b/xen/drivers/passthrough/vtd/x86/ats.c
> @@ -117,6 +117,7 @@ int dev_invalidate_iotlb(struct vtd_iommu *iommu, u16 did,
> if ( !ecap_dev_iotlb(iommu->ecap) )
> return ret;
>
> + spin_lock(&iommu->ats_list_lock);
> list_for_each_entry_safe( pdev, temp, &iommu->ats_devices, ats.list )
> {
> bool_t sbit;
> @@ -155,12 +156,14 @@ int dev_invalidate_iotlb(struct vtd_iommu *iommu, u16
> did,
> break;
> default:
> dprintk(XENLOG_WARNING VTDPREFIX, "invalid vt-d flush type\n");
> + spin_unlock(&iommu->ats_list_lock);
code style
> return -EOPNOTSUPP;
> }
>
> if ( !ret )
> ret = rc;
> }
> + spin_unlock(&iommu->ats_list_lock);
>
> return ret;
> }
> --
> 2.36.1
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |