diff -r 28083093cc5d xen/arch/x86/domctl.c --- a/xen/arch/x86/domctl.c Sat May 24 09:45:37 2008 +0100 +++ b/xen/arch/x86/domctl.c Tue May 27 15:45:34 2008 +0200 @@ -526,6 +526,45 @@ long arch_do_domctl( } break; + case XEN_DOMCTL_get_device_group: + { + struct domain *d; + u32 max_sdevs; + u8 bus, devfn; + XEN_GUEST_HANDLE_64(uint32) sdevs; + int num_sdevs; + + ret = -ENOSYS; + if ( !iommu_enabled ) + break; + + ret = -EINVAL; + if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) + break; + + bus = (domctl->u.get_device_group.machine_bdf >> 16) & 0xff; + devfn = (domctl->u.get_device_group.machine_bdf >> 8) & 0xff; + max_sdevs = domctl->u.get_device_group.max_sdevs; + sdevs = domctl->u.get_device_group.sdev_array; + + num_sdevs = iommu_get_device_group(d, bus, devfn, sdevs, max_sdevs); + if ( num_sdevs < 0 ) + { + dprintk(XENLOG_ERR, "iommu_get_device_group() failed!\n"); + ret = -EFAULT; + domctl->u.get_device_group.num_sdevs = 0; + } + else + { + ret = 0; + domctl->u.get_device_group.num_sdevs = num_sdevs; + } + if ( copy_to_guest(u_domctl, domctl, 1) ) + ret = -EFAULT; + rcu_unlock_domain(d); + } + break; + case XEN_DOMCTL_test_assign_device: { u8 bus, devfn; diff -r 28083093cc5d xen/drivers/passthrough/amd/pci_amd_iommu.c --- a/xen/drivers/passthrough/amd/pci_amd_iommu.c Sat May 24 09:45:37 2008 +0100 +++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c Tue May 27 15:45:34 2008 +0200 @@ -635,6 +635,16 @@ static void amd_iommu_return_device( reassign_device(s, t, bus, devfn); } +static int amd_iommu_group_id(u8 bus, u8 devfn) +{ + int rt; + int bdf = (bus << 8) | devfn; + rt = ( bdf < ivrs_bdf_entries ) ? + ivrs_mappings[bdf].dte_requestor_id : + bdf; + return rt; +} + struct iommu_ops amd_iommu_ops = { .init = amd_iommu_domain_init, .assign_device = amd_iommu_assign_device, @@ -642,4 +652,5 @@ struct iommu_ops amd_iommu_ops = { .map_page = amd_iommu_map_page, .unmap_page = amd_iommu_unmap_page, .reassign_device = amd_iommu_return_device, + .get_device_group_id = amd_iommu_group_id, }; diff -r 28083093cc5d xen/drivers/passthrough/iommu.c --- a/xen/drivers/passthrough/iommu.c Sat May 24 09:45:37 2008 +0100 +++ b/xen/drivers/passthrough/iommu.c Tue May 27 15:45:34 2008 +0200 @@ -16,6 +16,7 @@ #include #include #include +#include extern struct iommu_ops intel_iommu_ops; extern struct iommu_ops amd_iommu_ops; @@ -216,7 +217,41 @@ static int iommu_setup(void) } __initcall(iommu_setup); - +int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn, + XEN_GUEST_HANDLE_64(uint32) buf, int max_sdevs) +{ + struct hvm_iommu *hd = domain_hvm_iommu(d); + struct pci_dev *pdev; + int group_id, sdev_id; + u32 bdf; + int i = 0; + struct iommu_ops *ops = hd->platform_ops; + + if ( !iommu_enabled || !ops || !ops->get_device_group_id ) + return 0; + + group_id = ops->get_device_group_id(bus, devfn); + + list_for_each_entry(pdev, + &(dom0->arch.hvm_domain.hvm_iommu.pdev_list), list) + { + if ( (pdev->bus == bus) && (pdev->devfn == devfn) ) + continue; + + sdev_id = ops->get_device_group_id(pdev->bus, pdev->devfn); + if ( (sdev_id == group_id) && (i < max_sdevs) ) + { + bdf = 0; + bdf |= (pdev->bus & 0xff) << 16; + bdf |= (pdev->devfn & 0xff) << 8; + if ( unlikely(copy_to_guest_offset(buf, i, &bdf, 1)) ) + return -1; + i++; + } + } + + return i; +} /* * Local variables: * mode: C diff -r 28083093cc5d xen/drivers/passthrough/vtd/iommu.c --- a/xen/drivers/passthrough/vtd/iommu.c Sat May 24 09:45:37 2008 +0100 +++ b/xen/drivers/passthrough/vtd/iommu.c Tue May 27 15:45:34 2008 +0200 @@ -1946,6 +1946,7 @@ struct iommu_ops intel_iommu_ops = { .map_page = intel_iommu_map_page, .unmap_page = intel_iommu_unmap_page, .reassign_device = reassign_device_ownership, + .get_device_group_id = NULL, }; /* diff -r 28083093cc5d xen/include/public/domctl.h --- a/xen/include/public/domctl.h Sat May 24 09:45:37 2008 +0100 +++ b/xen/include/public/domctl.h Tue May 27 15:45:34 2008 +0200 @@ -448,6 +448,16 @@ typedef struct xen_domctl_assign_device typedef struct xen_domctl_assign_device xen_domctl_assign_device_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_assign_device_t); +/* Retrieve sibling devices infomation of machine_bdf */ +#define XEN_DOMCTL_get_device_group 50 +struct xen_domctl_get_device_group { + uint32_t machine_bdf; /* IN */ + uint32_t max_sdevs; /* IN */ + uint32_t num_sdevs; /* OUT */ + XEN_GUEST_HANDLE_64(uint32) sdev_array; /* OUT */ +}; +typedef struct xen_domctl_get_device_group xen_domctl_get_device_group_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_get_device_group_t); /* Pass-through interrupts: bind real irq -> hvm devfn. */ #define XEN_DOMCTL_bind_pt_irq 38 @@ -619,6 +629,7 @@ struct xen_domctl { struct xen_domctl_hvmcontext hvmcontext; struct xen_domctl_address_size address_size; struct xen_domctl_sendtrigger sendtrigger; + struct xen_domctl_get_device_group get_device_group; struct xen_domctl_assign_device assign_device; struct xen_domctl_bind_pt_irq bind_pt_irq; struct xen_domctl_memory_mapping memory_mapping; diff -r 28083093cc5d xen/include/xen/iommu.h --- a/xen/include/xen/iommu.h Sat May 24 09:45:37 2008 +0100 +++ b/xen/include/xen/iommu.h Tue May 27 15:45:34 2008 +0200 @@ -59,6 +59,8 @@ int device_assigned(u8 bus, u8 devfn); int device_assigned(u8 bus, u8 devfn); int assign_device(struct domain *d, u8 bus, u8 devfn); void deassign_device(struct domain *d, u8 bus, u8 devfn); +int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn, + XEN_GUEST_HANDLE_64(uint32) buf, int max_sdevs); void reassign_device_ownership(struct domain *source, struct domain *target, u8 bus, u8 devfn); @@ -95,6 +97,7 @@ struct iommu_ops { int (*unmap_page)(struct domain *d, unsigned long gfn); void (*reassign_device)(struct domain *s, struct domain *t, u8 bus, u8 devfn); + int (*get_device_group_id)(u8 bus, u8 devfn); }; #endif /* _IOMMU_H_ */