[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |