[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v6 6/9] xen/arm: smmuv3: Add PCI devices support for SMMUv3
From: Rahul Singh <rahul.singh@xxxxxxx> Signed-off-by: Rahul Singh <rahul.singh@xxxxxxx> Signed-off-by: Stewart Hildebrand <stewart.hildebrand@xxxxxxx> --- v5->v6: * check for hardware_domain == NULL (dom0less test case) * locking: assign pdev->domain before list_add() v4->v5: * deassign from hwdom * add TODO regarding locking * fixup after dropping ("xen/arm: Move is_protected flag to struct device") v3->v4: * no change v2->v3: * rebase * invoke iommu_add_pci_sideband_ids() from add_device hook v1->v2: * ignore add_device/assign_device/reassign_device calls for phantom functions (i.e. devfn != pdev->devfn) downstream->v1: * rebase * move 2 replacements of s/dt_device_set_protected(dev_to_dt(dev))/device_set_protected(dev)/ from this commit to ("xen/arm: Move is_protected flag to struct device") so as to not break ability to bisect * adjust patch title (remove stray space) * arm_smmu_(de)assign_dev: return error instead of crashing system * remove arm_smmu_remove_device() stub * update condition in arm_smmu_reassign_dev * style fixup (cherry picked from commit 7ed6c3ab250d899fe6e893a514278e406a2893e8 from the downstream branch poc/pci-passthrough from https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc.git) --- xen/drivers/passthrough/arm/smmu-v3.c | 131 ++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 10 deletions(-) diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c index cdbb505134b7..ac6532e29b02 100644 --- a/xen/drivers/passthrough/arm/smmu-v3.c +++ b/xen/drivers/passthrough/arm/smmu-v3.c @@ -1469,14 +1469,34 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid) } /* Forward declaration */ static struct arm_smmu_device *arm_smmu_get_by_dev(const struct device *dev); +static int arm_smmu_assign_dev(struct domain *d, u8 devfn, struct device *dev, + u32 flag); +static int arm_smmu_deassign_dev(struct domain *d, uint8_t devfn, + struct device *dev); static int arm_smmu_add_device(u8 devfn, struct device *dev) { int i, ret; struct arm_smmu_device *smmu; struct arm_smmu_master *master; - struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + struct iommu_fwspec *fwspec; + +#ifdef CONFIG_HAS_PCI + if ( dev_is_pci(dev) ) + { + struct pci_dev *pdev = dev_to_pci(dev); + int ret; + + if ( devfn != pdev->devfn ) + return 0; + + ret = iommu_add_pci_sideband_ids(pdev); + if ( ret < 0 ) + iommu_fwspec_free(dev); + } +#endif + fwspec = dev_iommu_fwspec_get(dev); if (!fwspec) return -ENODEV; @@ -1521,17 +1541,35 @@ static int arm_smmu_add_device(u8 devfn, struct device *dev) */ arm_smmu_enable_pasid(master); - if (dt_device_is_protected(dev_to_dt(dev))) { - dev_err(dev, "Already added to SMMUv3\n"); - return -EEXIST; - } + if ( !dev_is_pci(dev) ) + { + if (dt_device_is_protected(dev_to_dt(dev))) { + dev_err(dev, "Already added to SMMUv3\n"); + return -EEXIST; + } - /* Let Xen know that the master device is protected by an IOMMU. */ - dt_device_set_protected(dev_to_dt(dev)); + /* Let Xen know that the master device is protected by an IOMMU. */ + dt_device_set_protected(dev_to_dt(dev)); + } dev_info(dev, "Added master device (SMMUv3 %s StreamIds %u)\n", dev_name(fwspec->iommu_dev), fwspec->num_ids); +#ifdef CONFIG_HAS_PCI + if ( dev_is_pci(dev) ) + { + struct pci_dev *pdev = dev_to_pci(dev); + + /* + * During PHYSDEVOP_pci_device_add, Xen does not assign the + * device, so we must do it here. + */ + ret = arm_smmu_assign_dev(pdev->domain, devfn, dev, 0); + if (ret) + goto err_free_master; + } +#endif + return 0; err_free_master: @@ -2621,6 +2659,61 @@ static int arm_smmu_assign_dev(struct domain *d, u8 devfn, struct arm_smmu_domain *smmu_domain; struct arm_smmu_xen_domain *xen_domain = dom_iommu(d)->arch.priv; +#ifdef CONFIG_HAS_PCI + if ( dev_is_pci(dev) && !is_hardware_domain(d) ) + { + struct pci_dev *pdev = dev_to_pci(dev); + + printk(XENLOG_INFO "Assigning device %04x:%02x:%02x.%u to dom%d\n", + pdev->seg, pdev->bus, PCI_SLOT(devfn), + PCI_FUNC(devfn), d->domain_id); + + if ( devfn != pdev->devfn || pdev->domain == d ) + return 0; + + ASSERT(pcidevs_locked()); + + /* TODO: acquire pci_lock */ +#if 0 + write_lock(&pdev->domain->pci_lock); +#endif + list_del(&pdev->domain_list); +#if 0 + write_unlock(&pdev->domain->pci_lock); +#endif + + pdev->domain = d; + +#if 0 + write_lock(&d->pci_lock); +#endif + list_add(&pdev->domain_list, &d->pdev_list); +#if 0 + write_unlock(&d->pci_lock); +#endif + + if ( hardware_domain ) + { + io_domain = arm_smmu_get_domain(hardware_domain, dev); + + /* + * Xen may not deassign the device from hwdom before + * assigning it elsewhere. + */ + if ( io_domain ) + { + ret = arm_smmu_deassign_dev(hardware_domain, devfn, dev); + if ( ret ) + return ret; + } + } + + /* dom_io is used as a sentinel for quarantined devices */ + if ( d == dom_io ) + return 0; + } +#endif + spin_lock(&xen_domain->lock); /* @@ -2654,7 +2747,7 @@ out: return ret; } -static int arm_smmu_deassign_dev(struct domain *d, struct device *dev) +static int arm_smmu_deassign_dev(struct domain *d, uint8_t devfn, struct device *dev) { struct iommu_domain *io_domain = arm_smmu_get_domain(d, dev); struct arm_smmu_xen_domain *xen_domain = dom_iommu(d)->arch.priv; @@ -2666,6 +2759,24 @@ static int arm_smmu_deassign_dev(struct domain *d, struct device *dev) return -ESRCH; } +#ifdef CONFIG_HAS_PCI + if ( dev_is_pci(dev) ) + { + struct pci_dev *pdev = dev_to_pci(dev); + + printk(XENLOG_INFO "Deassigning device %04x:%02x:%02x.%u from dom%d\n", + pdev->seg, pdev->bus, PCI_SLOT(devfn), + PCI_FUNC(devfn), d->domain_id); + + if ( devfn != pdev->devfn ) + return 0; + + /* dom_io is used as a sentinel for quarantined devices */ + if ( d == dom_io ) + return 0; + } +#endif + spin_lock(&xen_domain->lock); arm_smmu_detach_dev(master); @@ -2685,13 +2796,13 @@ static int arm_smmu_reassign_dev(struct domain *s, struct domain *t, int ret = 0; /* Don't allow remapping on other domain than hwdom */ - if ( t && !is_hardware_domain(t) ) + if ( t && !is_hardware_domain(t) && (t != dom_io) ) return -EPERM; if (t == s) return 0; - ret = arm_smmu_deassign_dev(s, dev); + ret = arm_smmu_deassign_dev(s, devfn, dev); if (ret) return ret; -- 2.42.0
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |