|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] RE: [PATCH v2] pci/ats: do not allow broken devices to be assigned to guests
> From: Roger Pau Monne <roger.pau@xxxxxxxxxx>
> Sent: Friday, February 25, 2022 12:37 AM
>
> Introduce a new field to mark devices as broken: having it set
> prevents the device from being assigned to guests. Use the field in
> order to mark ATS devices that have failed a flush as broken, thus
> preventing them to be assigned to any guest.
>
> This allows the device IOMMU context entry to be cleaned up properly,
> as calling _pci_hide_device will just change the ownership of the
> device, but the IOMMU context entry of the device would be left as-is.
> It would also leak a Domain ID, as removing the device from it's
> previous owner will allow releasing the DID used by the device without
> having cleaned up the context entry.
>
> Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx>
> ---
> Cc: Oleksandr Andrushchenko <andr2000@xxxxxxxxx>
> ---
> Changes since v1:
> - Allow assigning broken devices to dom_io or the hardware domain.
> ---
> xen/drivers/passthrough/pci.c | 11 +++++++----
> xen/drivers/passthrough/vtd/qinval.c | 8 +++++++-
> xen/include/xen/pci.h | 3 +++
> 3 files changed, 17 insertions(+), 5 deletions(-)
>
> diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
> index 70b6684981..91b43a3f04 100644
> --- a/xen/drivers/passthrough/pci.c
> +++ b/xen/drivers/passthrough/pci.c
> @@ -501,7 +501,7 @@ static void free_pdev(struct pci_seg *pseg, struct
> pci_dev *pdev)
> xfree(pdev);
> }
>
> -static void _pci_hide_device(struct pci_dev *pdev)
> +static void __init _pci_hide_device(struct pci_dev *pdev)
> {
> if ( pdev->domain )
> return;
> @@ -1487,6 +1487,11 @@ static int assign_device(struct domain *d, u16 seg,
> u8 bus, u8 devfn, u32 flag)
> ASSERT(pdev && (pdev->domain == hardware_domain ||
> pdev->domain == dom_io));
>
> + /* Do not allow broken devices to be assigned to guests. */
> + rc = -EBADF;
> + if ( pdev->broken && d != hardware_domain && d != dom_io )
> + goto done;
> +
> rc = pdev_msix_assign(d, pdev);
> if ( rc )
> goto done;
> @@ -1585,9 +1590,7 @@ void iommu_dev_iotlb_flush_timeout(struct
> domain *d, struct pci_dev *pdev)
> return;
> }
>
> - list_del(&pdev->domain_list);
> - pdev->domain = NULL;
> - _pci_hide_device(pdev);
> + pdev->broken = true;
>
> if ( !d->is_shutting_down && printk_ratelimit() )
> printk(XENLOG_ERR "dom%d: ATS device %pp flush failed\n",
> diff --git a/xen/drivers/passthrough/vtd/qinval.c
> b/xen/drivers/passthrough/vtd/qinval.c
> index 9f291f47e5..510961a203 100644
> --- a/xen/drivers/passthrough/vtd/qinval.c
> +++ b/xen/drivers/passthrough/vtd/qinval.c
> @@ -227,7 +227,7 @@ static int __must_check dev_invalidate_sync(struct
> vtd_iommu *iommu,
>
> ASSERT(iommu->qinval_maddr);
> rc = queue_invalidate_wait(iommu, 0, 1, 1, 1);
> - if ( rc == -ETIMEDOUT )
> + if ( rc == -ETIMEDOUT && !pdev->broken )
> {
> struct domain *d = rcu_lock_domain_by_id(did_to_domain_id(iommu,
> did));
>
> @@ -241,6 +241,12 @@ static int __must_check dev_invalidate_sync(struct
> vtd_iommu *iommu,
> iommu_dev_iotlb_flush_timeout(d, pdev);
> rcu_unlock_domain(d);
> }
> + else if ( rc == -ETIMEDOUT )
> + /*
> + * The device is already marked as broken, ignore the error in order
> to
> + * allow {de,}assign to succeed.
> + */
> + rc = 0;
>
> return rc;
> }
> diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
> index b6d7e454f8..02b31f7259 100644
> --- a/xen/include/xen/pci.h
> +++ b/xen/include/xen/pci.h
> @@ -108,6 +108,9 @@ struct pci_dev {
> /* Device with errata, ignore the BARs. */
> bool ignore_bars;
>
> + /* Device misbehaving, prevent assigning it to guests. */
> + bool broken;
> +
> enum pdev_type {
> DEV_TYPE_PCI_UNKNOWN,
> DEV_TYPE_PCIe_ENDPOINT,
> --
> 2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |