MSI-X support
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 3 Apr 2014 22:53:13 +0000 (15:53 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 3 Apr 2014 23:04:39 +0000 (16:04 -0700)
Adds support for MSI-X interrupts, including routing of individual
vectors to cores, via the irq_handler.

Cleaned up MSI a bit too, extracting common code (they use the same
MSI addr and data format).

Still needs a little cleanup and synchronization support.

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

index eef4a57..a210164 100644 (file)
@@ -383,19 +383,31 @@ static int msi_irq_enable(struct irq_handler *irq_h, struct pci_device *p)
        lo = IPlow | TMedge | Pm | vno;
 
        msivec = (uint64_t) hi << 32 | lo;
-       if (pci_msi_enable(p, msivec) == -1) {
-               /* TODO: should free vno here */
-               return -1;
+       if (pci_msix_enable(irq_h, p, msivec) == -1) {
+               if (pci_msi_enable(p, msivec) == -1) {
+                       /* in case we turned it half-on */;
+                       msi_mask_irq(irq_h, 0 /* unused */);
+                       /* TODO: should free vno here */
+                       return -1;
+               }
+               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";
+               printk("MSI irq: (%x,%x,%x): enabling %p %s vno %d\n",
+                          p->bus, p->dev, p->func, msivec, irq_h->name, vno);
+               return vno;
        }
        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";
-       printk("msiirq: (%d,%d,%d): enabling %.16llp %s irq %d vno %d\n",
-              p->bus, p->dev, p->func, msivec,
-                  irq_h->name, irq_h->apic_vector, vno);
+       irq_h->mask = msix_mask_irq;
+       irq_h->unmask = msix_unmask_irq;
+       irq_h->route_irq = msix_route_irq;
+       irq_h->type = "msi-x";
+       printk("MSI-X irq: (%x,%x,%x): enabling %p %s vno %d\n",
+              p->bus, p->dev, p->func, msivec, irq_h->name, vno);
        return vno;
 }
 
@@ -555,8 +567,6 @@ int bus_irq_setup(struct irq_handler *irq_h)
                        irq_h->dev_private = pcidev;
                        if ((vecno = msi_irq_enable(irq_h, pcidev)) != -1)
                                return vecno;
-                       /* 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 2603508..503cce3 100644 (file)
@@ -73,14 +73,13 @@ enum{
        Msienable       = 1<<0, /* Enable. */
        /* msix capabilities */
        Msixenable      = 1<<15,
-       Msixmask        = 1<<15,
-       Msixsize        = 0x3ff,
+       Msixmask        = 1<<14,
+       Msixtblsize     = 0x7ff,
 };
 
 /* Find the offset in config space of this function of the msi capability.
  * It is defined in 6.8.1 and is variable-sized.  Returns 0 on failure. */
-static int
-msicap(struct pci_device *p)
+static int msicap(struct pci_device *p)
 {
        return p->caps[PCI_CAP_ID_MSI];
 }
@@ -88,23 +87,59 @@ msicap(struct pci_device *p)
 /* Find the offset in config space of this function of the msi-x capability.
  * It is defined in 6.8.1 and is variable-sized.
  */
-static int
-msixcap(struct pci_device *p)
+static int msixcap(struct pci_device *p)
 {
        return p->caps[PCI_CAP_ID_MSIX];
 }
 
-static int
-blacklist(struct pci_device *p)
+static int msi_blacklist(struct pci_device *p)
 {
-       switch(p->ven_id<<16 | p->dev_id){
-       case 0x11ab<<16 | 0x6485:
-       case 0x8086<<16 | 0x100f:
-               return -1;
+       switch (p->ven_id << 16 | p->dev_id) {
+               case 0x11ab << 16 | 0x6485:
+               case 0x8086 << 16 | 0x100f:
+                       return -1;
+       }
+       return 0;
+}
+
+static int msix_blacklist(struct pci_device *p)
+{
+       switch (p->ven_id << 16 | p->dev_id) {
+//             case 0x11ab << 16 | 0x6485:     /* placeholder */
+                       return -1;
        }
        return 0;
 }
 
+static uint32_t msi_make_addr_lo(uint64_t vec)
+{
+       unsigned int dest, lopri, logical;
+       /* The destination is the traditional 8-bit APIC id is in 63:56 of the
+        * vector.  Later we may need to deal with extra destination bits
+        * (Msiaedest, in this code).  I haven't seen anything in the Intel SDM
+        * about using Msiaedest (the bits are reserved) */
+       dest = vec >> 56;
+       /* lopri is rarely set, and intel doesn't recommend using it.  with msi, the
+        * lopri field is actually a redirection hint, and also must be set when
+        * sending logical messages. */
+       lopri = (vec & 0x700) == MTlp;
+       logical = (vec & Lm) != 0;
+       if (logical)
+               lopri = 1;
+       return Msiabase | Msiadest * dest | Msialowpri * lopri |
+              Msialogical * logical;
+}
+
+static uint32_t msi_make_data(uint64_t vec)
+{
+       unsigned int deliv_mode;
+       deliv_mode = (vec >> 8) & 7;
+       /* We can only specify the lower 16 bits of the MSI message, the rest gets
+        * forced to 0 by the device.  MSI-X can use the full 32 bits.  We're
+        * assuming edge triggered here. */
+       return Msidmode * deliv_mode | ((unsigned int)vec & 0xff);
+}
+
 /* see section 6.8.1 of the pci spec. */
 /* Set up a single function on a single device.
  * We need to take the vec, bust it up into bits,
@@ -113,8 +148,7 @@ blacklist(struct pci_device *p)
  */
 int pci_msi_enable(struct pci_device *p, uint64_t vec)
 {
-       char *s;
-       unsigned int c, f, dest, datao, lopri, dmode, logical;
+       unsigned int c, f, datao;
 
        /* Get the offset of the MSI capability
         * in the function's config space.
@@ -130,32 +164,12 @@ int pci_msi_enable(struct pci_device *p, uint64_t vec)
         */
        f = pcidev_read16(p, c + 2) & ~Mmesgmsk;
 
-       if (blacklist(p) != 0)
+       if (msi_blacklist(p) != 0)
                return -1;
 
        /* Data begins at 8 bytes in. */
        datao = 8;
-
-       /* The destination is the traditional 8-bit APIC id is in 63:56 of the
-        * vector.  Later we may need to deal with extra destination bits
-        * (Msiaedest, in this code).  I haven't seen anything in the Intel SDM
-        * about using Msiaedest (the bits are reserved) */
-       dest = vec >> 56;
-
-       /* lopri is rarely set, and intel doesn't recommend using it.  with msi, the
-        * lopri field is actually a redirection hint, and also must be set when
-        * sending logical messages. */
-       lopri = (vec & 0x700) == MTlp;
-
-       logical = (vec & Lm) != 0;
-       if (logical)
-               lopri = 1;
-
-       /* OK, Msiabase is fee00000, and we offset with the
-        * dest from above, lowpri, and logical.
-        */
-       p->msi_msg_addr_lo = Msiabase | Msiadest * dest | Msialowpri * lopri |
-                            Msialogical * logical;
+       p->msi_msg_addr_lo = msi_make_addr_lo(vec);
        printd("Write to %d %08lx \n",c + 4, p->msi_msg_addr_lo);
        pcidev_write32(p, c + 4, p->msi_msg_addr_lo);
 
@@ -169,12 +183,7 @@ int pci_msi_enable(struct pci_device *p, uint64_t vec)
        }
        p->msi_msg_addr_hi = 0;
 
-       /* pick up the delivery mode from the vector */
-       dmode = (vec >> 8) & 7;
-
-       /* We can only specify the lower 16 bits of the MSI message, the rest gets
-        * forced to 0 by the device.  We're assuming edge triggered here. */
-       p->msi_msg_data = Msidmode * dmode | ((unsigned int)vec & 0xff);
+       p->msi_msg_data = msi_make_data(vec);
        printd("Write data %d %04x\n", c + datao, p->msi_msg_data);
        pcidev_write16(p, c + datao, p->msi_msg_data);
 
@@ -186,157 +195,131 @@ int pci_msi_enable(struct pci_device *p, uint64_t vec)
 
        /* Now write the control bits back, with the Mmesg mask (which is a power of
         * 2) set to 0 (meaning one vector only).  Note we still haven't enabled
-        * MSI.  Will do that when we unmask. */
+        * MSI.  Will do that when we unmask.  According to the spec, we're not
+        * supposed to use the Msienable bit to mask the IRQ, though I don't see how
+        * we can mask on non-Vmask-supported HW. */
        printd("write @ %d %04lx\n",c + 2, f);
        pcidev_write16(p, c + 2, f);
        return 0;
 }
 
-/* see section 6.8.1 of the pci spec. */
-/* Set up a single function on a single device.
- * We need to take the vec, bust it up into bits,
- * and put parts of it in the msi address and parts
- * in the msi data.
- */
+static void msix_mask_entry(struct msix_entry *entry)
+{
+       uintptr_t reg = (uintptr_t)&entry->vector;
+       write_mmreg32(reg, read_mmreg32(reg) | 0x1);
+}
+
+static void msix_unmask_entry(struct msix_entry *entry)
+{
+       uintptr_t reg = (uintptr_t)&entry->vector;
+       write_mmreg32(reg, read_mmreg32(reg) & ~0x1);
+}
+
+static uintptr_t msix_get_capbar_paddr(struct pci_device *p, int offset)
+{
+       uint32_t bir, capbar_off;
+       uintptr_t membar;
+       
+       bir = pcidev_read32(p, offset);
+       capbar_off = bir & ~0x7;
+       bir &= 0x7;
+       membar = pci_get_membar(p, bir);
+
+       if (!membar) {
+               printk("MSI-X: no cap membar, bir %d\n", bir);
+               return 0;
+       }
+       membar += capbar_off;
+       if (PGOFF(membar)) {
+               printk("MSI-X: unaligned cap membar %p\n", membar);
+               return 0;
+       }
+       return membar;
+}
+
+/* One time initialization of MSI-X for a PCI device.  -1 on error.  Otherwise,
+ * the device will be ready to assign/route MSI-X entries/vectors.  All vectors
+ * are masked, but the overall MSI-X function is unmasked. */
 static int pci_msix_init(struct pci_device *p)
 {
-       char *s;
-       unsigned int c, d, datao, lopri, dmode, logical;
+       unsigned int c;
        uint16_t f;
-       int bars[2], found;
+       int tbl_bir, tbl_off, pba_bir, pba_off;
+       struct msix_entry *entry;
 
-       /* Get the offset of the MSI capability
-        * in the function's config space.
-        */
+       if (msix_blacklist(p) != 0)
+               return -1;
+       /* Get the offset of the MSI capability in the function's config space. */
        c = msixcap(p);
-       if(c == 0)
+       if (c == 0)
                return -1;
+       f = pcidev_read16(p, c + 2);
+       /* enable and mask the entire function/all vectors */
+       f |= Msixenable | Msixmask;
+       pcidev_write16(p, c + 2, f);
 
-       /* for this to work, we need at least one free BAR. */
-       found = pci_find_unused_bars(p, bars, 1);
-
-       /* we'll use one for now. */
-       if (found < 1)
+       p->msix_tbl_paddr = msix_get_capbar_paddr(p, c + 4);
+       p->msix_pba_paddr = msix_get_capbar_paddr(p, c + 8);
+       if (!p->msix_tbl_paddr || !p->msix_pba_paddr)
                return -1;
-
-       f = pcidev_read16(p, c + 2);
-       printd("msix control %04x\n", f);
-       if (!(f & Msixenable)){
-               printk("msix not enabled, f is 0x%x; done\n", f);
+       p->msix_nr_vec = (f & Msixtblsize) + 1;
+       p->msix_tbl_vaddr = vmap_pmem_nocache(p->msix_tbl_paddr, p->msix_nr_vec *
+                                             sizeof(struct msix_entry));
+       if (!p->msix_tbl_vaddr) {
+               printk("MSI-X: unable to vmap the Table!\n");
                return -1;
        }
-
-       /* See if it's a broken device.
-        */
-       if(blacklist(p) != 0)
-               return -1;
-
-       /* alloc 8 physically contiguous pages. */
-       p->msix = get_cont_pages(8, KMALLOC_WAIT);
-       if (! p->msix)
+       p->msix_pba_vaddr = vmap_pmem_nocache(p->msix_pba_paddr,
+                                             ROUNDUP(p->msix_nr_vec, 8) / 8);
+       if (!p->msix_pba_vaddr) {
+               printk("MSI-X: unable to vmap the PBA!\n");
+               vunmap_vmem(p->msix_tbl_paddr,
+                       p->msix_nr_vec * sizeof(struct msix_entry));
                return -1;
-       /* init them. */
-       memset(p->msix, 0, 8*PAGE_SIZE);
-       /* point the bar you found to them. */
-       p->msixbar = found;
-       p->msixsize = f & Msixsize;
-       /* what do we do for 64-bit bars? Who knows? */
-       /* there's an issue here. Does it need to be 8k aligned? Hmm. */
-       pcidev_write32(p, 0x10 + p->msixbar, paddr_low32(p->msix));
-       /* set the caps to point to the bar. */
-       /* Format is offset from the msibar | which bar it is. */
-       /* table is at offset 0. */
-       pcidev_write32(p, c + 4, found);
-       /* PBA is at offset 4096 */
-       pcidev_write32(p, c + 8, found | 4*PAGE_SIZE);
-       /* that seems to be it for the config space. */
+       }
+       /* they should all be masked already, but just in case */
+       entry = (struct msix_entry*)p->msix_tbl_vaddr;
+       for (int i = 0; i < p->msix_nr_vec; i++, entry++) {
+               msix_mask_entry(entry);
+       }
+       /* unmask the device, now that all the vectors are masked */
+       f &= ~Msixmask;
+       pcidev_write16(p, c + 2, f);
        return 0;
 }
 
-struct msixentry {
-       uint32_t addrlo, addrhi, data, vector;
-};
-
-int pci_msix_enable(struct pci_device *p, uint64_t vec)
+int pci_msix_enable(struct irq_handler *irq_h, struct pci_device *p,
+                    uint64_t vec)
 {
        int i;
-       struct msixentry *entry;
-       unsigned int c, d, datao, lopri, dmode, logical;
-       /* we don't call this much, so we don't mind
-        * retrying it.
-        */
-       if (! p->msixready) {
+       struct msix_entry *entry;
+       struct msix_irq_vector *linkage;
+       unsigned int c, datao;
+
+       /* TODO: sync protection */
+       if (!p->msix_ready) {
                if (pci_msix_init(p) < 0)
                        return -1;
-               p->msixready = 1;
+               p->msix_ready = TRUE;
        }
-
-       /* find an unused slot. */
-       for(i = 0, entry = p->msix; i < p->msixsize; i++, entry++)
-               if (! entry->vector)
+       /* find an unused slot (no apic_vector assigned).  later, we might want to
+        * point back to the irq_hs for each entry.  not a big deal now. */
+       entry = (struct msix_entry*)p->msix_tbl_vaddr;
+       for (i = 0; i < p->msix_nr_vec; i++, entry++)
+               if (!(read_mmreg32((uintptr_t)&entry->data) & 0xff))
                        break;
-       if (i == p->msixsize)
+       if (i == p->msix_nr_vec)
                return -1;
-
-       /* The data we write is 16 bits, scarfed
-        * in the upper 16 bits of d.
-        */
-       /* The data we write is 16 bits, scarfed
-        * in the upper 16 bits of d.
-        */
-       d = vec>>48;
-
-       entry->data = d;
-
-       /* Hard to see it being anything but lopri but ... */
-       lopri = (vec & 0x700) == MTlp;
-
-       logical = (vec & Lm) != 0;
-
-       /* OK, Msiabase is fee00000, and we offset with the
-        * dest from above, lowpri, and logical.
-        */
-       printd("Write to %d %08lx \n",c + 4, Msiabase | Msiaedest * d
-               | Msialowpri * lopri | Msialogical * logical);
-       entry->addrlo = Msiabase | Msiaedest * d
-               | Msialowpri * lopri | Msialogical * logical;
-       
-       /* And even if it's 64-bit capable, we do nothing with
-        * the high order bits. If it is 64-bit we need to offset
-        * datao (data offset) by 4 (i.e. another 32 bits)
-        */
-       entry->addrhi = 0;
-
-       /* pick up the delivery mode from the vector */
-       dmode = (vec >> 8) & 7;
-
-       /* the data we write to that location is a combination
-        * of things. It's not yet clear if this is a plan 9 chosen
-        * thing or a PCI spec chosen thing.
-        */
-       printd("Write data @%p %04x\n", &entry->data, Msidassert |
-              Msidmode * dmode | ((unsigned int)vec & 0xff));
-       entry->data = Msidassert | Msidmode * dmode | ((unsigned int)vec & 0xff);
-       return 0;
-}
-/* Mask the msi function. Since 'masking' means disable it,
- * but the parameter has a 1 for disabling it, well, it's a
- * bit clear operation.
- */
-int
-pcimsimask(struct pci_device *p, int mask)
-{
-       unsigned int c, f;
-
-       c = msicap(p);
-       if(c == 0)
-               return -1;
-       f = pcidev_read16(p, c + 2);
-       if(mask){
-               pcidev_write16(p, c + 2, f & ~Msienable);
-       }else{
-               pcidev_write16(p, c + 2, f | Msienable);
-       }
+       linkage = kmalloc(sizeof(struct msix_irq_vector), KMALLOC_WAIT);
+       linkage->pcidev = p;
+       linkage->entry = entry;
+       linkage->addr_lo = msi_make_addr_lo(vec);
+       linkage->addr_hi = 0;
+       linkage->data = msi_make_data(vec);
+       write_mmreg32((uintptr_t)&entry->data, linkage->data);
+       write_mmreg32((uintptr_t)&entry->addr_lo, linkage->addr_lo);
+       write_mmreg32((uintptr_t)&entry->addr_hi, linkage->addr_hi);
+       irq_h->dev_private = linkage;
        return 0;
 }
 
@@ -373,7 +356,29 @@ int msi_route_irq(struct irq_handler *irq_h, int apic_vector, int dest)
 
        /* mask out the old destination, replace with new */
        p->msi_msg_addr_lo &= ~(((1 << 8) - 1) << 12);
-       p->msi_msg_addr_lo |= dest << 12;
+       p->msi_msg_addr_lo |= (dest & 0xff) << 12;
        pcidev_write32(p, c + 4, p->msi_msg_addr_lo);
        return 0;
 }
+
+void msix_mask_irq(struct irq_handler *irq_h, int apic_vector)
+{
+       struct msix_irq_vector *linkage = irq_h->dev_private;
+       msix_mask_entry(linkage->entry);
+}
+
+void msix_unmask_irq(struct irq_handler *irq_h, int apic_vector)
+{
+       struct msix_irq_vector *linkage = irq_h->dev_private;
+       msix_unmask_entry(linkage->entry);
+}
+
+int msix_route_irq(struct irq_handler *irq_h, int apic_vector, int dest)
+{
+       struct msix_irq_vector *linkage = irq_h->dev_private;
+       /* mask out the old destination, replace with new */
+       linkage->addr_lo &= ~(((1 << 8) - 1) << 12);
+       linkage->addr_lo |= (dest & 0xff) << 12;
+       write_mmreg32((uintptr_t)&linkage->entry->addr_lo, linkage->addr_lo);
+       return 0;
+}
index baafeab..5f76b25 100644 (file)
@@ -339,6 +339,18 @@ uint32_t pci_getiobar32(uint32_t bar)
        return bar & 0xfffffffc;
 }
 
+/* Helper to get the membar value for BAR index bir */
+uintptr_t pci_get_membar(struct pci_device *pcidev, int bir)
+{
+       if (bir >= pcidev->nr_bars)
+               return 0;
+       if (pci_is_iobar(pcidev->bar[bir].raw_bar))
+               return 0;
+       return (pci_is_membar64(pcidev->bar[bir].raw_bar) ?
+               pcidev->bar[bir].mmio_base64 :
+               pcidev->bar[bir].mmio_base32);
+}
+
 /* Helper to get the class description strings.  Adapted from
  * http://www.pcidatabase.com/reports.php?type=c-header */
 static void pcidev_get_cldesc(struct pci_device *pcidev, char **class,
@@ -424,7 +436,8 @@ void pcidev_print_info(struct pci_device *pcidev, int verbosity)
                        printk("IO port 0x%04x\n", pcidev->bar[i].pio_base);
                } else {
                        bool bar_is_64 = pci_is_membar64(pcidev->bar[i].raw_bar);
-                       printk("MMIO Base %p, MMIO Size %p\n",
+                       printk("MMIO Base%s %p, MMIO Size %p\n",
+                              bar_is_64 ? "64" : "32",
                               bar_is_64 ? pcidev->bar[i].mmio_base64 :
                                           pcidev->bar[i].mmio_base32,
                               pcidev->bar[i].mmio_sz);
@@ -457,17 +470,6 @@ void pci_clr_bus_master(struct pci_device *pcidev)
        pcidev_write16(pcidev, PCI_CMD_REG, reg);
 }
 
-/* Find up to 'need' unused bars. Needed for MSI-X */
-int pci_find_unused_bars(struct pci_device *dev, int *bars, int need)
-{
-       int i, found;
-       for(i = found = 0; found < need && i < ARRAY_SIZE(dev->bar); i++)
-               if (!dev->bar[i].raw_bar)
-                       bars[found++] = i;
-       return found;
-
-}
-
 struct pci_device *pci_match_tbdf(int tbdf)
 {
        struct pci_device *search;
index 72106c0..b39c588 100644 (file)
 #define  PCI_AF_STATUS_TP      0x01
 #define PCI_CAP_AF_SIZEOF      6       /* size of AF registers */
 
-/* this part of the file is from linux, with an odd copyright. */
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#define msi_control_reg(base)          (base + PCI_MSI_FLAGS)
-#define msi_lower_address_reg(base)    (base + PCI_MSI_ADDRESS_LO)
-#define msi_upper_address_reg(base)    (base + PCI_MSI_ADDRESS_HI)
-#define msi_data_reg(base, is64bit)    \
-       (base + ((is64bit == 1) ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32))
-#define msi_mask_reg(base, is64bit)    \
-       (base + ((is64bit == 1) ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32))
-#define is_64bit_address(control)      (!!(control & PCI_MSI_FLAGS_64BIT))
-#define is_mask_bit_support(control)   (!!(control & PCI_MSI_FLAGS_MASKBIT))
-
-#define msix_table_offset_reg(base)    (base + PCI_MSIX_TABLE)
-#define msix_pba_offset_reg(base)      (base + PCI_MSIX_PBA)
-#define msix_table_size(control)       ((control & PCI_MSIX_FLAGS_QSIZE)+1)
-#define multi_msix_capable(control)    msix_table_size((control))
-
-/* end odd copyright. */
-
 struct pci_bar {
        uint32_t                                        raw_bar;
        uint32_t                                        pio_base;
@@ -361,11 +338,24 @@ struct pci_device {
        uint8_t                                         nr_bars;
        struct pci_bar                          bar[MAX_PCI_BAR];
        uint32_t                                        caps[PCI_CAP_ID_MAX + 1];
-       /* for MSI-X we might have allocated two physically contiguous pages. */
-       void *                                          msix;
-       int                                             msixbar;
-       int                                             msixready;
-       int                                             msixsize;
+       uintptr_t                                       msix_tbl_paddr;
+       uintptr_t                                       msix_tbl_vaddr;
+       uintptr_t                                       msix_pba_paddr;
+       uintptr_t                                       msix_pba_vaddr;
+       unsigned int                            msix_nr_vec;
+       bool                                            msix_ready;
+};
+
+struct msix_entry {
+       uint32_t addr_lo, addr_hi, data, vector;
+};
+
+struct msix_irq_vector {
+       struct pci_device *pcidev;
+       struct msix_entry *entry;
+       uint32_t addr_lo;
+       uint32_t addr_hi;
+       uint32_t data;
 };
 
 /* List of all discovered devices */
@@ -403,22 +393,26 @@ bool pci_is_membar32(uint32_t bar);
 bool pci_is_membar64(uint32_t bar);
 uint32_t pci_getmembar32(uint32_t bar);
 uint32_t pci_getiobar32(uint32_t bar);
+uintptr_t pci_get_membar(struct pci_device *pcidev, int bir);
 
 /* Other common PCI functions */
 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);
 
+struct irq_handler; /* include loops */
 /* MSI functions, msi.c */
 int pci_msi_enable(struct pci_device *p, uint64_t vec);
-int pci_msix_enable(struct pci_device *p, uint64_t vec);
+int pci_msix_enable(struct irq_handler *irq_h, 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);
-int pci_find_unused_bars(struct pci_device *dev, int *bars, int need);
+void msix_mask_irq(struct irq_handler *irq_h, int apic_vector);
+void msix_unmask_irq(struct irq_handler *irq_h, int apic_vector);
+int msix_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;\
index e2074f2..560bd50 100644 (file)
@@ -512,7 +512,7 @@ int register_irq(int irq, isr_t handler, void *irq_arg, uint32_t tbdf)
                kfree(irq_h);
                return -1;
        }
-       printd("IRQ %d, vector %d, type %s\n", irq, vector, irq_h->type);
+       printk("IRQ %d, vector %d (%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;