[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [linux-2.6.18-xen] linux/pci-msi: translate Xen-provided PIRQs (take 2)



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1220876015 -3600
# Node ID 7886619f623ef822f02d38af8a948792d4d90121
# Parent  67ff2b5a88ec1873ef0ed698dc701640fbbbfd6f
linux/pci-msi: translate Xen-provided PIRQs (take 2)

Previously, the kernel depended upon Xen's NR_IRQS to be no larger
than the kernel's NR_PIRQS.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
---
 arch/i386/kernel/io_apic-xen.c          |    3 -
 arch/x86_64/kernel/io_apic-xen.c        |    3 -
 drivers/pci/msi-xen.c                   |   16 ++++-
 drivers/xen/core/evtchn.c               |   86 ++++++++++++++++++++++++++++----
 include/asm-i386/mach-xen/irq_vectors.h |    8 ++
 include/xen/evtchn.h                    |    7 ++
 6 files changed, 107 insertions(+), 16 deletions(-)

diff -r 67ff2b5a88ec -r 7886619f623e arch/i386/kernel/io_apic-xen.c
--- a/arch/i386/kernel/io_apic-xen.c    Sat Sep 06 14:14:42 2008 +0100
+++ b/arch/i386/kernel/io_apic-xen.c    Mon Sep 08 13:13:35 2008 +0100
@@ -47,6 +47,7 @@
 
 #include <xen/interface/xen.h>
 #include <xen/interface/physdev.h>
+#include <xen/evtchn.h>
 
 /* Fake i8259 */
 #define make_8259A_irq(_irq)     (io_apic_irqs &= ~(1UL<<(_irq)))
@@ -1260,7 +1261,7 @@ static void ioapic_register_intr(int irq
        set_intr_gate(vector, interrupt[idx]);
 }
 #else
-#define ioapic_register_intr(_irq,_vector,_trigger) ((void)0)
+#define ioapic_register_intr(irq, vector, trigger) evtchn_register_pirq(irq)
 #endif
 
 static void __init setup_IO_APIC_irqs(void)
diff -r 67ff2b5a88ec -r 7886619f623e arch/x86_64/kernel/io_apic-xen.c
--- a/arch/x86_64/kernel/io_apic-xen.c  Sat Sep 06 14:14:42 2008 +0100
+++ b/arch/x86_64/kernel/io_apic-xen.c  Mon Sep 08 13:13:35 2008 +0100
@@ -95,6 +95,7 @@ int vector_irq[NR_VECTORS] __read_mostly
 
 #include <xen/interface/xen.h>
 #include <xen/interface/physdev.h>
+#include <xen/evtchn.h>
 
 /* Fake i8259 */
 #define make_8259A_irq(_irq)     (io_apic_irqs &= ~(1UL<<(_irq)))
@@ -940,7 +941,7 @@ static void ioapic_register_intr(int irq
        set_intr_gate(vector, interrupt[idx]);
 }
 #else
-#define ioapic_register_intr(_irq,_vector,_trigger) ((void)0)
+#define ioapic_register_intr(irq, vector, trigger) evtchn_register_pirq(irq)
 #endif /* !CONFIG_XEN */
 
 static void __init setup_IO_APIC_irqs(void)
diff -r 67ff2b5a88ec -r 7886619f623e drivers/pci/msi-xen.c
--- a/drivers/pci/msi-xen.c     Sat Sep 06 14:14:42 2008 +0100
+++ b/drivers/pci/msi-xen.c     Mon Sep 08 13:13:35 2008 +0100
@@ -15,6 +15,8 @@
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 
+#include <xen/evtchn.h>
+
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -156,13 +158,15 @@ static int msi_unmap_pirq(struct pci_dev
        int rc;
 
        unmap.domid = msi_get_dev_owner(dev);
-       unmap.pirq = pirq;
+       unmap.pirq = evtchn_get_xen_pirq(pirq);
 
        if ((rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap)))
                printk(KERN_WARNING "unmap irq %x failed\n", pirq);
 
        if (rc < 0)
                return rc;
+
+       evtchn_map_pirq(pirq, 0);
        return 0;
 }
 
@@ -197,7 +201,7 @@ static int msi_map_pirq_to_vector(struct
        map_irq.domid = domid;
        map_irq.type = MAP_PIRQ_TYPE_MSI;
        map_irq.index = -1;
-       map_irq.pirq = pirq;
+       map_irq.pirq = pirq < 0 ? -1 : evtchn_get_xen_pirq(pirq);
        map_irq.bus = dev->bus->number;
        map_irq.devfn = dev->devfn;
        map_irq.entry_nr = entry_nr;
@@ -208,8 +212,12 @@ static int msi_map_pirq_to_vector(struct
 
        if (rc < 0)
                return rc;
-
-       return map_irq.pirq;
+       /* This happens when MSI support is not enabled in Xen. */
+       if (rc == 0 && map_irq.pirq < 0)
+               return -ENOSYS;
+
+       BUG_ON(map_irq.pirq <= 0);
+       return evtchn_map_pirq(pirq, map_irq.pirq);
 }
 
 static int msi_map_vector(struct pci_dev *dev, int entry_nr, u64 table_base)
diff -r 67ff2b5a88ec -r 7886619f623e drivers/xen/core/evtchn.c
--- a/drivers/xen/core/evtchn.c Sat Sep 06 14:14:42 2008 +0100
+++ b/drivers/xen/core/evtchn.c Mon Sep 08 13:13:35 2008 +0100
@@ -66,13 +66,27 @@ enum {
        IRQT_VIRQ,
        IRQT_IPI,
        IRQT_LOCAL_PORT,
-       IRQT_CALLER_PORT
+       IRQT_CALLER_PORT,
+       _IRQT_COUNT
 };
+
+#define _IRQT_BITS 4
+#define _EVTCHN_BITS 12
+#define _INDEX_BITS (32 - _IRQT_BITS - _EVTCHN_BITS)
 
 /* Constructor for packed IRQ information. */
 static inline u32 mk_irq_info(u32 type, u32 index, u32 evtchn)
 {
-       return ((type << 24) | (index << 16) | evtchn);
+       BUILD_BUG_ON(_IRQT_COUNT > (1U << _IRQT_BITS));
+
+       BUILD_BUG_ON(NR_PIRQS > (1U << _INDEX_BITS));
+       BUILD_BUG_ON(NR_VIRQS > (1U << _INDEX_BITS));
+       BUILD_BUG_ON(NR_IPIS > (1U << _INDEX_BITS));
+       BUG_ON(index >> _INDEX_BITS);
+
+       BUILD_BUG_ON(NR_EVENT_CHANNELS > (1U << _EVTCHN_BITS));
+
+       return ((type << (32 - _IRQT_BITS)) | (index << _EVTCHN_BITS) | evtchn);
 }
 
 /* Convenient shorthand for packed representation of an unbound IRQ. */
@@ -84,17 +98,17 @@ static inline u32 mk_irq_info(u32 type, 
 
 static inline unsigned int evtchn_from_irq(int irq)
 {
-       return (u16)(irq_info[irq]);
+       return irq_info[irq] & ((1U << _EVTCHN_BITS) - 1);
 }
 
 static inline unsigned int index_from_irq(int irq)
 {
-       return (u8)(irq_info[irq] >> 16);
+       return (irq_info[irq] >> _EVTCHN_BITS) & ((1U << _INDEX_BITS) - 1);
 }
 
 static inline unsigned int type_from_irq(int irq)
 {
-       return (u8)(irq_info[irq] >> 24);
+       return irq_info[irq] >> (32 - _IRQT_BITS);
 }
 
 /* IRQ <-> VIRQ mapping. */
@@ -742,6 +756,60 @@ static struct hw_interrupt_type dynirq_t
        .retrigger = resend_irq_on_evtchn,
 };
 
+void evtchn_register_pirq(int irq)
+{
+       irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, 0);
+}
+
+#ifndef CONFIG_X86_IO_APIC
+#undef IO_APIC_IRQ
+#define IO_APIC_IRQ(irq) ((irq) >= pirq_to_irq(16))
+#endif
+
+int evtchn_map_pirq(int irq, int xen_pirq)
+{
+       if (irq < 0) {
+               static DEFINE_SPINLOCK(irq_alloc_lock);
+
+               irq = pirq_to_irq(NR_PIRQS - 1);
+               spin_lock(&irq_alloc_lock);
+               do {
+                       if (!IO_APIC_IRQ(irq))
+                               continue;
+                       if (!index_from_irq(irq)) {
+                               BUG_ON(type_from_irq(irq) != IRQT_UNBOUND);
+                               irq_info[irq] = mk_irq_info(IRQT_PIRQ,
+                                                           xen_pirq, 0);
+                               break;
+                       }
+               } while (--irq);
+               spin_unlock(&irq_alloc_lock);
+               if (irq < pirq_to_irq(16))
+                       return -ENOSPC;
+       } else if (!xen_pirq) {
+               if (unlikely(type_from_irq(irq) != IRQT_PIRQ))
+                       return -EINVAL;
+               irq_info[irq] = IRQ_UNBOUND;
+               return 0;
+       } else if (type_from_irq(irq) != IRQT_PIRQ
+                  || index_from_irq(irq) != xen_pirq) {
+               printk(KERN_ERR "IRQ#%d is already mapped to %d:%u - "
+                               "cannot map to PIRQ#%u\n",
+                      irq, type_from_irq(irq), index_from_irq(irq), xen_pirq);
+               return -EINVAL;
+       }
+       return index_from_irq(irq) ? irq : -EINVAL;
+}
+
+int evtchn_get_xen_pirq(int irq)
+{
+       if (!IO_APIC_IRQ(irq))
+               return irq;
+       if (unlikely(type_from_irq(irq) != IRQT_PIRQ))
+               return 0;
+       return index_from_irq(irq);
+}
+
 static inline void pirq_unmask_notify(int pirq)
 {
        struct physdev_eoi eoi = { .irq = pirq };
@@ -774,7 +842,7 @@ static unsigned int startup_pirq(unsigne
        if (VALID_EVTCHN(evtchn))
                goto out;
 
-       bind_pirq.pirq  = irq;
+       bind_pirq.pirq = evtchn_get_xen_pirq(irq);
        /* NB. We are happy to share unless we are probing. */
        bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE;
        if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq) != 0) {
@@ -789,7 +857,7 @@ static unsigned int startup_pirq(unsigne
 
        evtchn_to_irq[evtchn] = irq;
        bind_evtchn_to_cpu(evtchn, 0);
-       irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, evtchn);
+       irq_info[irq] = mk_irq_info(IRQT_PIRQ, bind_pirq.pirq, evtchn);
 
  out:
        unmask_evtchn(evtchn);
@@ -814,7 +882,7 @@ static void shutdown_pirq(unsigned int i
 
        bind_evtchn_to_cpu(evtchn, 0);
        evtchn_to_irq[evtchn] = -1;
-       irq_info[irq] = IRQ_UNBOUND;
+       irq_info[irq] = mk_irq_info(IRQT_PIRQ, index_from_irq(irq), 0);
 }
 
 static void enable_pirq(unsigned int irq)
@@ -1008,7 +1076,7 @@ void irq_resume(void)
 
        /* No IRQ <-> event-channel mappings. */
        for (irq = 0; irq < NR_IRQS; irq++)
-               irq_info[irq] &= ~0xFFFF; /* zap event-channel binding */
+               irq_info[irq] &= ~((1U << _EVTCHN_BITS) - 1);
        for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
                evtchn_to_irq[evtchn] = -1;
 
diff -r 67ff2b5a88ec -r 7886619f623e include/asm-i386/mach-xen/irq_vectors.h
--- a/include/asm-i386/mach-xen/irq_vectors.h   Sat Sep 06 14:14:42 2008 +0100
+++ b/include/asm-i386/mach-xen/irq_vectors.h   Mon Sep 08 13:13:35 2008 +0100
@@ -108,7 +108,13 @@
  */
 
 #define PIRQ_BASE              0
-#define NR_PIRQS               256
+#if !defined(MAX_IO_APICS)
+# define NR_PIRQS              (NR_VECTORS + 32 * NR_CPUS)
+#elif NR_CPUS < MAX_IO_APICS
+# define NR_PIRQS              (NR_VECTORS + 32 * NR_CPUS)
+#else
+# define NR_PIRQS              (NR_VECTORS + 32 * MAX_IO_APICS)
+#endif
 
 #define DYNIRQ_BASE            (PIRQ_BASE + NR_PIRQS)
 #define NR_DYNIRQS             256
diff -r 67ff2b5a88ec -r 7886619f623e include/xen/evtchn.h
--- a/include/xen/evtchn.h      Sat Sep 06 14:14:42 2008 +0100
+++ b/include/xen/evtchn.h      Mon Sep 08 13:13:35 2008 +0100
@@ -101,6 +101,13 @@ asmlinkage void evtchn_do_upcall(struct 
 /* Entry point for notifications into the userland character device. */
 void evtchn_device_upcall(int port);
 
+/* Mark a PIRQ as unavailable for dynamic allocation. */
+void evtchn_register_pirq(int irq);
+/* Map a Xen-supplied PIRQ to a dynamically allocated one. */
+int evtchn_map_pirq(int irq, int xen_pirq);
+/* Look up a Xen-supplied PIRQ for a dynamically allocated one. */
+int evtchn_get_xen_pirq(int irq);
+
 void mask_evtchn(int port);
 void disable_all_local_evtchn(void);
 void unmask_evtchn(int port);

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.