xen/pci: Add xen_[find|register|unregister]_device_domain_owner functions.
When the Xen PCI backend is told to enable or disable MSI/MSI-X functions, the initial domain performs these operations. The initial domain needs to know which domain (guest) is going to use the PCI device so when it makes the appropiate hypercall to retrieve the MSI/MSI-X vector it will also assign the PCI device to the appropiate domain (guest). This boils down to us needing a mechanism to find, set and unset the domain id that will be using the device. [v2: EXPORT_SYMBOL -> EXPORT_SYMBOL_GPL.] Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
This commit is contained in:
parent
a6360dd37e
commit
c55fa78b13
2 changed files with 89 additions and 0 deletions
|
@ -15,10 +15,26 @@ static inline int pci_xen_hvm_init(void)
|
|||
#endif
|
||||
#if defined(CONFIG_XEN_DOM0)
|
||||
void __init xen_setup_pirqs(void);
|
||||
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 void __init xen_setup_pirqs(void)
|
||||
{
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -461,3 +461,76 @@ void __init xen_setup_pirqs(void)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue