x86: one register_irq() for all types of buses
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 12 Mar 2014 23:31:41 +0000 (16:31 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 29 Mar 2014 01:16:11 +0000 (18:16 -0700)
The 'raw' vectors are just the BusLAPIC type.  I didn't like the nxm way
of relying on BUSUNKNOWN to detect if it was potentially LAPIC.  That
meant you'd always need a bus (like BusPCI) and not just the IRQ for any
external IRQ numbers that were within the LAPIC vector range.

Another way to put it: the LAPIC 'irq' and the global system irq
(devices/acpi) share a different domain, so we need to differentiate on
the bus.

kern/arch/x86/init.c
kern/arch/x86/io.h
kern/arch/x86/ioapic.c
kern/arch/x86/smp.c
kern/arch/x86/trap.c
kern/arch/x86/trap.h
kern/drivers/dev/ether.c
kern/include/trap.h
kern/src/testing.c

index fc5dac5..3eb9ced 100644 (file)
@@ -55,7 +55,7 @@ static void cons_irq_init(void)
        struct cons_dev *i;
        /* Register interrupt handlers for all console devices */
        SLIST_FOREACH(i, &cdev_list, next)
-               register_dev_irq(i->irq, irq_console, i, -1);
+               register_irq(i->irq, irq_console, i, MKBUS(BusISA, 0, 0, 0));
 }
 
 void arch_init()
index abe27b0..6615f1a 100644 (file)
@@ -7,6 +7,8 @@
  * in the LICENSE file.
  */
 
+#ifndef ROS_KERN_ARCH_IO_H
+#define ROS_KERN_ARCH_IO_H
 
 struct Vkey {
        int tbdf;                                       /* pci: ioapic or msi sources */
@@ -21,7 +23,7 @@ typedef struct Vctl {
        struct Vkey;                            /* source-specific key; tbdf for pci */
        void (*f) (void *, void *);     /* handler to call */
        void *a;                                        /* argument to call it with */
-       char name[KNAMELEN];            /* of driver */
+       char name[26];          /* of driver */
        char *type;
 
        int (*isr) (int);                       /* get isr bit for this irq */
@@ -34,7 +36,7 @@ struct ACVctl {
        //char* (*f)(Ureg*,void*);
        void *a;
        int vno;
-       char name[KNAMELEN];            /* of driver */
+       char name[26];          /* of driver */
 };
 
 enum {
@@ -56,6 +58,7 @@ enum {
        BusVL,  /* VESA Local bus */
        BusVME, /* VMEbus */
        BusXPRESS,      /* Express System Bus */
+       BusLAPIC,       /* Local APIC, fake type */
 };
 
 #define MKBUS(t,b,d,f) (((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
@@ -257,3 +260,5 @@ struct Pcidev {
 #define PCIWADDR(va)   (PADDR(va)+PCIWINDOW)
 #define ISAWINDOW      0
 #define ISAWADDR(va)   (PADDR(va)+ISAWINDOW)
+
+#endif /* ROS_KERN_ARCH_IO_H */
index 62eb75b..dbca5a1 100644 (file)
@@ -358,9 +358,10 @@ int nextvec(void)
 {
        unsigned int vecno;
 
+       /* TODO: half-way decent integer service (vmem) */
        spin_lock(&idtnolock);
        vecno = idtno;
-       idtno = (idtno + 8) % IdtMAX;
+       idtno = (idtno + 1) % IdtMAX;
        if (idtno < IdtIOAPIC)
                idtno += IdtIOAPIC;
        spin_unlock(&idtnolock);
@@ -421,75 +422,75 @@ int disablemsi(Vctl *, Pcidev * p)
        return pcimsimask(p, 1);
 }
 #endif
+
+
+/* V does a bunch of IRQ things.  has the device (via tbdf) and irq we are
+ * trying to enable, returns some other stuff like the type, and esp the
+ * IRQ/APIC vector (for the IDT).
+ *
+ *     inputs
+ *             v->irq, v->tbdf
+ *                     v->func and v->arg are also already set
+ *     outputs
+ *             v->type
+ *             returns vector number
+ *             v->isr (but not for spurious LAPIC IRQs)
+ *             v->eoi (sometimes, not for LAPIC)
+ *             v->vno (vector number, but not on LAPICs)
+ *
+ *             do we want unmask functions too?  (like pic_unmask)
+ *
+ * */
 int ioapicintrenable(Vctl * v)
 {
        struct Rbus *rbus;
        struct Rdt *rdt;
        uint32_t hi, lo;
        int busno = 0, devno, vecno;
+       extern int mpisabusno;
+       struct pci_device pcidev;
 
-/*
- * Bridge between old and unspecified new scheme,
- * the work in progress...
- */
-       if (v->tbdf == BUSUNKNOWN) {
-               printk("%s; BUSUNKNOWN\n", __func__);
-               if (idt_vec_is_lapic(v->irq)) {
+       switch (BUSTYPE(v->tbdf)) {
+               case BusLAPIC:
                        if (v->irq != IdtLAPIC_SPURIOUS)
                                v->isr = apiceoi;
                        v->type = "lapic";
+                       /* For the LAPIC, irq == vector */
                        return v->irq;
-               } else {
-                       printk("%s; legacy isa\n", __func__);
-
-                       /*
-                        * Legacy ISA.
-                        * Make a busno and devno using the
-                        * ISA bus number and the irq.
-                        */
-                       extern int mpisabusno;
-
+               case BusISA:
                        if (mpisabusno == -1)
                                panic("no ISA bus allocated");
                        busno = mpisabusno;
                        /* need to track the irq in devno in PCI interrupt assignment entry
                         * format (see mp.c or MP spec D.3). */
                        devno = v->irq << 2;
-               }
-       } else if (BUSTYPE(v->tbdf) == BusPCI) {
-               printk("%s; BusPCI \n", __func__);
-               /*
-                * PCI.
-                * Make a devno from BUSDNO(tbdf) and pcidev->intp.
-                */
-               /* we'll assume it's there. */
+                       break;
+               case BusPCI:
+                       /* we'll assume it's there. */
 #if 0
-               Pcidev *pcidev;
-
-               busno = BUSBNO(v->tbdf);
-               if ((pcidev = pcimatchtbdf(v->tbdf)) == NULL)
-                       panic("no PCI dev for tbdf %p", v->tbdf);
-               if ((vecno = intrenablemsi(v, pcidev)) != -1)
-                       return vecno;
-               disablemsi(v, pcidev);
+                       Pcidev *pcidev;
+
+                       busno = BUSBNO(v->tbdf);
+                       if ((pcidev = pcimatchtbdf(v->tbdf)) == NULL)
+                               panic("no PCI dev for tbdf %p", v->tbdf);
+                       if ((vecno = intrenablemsi(v, pcidev)) != -1)
+                               return vecno;
+                       disablemsi(v, pcidev);
 #endif
-
-               struct pci_device pcidev;
-
-               explode_tbdf(v->tbdf);
-               devno = pcidev_read8(&pcidev, PciINTP);
-               printk("INTP is %d\n", devno);
-
-               if (devno == 0)
-                       panic("no INTP for tbdf %p", v->tbdf);
-               devno = BUSDNO(v->tbdf) << 2 | (devno - 1);
-               printk("devno is %08lx\n", devno);
-               printk("ioapicintrenable: tbdf %p busno %d devno %d\n",
-                          v->tbdf, busno, devno);
-       } else {
-               //SET(busno, devno);
-               busno = devno = 0;
-               panic("unknown tbdf %px", v->tbdf);
+                       explode_tbdf(v->tbdf);
+                       devno = pcidev_read8(&pcidev, PciINTP);
+                       printk("INTP is %d\n", devno);
+
+                       if (devno == 0)
+                               panic("no INTP for tbdf %p", v->tbdf);
+                       /* remember, devno is the device shifted with irq pin in bits 0-1 */
+                       devno = BUSDNO(v->tbdf) << 2 | (devno - 1);
+                       printk("devno is %08lx\n", devno);
+                       printk("ioapicintrenable: tbdf %p busno %d devno %d\n",
+                                  v->tbdf, busno, devno);
+                       break;
+               default:
+                       panic("Unknown bus type, TBDF %p", v->tbdf);
        }
 
        rdt = NULL;
@@ -624,7 +625,6 @@ int intrenable(int irq, void (*f) (void *, void *), void *a, int tbdf)
 
        //spilock(&vctllock);
        vno = ioapicintrenable(v);
-       printk("INTRENABLE, vno is %d\n", vno);
        if (vno == -1) {
                //iunlock(&vctllock);
                printk("intrenable: couldn't enable irq %d, tbdf %p for %s\n",
@@ -654,7 +654,7 @@ int intrenable(int irq, void (*f) (void *, void *), void *a, int tbdf)
         * the handler; the IRQ is useless in the wonderful world
         * of the IOAPIC.
         */
-       printk("INTRNABLE returns %p\n", v);
-       printk("INTRNABLE returns %d\n", v->vno);
-       return v->vno;
+       printk("INTRNABLE returns %d\n", vno);
+       kfree(v);
+       return vno;
 }
index e3d6dc3..5474f9b 100644 (file)
@@ -120,7 +120,7 @@ static int smp_call_function(uint8_t type, uint32_t dest, isr_t handler,
         * We're waiting on RCU to do a nice unregister. */
        extern struct irq_handler *irq_handlers[];
        if (!irq_handlers[wrapper->vector]) {
-               register_raw_irq(wrapper->vector, handler, data);
+               register_irq(wrapper->vector, handler, data, MKBUS(BusLAPIC, 0, 0, 0));
        } else {
                /* we're replacing the old one.  hope it was ours, and the IRQ is firing
                 * concurrently (if it is, there's an smp_call bug)! */
index 6bc1079..7c80bb9 100644 (file)
@@ -188,9 +188,11 @@ void idt_init(void)
 #endif
 
        /* register the generic timer_interrupt() handler for the per-core timers */
-       register_raw_irq(IdtLAPIC_TIMER, timer_interrupt, NULL);
+       register_irq(IdtLAPIC_TIMER, timer_interrupt, NULL,
+                        MKBUS(BusLAPIC, 0, 0, 0));
        /* register the kernel message handler */
-       register_raw_irq(I_KERNEL_MSG, handle_kmsg_ipi, NULL);
+       register_irq(I_KERNEL_MSG, handle_kmsg_ipi, NULL,
+                        MKBUS(BusLAPIC, 0, 0, 0));
 }
 
 static void handle_fperr(struct hw_trapframe *hw_tf)
@@ -516,7 +518,7 @@ static bool irq_from_pic(uint32_t trap_nr)
 }
 
 /* TODO: remove the distinction btw raw and device IRQs */
-void register_raw_irq(unsigned int vector, isr_t handler, void *data)
+static void register_raw_irq(unsigned int vector, isr_t handler, void *data)
 {
        struct irq_handler *irq_h;
        irq_h = kmalloc(sizeof(struct irq_handler), 0);
@@ -555,7 +557,7 @@ void unregister_raw_irq(unsigned int vector, isr_t handler, void *data)
 /* The devno is arbitrary data. Normally, however, it will be a
  * PCI type-bus-dev.func. It is required for ioapics.
  */
-int register_dev_irq(int irq, isr_t handler, void *irq_arg, uint32_t tbdf)
+int register_irq(int irq, isr_t handler, void *irq_arg, uint32_t tbdf)
 {
        /* TODO: whenever we sort out the ACPI/IOAPIC business, we'll probably want
         * a helper to reroute an irq? */
@@ -566,8 +568,12 @@ int x =    intrenable(irq, handler, irq_arg, tbdf);
        if (x > 0)
                register_raw_irq(x, handler, irq_arg);
 #else
-       register_raw_irq(irq + IdtPIC, handler, irq_arg);
-       pic_unmask_irq(irq + IdtPIC);
+       if (irq_from_pic(irq + IdtPIC)) {
+               register_raw_irq(irq + IdtPIC, handler, irq_arg);
+               pic_unmask_irq(irq + IdtPIC);
+       } else {
+               register_raw_irq(irq, handler, irq_arg);
+       }
 #endif
        return 0;
 }
index caeb26e..637c9c0 100644 (file)
 #include <arch/pci.h>
 #include <arch/pic.h>
 #include <arch/coreid.h>
+#include <arch/io.h>
 
 struct irq_handler {
        struct irq_handler *next;
index cc482c2..fdc7c56 100644 (file)
@@ -26,7 +26,7 @@
 #include <pmap.h>
 #include <smp.h>
 #include <ip.h>
-#include <arch/io.h>
+
 enum {
        Type8021Q = 0x8100,                     /* value of type field for 802.1[pQ] tags */
 };
@@ -682,7 +682,7 @@ static void etherreset(void)
                        snprintf(name, sizeof(name), "ether%d", ctlrno);
 
                        if (ether->interrupt != NULL)
-                               register_dev_irq(ether->irq, ether->interrupt, ether, ether->tbdf);
+                               register_irq(ether->irq, ether->interrupt, ether, ether->tbdf);
 
                        i = snprintf(buf, sizeof(buf),
                                                 "#l%d: %s: %dMbps port 0x%x irq %u", ctlrno,
index 39f45e9..28d1cff 100644 (file)
@@ -13,9 +13,7 @@
 typedef void (*isr_t)(struct hw_trapframe *hw_tf, void *data);
 
 void idt_init(void);
-void register_raw_irq(unsigned int vector, isr_t handler, void *data);
-void unregister_raw_irq(unsigned int vector, isr_t handler, void *data);
-int register_dev_irq(int irq, isr_t handler, void *irq_arg, uint32_t tbdf);
+int register_irq(int irq, isr_t handler, void *irq_arg, uint32_t tbdf);
 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
index 808bfff..596698d 100644 (file)
@@ -51,7 +51,8 @@ void test_ipi_sending(void)
 {
        int8_t state = 0;
 
-       register_raw_irq(I_TESTING, test_hello_world_handler, NULL);
+       register_irq(I_TESTING, test_hello_world_handler, NULL,
+                        MKBUS(BusLAPIC, 0, 0, 0));
        enable_irqsave(&state);
        cprintf("\nCORE 0 sending broadcast\n");
        send_broadcast_ipi(I_TESTING);
@@ -87,7 +88,8 @@ void test_ipi_sending(void)
 // Note this never returns and will muck with any other timer work
 void test_pic_reception(void)
 {
-       register_raw_irq(0x20, test_hello_world_handler, NULL);
+       register_irq(0x20, test_hello_world_handler, NULL,
+                        MKBUS(BusLAPIC, 0, 0, 0));
        pit_set_timer(100,TIMER_RATEGEN); // totally arbitrary time
        pic_unmask_irq(0);
        cprintf("PIC1 Mask = 0x%04x\n", inb(PIC1_DATA));
@@ -100,7 +102,8 @@ void test_pic_reception(void)
 
 void test_ioapic_pit_reroute(void) 
 {
-       register_raw_irq(0x20, test_hello_world_handler, NULL);
+       register_irq(0x20, test_hello_world_handler, NULL,
+                        MKBUS(BusLAPIC, 0, 0, 0));
 #ifdef CONFIG_ENABLE_MPTABLES
 #warning "not routing the irq"
        //ioapic_route_irq(0, 3);       
@@ -555,7 +558,8 @@ void test_smp_call_functions(void)
 #ifdef CONFIG_X86
 void test_lapic_status_bit(void)
 {
-       register_raw_irq(I_TESTING, test_incrementer_handler, &a);
+       register_irq(I_TESTING, test_incrementer_handler, &a,
+                        MKBUS(BusLAPIC, 0, 0, 0));
        #define NUM_IPI 100000
        atomic_set(&a,0);
        printk("IPIs received (should be 0): %d\n", a);
@@ -657,7 +661,8 @@ void test_pit(void)
 
        atomic_t waiting;
        atomic_init(&waiting, 1);
-       register_raw_irq(I_TESTING, test_waiting_handler, &waiting);
+       register_irq(I_TESTING, test_waiting_handler, &waiting,
+                        MKBUS(BusLAPIC, 0, 0, 0));
        while(atomic_read(&waiting))
                cpu_relax();
        cprintf("End now\n");