IRQ routing
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 4 Apr 2014 20:20:39 +0000 (13:20 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 4 Apr 2014 20:20:39 +0000 (13:20 -0700)
Call route_irqs() to reroute a all IRQs for a particular vector to an os
coreid.  We don't support routing to multiple cores yet.

kern/arch/riscv/trap.c
kern/arch/x86/ioapic.c
kern/arch/x86/trap.c
kern/arch/x86/trap.h
kern/include/trap.h

index d87abec..1d9055d 100644 (file)
@@ -356,18 +356,13 @@ void send_nmi(uint32_t os_coreid)
        printk("%s not implemented\n", __FUNCTION);
 }
 
-void register_raw_irq(unsigned int vector, isr_t handler, void *data)
-{
-       printk("%s not implemented\n", __FUNCTION);
-}
-
-void unregister_raw_irq(unsigned int vector, isr_t handler, void *data)
+int register_irq(int irq, isr_t handler, void *irq_arg, uint32_t tbdf)
 {
        printk("%s not implemented\n", __FUNCTION);
+       return -1;
 }
 
-int register_dev_irq(int irq, void (*handler)(struct hw_trapframe *, void *),
-                     void *irq_arg)
+int route_irqs(int cpu_vec, int coreid)
 {
        printk("%s not implemented\n", __FUNCTION);
        return -1;
index 4035710..215c2c9 100644 (file)
@@ -382,10 +382,9 @@ static void msi_unmask_irq(struct irq_handler *irq_h, int apic_vector)
        pci_msi_unmask(irq_h->dev_private);
 }
 
-static int msi_route_irq(struct irq_handler *irq_h, int apic_vector, int dest)
+static void msi_route_irq(struct irq_handler *irq_h, int apic_vector, int dest)
 {
        pci_msi_route(irq_h->dev_private, dest);
-       return 0;
 }
 
 static void msix_mask_irq(struct irq_handler *irq_h, int apic_vector)
@@ -398,10 +397,9 @@ static void msix_unmask_irq(struct irq_handler *irq_h, int apic_vector)
        pci_msix_unmask_vector(irq_h->dev_private);
 }
 
-static int msix_route_irq(struct irq_handler *irq_h, int apic_vector, int dest)
+static void msix_route_irq(struct irq_handler *irq_h, int apic_vector, int dest)
 {
        pci_msix_route_vector(irq_h->dev_private, dest);
-       return 0;
 }
 
 static int msi_irq_enable(struct irq_handler *irq_h, struct pci_device *p)
@@ -461,37 +459,28 @@ static struct Rdt *ioapic_vector2rdt(int apic_vector)
        return rdt;
 }
 
-/* Routes the IRQ to the os_coreid.  Will take effect immediately.  Route
- * masking from rdt->lo will take effect. */
-static int ioapic_route_irq(struct irq_handler *unused, int apic_vector,
-                            int os_coreid)
+/* Routes the IRQ to the hw_coreid.  Will take effect immediately.  Route
+ * masking from rdt->lo will take effect.  The early return cases are probably
+ * bugs in IOAPIC irq_h setup. */
+static void ioapic_route_irq(struct irq_handler *unused, int apic_vector,
+                             int hw_coreid)
 {
-       int hw_coreid;
        struct Rdt *rdt = ioapic_vector2rdt(apic_vector);
-       if (!rdt)
-               return -1;
-       if (os_coreid >= MAX_NUM_CPUS) {
-               printk("os_coreid %d out of range!\n", os_coreid);
-               return -1;
-       }
-       /* using the old akaros-style lapic id lookup */
-       hw_coreid = get_hw_coreid(os_coreid);
-       if (hw_coreid == -1) {
-               printk("os_coreid %d not a valid hw core!", os_coreid);
-               return -1;
+       if (!rdt) {
+               printk("Missing IOAPIC route for vector!\n", apic_vector);
+               return;
        }
        spin_lock(&rdt->apic->lock);
        /* this bit gets set in apicinit, only if we found it via MP or ACPI */
        if (!xlapic[hw_coreid].useable) {
                printk("Can't route to uninitialized LAPIC %d!\n", hw_coreid);
                spin_unlock(&rdt->apic->lock);
-               return -1;
+               return;
        }
        rdt->hi = hw_coreid << 24;
        rdt->lo |= Pm | MTf;
        rtblput(rdt->apic, rdt->intin, rdt->hi, rdt->lo);
        spin_unlock(&rdt->apic->lock);
-       return 0;
 }
 
 static void ioapic_mask_irq(struct irq_handler *unused, int apic_vector)
index 560bd50..d91fe22 100644 (file)
@@ -447,6 +447,12 @@ void trap(struct hw_trapframe *hw_tf)
        assert(0);
 }
 
+static bool vector_is_irq(int apic_vec)
+{
+       /* arguably, we could limit them to MaxIdtIOAPIC */
+       return (IdtPIC <= apic_vec) && (apic_vec <= IdtMAX);
+}
+
 /* Note IRQs are disabled unless explicitly turned on.
  *
  * In general, we should only get trapno's >= PIC1_OFFSET (32).  Anything else
@@ -512,7 +518,8 @@ int register_irq(int irq, isr_t handler, void *irq_arg, uint32_t tbdf)
                kfree(irq_h);
                return -1;
        }
-       printk("IRQ %d, vector %d (%x), type %s\n", irq, vector, vector, irq_h->type);
+       printk("IRQ %d, vector %d (0x%x), type %s\n", irq, vector, vector,
+              irq_h->type);
        assert(irq_h->check_spurious && irq_h->eoi);
        irq_h->isr = handler;
        irq_h->data = irq_arg;
@@ -531,6 +538,50 @@ int register_irq(int irq, isr_t handler, void *irq_arg, uint32_t tbdf)
        return 0;
 }
 
+/* These routing functions only allow the routing of an irq to a single core.
+ * If we want to route to multiple cores, we'll probably need to set up logical
+ * groups or something and take some additional parameters. */
+static int route_irq_h(struct irq_handler *irq_h, int os_coreid)
+{
+       int hw_coreid;
+       if (!irq_h->route_irq) {
+               printk("[kernel] apic_vec %d, type %s cannot be routed\n",
+                      irq_h->apic_vector, irq_h->type);
+               return -1;
+       }
+       if (os_coreid >= MAX_NUM_CPUS) {
+               printk("[kernel] os_coreid %d out of range!\n", os_coreid);
+               return -1;
+       }
+       hw_coreid = get_hw_coreid(os_coreid);
+       if (hw_coreid == -1) {
+               printk("[kernel] os_coreid %d not a valid hw core!\n", os_coreid);
+               return -1;
+       }
+       irq_h->route_irq(irq_h, irq_h->apic_vector, hw_coreid);
+       return 0;
+}
+
+/* Routes all irqs for a given apic_vector to os_coreid.  Returns 0 if all of
+ * them succeeded.  -1 if there were none or if any of them failed.  We don't
+ * share IRQs often (if ever anymore), so this shouldn't be an issue. */
+int route_irqs(int apic_vec, int os_coreid)
+{
+       struct irq_handler *irq_h;
+       int ret = -1;
+       if (!vector_is_irq(apic_vec)) {
+               printk("[kernel] vector %d is not an IRQ vector!\n", apic_vec);
+               return -1;
+       }
+       irq_h = irq_handlers[apic_vec];
+       while (irq_h) {
+               assert(irq_h->apic_vector == apic_vec);
+               ret = route_irq_h(irq_h, os_coreid);
+               irq_h = irq_h->next;
+       }
+       return ret;
+}
+
 /* It's a moderate pain in the ass to put these in bit-specific files (header
  * hell with the set_current_ helpers) */
 #ifdef CONFIG_X86_64
index a9a4692..945d795 100644 (file)
@@ -133,7 +133,7 @@ struct irq_handler {
        void (*eoi)(int);
        void (*mask)(struct irq_handler *irq_h, int vec);
        void (*unmask)(struct irq_handler *irq_h, int vec);
-       int (*route_irq)(struct irq_handler *irq_h, int vec, int dest);
+       void (*route_irq)(struct irq_handler *irq_h, int vec, int dest);
 
        int tbdf;
        int dev_irq;
index 28d1cff..94a9f44 100644 (file)
@@ -14,6 +14,7 @@ typedef void (*isr_t)(struct hw_trapframe *hw_tf, void *data);
 
 void idt_init(void);
 int register_irq(int irq, isr_t handler, void *irq_arg, uint32_t tbdf);
+int route_irqs(int cpu_vec, int coreid);
 void print_trapframe(struct hw_trapframe *hw_tf);
 void print_user_ctx(struct user_context *ctx);
 /* Generic per-core timer interrupt handler.  set_percore_timer() will fire the