WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 2/3] xen: add msi support for dom0

This patch adds msi support for dom0, based on
arch_setup_msi_irqs hook, a xen_setup_msi_irqs is called
if it's Xen domain. No interrupt remapping is handled since
Xen domain isn't exposed with such feature at this time.

Signed-off-by: Yunhong Jiang <yunhong.jiang@xxxxxxxxx>
Signed-off-by: Qing He <qing.he@xxxxxxxxx>

---
 arch/x86/include/asm/xen/pci.h  |   20 +++++++++
 arch/x86/kernel/apic/io_apic.c  |    9 +++-
 arch/x86/xen/pci.c              |   24 ++++++++++
 drivers/xen/events.c            |   91 ++++++++++++++++++++++++++++++++++++++-
 include/xen/interface/physdev.h |   30 +++++++++++++
 5 files changed, 172 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h
index 0563fc6..714443b 100644
--- a/arch/x86/include/asm/xen/pci.h
+++ b/arch/x86/include/asm/xen/pci.h
@@ -3,11 +3,31 @@
 
 #ifdef CONFIG_XEN_DOM0_PCI
 int xen_register_gsi(u32 gsi, int triggering, int polarity);
+int xen_create_msi_irq(struct pci_dev *dev,
+                       struct msi_desc *msidesc,
+                       int type);
+int xen_destroy_irq(int irq);
+int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
 #else
 static inline int xen_register_gsi(u32 gsi, int triggering, int polarity)
 {
        return -1;
 }
+
+static int xen_create_msi_irq(struct pci_dev *dev,
+                               struct msi_desc *msidesc,
+                               int type)
+{
+       return -1;
+}
+static int xen_destroy_irq(int irq)
+{
+       return -1;
+}
+static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       return -1;
+}
 #endif
 
 #endif /* _ASM_X86_XEN_PCI_H */
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index b562550..ce82ddb 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -66,6 +66,7 @@
 #include <asm/xen/hypervisor.h>
 #include <asm/apic.h>
 
+#include <asm/xen/pci.h>
 
 #define __apicdebuginit(type) static type __init
 
@@ -3502,6 +3503,9 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, 
int type)
        if (type == PCI_CAP_ID_MSI && nvec > 1)
                return 1;
 
+       if (xen_domain())
+               return xen_setup_msi_irqs(dev, nvec, type);
+
        irq_want = nr_irqs_gsi;
        sub_handle = 0;
        list_for_each_entry(msidesc, &dev->msi_list, list) {
@@ -3550,7 +3554,10 @@ error:
 
 void arch_teardown_msi_irq(unsigned int irq)
 {
-       destroy_irq(irq);
+       if (xen_domain())
+               xen_destroy_irq(irq);
+       else
+               destroy_irq(irq);
 }
 
 #if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP)
diff --git a/arch/x86/xen/pci.c b/arch/x86/xen/pci.c
index 07b59fe..c0ef627 100644
--- a/arch/x86/xen/pci.c
+++ b/arch/x86/xen/pci.c
@@ -1,12 +1,14 @@
 #include <linux/kernel.h>
 #include <linux/acpi.h>
 #include <linux/pci.h>
+#include <linux/msi.h>
 
 #include <asm/mpspec.h>
 #include <asm/io_apic.h>
 #include <asm/pci_x86.h>
 
 #include <asm/xen/hypervisor.h>
+#include <asm/xen/pci.h>
 
 #include <xen/interface/xen.h>
 #include <xen/events.h>
@@ -84,3 +86,25 @@ void __init xen_setup_pirqs(void)
                        polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH);
        }
 }
+
+int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       unsigned int irq;
+       int ret;
+       struct msi_desc *msidesc;
+
+       list_for_each_entry(msidesc, &dev->msi_list, list) {
+               irq = xen_create_msi_irq(dev, msidesc, type);
+               if (irq == 0)
+                       return -1;
+
+               ret = set_irq_msi(irq, msidesc);
+               if (ret)
+                       goto error;
+       }
+       return 0;
+
+error:
+       xen_destroy_irq(irq);
+       return ret;
+}
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index af2aad4..eef4834 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -28,6 +28,9 @@
 #include <linux/string.h>
 #include <linux/bootmem.h>
 #include <linux/irqnr.h>
+#include <linux/pci_regs.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
 
 #include <asm/ptrace.h>
 #include <asm/irq.h>
@@ -42,6 +45,8 @@
 #include <xen/interface/xen.h>
 #include <xen/interface/event_channel.h>
 
+#include "../pci/msi.h"
+
 /*
  * This lock protects updates to the following mapping and reference-count
  * arrays. The lock does not need to be acquired to read the mapping tables.
@@ -560,14 +565,98 @@ int xen_allocate_pirq(unsigned gsi, char *name)
        if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) {
                dynamic_irq_cleanup(irq);
                irq = -ENOSPC;
+               goto out;
+       }
+
+       irq_info[irq] = mk_pirq_info(0, gsi, irq_op.vector);
+out:
+       spin_unlock(&irq_mapping_update_lock);
+       return irq;
+}
+
+int xen_destroy_irq(int irq)
+{
+       struct irq_desc *desc;
+       struct physdev_unmap_pirq unmap_irq;
+       int rc = -ENOENT;
+
+       spin_lock(&irq_mapping_update_lock);
+
+       desc = irq_to_desc(irq);
+       if (!desc)
+               goto out;
+
+       unmap_irq.pirq = irq;
+       unmap_irq.domid = DOMID_SELF;
+       rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
+       if (rc) {
+               printk(KERN_WARNING "unmap irq failed %x\n", rc);
                goto out;
        }
 
-       irq_info[irq] = mk_pirq_info(0, gsi, irq_op.vector);
+       irq_info[irq] = mk_unbound_info();
+
+       dynamic_irq_cleanup(irq);
 
 out:
        spin_unlock(&irq_mapping_update_lock);
+       return rc;
+}
 
+int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type)
+{
+       int irq = 0;
+       struct physdev_map_pirq map_irq;
+       int rc;
+       domid_t domid = DOMID_SELF;
+       int pos;
+       u32 table_offset, bir;
+
+       memset(&map_irq, 0, sizeof(map_irq));
+       map_irq.domid = domid;
+       map_irq.type = MAP_PIRQ_TYPE_MSI;
+       map_irq.index = -1;
+       map_irq.bus = dev->bus->number;
+       map_irq.devfn = dev->devfn;
+
+       if (type == PCI_CAP_ID_MSIX) {
+               pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+
+               pci_read_config_dword(dev, msix_table_offset_reg(pos),
+                                       &table_offset);
+               bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
+
+               map_irq.table_base = pci_resource_start(dev, bir);
+               map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
+       }
+
+       spin_lock(&irq_mapping_update_lock);
+
+       irq = find_unbound_irq();
+
+       if (irq == -1)
+               goto out;
+
+       map_irq.pirq = irq;
+
+       rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+       if (rc) {
+
+               printk(KERN_WARNING "xen map irq failed %x\n", rc);
+
+               dynamic_irq_cleanup(irq);
+
+               irq = -1;
+               goto out;
+       }
+
+       irq_info[irq] = mk_pirq_info(0, -1, map_irq.index);
+       set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
+                       handle_level_irq,
+                       (type == PCI_CAP_ID_MSIX) ? "msi-x":"msi");
+
+out:
+       spin_unlock(&irq_mapping_update_lock);
        return irq;
 }
 
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
index 7a7d007..ac5de37 100644
--- a/include/xen/interface/physdev.h
+++ b/include/xen/interface/physdev.h
@@ -106,6 +106,36 @@ struct physdev_irq {
        uint32_t vector;
 };
 
+#define MAP_PIRQ_TYPE_MSI              0x0
+#define MAP_PIRQ_TYPE_GSI              0x1
+#define MAP_PIRQ_TYPE_UNKNOWN          0x2
+
+#define PHYSDEVOP_map_pirq             13
+struct physdev_map_pirq {
+    domid_t domid;
+    /* IN */
+    int type;
+    /* IN */
+    int index;
+    /* IN or OUT */
+    int pirq;
+    /* IN */
+    int bus;
+    /* IN */
+    int devfn;
+    /* IN */
+    int entry_nr;
+    /* IN */
+    uint64_t table_base;
+};
+
+#define PHYSDEVOP_unmap_pirq           14
+struct physdev_unmap_pirq {
+    domid_t domid;
+    /* IN */
+    int pirq;
+};
+
 #define PHYSDEVOP_manage_pci_add       15
 #define PHYSDEVOP_manage_pci_remove    16
 struct physdev_manage_pci {
-- 
1.6.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel