[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [v4][PATCH 04/19] xen/passthrough: extend hypercall to support rdm reservation policy
This patch extends the existing hypercall to support rdm reservation policy. We return error or just throw out a warning message depending on whether the policy is "strict" or "relaxed" when reserving RDM regions in pfn space. Note in some special cases, e.g. add a device to hwdomain, and remove a device from user domain, 'relaxed' is fine enough since this is always safe to hwdomain. CC: Tim Deegan <tim@xxxxxxx> CC: Keir Fraser <keir@xxxxxxx> CC: Jan Beulich <jbeulich@xxxxxxxx> CC: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> CC: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx> CC: Aravind Gopalakrishnan <Aravind.Gopalakrishnan@xxxxxxx> CC: Ian Campbell <ian.campbell@xxxxxxxxxx> CC: Stefano Stabellini <stefano.stabellini@xxxxxxxxxx> CC: Yang Zhang <yang.z.zhang@xxxxxxxxx> CC: Kevin Tian <kevin.tian@xxxxxxxxx> Signed-off-by: Tiejun Chen <tiejun.chen@xxxxxxxxx> --- v4: * Add code comments to describer why we fix to set a policy flag in some cases like adding a device to hwdomain, and removing a device from user domain. * Avoid using fixed width types for the parameter of set_identity_p2m_entry() * Fix one judging condition domctl->u.assign_device.flag == XEN_DOMCTL_DEV_NO_RDM -> domctl->u.assign_device.flag != XEN_DOMCTL_DEV_NO_RDM * Add to range check the flag passed to make future extensions possible (and to avoid ambiguity on what out of range values would mean). xen/arch/x86/mm/p2m.c | 7 ++++-- xen/drivers/passthrough/amd/pci_amd_iommu.c | 3 ++- xen/drivers/passthrough/arm/smmu.c | 2 +- xen/drivers/passthrough/device_tree.c | 11 +++++++++- xen/drivers/passthrough/pci.c | 15 +++++++++---- xen/drivers/passthrough/vtd/iommu.c | 34 ++++++++++++++++++++++------- xen/include/asm-x86/p2m.h | 2 +- xen/include/public/domctl.h | 5 +++++ xen/include/xen/iommu.h | 2 +- 9 files changed, 62 insertions(+), 19 deletions(-) diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 7e50db6..a3e07d3 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -901,7 +901,7 @@ int set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, } int set_identity_p2m_entry(struct domain *d, unsigned long gfn, - p2m_access_t p2ma) + p2m_access_t p2ma, unsigned int flag) { p2m_type_t p2mt; p2m_access_t a; @@ -923,7 +923,10 @@ int set_identity_p2m_entry(struct domain *d, unsigned long gfn, ret = 0; else { - ret = -EBUSY; + if ( flag == XEN_DOMCTL_DEV_RDM_STRICT ) + ret = -EBUSY; + else + ret = 0; printk(XENLOG_G_WARNING "Cannot setup identity map d%d:%lx," " gfn already mapped to %lx.\n", diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c b/xen/drivers/passthrough/amd/pci_amd_iommu.c index e83bb35..920b35a 100644 --- a/xen/drivers/passthrough/amd/pci_amd_iommu.c +++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c @@ -394,7 +394,8 @@ static int reassign_device(struct domain *source, struct domain *target, } static int amd_iommu_assign_device(struct domain *d, u8 devfn, - struct pci_dev *pdev) + struct pci_dev *pdev, + u32 flag) { struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(pdev->seg); int bdf = PCI_BDF2(pdev->bus, devfn); diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c index 6cc4394..9a667e9 100644 --- a/xen/drivers/passthrough/arm/smmu.c +++ b/xen/drivers/passthrough/arm/smmu.c @@ -2605,7 +2605,7 @@ static void arm_smmu_destroy_iommu_domain(struct iommu_domain *domain) } static int arm_smmu_assign_dev(struct domain *d, u8 devfn, - struct device *dev) + struct device *dev, u32 flag) { struct iommu_domain *domain; struct arm_smmu_xen_domain *xen_domain; diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c index 5d3842a..e286f1e 100644 --- a/xen/drivers/passthrough/device_tree.c +++ b/xen/drivers/passthrough/device_tree.c @@ -52,7 +52,8 @@ int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev) goto fail; } - rc = hd->platform_ops->assign_device(d, 0, dt_to_dev(dev)); + rc = hd->platform_ops->assign_device(d, 0, dt_to_dev(dev), + XEN_DOMCTL_DEV_NO_RDM); if ( rc ) goto fail; @@ -148,6 +149,14 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d, if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_DT ) break; + if ( domctl->u.assign_device.flag != XEN_DOMCTL_DEV_NO_RDM ) + { + printk(XENLOG_G_ERR "XEN_DOMCTL_assign_device: assign \"%s\"" + " to dom%u failed (%d) since we don't support RDM.\n", + dt_node_full_name(dev), d->domain_id, ret); + break; + } + if ( unlikely(d->is_dying) ) { ret = -EINVAL; diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index e30be43..0845bd2 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -1335,7 +1335,7 @@ static int device_assigned(u16 seg, u8 bus, u8 devfn) return pdev ? 0 : -EBUSY; } -static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn) +static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) { struct hvm_iommu *hd = domain_hvm_iommu(d); struct pci_dev *pdev; @@ -1371,7 +1371,7 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn) pdev->fault.count = 0; - if ( (rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev))) ) + if ( (rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag)) ) goto done; for ( ; pdev->phantom_stride; rc = 0 ) @@ -1379,7 +1379,7 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn) devfn += pdev->phantom_stride; if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) ) break; - rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev)); + rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag); if ( rc ) printk(XENLOG_G_WARNING "d%d: assign %04x:%02x:%02x.%u failed (%d)\n", d->domain_id, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), @@ -1496,6 +1496,7 @@ int iommu_do_pci_domctl( { u16 seg; u8 bus, devfn; + u32 flag; int ret = 0; uint32_t machine_sbdf; @@ -1577,9 +1578,15 @@ int iommu_do_pci_domctl( seg = machine_sbdf >> 16; bus = PCI_BUS(machine_sbdf); devfn = PCI_DEVFN2(machine_sbdf); + flag = domctl->u.assign_device.flag; + if ( flag > XEN_DOMCTL_DEV_RDM_STRICT ) + { + ret = -EINVAL; + break; + } ret = device_assigned(seg, bus, devfn) ?: - assign_device(d, seg, bus, devfn); + assign_device(d, seg, bus, devfn, flag); if ( ret == -ERESTART ) ret = hypercall_create_continuation(__HYPERVISOR_domctl, "h", u_domctl); diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 202b2d0..59d5fd7 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -1807,7 +1807,8 @@ static void iommu_set_pgd(struct domain *d) } static int rmrr_identity_mapping(struct domain *d, bool_t map, - const struct acpi_rmrr_unit *rmrr) + const struct acpi_rmrr_unit *rmrr, + u32 flag) { unsigned long base_pfn = rmrr->base_address >> PAGE_SHIFT_4K; unsigned long end_pfn = PAGE_ALIGN_4K(rmrr->end_address) >> PAGE_SHIFT_4K; @@ -1855,7 +1856,7 @@ static int rmrr_identity_mapping(struct domain *d, bool_t map, while ( base_pfn < end_pfn ) { - int err = set_identity_p2m_entry(d, base_pfn, p2m_access_rw); + int err = set_identity_p2m_entry(d, base_pfn, p2m_access_rw, flag); if ( err ) return err; @@ -1898,7 +1899,13 @@ static int intel_iommu_add_device(u8 devfn, struct pci_dev *pdev) PCI_BUS(bdf) == pdev->bus && PCI_DEVFN2(bdf) == devfn ) { - ret = rmrr_identity_mapping(pdev->domain, 1, rmrr); + /* + * RMRR is always reserved on e820 so either of flag + * is fine for hardware domain and here we'd like to + * pass XEN_DOMCTL_DEV_RDM_RELAXED. + */ + ret = rmrr_identity_mapping(pdev->domain, 1, rmrr, + XEN_DOMCTL_DEV_RDM_RELAXED); if ( ret ) dprintk(XENLOG_ERR VTDPREFIX, "d%d: RMRR mapping failed\n", pdev->domain->domain_id); @@ -1939,7 +1946,8 @@ static int intel_iommu_remove_device(u8 devfn, struct pci_dev *pdev) PCI_DEVFN2(bdf) != devfn ) continue; - rmrr_identity_mapping(pdev->domain, 0, rmrr); + rmrr_identity_mapping(pdev->domain, 0, rmrr, + XEN_DOMCTL_DEV_RDM_RELAXED); } return domain_context_unmap(pdev->domain, devfn, pdev); @@ -2098,7 +2106,12 @@ static void __hwdom_init setup_hwdom_rmrr(struct domain *d) spin_lock(&pcidevs_lock); for_each_rmrr_device ( rmrr, bdf, i ) { - ret = rmrr_identity_mapping(d, 1, rmrr); + /* + * RMRR is always reserved on e820 so either of flag + * is fine for hardware domain and here we'd like to + * pass XEN_DOMCTL_DEV_RDM_RELAXED. + */ + ret = rmrr_identity_mapping(d, 1, rmrr, XEN_DOMCTL_DEV_RDM_RELAXED); if ( ret ) dprintk(XENLOG_ERR VTDPREFIX, "IOMMU: mapping reserved region failed\n"); @@ -2241,7 +2254,12 @@ static int reassign_device_ownership( PCI_BUS(bdf) == pdev->bus && PCI_DEVFN2(bdf) == devfn ) { - ret = rmrr_identity_mapping(source, 0, rmrr); + /* + * Any RMRR flag is always ignored when remove a device, + * so just pass XEN_DOMCTL_DEV_RDM_RELAXED. + */ + ret = rmrr_identity_mapping(source, 0, rmrr, + XEN_DOMCTL_DEV_RDM_RELAXED); if ( ret != -ENOENT ) return ret; } @@ -2265,7 +2283,7 @@ static int reassign_device_ownership( } static int intel_iommu_assign_device( - struct domain *d, u8 devfn, struct pci_dev *pdev) + struct domain *d, u8 devfn, struct pci_dev *pdev, u32 flag) { struct acpi_rmrr_unit *rmrr; int ret = 0, i; @@ -2294,7 +2312,7 @@ static int intel_iommu_assign_device( PCI_BUS(bdf) == bus && PCI_DEVFN2(bdf) == devfn ) { - ret = rmrr_identity_mapping(d, 1, rmrr); + ret = rmrr_identity_mapping(d, 1, rmrr, flag); if ( ret ) { reassign_device_ownership(d, hardware_domain, devfn, pdev); diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h index 538a1cf..408109f 100644 --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -545,7 +545,7 @@ int clear_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn); /* Set identity addresses in the p2m table (for pass-through) */ int set_identity_p2m_entry(struct domain *d, unsigned long gfn, - p2m_access_t p2ma); + p2m_access_t p2ma, unsigned int flag); /* Add foreign mapping to the guest's p2m table. */ int p2m_add_foreign(struct domain *tdom, unsigned long fgfn, diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index bc45ea5..2f9e40e 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -478,6 +478,11 @@ struct xen_domctl_assign_device { XEN_GUEST_HANDLE_64(char) path; /* path to the device tree node */ } dt; } u; + /* IN */ +#define XEN_DOMCTL_DEV_NO_RDM 0 +#define XEN_DOMCTL_DEV_RDM_RELAXED 1 +#define XEN_DOMCTL_DEV_RDM_STRICT 2 + uint32_t flag; /* flag of assigned device */ }; typedef struct xen_domctl_assign_device xen_domctl_assign_device_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_assign_device_t); diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index e2f584d..02b2b02 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -140,7 +140,7 @@ struct iommu_ops { int (*add_device)(u8 devfn, device_t *dev); int (*enable_device)(device_t *dev); int (*remove_device)(u8 devfn, device_t *dev); - int (*assign_device)(struct domain *, u8 devfn, device_t *dev); + int (*assign_device)(struct domain *, u8 devfn, device_t *dev, u32 flag); int (*reassign_device)(struct domain *s, struct domain *t, u8 devfn, device_t *dev); #ifdef HAS_PCI -- 1.9.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |