PCI/MSI: pci_msix_init()
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 26 Feb 2015 16:25:58 +0000 (11:25 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sun, 1 Mar 2015 14:36:00 +0000 (09:36 -0500)
Drivers that want to use MSIX should call pci_msix_init() during reset (which
is at boot time).  If they do this, they can register_irq() at attach time,
which is after booting.  Otherwise, they must register_irq() during reset.

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

index fd348dc..292677c 100644 (file)
@@ -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. */
index 6d5a256..6d18084 100644 (file)
@@ -269,6 +269,7 @@ static inline void *pci_get_drvdata(struct pci_device *pcidev);
 
 /* MSI functions, msi.c */
 int pci_msi_enable(struct pci_device *p, uint64_t vec);
+int pci_msix_init(struct pci_device *p);
 struct msix_irq_vector *pci_msix_enable(struct pci_device *p, uint64_t vec);
 void pci_msi_mask(struct pci_device *p);
 void pci_msi_unmask(struct pci_device *p);