From mboxrd@z Thu Jan 1 00:00:00 1970 From: Tiejun Chen Subject: [v7][PATCH 03/16] xen/passthrough: extend hypercall to support rdm reservation policy Date: Thu, 9 Jul 2015 13:33:54 +0800 Message-ID: <1436420047-25356-4-git-send-email-tiejun.chen@intel.com> References: <1436420047-25356-1-git-send-email-tiejun.chen@intel.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1436420047-25356-1-git-send-email-tiejun.chen@intel.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xen.org Cc: Kevin Tian , Keir Fraser , Jan Beulich , Andrew Cooper , Tim Deegan , Aravind Gopalakrishnan , Suravee Suthikulpanit , Yang Zhang , Stefano Stabellini , Ian Campbell List-Id: xen-devel@lists.xenproject.org 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 CC: Keir Fraser CC: Jan Beulich CC: Andrew Cooper CC: Suravee Suthikulpanit CC: Aravind Gopalakrishnan CC: Ian Campbell CC: Stefano Stabellini CC: Yang Zhang CC: Kevin Tian Signed-off-by: Tiejun Chen --- v6 ~ v7: * Nothing is changed. v5: * Just leave one bit XEN_DOMCTL_DEV_RDM_RELAXED as our flag, so "0" means "strict" and "1" means "relaxed". * So make DT device ignore the flag field * Improve the code comments 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 | 3 ++- xen/drivers/passthrough/pci.c | 15 ++++++++--- xen/drivers/passthrough/vtd/iommu.c | 40 +++++++++++++++++++++++------ xen/include/asm-x86/p2m.h | 2 +- xen/include/public/domctl.h | 3 +++ xen/include/xen/iommu.h | 2 +- 9 files changed, 58 insertions(+), 19 deletions(-) diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 99a26ca..47785dc 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_RELAXED ) + ret = 0; + else + ret = -EBUSY; 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..7ff79f8 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)); + /* The flag field doesn't matter to DT device. */ + rc = hd->platform_ops->assign_device(d, 0, dt_to_dev(dev), 0); if ( rc ) goto fail; diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index e30be43..6e23fc6 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_RELAXED ) + { + 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 8415958..56f5911 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,14 @@ 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); + /* + * Here means we're add a device to the hardware domain + * so actually 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 +1947,12 @@ static int intel_iommu_remove_device(u8 devfn, struct pci_dev *pdev) PCI_DEVFN2(bdf) != devfn ) continue; - rmrr_identity_mapping(pdev->domain, 0, rmrr); + /* + * Any flag is nothing to clear these mappings so here + * its always safe to set XEN_DOMCTL_DEV_RDM_RELAXED. + */ + rmrr_identity_mapping(pdev->domain, 0, rmrr, + XEN_DOMCTL_DEV_RDM_RELAXED); } return domain_context_unmap(pdev->domain, devfn, pdev); @@ -2098,7 +2111,13 @@ 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); + /* + * Here means we're add a device to the hardware domain + * so actually 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 +2260,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 +2289,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 +2318,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 190a286..68da0a9 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); #define clear_identity_p2m_entry(d, gfn, page_order) \ guest_physmap_remove_page(d, gfn, gfn, page_order) diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index bc45ea5..bca25c9 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -478,6 +478,9 @@ struct xen_domctl_assign_device { XEN_GUEST_HANDLE_64(char) path; /* path to the device tree node */ } dt; } u; + /* IN */ +#define XEN_DOMCTL_DEV_RDM_RELAXED 1 + 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