Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen-pciback: allow compiling on other archs than x86

Xen-pciback driver was designed to be built for x86 only. But it
can also be used by other architectures, e.g. Arm.

Currently PCI backend implements multiple functionalities at a time,
such as:
1. It is used as a database for assignable PCI devices, e.g. xl
pci-assignable-{add|remove|list} manipulates that list. So, whenever
the toolstack needs to know which PCI devices can be passed through
it reads that from the relevant sysfs entries of the pciback.
2. It is used to hold the unbound PCI devices list, e.g. when passing
through a PCI device it needs to be unbound from the relevant device
driver and bound to pciback (strictly speaking it is not required
that the device is bound to pciback, but pciback is again used as a
database of the passed through PCI devices, so we can re-bind the
devices back to their original drivers when guest domain shuts down)
3. Device reset for the devices being passed through
4. Para-virtualised use-cases support

The para-virtualised part of the driver is not always needed as some
architectures, e.g. Arm or x86 PVH Dom0, are not using backend-frontend
model for PCI device passthrough.

For such use-cases make the very first step in splitting the
xen-pciback driver into two parts: Xen PCI stub and PCI PV backend
drivers.

For that add new configuration options CONFIG_XEN_PCI_STUB and
CONFIG_XEN_PCIDEV_STUB, so the driver can be limited in its
functionality, e.g. no support for para-virtualised scenario.
x86 platform will continue using CONFIG_XEN_PCIDEV_BACKEND for the
fully featured backend driver.

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Signed-off-by: Anastasiia Lukianenko <anastasiia_lukianenko@epam.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
Reviewed-by: Juergen Gross <jgross@suse.com>
Link: https://lore.kernel.org/r/20211028143620.144936-1-andr2000@gmail.com
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>

authored by

Oleksandr Andrushchenko and committed by
Boris Ostrovsky
a67efff2 e453f872

+156 -100
-19
arch/x86/include/asm/xen/pci.h
··· 22 22 return -1; 23 23 } 24 24 #endif 25 - #ifdef CONFIG_XEN_DOM0 26 - int xen_find_device_domain_owner(struct pci_dev *dev); 27 - int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain); 28 - int xen_unregister_device_domain_owner(struct pci_dev *dev); 29 - #else 30 - static inline int xen_find_device_domain_owner(struct pci_dev *dev) 31 - { 32 - return -1; 33 - } 34 - static inline int xen_register_device_domain_owner(struct pci_dev *dev, 35 - uint16_t domain) 36 - { 37 - return -1; 38 - } 39 - static inline int xen_unregister_device_domain_owner(struct pci_dev *dev) 40 - { 41 - return -1; 42 - } 43 - #endif 44 25 45 26 #if defined(CONFIG_PCI_MSI) 46 27 #if defined(CONFIG_PCI_XEN)
+1 -75
arch/x86/pci/xen.c
··· 23 23 24 24 #include <xen/features.h> 25 25 #include <xen/events.h> 26 + #include <xen/pci.h> 26 27 #include <asm/xen/pci.h> 27 28 #include <asm/xen/cpuid.h> 28 29 #include <asm/apic.h> ··· 586 585 } 587 586 #endif 588 587 589 - #ifdef CONFIG_XEN_DOM0 590 - 591 - struct xen_device_domain_owner { 592 - domid_t domain; 593 - struct pci_dev *dev; 594 - struct list_head list; 595 - }; 596 - 597 - static DEFINE_SPINLOCK(dev_domain_list_spinlock); 598 - static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list); 599 - 600 - static struct xen_device_domain_owner *find_device(struct pci_dev *dev) 601 - { 602 - struct xen_device_domain_owner *owner; 603 - 604 - list_for_each_entry(owner, &dev_domain_list, list) { 605 - if (owner->dev == dev) 606 - return owner; 607 - } 608 - return NULL; 609 - } 610 - 611 - int xen_find_device_domain_owner(struct pci_dev *dev) 612 - { 613 - struct xen_device_domain_owner *owner; 614 - int domain = -ENODEV; 615 - 616 - spin_lock(&dev_domain_list_spinlock); 617 - owner = find_device(dev); 618 - if (owner) 619 - domain = owner->domain; 620 - spin_unlock(&dev_domain_list_spinlock); 621 - return domain; 622 - } 623 - EXPORT_SYMBOL_GPL(xen_find_device_domain_owner); 624 - 625 - int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain) 626 - { 627 - struct xen_device_domain_owner *owner; 628 - 629 - owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL); 630 - if (!owner) 631 - return -ENODEV; 632 - 633 - spin_lock(&dev_domain_list_spinlock); 634 - if (find_device(dev)) { 635 - spin_unlock(&dev_domain_list_spinlock); 636 - kfree(owner); 637 - return -EEXIST; 638 - } 639 - owner->domain = domain; 640 - owner->dev = dev; 641 - list_add_tail(&owner->list, &dev_domain_list); 642 - spin_unlock(&dev_domain_list_spinlock); 643 - return 0; 644 - } 645 - EXPORT_SYMBOL_GPL(xen_register_device_domain_owner); 646 - 647 - int xen_unregister_device_domain_owner(struct pci_dev *dev) 648 - { 649 - struct xen_device_domain_owner *owner; 650 - 651 - spin_lock(&dev_domain_list_spinlock); 652 - owner = find_device(dev); 653 - if (!owner) { 654 - spin_unlock(&dev_domain_list_spinlock); 655 - return -ENODEV; 656 - } 657 - list_del(&owner->list); 658 - spin_unlock(&dev_domain_list_spinlock); 659 - kfree(owner); 660 - return 0; 661 - } 662 - EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner); 663 - #endif /* CONFIG_XEN_DOM0 */
+24
drivers/xen/Kconfig
··· 181 181 select DMA_OPS 182 182 select SWIOTLB 183 183 184 + config XEN_PCI_STUB 185 + bool 186 + 187 + config XEN_PCIDEV_STUB 188 + tristate "Xen PCI-device stub driver" 189 + depends on PCI && !X86 && XEN 190 + depends on XEN_BACKEND 191 + select XEN_PCI_STUB 192 + default m 193 + help 194 + The PCI device stub driver provides limited version of the PCI 195 + device backend driver without para-virtualized support for guests. 196 + If you select this to be a module, you will need to make sure no 197 + other driver has bound to the device(s) you want to make visible to 198 + other guests. 199 + 200 + The "hide" parameter (only applicable if backend driver is compiled 201 + into the kernel) allows you to bind the PCI devices to this module 202 + from the default device drivers. The argument is the list of PCI BDFs: 203 + xen-pciback.hide=(03:00.0)(04:00.0) 204 + 205 + If in doubt, say m. 206 + 184 207 config XEN_PCIDEV_BACKEND 185 208 tristate "Xen PCI-device backend driver" 186 209 depends on PCI && X86 && XEN 187 210 depends on XEN_BACKEND 211 + select XEN_PCI_STUB 188 212 default m 189 213 help 190 214 The PCI device backend driver allows the kernel to export arbitrary
+1 -1
drivers/xen/Makefile
··· 24 24 obj-$(CONFIG_XEN_PVHVM_GUEST) += platform-pci.o 25 25 obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o 26 26 obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o 27 - obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ 27 + obj-$(CONFIG_XEN_PCI_STUB) += xen-pciback/ 28 28 obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o 29 29 obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o 30 30 obj-$(CONFIG_XEN_EFI) += efi.o
+76
drivers/xen/pci.c
··· 8 8 #include <linux/pci.h> 9 9 #include <linux/acpi.h> 10 10 #include <linux/pci-acpi.h> 11 + #include <xen/pci.h> 11 12 #include <xen/xen.h> 12 13 #include <xen/interface/physdev.h> 13 14 #include <xen/interface/xen.h> ··· 254 253 } 255 254 return 0; 256 255 } 256 + #endif 257 + 258 + #ifdef CONFIG_XEN_DOM0 259 + struct xen_device_domain_owner { 260 + domid_t domain; 261 + struct pci_dev *dev; 262 + struct list_head list; 263 + }; 264 + 265 + static DEFINE_SPINLOCK(dev_domain_list_spinlock); 266 + static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list); 267 + 268 + static struct xen_device_domain_owner *find_device(struct pci_dev *dev) 269 + { 270 + struct xen_device_domain_owner *owner; 271 + 272 + list_for_each_entry(owner, &dev_domain_list, list) { 273 + if (owner->dev == dev) 274 + return owner; 275 + } 276 + return NULL; 277 + } 278 + 279 + int xen_find_device_domain_owner(struct pci_dev *dev) 280 + { 281 + struct xen_device_domain_owner *owner; 282 + int domain = -ENODEV; 283 + 284 + spin_lock(&dev_domain_list_spinlock); 285 + owner = find_device(dev); 286 + if (owner) 287 + domain = owner->domain; 288 + spin_unlock(&dev_domain_list_spinlock); 289 + return domain; 290 + } 291 + EXPORT_SYMBOL_GPL(xen_find_device_domain_owner); 292 + 293 + int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain) 294 + { 295 + struct xen_device_domain_owner *owner; 296 + 297 + owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL); 298 + if (!owner) 299 + return -ENODEV; 300 + 301 + spin_lock(&dev_domain_list_spinlock); 302 + if (find_device(dev)) { 303 + spin_unlock(&dev_domain_list_spinlock); 304 + kfree(owner); 305 + return -EEXIST; 306 + } 307 + owner->domain = domain; 308 + owner->dev = dev; 309 + list_add_tail(&owner->list, &dev_domain_list); 310 + spin_unlock(&dev_domain_list_spinlock); 311 + return 0; 312 + } 313 + EXPORT_SYMBOL_GPL(xen_register_device_domain_owner); 314 + 315 + int xen_unregister_device_domain_owner(struct pci_dev *dev) 316 + { 317 + struct xen_device_domain_owner *owner; 318 + 319 + spin_lock(&dev_domain_list_spinlock); 320 + owner = find_device(dev); 321 + if (!owner) { 322 + spin_unlock(&dev_domain_list_spinlock); 323 + return -ENODEV; 324 + } 325 + list_del(&owner->list); 326 + spin_unlock(&dev_domain_list_spinlock); 327 + kfree(owner); 328 + return 0; 329 + } 330 + EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner); 257 331 #endif
+7
drivers/xen/xen-pciback/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 + 3 + # N.B. The below cannot be expressed with a single line using 4 + # CONFIG_XEN_PCI_STUB as it always remains in "y" state, 5 + # thus preventing the driver to be built as a module. 6 + # Please note, that CONFIG_XEN_PCIDEV_BACKEND and 7 + # CONFIG_XEN_PCIDEV_STUB are mutually exclusive. 2 8 obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback.o 9 + obj-$(CONFIG_XEN_PCIDEV_STUB) += xen-pciback.o 3 10 4 11 xen-pciback-y := pci_stub.o pciback_ops.o xenbus.o 5 12 xen-pciback-y += conf_space.o conf_space_header.o \
+6 -2
drivers/xen/xen-pciback/conf_space_header.c
··· 236 236 else { 237 237 pos = (offset - PCI_BASE_ADDRESS_0) / 4; 238 238 if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) { 239 - bar->val = res[pos - 1].start >> 32; 240 - bar->len_val = -resource_size(&res[pos - 1]) >> 32; 239 + /* 240 + * Use ">> 16 >> 16" instead of direct ">> 32" shift 241 + * to avoid warnings on 32-bit architectures. 242 + */ 243 + bar->val = res[pos - 1].start >> 16 >> 16; 244 + bar->len_val = -resource_size(&res[pos - 1]) >> 16 >> 16; 241 245 return bar; 242 246 } 243 247 }
+2 -1
drivers/xen/xen-pciback/pci_stub.c
··· 19 19 #include <linux/sched.h> 20 20 #include <linux/atomic.h> 21 21 #include <xen/events.h> 22 - #include <asm/xen/pci.h> 22 + #include <xen/pci.h> 23 + #include <xen/xen.h> 23 24 #include <asm/xen/hypervisor.h> 24 25 #include <xen/interface/physdev.h> 25 26 #include "pciback.h"
+5
drivers/xen/xen-pciback/pciback.h
··· 71 71 struct pci_dev *dev); 72 72 void pcistub_put_pci_dev(struct pci_dev *dev); 73 73 74 + static inline bool xen_pcibk_pv_support(void) 75 + { 76 + return IS_ENABLED(CONFIG_XEN_PCIDEV_BACKEND); 77 + } 78 + 74 79 /* Ensure a device is turned off or reset */ 75 80 void xen_pcibk_reset_device(struct pci_dev *pdev); 76 81
+6 -2
drivers/xen/xen-pciback/xenbus.c
··· 14 14 #include <linux/workqueue.h> 15 15 #include <xen/xenbus.h> 16 16 #include <xen/events.h> 17 - #include <asm/xen/pci.h> 17 + #include <xen/pci.h> 18 18 #include "pciback.h" 19 19 20 20 #define INVALID_EVTCHN_IRQ (-1) ··· 743 743 744 744 int __init xen_pcibk_xenbus_register(void) 745 745 { 746 + if (!xen_pcibk_pv_support()) 747 + return 0; 748 + 746 749 xen_pcibk_backend = &xen_pcibk_vpci_backend; 747 750 if (passthrough) 748 751 xen_pcibk_backend = &xen_pcibk_passthrough_backend; ··· 755 752 756 753 void __exit xen_pcibk_xenbus_unregister(void) 757 754 { 758 - xenbus_unregister_driver(&xen_pcibk_driver); 755 + if (xen_pcibk_pv_support()) 756 + xenbus_unregister_driver(&xen_pcibk_driver); 759 757 }
+28
include/xen/pci.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __XEN_PCI_H__ 4 + #define __XEN_PCI_H__ 5 + 6 + #if defined(CONFIG_XEN_DOM0) 7 + int xen_find_device_domain_owner(struct pci_dev *dev); 8 + int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain); 9 + int xen_unregister_device_domain_owner(struct pci_dev *dev); 10 + #else 11 + static inline int xen_find_device_domain_owner(struct pci_dev *dev) 12 + { 13 + return -1; 14 + } 15 + 16 + static inline int xen_register_device_domain_owner(struct pci_dev *dev, 17 + uint16_t domain) 18 + { 19 + return -1; 20 + } 21 + 22 + static inline int xen_unregister_device_domain_owner(struct pci_dev *dev) 23 + { 24 + return -1; 25 + } 26 + #endif 27 + 28 + #endif