Build gcc with USE_PT_GNU_EH_FRAME (XCC)
[akaros.git] / kern / arch / x86 / msi.c
index fd348dc..3e704d9 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * This file is part of the UCB release of Plan 9. It is subject to the license
  * terms in the LICENSE file found in the top-level directory of this
  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
@@ -172,7 +172,7 @@ int pci_msi_enable(struct pci_device *p, uint64_t vec)
                return -1;
        }
 
-       /* read it, clear out the Mmesgmsk bits. 
+       /* read it, clear out the Mmesgmsk bits.
         * This means that there will be no multiple
         * messages enabled.
         */
@@ -236,7 +236,7 @@ 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;
@@ -262,6 +262,8 @@ static int __pci_msix_init(struct pci_device *p)
        int tbl_bir, tbl_off, pba_bir, pba_off;
        struct msix_entry *entry;
 
+       if (p->msix_ready)
+               return 0;
        if (p->msi_ready) {
                printk("MSI-X: MSI is already on, aborting\n");
                return -1;
@@ -314,9 +316,23 @@ static int __pci_msix_init(struct pci_device *p)
        /* unmask the device, now that all the vectors are masked */
        f &= ~Msixmask;
        pcidev_write16(p, c + 2, f);
+       p->msix_ready = TRUE;
        return 0;
 }
 
+/* Some parts of msix init need to happen during boot.  Devices can call this
+ * during their reset methods, and then later register their IRQs during attach.
+ * Other OS's also alloc the vector around this time, though we'll hold off on
+ * that for now. */
+int pci_msix_init(struct pci_device *p)
+{
+       int ret;
+       spin_lock_irqsave(&p->lock);
+       ret = __pci_msix_init(p);
+       spin_unlock_irqsave(&p->lock);
+       return ret;
+}
+
 /* Enables an MSI-X vector for a PCI device.  vec is formatted like an ioapic
  * route.  This should be able to handle multiple vectors for a device.  Returns
  * a msix_irq_vector linkage struct on success (the connection btw an irq_h and
@@ -329,12 +345,11 @@ struct msix_irq_vector *pci_msix_enable(struct pci_device *p, uint64_t vec)
        unsigned int c, datao;
 
        spin_lock_irqsave(&p->lock);
-       if (!p->msix_ready) {
-               if (__pci_msix_init(p) < 0) {
-                       spin_unlock_irqsave(&p->lock);
-                       return 0;
-               }
-               p->msix_ready = TRUE;
+       /* Ensure we're init'd.  We could remove this in the future, though not
+        * everyone calls the extern pci_msix_init. */
+       if (__pci_msix_init(p) < 0) {
+               spin_unlock_irqsave(&p->lock);
+               return 0;
        }
        /* 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. */
@@ -347,7 +362,7 @@ struct msix_irq_vector *pci_msix_enable(struct pci_device *p, uint64_t vec)
                spin_unlock_irqsave(&p->lock);
                return 0;
        }
-       linkage = kmalloc(sizeof(struct msix_irq_vector), KMALLOC_WAIT);
+       linkage = kmalloc(sizeof(struct msix_irq_vector), MEM_WAIT);
        linkage->pcidev = p;
        linkage->entry = entry;
        linkage->addr_lo = msi_make_addr_lo(vec);