[Xen-devel] [PATCH 2/6] [xen-pci] Provide a mechanism to register domain owner of a PCI device.

Konrad Rzeszutek Wilk
Wed, 09 Dec 2009 16:29:29 -0000

. and also to find the domain owner based on the PCI device and
to unregister a domain owner of a PCI device.

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 arch/x86/include/asm/xen/pci.h |   16 +++++++++
 arch/x86/xen/pci.c             |   73 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h
index 6c022c8..6e9e9f2 100644
--- a/arch/x86/include/asm/xen/pci.h
+++ b/arch/x86/include/asm/xen/pci.h
@@ -8,6 +8,11 @@ int xen_create_msi_irq(struct pci_dev *dev,
 			int type, int pirq_override);
 int xen_destroy_irq(int irq);
 void xen_teardown_msi_dev(struct pci_dev *dev);
+
+int find_device_owner(struct pci_dev *dev);
+int register_device_owner(struct pci_dev *dev, domid_t domain);
+int unregister_device_owner(struct pci_dev *dev);
+
 #else
 static inline int xen_register_gsi(u32 gsi, int triggering, int polarity)
 {
@@ -25,6 +30,17 @@ static inline int xen_destroy_irq(int irq)
 	return -1;
 }
 static inline void xen_teardown_msi_dev(struct pci_dev *dev) { }
+
+static inline int find_device_owner(struct pci_dev *dev) { return -1; }
+static inline int register_device_owner(struct pci_dev *dev, domid_t domain)
+{
+	return -1;
+}
+static inline int unregister_device_owner(struct pci_dev *dev)
+{
+	return -1;
+}
+
 #endif

 #if defined(CONFIG_PCI_MSI) && defined(CONFIG_XEN_DOM0_PCI)
diff --git a/arch/x86/xen/pci.c b/arch/x86/xen/pci.c
index fc3508c..151b4b7 100644
--- a/arch/x86/xen/pci.c
+++ b/arch/x86/xen/pci.c
@@ -2,6 +2,7 @@
 #include <linux/acpi.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
+#include <linux/slab.h>

 #include <asm/mpspec.h>
 #include <asm/io_apic.h>
@@ -151,3 +152,75 @@ void xen_teardown_msi_dev(struct pci_dev *dev)
 }

 #endif
+
+struct device_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);
+
+struct device_owner *find_device(struct pci_dev *dev)
+{
+
+	struct device_owner *owner;
+
+	list_for_each_entry(owner, &dev_domain_list, list) {
+		if (owner->dev == dev)
+			return owner;
+	}
+	return NULL;
+}
+
+int find_device_owner(struct pci_dev *dev)
+{
+
+	struct device_owner *owner = NULL;
+
+	owner = find_device(dev);
+	if (!owner)
+		return -ENODEV;
+
+	return owner->domain;
+}
+EXPORT_SYMBOL(find_device_owner);
+
+int register_device_owner(struct pci_dev *dev, domid_t domain)
+{
+	struct device_owner *owner;
+	unsigned long flags;
+
+	if (find_device(dev))
+		return -EEXIST;
+
+	owner = kzalloc(sizeof(struct device_owner), GFP_KERNEL);
+	owner->domain = domain;
+	owner->dev = dev;
+
+	spin_lock_irqsave(&dev_domain_list_spinlock, flags);
+	list_add_tail(&owner->list, &dev_domain_list);
+	spin_unlock_irqrestore(&dev_domain_list_spinlock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(register_device_owner);
+
+int unregister_device_owner(struct pci_dev *dev)
+{
+	struct device_owner *owner = NULL;
+	unsigned long flags;
+
+	owner = find_device(dev);
+	if (!owner)
+		return -ENODEV;
+
+	spin_lock_irqsave(&dev_domain_list_spinlock, flags);
+	list_del(&owner->list);
+	spin_unlock_irqrestore(&dev_domain_list_spinlock, flags);
+
+	kfree(owner);
+	return 0;
+}
+EXPORT_SYMBOL(unregister_device_owner);