mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 04:42:12 +00:00
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>
This commit is contained in:
parent
e453f872b7
commit
a67efff288
@ -22,25 +22,6 @@ static inline int __init pci_xen_initial_domain(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_XEN_DOM0
|
|
||||||
int xen_find_device_domain_owner(struct pci_dev *dev);
|
|
||||||
int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain);
|
|
||||||
int xen_unregister_device_domain_owner(struct pci_dev *dev);
|
|
||||||
#else
|
|
||||||
static inline int xen_find_device_domain_owner(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
static inline int xen_register_device_domain_owner(struct pci_dev *dev,
|
|
||||||
uint16_t domain)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
static inline int xen_unregister_device_domain_owner(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(CONFIG_PCI_MSI)
|
#if defined(CONFIG_PCI_MSI)
|
||||||
#if defined(CONFIG_PCI_XEN)
|
#if defined(CONFIG_PCI_XEN)
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <xen/features.h>
|
#include <xen/features.h>
|
||||||
#include <xen/events.h>
|
#include <xen/events.h>
|
||||||
|
#include <xen/pci.h>
|
||||||
#include <asm/xen/pci.h>
|
#include <asm/xen/pci.h>
|
||||||
#include <asm/xen/cpuid.h>
|
#include <asm/xen/cpuid.h>
|
||||||
#include <asm/apic.h>
|
#include <asm/apic.h>
|
||||||
@ -585,78 +586,3 @@ int __init pci_xen_initial_domain(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_XEN_DOM0
|
|
||||||
|
|
||||||
struct xen_device_domain_owner {
|
|
||||||
domid_t domain;
|
|
||||||
struct pci_dev *dev;
|
|
||||||
struct list_head list;
|
|
||||||
};
|
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(dev_domain_list_spinlock);
|
|
||||||
static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list);
|
|
||||||
|
|
||||||
static struct xen_device_domain_owner *find_device(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
struct xen_device_domain_owner *owner;
|
|
||||||
|
|
||||||
list_for_each_entry(owner, &dev_domain_list, list) {
|
|
||||||
if (owner->dev == dev)
|
|
||||||
return owner;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xen_find_device_domain_owner(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
struct xen_device_domain_owner *owner;
|
|
||||||
int domain = -ENODEV;
|
|
||||||
|
|
||||||
spin_lock(&dev_domain_list_spinlock);
|
|
||||||
owner = find_device(dev);
|
|
||||||
if (owner)
|
|
||||||
domain = owner->domain;
|
|
||||||
spin_unlock(&dev_domain_list_spinlock);
|
|
||||||
return domain;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(xen_find_device_domain_owner);
|
|
||||||
|
|
||||||
int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain)
|
|
||||||
{
|
|
||||||
struct xen_device_domain_owner *owner;
|
|
||||||
|
|
||||||
owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL);
|
|
||||||
if (!owner)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
spin_lock(&dev_domain_list_spinlock);
|
|
||||||
if (find_device(dev)) {
|
|
||||||
spin_unlock(&dev_domain_list_spinlock);
|
|
||||||
kfree(owner);
|
|
||||||
return -EEXIST;
|
|
||||||
}
|
|
||||||
owner->domain = domain;
|
|
||||||
owner->dev = dev;
|
|
||||||
list_add_tail(&owner->list, &dev_domain_list);
|
|
||||||
spin_unlock(&dev_domain_list_spinlock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(xen_register_device_domain_owner);
|
|
||||||
|
|
||||||
int xen_unregister_device_domain_owner(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
struct xen_device_domain_owner *owner;
|
|
||||||
|
|
||||||
spin_lock(&dev_domain_list_spinlock);
|
|
||||||
owner = find_device(dev);
|
|
||||||
if (!owner) {
|
|
||||||
spin_unlock(&dev_domain_list_spinlock);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
list_del(&owner->list);
|
|
||||||
spin_unlock(&dev_domain_list_spinlock);
|
|
||||||
kfree(owner);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner);
|
|
||||||
#endif /* CONFIG_XEN_DOM0 */
|
|
||||||
|
@ -181,10 +181,34 @@ config SWIOTLB_XEN
|
|||||||
select DMA_OPS
|
select DMA_OPS
|
||||||
select SWIOTLB
|
select SWIOTLB
|
||||||
|
|
||||||
|
config XEN_PCI_STUB
|
||||||
|
bool
|
||||||
|
|
||||||
|
config XEN_PCIDEV_STUB
|
||||||
|
tristate "Xen PCI-device stub driver"
|
||||||
|
depends on PCI && !X86 && XEN
|
||||||
|
depends on XEN_BACKEND
|
||||||
|
select XEN_PCI_STUB
|
||||||
|
default m
|
||||||
|
help
|
||||||
|
The PCI device stub driver provides limited version of the PCI
|
||||||
|
device backend driver without para-virtualized support for guests.
|
||||||
|
If you select this to be a module, you will need to make sure no
|
||||||
|
other driver has bound to the device(s) you want to make visible to
|
||||||
|
other guests.
|
||||||
|
|
||||||
|
The "hide" parameter (only applicable if backend driver is compiled
|
||||||
|
into the kernel) allows you to bind the PCI devices to this module
|
||||||
|
from the default device drivers. The argument is the list of PCI BDFs:
|
||||||
|
xen-pciback.hide=(03:00.0)(04:00.0)
|
||||||
|
|
||||||
|
If in doubt, say m.
|
||||||
|
|
||||||
config XEN_PCIDEV_BACKEND
|
config XEN_PCIDEV_BACKEND
|
||||||
tristate "Xen PCI-device backend driver"
|
tristate "Xen PCI-device backend driver"
|
||||||
depends on PCI && X86 && XEN
|
depends on PCI && X86 && XEN
|
||||||
depends on XEN_BACKEND
|
depends on XEN_BACKEND
|
||||||
|
select XEN_PCI_STUB
|
||||||
default m
|
default m
|
||||||
help
|
help
|
||||||
The PCI device backend driver allows the kernel to export arbitrary
|
The PCI device backend driver allows the kernel to export arbitrary
|
||||||
|
@ -24,7 +24,7 @@ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
|
|||||||
obj-$(CONFIG_XEN_PVHVM_GUEST) += platform-pci.o
|
obj-$(CONFIG_XEN_PVHVM_GUEST) += platform-pci.o
|
||||||
obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
|
obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
|
||||||
obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o
|
obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o
|
||||||
obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/
|
obj-$(CONFIG_XEN_PCI_STUB) += xen-pciback/
|
||||||
obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o
|
obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o
|
||||||
obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o
|
obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o
|
||||||
obj-$(CONFIG_XEN_EFI) += efi.o
|
obj-$(CONFIG_XEN_EFI) += efi.o
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/pci-acpi.h>
|
#include <linux/pci-acpi.h>
|
||||||
|
#include <xen/pci.h>
|
||||||
#include <xen/xen.h>
|
#include <xen/xen.h>
|
||||||
#include <xen/interface/physdev.h>
|
#include <xen/interface/physdev.h>
|
||||||
#include <xen/interface/xen.h>
|
#include <xen/interface/xen.h>
|
||||||
@ -254,3 +255,78 @@ static int xen_mcfg_late(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_XEN_DOM0
|
||||||
|
struct xen_device_domain_owner {
|
||||||
|
domid_t domain;
|
||||||
|
struct pci_dev *dev;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(dev_domain_list_spinlock);
|
||||||
|
static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list);
|
||||||
|
|
||||||
|
static struct xen_device_domain_owner *find_device(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
struct xen_device_domain_owner *owner;
|
||||||
|
|
||||||
|
list_for_each_entry(owner, &dev_domain_list, list) {
|
||||||
|
if (owner->dev == dev)
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xen_find_device_domain_owner(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
struct xen_device_domain_owner *owner;
|
||||||
|
int domain = -ENODEV;
|
||||||
|
|
||||||
|
spin_lock(&dev_domain_list_spinlock);
|
||||||
|
owner = find_device(dev);
|
||||||
|
if (owner)
|
||||||
|
domain = owner->domain;
|
||||||
|
spin_unlock(&dev_domain_list_spinlock);
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xen_find_device_domain_owner);
|
||||||
|
|
||||||
|
int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain)
|
||||||
|
{
|
||||||
|
struct xen_device_domain_owner *owner;
|
||||||
|
|
||||||
|
owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL);
|
||||||
|
if (!owner)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
spin_lock(&dev_domain_list_spinlock);
|
||||||
|
if (find_device(dev)) {
|
||||||
|
spin_unlock(&dev_domain_list_spinlock);
|
||||||
|
kfree(owner);
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
|
owner->domain = domain;
|
||||||
|
owner->dev = dev;
|
||||||
|
list_add_tail(&owner->list, &dev_domain_list);
|
||||||
|
spin_unlock(&dev_domain_list_spinlock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xen_register_device_domain_owner);
|
||||||
|
|
||||||
|
int xen_unregister_device_domain_owner(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
struct xen_device_domain_owner *owner;
|
||||||
|
|
||||||
|
spin_lock(&dev_domain_list_spinlock);
|
||||||
|
owner = find_device(dev);
|
||||||
|
if (!owner) {
|
||||||
|
spin_unlock(&dev_domain_list_spinlock);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
list_del(&owner->list);
|
||||||
|
spin_unlock(&dev_domain_list_spinlock);
|
||||||
|
kfree(owner);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner);
|
||||||
|
#endif
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
# N.B. The below cannot be expressed with a single line using
|
||||||
|
# CONFIG_XEN_PCI_STUB as it always remains in "y" state,
|
||||||
|
# thus preventing the driver to be built as a module.
|
||||||
|
# Please note, that CONFIG_XEN_PCIDEV_BACKEND and
|
||||||
|
# CONFIG_XEN_PCIDEV_STUB are mutually exclusive.
|
||||||
obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback.o
|
obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback.o
|
||||||
|
obj-$(CONFIG_XEN_PCIDEV_STUB) += xen-pciback.o
|
||||||
|
|
||||||
xen-pciback-y := pci_stub.o pciback_ops.o xenbus.o
|
xen-pciback-y := pci_stub.o pciback_ops.o xenbus.o
|
||||||
xen-pciback-y += conf_space.o conf_space_header.o \
|
xen-pciback-y += conf_space.o conf_space_header.o \
|
||||||
|
@ -236,8 +236,12 @@ static void *bar_init(struct pci_dev *dev, int offset)
|
|||||||
else {
|
else {
|
||||||
pos = (offset - PCI_BASE_ADDRESS_0) / 4;
|
pos = (offset - PCI_BASE_ADDRESS_0) / 4;
|
||||||
if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) {
|
if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) {
|
||||||
bar->val = res[pos - 1].start >> 32;
|
/*
|
||||||
bar->len_val = -resource_size(&res[pos - 1]) >> 32;
|
* Use ">> 16 >> 16" instead of direct ">> 32" shift
|
||||||
|
* to avoid warnings on 32-bit architectures.
|
||||||
|
*/
|
||||||
|
bar->val = res[pos - 1].start >> 16 >> 16;
|
||||||
|
bar->len_val = -resource_size(&res[pos - 1]) >> 16 >> 16;
|
||||||
return bar;
|
return bar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <xen/events.h>
|
#include <xen/events.h>
|
||||||
#include <asm/xen/pci.h>
|
#include <xen/pci.h>
|
||||||
|
#include <xen/xen.h>
|
||||||
#include <asm/xen/hypervisor.h>
|
#include <asm/xen/hypervisor.h>
|
||||||
#include <xen/interface/physdev.h>
|
#include <xen/interface/physdev.h>
|
||||||
#include "pciback.h"
|
#include "pciback.h"
|
||||||
|
@ -71,6 +71,11 @@ struct pci_dev *pcistub_get_pci_dev(struct xen_pcibk_device *pdev,
|
|||||||
struct pci_dev *dev);
|
struct pci_dev *dev);
|
||||||
void pcistub_put_pci_dev(struct pci_dev *dev);
|
void pcistub_put_pci_dev(struct pci_dev *dev);
|
||||||
|
|
||||||
|
static inline bool xen_pcibk_pv_support(void)
|
||||||
|
{
|
||||||
|
return IS_ENABLED(CONFIG_XEN_PCIDEV_BACKEND);
|
||||||
|
}
|
||||||
|
|
||||||
/* Ensure a device is turned off or reset */
|
/* Ensure a device is turned off or reset */
|
||||||
void xen_pcibk_reset_device(struct pci_dev *pdev);
|
void xen_pcibk_reset_device(struct pci_dev *pdev);
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <xen/xenbus.h>
|
#include <xen/xenbus.h>
|
||||||
#include <xen/events.h>
|
#include <xen/events.h>
|
||||||
#include <asm/xen/pci.h>
|
#include <xen/pci.h>
|
||||||
#include "pciback.h"
|
#include "pciback.h"
|
||||||
|
|
||||||
#define INVALID_EVTCHN_IRQ (-1)
|
#define INVALID_EVTCHN_IRQ (-1)
|
||||||
@ -743,6 +743,9 @@ const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend;
|
|||||||
|
|
||||||
int __init xen_pcibk_xenbus_register(void)
|
int __init xen_pcibk_xenbus_register(void)
|
||||||
{
|
{
|
||||||
|
if (!xen_pcibk_pv_support())
|
||||||
|
return 0;
|
||||||
|
|
||||||
xen_pcibk_backend = &xen_pcibk_vpci_backend;
|
xen_pcibk_backend = &xen_pcibk_vpci_backend;
|
||||||
if (passthrough)
|
if (passthrough)
|
||||||
xen_pcibk_backend = &xen_pcibk_passthrough_backend;
|
xen_pcibk_backend = &xen_pcibk_passthrough_backend;
|
||||||
@ -752,5 +755,6 @@ int __init xen_pcibk_xenbus_register(void)
|
|||||||
|
|
||||||
void __exit xen_pcibk_xenbus_unregister(void)
|
void __exit xen_pcibk_xenbus_unregister(void)
|
||||||
{
|
{
|
||||||
xenbus_unregister_driver(&xen_pcibk_driver);
|
if (xen_pcibk_pv_support())
|
||||||
|
xenbus_unregister_driver(&xen_pcibk_driver);
|
||||||
}
|
}
|
||||||
|
28
include/xen/pci.h
Normal file
28
include/xen/pci.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
#ifndef __XEN_PCI_H__
|
||||||
|
#define __XEN_PCI_H__
|
||||||
|
|
||||||
|
#if defined(CONFIG_XEN_DOM0)
|
||||||
|
int xen_find_device_domain_owner(struct pci_dev *dev);
|
||||||
|
int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain);
|
||||||
|
int xen_unregister_device_domain_owner(struct pci_dev *dev);
|
||||||
|
#else
|
||||||
|
static inline int xen_find_device_domain_owner(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int xen_register_device_domain_owner(struct pci_dev *dev,
|
||||||
|
uint16_t domain)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int xen_unregister_device_domain_owner(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user