⬢ DragonFlyBSD Kernel Audit
DF-4706 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/amr/amr_pci.c
+++ b/sys/dev/raid/amr/amr_pci.c
@@ -253,15 +253,6 @@
-    /*
-     * Allocate and connect our interrupt.
-     */
-    rid = 0;
-    sc->amr_irq = bus_alloc_resource_any(sc->amr_dev, SYS_RES_IRQ, &rid,
-        RF_SHAREABLE | RF_ACTIVE);
-    if (sc->amr_irq == NULL) {
-        device_printf(sc->amr_dev, "can't allocate interrupt\n");
-	goto out;
-    }
-    if (bus_setup_intr(sc->amr_dev, sc->amr_irq,
-	INTR_MPSAFE, amr_pci_intr,
-	sc, &sc->amr_intr, NULL)) {
-        device_printf(sc->amr_dev, "can't set up interrupt\n");
-	goto out;
-    }
-
-    debug(2, "interrupt attached");
-
     /* assume failure is 'out of memory' */
     error = ENOMEM;
@@ -343,8 +334,25 @@
     /*
      * Do bus-independant initialisation, bring controller online.
      */
     error = amr_attach(sc);
+    if (error != 0)
+	goto out;
+
+    /*
+     * Connect our interrupt only once the handler's state exists
+     * (amr_get_work dispatch, locks, mailbox DMA all initialised by
+     * amr_attach); a shared-line IRQ before that point would call
+     * amr_done() -> sc->amr_get_work() while still NULL.
+     */
+    rid = 0;
+    sc->amr_irq = bus_alloc_resource_any(sc->amr_dev, SYS_RES_IRQ, &rid,
+        RF_SHAREABLE | RF_ACTIVE);
+    if (sc->amr_irq == NULL) {
+        device_printf(sc->amr_dev, "can't allocate interrupt\n");
+	error = ENXIO;
+	goto out;
+    }
+    if (bus_setup_intr(sc->amr_dev, sc->amr_irq,
+	INTR_MPSAFE, amr_pci_intr,
+	sc, &sc->amr_intr, NULL)) {
+        device_printf(sc->amr_dev, "can't set up interrupt\n");
+	error = ENXIO;
+	goto out;
+    }
+    debug(2, "interrupt attached");
 
 out:
     if (error)
--- a/sys/dev/raid/amr/amr_pci.c
+++ b/sys/dev/raid/amr/amr_pci.c
@@ -461,6 +461,9 @@ amr_pci_intr(void *arg)
 
     debug_called(3);
 
+    if ((sc->amr_state & AMR_STATE_INTEN) == 0)
+	return;			/* not our interrupt / not initialised */
+
     /* collect finished commands, queue anything waiting */
     amr_done(sc);
 }