bce: Split out frontend for interrupt handler
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 28 Dec 2011 04:07:22 +0000 (12:07 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 28 Dec 2011 04:07:22 +0000 (12:07 +0800)
For non-oneshot MSI, we don't need to make sure that status block has
been updated and we don't need extra register read to flush the ACK_CMD;
MSI has already made sure about those.

For oneshot MSI, we don't even need to ACK the interrupt

Obtaied-from: bnx2

sys/dev/netif/bce/if_bce.c
sys/dev/netif/bce/if_bcereg.h

index 8849680..0ade256 100644 (file)
@@ -436,7 +436,10 @@ static void        bce_enable_intr(struct bce_softc *, int);
 #ifdef DEVICE_POLLING
 static void    bce_poll(struct ifnet *, enum poll_cmd, int);
 #endif
-static void    bce_intr(void *);
+static void    bce_intr(struct bce_softc *);
+static void    bce_intr_legacy(void *);
+static void    bce_intr_msi(void *);
+static void    bce_intr_msi_oneshot(void *);
 static void    bce_set_rx_mode(struct bce_softc *);
 static void    bce_stats_update(struct bce_softc *);
 static void    bce_tick(void *);
@@ -667,6 +670,7 @@ bce_attach(device_t dev)
        struct ifnet *ifp = &sc->arpcom.ac_if;
        uint32_t val;
        u_int irq_flags;
+       void (*irq_handle)(void *);
        int rid, rc = 0;
        int i, j;
 
@@ -732,6 +736,19 @@ bce_attach(device_t dev)
                goto fail;
        }
 
+       if (sc->bce_irq_type == PCI_INTR_TYPE_LEGACY) {
+               irq_handle = bce_intr_legacy;
+       } else if (sc->bce_irq_type == PCI_INTR_TYPE_MSI) {
+               irq_handle = bce_intr_msi;
+               if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
+                       irq_handle = bce_intr_msi_oneshot;
+                       sc->bce_flags |= BCE_ONESHOT_MSI_FLAG;
+               }
+       } else {
+               panic("%s: unsupported intr type %d\n",
+                   device_get_nameunit(dev), sc->bce_irq_type);
+       }
+
        /*
         * Find the base address for shared memory access.
         * Newer versions of bootcode use a signature and offset
@@ -945,7 +962,7 @@ bce_attach(device_t dev)
        callout_init_mp(&sc->bce_pulse_callout);
 
        /* Hookup IRQ last. */
-       rc = bus_setup_intr(dev, sc->bce_res_irq, INTR_MPSAFE, bce_intr, sc,
+       rc = bus_setup_intr(dev, sc->bce_res_irq, INTR_MPSAFE, irq_handle, sc,
                            &sc->bce_intrhand, ifp->if_serializer);
        if (rc != 0) {
                device_printf(dev, "Failed to setup IRQ!\n");
@@ -3643,9 +3660,14 @@ bce_blockinit(struct bce_softc *sc)
               (sc->bce_cmd_ticks_int << 16) | sc->bce_cmd_ticks);
        REG_WR(sc, BCE_HC_STATS_TICKS, (sc->bce_stats_ticks & 0xffff00));
        REG_WR(sc, BCE_HC_STAT_COLLECT_TICKS, 0xbb8);   /* 3ms */
-       REG_WR(sc, BCE_HC_CONFIG,
-              BCE_HC_CONFIG_TX_TMR_MODE |
-              BCE_HC_CONFIG_COLLECT_STATS);
+
+       val = BCE_HC_CONFIG_TX_TMR_MODE | BCE_HC_CONFIG_COLLECT_STATS;
+       if (sc->bce_flags & BCE_ONESHOT_MSI_FLAG) {
+               if (bootverbose)
+                       if_printf(&sc->arpcom.ac_if, "oneshot MSI\n");
+               val |= BCE_HC_CONFIG_ONE_SHOT | BCE_HC_CONFIG_USE_INT_PARAM;
+       }
+       REG_WR(sc, BCE_HC_CONFIG, val);
 
        /* Clear the internal statistics counters. */
        REG_WR(sc, BCE_HC_COMMAND, BCE_HC_COMMAND_CLR_STAT_NOW);
@@ -5354,9 +5376,8 @@ bce_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
 /*   0 for success, positive value for failure.                             */
 /****************************************************************************/
 static void
-bce_intr(void *xsc)
+bce_intr(struct bce_softc *sc)
 {
-       struct bce_softc *sc = xsc;
        struct ifnet *ifp = &sc->arpcom.ac_if;
        struct status_block *sblk;
        uint16_t hw_rx_cons, hw_tx_cons;
@@ -5368,27 +5389,6 @@ bce_intr(void *xsc)
 
        sblk = sc->status_block;
 
-       /*
-        * If the hardware status block index matches the last value
-        * read by the driver and we haven't asserted our interrupt
-        * then there's nothing to do.
-        */
-       if (sblk->status_idx == sc->last_status_idx &&
-           (REG_RD(sc, BCE_PCICFG_MISC_STATUS) &
-            BCE_PCICFG_MISC_STATUS_INTA_VALUE))
-               return;
-
-       /* Ack the interrupt and stop others from occuring. */
-       REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
-              BCE_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
-              BCE_PCICFG_INT_ACK_CMD_MASK_INT);
-
-       /*
-        * Read back to deassert IRQ immediately to avoid too
-        * many spurious interrupts.
-        */
-       REG_RD(sc, BCE_PCICFG_INT_ACK_CMD);
-
        /* Check if the hardware has finished any work. */
        hw_rx_cons = bce_get_hw_rx_cons(sc);
        hw_tx_cons = bce_get_hw_tx_cons(sc);
@@ -5480,6 +5480,57 @@ bce_intr(void *xsc)
                if_devstart(ifp);
 }
 
+static void
+bce_intr_legacy(void *xsc)
+{
+       struct bce_softc *sc = xsc;
+       struct status_block *sblk;
+
+       sblk = sc->status_block;
+
+       /*
+        * If the hardware status block index matches the last value
+        * read by the driver and we haven't asserted our interrupt
+        * then there's nothing to do.
+        */
+       if (sblk->status_idx == sc->last_status_idx &&
+           (REG_RD(sc, BCE_PCICFG_MISC_STATUS) &
+            BCE_PCICFG_MISC_STATUS_INTA_VALUE))
+               return;
+
+       /* Ack the interrupt and stop others from occuring. */
+       REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
+              BCE_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
+              BCE_PCICFG_INT_ACK_CMD_MASK_INT);
+
+       /*
+        * Read back to deassert IRQ immediately to avoid too
+        * many spurious interrupts.
+        */
+       REG_RD(sc, BCE_PCICFG_INT_ACK_CMD);
+
+       bce_intr(sc);
+}
+
+static void
+bce_intr_msi(void *xsc)
+{
+       struct bce_softc *sc = xsc;
+
+       /* Ack the interrupt and stop others from occuring. */
+       REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
+              BCE_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
+              BCE_PCICFG_INT_ACK_CMD_MASK_INT);
+
+       bce_intr(sc);
+}
+
+static void
+bce_intr_msi_oneshot(void *xsc)
+{
+       bce_intr(xsc);
+}
+
 
 /****************************************************************************/
 /* Programs the various packet receive modes (broadcast and multicast).     */
index b27fd8b..85c316f 100644 (file)
@@ -5872,6 +5872,7 @@ struct bce_softc {
 #define BCE_USING_DAC_FLAG     0x00000010
 #define BCE_MFW_ENABLE_FLAG    0x00000040      /* Management F/W is enabled */
 #define BCE_PCIE_FLAG          0x00000200
+#define BCE_ONESHOT_MSI_FLAG   0x00000400
 
        uint32_t                bce_cap_flags;
 #define BCE_PCIE_CAPABLE_FLAG  0x00000004