From: Luca Fancellu <luca.fance...@arm.com> Currently pci_add_device is called from hypercalls requested by Dom0 to add pci devices and when the device has no domain associated with it, it is assumed that hardware_domain is the owner.
On the dom0less scenario, the enumeration is performed by the firmware and Xen at boot time might want to assign some pci devices to guests, so it has to firstly add the device and then assign it to the final guest. Modify pci_add_device to have the owner domain passed as a parameter to the function, so that when it is called from the hypercall the owner would be the caller domain, otherwise when Xen is calling it, it would be another domain since hw domain could not be there (dom0less guests without Dom0 use case). Signed-off-by: Luca Fancellu <luca.fance...@arm.com> Signed-off-by: Mykyta Poturai <mykyta_potu...@epam.com> --- (cherry picked from commit f0c85d9043f7c9402e85b73361c8a13c683428ca from the downstream branch poc/pci-passthrough from https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc.git) v1->v2: * remove dom_io check * fixup pci_add_device parameters * use current->domain instead of hardware_domain changes since cherry-pick: * s/hardware_domain/d/ in some write_unlock calls in xen/drivers/passthrough/pci.c --- xen/arch/x86/physdev.c | 9 ++++----- xen/drivers/passthrough/pci.c | 29 +++++++++++++++++++---------- xen/drivers/pci/physdev.c | 3 ++- xen/include/xen/pci.h | 5 +++-- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 4dfa1c0191..04d179e81b 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -446,8 +446,8 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) if ( copy_from_guest(&manage_pci, arg, 1) != 0 ) break; - ret = pci_add_device(0, manage_pci.bus, manage_pci.devfn, - NULL, NUMA_NO_NODE); + ret = pci_add_device(0, manage_pci.bus, manage_pci.devfn, NULL, + NUMA_NO_NODE, current->domain); break; } @@ -477,9 +477,8 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) pdev_info.is_virtfn = manage_pci_ext.is_virtfn; pdev_info.physfn.bus = manage_pci_ext.physfn.bus; pdev_info.physfn.devfn = manage_pci_ext.physfn.devfn; - ret = pci_add_device(0, manage_pci_ext.bus, - manage_pci_ext.devfn, - &pdev_info, NUMA_NO_NODE); + ret = pci_add_device(0, manage_pci_ext.bus, manage_pci_ext.devfn, + &pdev_info, NUMA_NO_NODE, current->domain); break; } diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index 3edcfa8a04..09b424d1b3 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -654,8 +654,9 @@ unsigned int pci_size_mem_bar(pci_sbdf_t sbdf, unsigned int pos, return is64bits ? 2 : 1; } -int pci_add_device(u16 seg, u8 bus, u8 devfn, - const struct pci_dev_info *info, nodeid_t node) +int pci_add_device(uint16_t seg, uint8_t bus, uint8_t devfn, + const struct pci_dev_info *info, nodeid_t node, + struct domain *d) { struct pci_seg *pseg; struct pci_dev *pdev; @@ -663,6 +664,9 @@ int pci_add_device(u16 seg, u8 bus, u8 devfn, const char *type; int ret; + if ( !d ) + return -EINVAL; + if ( !info ) type = "device"; else if ( info->is_virtfn ) @@ -767,9 +771,9 @@ int pci_add_device(u16 seg, u8 bus, u8 devfn, ret = 0; if ( !pdev->domain ) { - pdev->domain = hardware_domain; - write_lock(&hardware_domain->pci_lock); - list_add(&pdev->domain_list, &hardware_domain->pdev_list); + pdev->domain = d; + write_lock(&d->pci_lock); + list_add(&pdev->domain_list, &pdev->domain->pdev_list); /* * For devices not discovered by Xen during boot, add vPCI handlers @@ -779,25 +783,30 @@ int pci_add_device(u16 seg, u8 bus, u8 devfn, if ( ret ) { list_del(&pdev->domain_list); - write_unlock(&hardware_domain->pci_lock); + write_unlock(&d->pci_lock); pdev->domain = NULL; printk(XENLOG_ERR "Setup of vPCI failed: %d\n", ret); goto out; } - write_unlock(&hardware_domain->pci_lock); + write_unlock(&d->pci_lock); ret = iommu_add_device(pdev); if ( ret ) { - write_lock(&hardware_domain->pci_lock); + write_lock(&d->pci_lock); vpci_deassign_device(pdev); list_del(&pdev->domain_list); - write_unlock(&hardware_domain->pci_lock); + write_unlock(&d->pci_lock); pdev->domain = NULL; goto out; } } - else + else if ( pdev->domain == d ) iommu_enable_device(pdev); + else + { + ret = -EINVAL; + goto out; + } pci_enable_acs(pdev); diff --git a/xen/drivers/pci/physdev.c b/xen/drivers/pci/physdev.c index d46501b884..cd3a36903b 100644 --- a/xen/drivers/pci/physdev.c +++ b/xen/drivers/pci/physdev.c @@ -50,7 +50,8 @@ ret_t pci_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) } #endif - ret = pci_add_device(add.seg, add.bus, add.devfn, &pdev_info, node); + ret = pci_add_device(add.seg, add.bus, add.devfn, + &pdev_info, node, current->domain); break; } diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h index 130c2a8c1a..89f3281b7c 100644 --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -226,8 +226,9 @@ void setup_hwdom_pci_devices(struct domain *d, int pci_release_devices(struct domain *d); int pci_add_segment(u16 seg); const unsigned long *pci_get_ro_map(u16 seg); -int pci_add_device(u16 seg, u8 bus, u8 devfn, - const struct pci_dev_info *info, nodeid_t node); +int pci_add_device(uint16_t seg, uint8_t bus, uint8_t devfn, + const struct pci_dev_info *info, nodeid_t node, + struct domain *d); int pci_remove_device(u16 seg, u8 bus, u8 devfn); int pci_ro_device(int seg, int bus, int devfn); int pci_hide_device(unsigned int seg, unsigned int bus, unsigned int devfn); -- 2.34.1