x86: use a proper allocator for IRQ vectors
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 8 Oct 2019 21:00:23 +0000 (17:00 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 8 Oct 2019 21:11:11 +0000 (17:11 -0400)
Yet another arena allocator!

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/riscv/trap.c
kern/arch/x86/ioapic.c
kern/arch/x86/trap.c
kern/include/trap.h

index 78150be..32d1f95 100644 (file)
@@ -362,6 +362,17 @@ int route_irqs(int cpu_vec, int coreid)
        return -1;
 }
 
+int get_irq_vector(void)
+{
+       printk("%s not implemented\n", __FUNCTION);
+       return -1;
+}
+
+void put_irq_vector(int vec)
+{
+       printk("%s not implemented\n", __FUNCTION);
+}
+
 void __arch_reflect_trap_hwtf(struct hw_trapframe *hw_tf, unsigned int trap_nr,
                               unsigned int err, unsigned long aux)
 {
index 8d2d197..70a71d2 100644 (file)
@@ -59,9 +59,6 @@ static struct Rbus *rdtbus[Nbus];
 /* reverse mapping of IDT vector to the RDT/IOAPIC entry triggering vector */
 static struct Rdt *rdtvecno[IdtMAX + 1];
 
-static spinlock_t idtnolock;
-static int idtno = IdtIOAPIC;
-
 struct apic xioapic[Napic];
 
 static bool ioapic_exists(void)
@@ -372,21 +369,6 @@ void ioapiconline(void)
        }
 }
 
-int nextvec(void)
-{
-       unsigned int vecno;
-
-       /* TODO: half-way decent integer service (vmem) */
-       spin_lock(&idtnolock);
-       vecno = idtno;
-       idtno = (idtno + 1) % IdtMAX;
-       if (idtno < IdtIOAPIC)
-               idtno += IdtIOAPIC;
-       spin_unlock(&idtnolock);
-
-       return vecno;
-}
-
 static void msi_mask_irq(struct irq_handler *irq_h, int apic_vector)
 {
        pci_msi_mask(irq_h->dev_private);
@@ -423,7 +405,11 @@ static int msi_irq_enable(struct irq_handler *irq_h, struct pci_device *p)
        uint64_t msivec;
        struct msix_irq_vector *linkage;
 
-       vno = nextvec();
+       vno = get_irq_vector();
+       if (!vno) {
+               printk("[kernel] Unable to get a vector for MSI(X)!\n");
+               return -1;
+       }
 
        /* routing the IRQ to core 0 (hi = 0) in physical mode (Pm) */
        lo = IPlow | TMedge | Pm | vno;
@@ -432,7 +418,7 @@ static int msi_irq_enable(struct irq_handler *irq_h, struct pci_device *p)
        irq_h->dev_private = pci_msix_enable(p, msivec);
        if (!irq_h->dev_private) {
                if (pci_msi_enable(p, msivec) == -1) {
-                       /* TODO: should free vno here */
+                       put_irq_vector(vno);
                        return -1;
                }
                irq_h->dev_private = p;
@@ -657,7 +643,12 @@ int bus_irq_setup(struct irq_handler *irq_h)
         * this stays around regardless of enabled/disabled, since we don't reap
         * vectors yet.  nor do we really mess with enabled... */
        if ((rdt->lo & 0xff) == 0) {
-               vecno = nextvec();
+               vecno = get_irq_vector();
+               if (!vecno) {
+                       printk("[kernel] unable to get an IOAPIC vector\n");
+                       spin_unlock(&rdt->apic->lock);
+                       return -1;
+               }
                rdt->lo |= vecno;
                rdtvecno[vecno] = rdt;
        } else {
index 799d6e3..daa7588 100644 (file)
@@ -38,6 +38,8 @@ pseudodesc_t idt_pd;
 struct irq_handler *irq_handlers[NUM_IRQS];
 spinlock_t irq_handler_wlock = SPINLOCK_INITIALIZER_IRQSAVE;
 
+static struct arena *irq_vectors;
+
 static bool try_handle_exception_fixup(struct hw_trapframe *hw_tf)
 {
        if (in_kernel(hw_tf)) {
@@ -181,6 +183,11 @@ void idt_init(void)
 
        asm volatile("lidt %0" : : "m"(idt_pd));
 
+       irq_vectors = arena_create("irq_vectors", (void*)IdtIOAPIC,
+                                  MaxIdtIOAPIC - IdtIOAPIC, 1,
+                                  NULL, NULL, NULL, 0, MEM_ATOMIC);
+       assert(irq_vectors);
+
        pic_remap();
        pic_mask_all();
 
@@ -838,6 +845,18 @@ int deregister_irq(int vector, uint32_t tbdf)
        return 0;
 }
 
+/* 0 is an error.  It's not a valid IRQ vector for Akaros, even if
+ * divide-by-zero has trap/irq vector 0 (T_DIVIDE). */
+int get_irq_vector(void)
+{
+       return (int)(long)arena_alloc(irq_vectors, 1, MEM_ATOMIC);
+}
+
+void put_irq_vector(int vec)
+{
+       arena_free(irq_vectors, (void*)(long)vec, 1);
+}
+
 /* 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. */
index c3ae8d1..6056b2c 100644 (file)
@@ -18,6 +18,9 @@ struct irq_handler *register_irq(int irq, isr_t handler, void *irq_arg,
                                 uint32_t tbdf);
 int deregister_irq(int vector, uint32_t tbdf);
 int route_irqs(int cpu_vec, int coreid);
+int get_irq_vector(void);
+void put_irq_vector(int vec);
+
 void print_trapframe(struct hw_trapframe *hw_tf);
 void print_swtrapframe(struct sw_trapframe *sw_tf);
 void print_vmtrapframe(struct vm_trapframe *vm_tf);