x86: MSI enabling and cleanup
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 28 Mar 2014 00:16:53 +0000 (17:16 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 29 Mar 2014 01:17:06 +0000 (18:17 -0700)
MSI has the irq_h style function pointers and fits in to the x86 irq
handling system.  The global MSI funcs fall under pci.h too.

Also, this takes MSI out of the business of messing with PCI bus
mastering.

kern/arch/x86/apic.h
kern/arch/x86/ioapic.c
kern/arch/x86/msi.c
kern/arch/x86/pci.h
kern/arch/x86/trap.h

index 2d53568..b85f61d 100644 (file)
@@ -334,9 +334,4 @@ char *apicdump(char *, char *);
 void apictimerenab(void);
 void apicinit(int apicno, uintptr_t pa, int isbp);
 
-/*
-extern int pcimsienable(Pcidev*, uint64_t);
-extern int pcimsimask(Pcidev*, int);
-*/
-
 #endif /* ROS_KERN_APIC_H */
index 9c1e521..73c13a6 100644 (file)
@@ -65,7 +65,6 @@ static spinlock_t idtnolock;
 static int idtno = IdtIOAPIC;
 
 struct apic xioapic[Napic];
-int pcimsimask(struct pci_device *p, int mask);
 
 static bool ioapic_exists(void)
 {
@@ -380,47 +379,33 @@ int nextvec(void)
        return vecno;
 }
 
-static int msimask(struct vkey *v, int mask)
+static int msi_irq_enable(struct irq_handler *irq_h, struct pci_device *p)
 {
-       int pcimsimask(struct pci_device *p, int mask);
-
-       struct pci_device *p;
-       p = pci_match_tbdf(v->tbdf);
-       if (p == NULL)
-               return -1;
-       return pcimsimask(p, mask);
-}
-
-static int intrenablemsi(struct irq_handler *v, struct pci_device *p)
-{
-       int pcimsienable(struct pci_device *p, uint64_t vec);
-
        unsigned int vno, lo, hi = 0;
        uint64_t msivec;
 
        vno = nextvec();
 
-       lo = IPlow | TMedge | vno;
-
-       if (lo & Lm)
-               lo |= MTlp;
+       /* routing the IRQ to core 0 (hi = 0) in physical mode (Pm) */
+       lo = IPlow | TMedge | Pm | vno;
 
        msivec = (uint64_t) hi << 32 | lo;
-       if (pcimsienable(p, msivec) == -1)
+       if (pci_msi_enable(p, msivec) == -1) {
+               /* TODO: should free vno here */
                return -1;
-
-       printk("msiirq: (%d,%d,%d): enabling %.16llp %s irq %d vno %d\n", 
+       }
+       p->msi_hi = hi;
+       p->msi_lo = lo;
+       irq_h->check_spurious = lapic_check_spurious;
+       irq_h->eoi = lapic_send_eoi;
+       irq_h->mask = msi_mask_irq;
+       irq_h->unmask = msi_unmask_irq;
+       irq_h->route_irq = msi_route_irq;
+       irq_h->type = "msi";
+       printd("msiirq: (%d,%d,%d): enabling %.16llp %s irq %d vno %d\n",
               p->bus, p->dev, p->func, msivec,
-                  v->name, v->apic_vector, vno);
-       return -1; //vno;
-}
-
-int disablemsi(void *unused, struct pci_device *p)
-{
-
-       if (p == NULL)
-               return -1;
-       return pcimsimask(p, 1);
+                  irq_h->name, irq_h->apic_vector, vno);
+       return vno;
 }
 
 static struct Rdt *ioapic_vector2rdt(int apic_vector)
@@ -576,9 +561,11 @@ int bus_irq_setup(struct irq_handler *irq_h)
                                printk("No PCI dev for tbdf %p!", irq_h->tbdf);
                                return -1;
                        }
-                       if ((vecno = intrenablemsi(irq_h, pcidev)) != -1)
+                       irq_h->dev_private = pcidev;
+                       if ((vecno = msi_irq_enable(irq_h, pcidev)) != -1)
                                return vecno;
-                       disablemsi(irq_h, pcidev);
+                       /* in case we turned it half-on */;
+                       msi_mask_irq(irq_h, 0 /* unused */);
                        busno = BUSBNO(irq_h->tbdf);
                        assert(busno == pcidev->bus);
                        devno = pcidev_read8(pcidev, PciINTP);
index c15c466..cbb2be5 100644 (file)
@@ -54,8 +54,7 @@ enum{
 };
 
 /* Find an arbitrary capability. This should move to pci.c? */
-int
-pcicap(struct pci_device *p, int cap)
+int pci_cap(struct pci_device *p, int cap)
 {
        int i, c, off;
 
@@ -96,7 +95,7 @@ msicap(struct pci_device *p)
 {
        int c;
 
-       c = pcicap(p, PciCapMSI);
+       c = pci_cap(p, PciCapMSI);
        if(c == -1)
                return 0;
        return c;
@@ -118,8 +117,7 @@ blacklist(struct pci_device *p)
  * and put parts of it in the msi address and parts
  * in the msi data.
  */
-int
-pcimsienable(struct pci_device *p, uint64_t vec)
+int pci_msi_enable(struct pci_device *p, uint64_t vec)
 {
        char *s;
        unsigned int c, f, d, datao, lopri, dmode, logical;
@@ -131,7 +129,6 @@ pcimsienable(struct pci_device *p, uint64_t vec)
        if(c == 0)
                return -1;
 
-       printk("Found cap at %d\n", c);
        /* read it, clear out the Mmesgmsk bits. 
         * This means that there will be no multiple
         * messages enabled.
@@ -160,7 +157,7 @@ pcimsienable(struct pci_device *p, uint64_t vec)
        /* OK, Msiabase is fee00000, and we offset with the
         * dest from above, lowpri, and logical.
         */
-       printk("Write to %d %08lx \n",c + 4, Msiabase | Msiaedest * d
+       printd("Write to %d %08lx \n",c + 4, Msiabase | Msiaedest * d
                | Msialowpri * lopri | Msialogical * logical);
        pcidev_write32(p, c + 4, Msiabase | Msiaedest * d
                | Msialowpri * lopri | Msialogical * logical);
@@ -181,7 +178,7 @@ pcimsienable(struct pci_device *p, uint64_t vec)
         * of things. It's not yet clear if this is a plan 9 chosen
         * thing or a PCI spec chosen thing.
         */
-       printk("Write data %p %d %04x\n", c + datao, Msidassert | Msidlogical * logical
+       printd("Write data %d %04x\n", c + datao, Msidassert | Msidlogical * logical
                       | Msidmode * dmode | ((unsigned int)vec & 0xff));
        pcidev_write16(p, c + datao, Msidassert | Msidlogical * logical
                       | Msidmode * dmode | ((unsigned int)vec & 0xff));
@@ -196,9 +193,9 @@ pcimsienable(struct pci_device *p, uint64_t vec)
         * Mmesg mask (which is a power of 2) set to 0
         * (meaning one message only).
         */
-       printk("write @ %d %04lx\n",c + 2, f); 
+       printd("write @ %d %04lx\n",c + 2, f);
        pcidev_write16(p, c + 2, f);
-       return -1; //0;
+       return 0;
 }
 
 /* Mask the msi function. Since 'masking' means disable it,
@@ -215,13 +212,43 @@ pcimsimask(struct pci_device *p, int mask)
                return -1;
        f = pcidev_read16(p, c + 2);
        if(mask){
-               printk("DISABLE MSI\n");
                pcidev_write16(p, c + 2, f & ~Msienable);
-               pci_clr_bus_master(p);
        }else{
-               printk("ENABLE MSI\n");
-               pci_set_bus_master(p);
                pcidev_write16(p, c + 2, f | Msienable);
        }
        return 0;
 }
+
+void msi_mask_irq(struct irq_handler *irq_h, int apic_vector)
+{
+       struct pci_device *p = (struct pci_device*)irq_h->dev_private;
+       unsigned int c, f;
+       c = msicap(p);
+       assert(c);
+
+       f = pcidev_read16(p, c + 2);
+       pcidev_write16(p, c + 2, f & ~Msienable);
+}
+
+void msi_unmask_irq(struct irq_handler *irq_h, int apic_vector)
+{
+       struct pci_device *p = (struct pci_device*)irq_h->dev_private;
+       unsigned int c, f;
+       c = msicap(p);
+       assert(c);
+
+       f = pcidev_read16(p, c + 2);
+       pcidev_write16(p, c + 2, f | Msienable);
+}
+
+int msi_route_irq(struct irq_handler *irq_h, int apic_vector, int dest)
+{
+       struct pci_device *p = (struct pci_device*)irq_h->dev_private;
+       unsigned int c, f;
+       c = msicap(p);
+       assert(c);
+
+       /* TODO */
+       printk("Not routing MSI yet, fix me!\n");
+       return -1;
+}
index c6d1cd3..7f3bc57 100644 (file)
@@ -355,6 +355,8 @@ struct pci_device {
        uint8_t                                         class;
        uint8_t                                         subclass;
        uint8_t                                         progif;
+       uint32_t                                        msi_hi;
+       uint32_t                                        msi_lo;
        uint8_t                                         nr_bars;
        struct pci_bar                          bar[MAX_PCI_BAR];
 };
@@ -394,6 +396,16 @@ void pci_set_bus_master(struct pci_device *pcidev);
 void pci_clr_bus_master(struct pci_device *pcidev);
 struct pci_device *pci_match_tbdf(int tbdf);
 
+/* MSI functions, msi.c */
+int pci_cap(struct pci_device *p, int cap);
+int pci_msi_enable(struct pci_device *p, uint64_t vec);
+
+/* MSI irq handler functions, msi.c */
+struct irq_handler; /* include loops */
+void msi_mask_irq(struct irq_handler *irq_h, int apic_vector);
+void msi_unmask_irq(struct irq_handler *irq_h, int apic_vector);
+int msi_route_irq(struct irq_handler *irq_h, int apic_vector, int dest);
+
 /* TODO: this is quite the Hacke */
 #define explode_tbdf(tbdf) {pcidev.bus = tbdf >> 16;\
                pcidev.dev = (tbdf>>11)&0x1f;\
index 30a2318..a9a4692 100644 (file)
 #include <arch/coreid.h>
 #include <arch/io.h>
 
-struct vkey {
-       int tbdf;
-       int dev_irq;
-};
-
 struct irq_handler {
        struct irq_handler *next;
        void (*isr)(struct hw_trapframe *hw_tf, void *data);
        void *data;
+       int apic_vector;
 
        /* all handlers in the chain need to have the same func pointers.  we only
         * really use the first one, and the latter are to catch bugs.  also, we
@@ -141,8 +137,8 @@ struct irq_handler {
 
        int tbdf;
        int dev_irq;
-       int apic_vector;
 
+       void *dev_private;
        char *type;
        #define IRQ_NAME_LEN 26
        char name[IRQ_NAME_LEN];