Make all network interrupt service routines MPSAFE part 1/3.
[dragonfly.git] / sys / dev / netif / rl / if_rl.c
index 1535c97..fe4fd63 100644 (file)
@@ -30,7 +30,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/pci/if_rl.c,v 1.38.2.16 2003/03/05 18:42:33 njl Exp $
- * $DragonFly: src/sys/dev/netif/rl/if_rl.c,v 1.18 2005/02/21 18:40:37 joerg Exp $
+ * $DragonFly: src/sys/dev/netif/rl/if_rl.c,v 1.29 2005/11/28 17:13:43 dillon Exp $
  */
 
 /*
@@ -84,6 +84,8 @@
  * to select which interface to use depending on the chip type.
  */
 
+#include "opt_polling.h"
+
 #include <sys/param.h>
 #include <sys/endian.h>
 #include <sys/systm.h>
@@ -93,6 +95,8 @@
 #include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/socket.h>
+#include <sys/serialize.h>
+#include <sys/thread2.h>
 
 #include <net/if.h>
 #include <net/ifq_var.h>
@@ -207,6 +211,9 @@ static void rl_list_tx_init(struct rl_softc *);
 
 static void    rl_dma_map_rxbuf(void *, bus_dma_segment_t *, int, int);
 static void    rl_dma_map_txbuf(void *, bus_dma_segment_t *, int, int);
+#ifdef DEVICE_POLLING
+static poll_handler_t rl_poll;
+#endif
 
 #ifdef RL_USEIOSPACE
 #define        RL_RES                  SYS_RES_IOPORT
@@ -409,9 +416,7 @@ rl_mii_send(struct rl_softc *sc, uint32_t bits, int cnt)
 static int
 rl_mii_readreg(struct rl_softc *sc, struct rl_mii_frame *frame)        
 {
-       int i, ack, s;
-
-       s = splimp();
+       int ack, i;
 
        /*
         * Set up frame for RX.
@@ -484,8 +489,6 @@ rl_mii_readreg(struct rl_softc *sc, struct rl_mii_frame *frame)
        MII_SET(RL_MII_CLK);
        DELAY(1);
 
-       splx(s);
-
        return(ack ? 1 : 0);
 }
 
@@ -495,13 +498,9 @@ rl_mii_readreg(struct rl_softc *sc, struct rl_mii_frame *frame)
 static int
 rl_mii_writereg(struct rl_softc *sc, struct rl_mii_frame *frame)
 {
-       int s;
-
-       s = splimp();
        /*
         * Set up frame for TX.
         */
-
        frame->mii_stdelim = RL_MII_STARTDELIM;
        frame->mii_opcode = RL_MII_WRITEOP;
        frame->mii_turnaround = RL_MII_TURNAROUND;
@@ -531,8 +530,6 @@ rl_mii_writereg(struct rl_softc *sc, struct rl_mii_frame *frame)
         */
        MII_CLR(RL_MII_DIR);
 
-       splx(s);
-
        return(0);
 }
 
@@ -687,7 +684,7 @@ rl_setmulti(struct rl_softc *sc)
                        continue;
                h = ether_crc32_be(
                    LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
-                   ETHER_ADDR_LEN >> 26);
+                   ETHER_ADDR_LEN) >> 26;
                if (h < 32)
                        hashes[0] |= (1 << h);
                else
@@ -784,15 +781,10 @@ rl_attach(device_t dev)
                pci_write_config(dev, RL_PCI_INTLINE, irq, 4);
        }
 
-       /*
-        * Map control/status registers.
-        */
        pci_enable_busmaster(dev);
-       pci_enable_io(dev, RL_RES);
 
        rid = RL_RID; 
-       sc->rl_res = bus_alloc_resource(dev, RL_RES, &rid,
-           0, ~0, 1, RF_ACTIVE);
+       sc->rl_res = bus_alloc_resource_any(dev, RL_RES, &rid, RF_ACTIVE);
 
        if (sc->rl_res == NULL) {
                device_printf(dev, "couldn't map ports/memory\n");
@@ -927,7 +919,7 @@ rl_attach(device_t dev)
        ifp->if_baudrate = 10000000;
        ifp->if_capabilities = IFCAP_VLAN_MTU;
 #ifdef DEVICE_POLLING
-       ifp->if_capabilities |= IFCAP_POLLING;
+       ifp->if_poll = rl_poll;
 #endif
        ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
        ifq_set_ready(&ifp->if_snd);
@@ -935,10 +927,10 @@ rl_attach(device_t dev)
        /*
         * Call MI attach routine.
         */
-       ether_ifattach(ifp, eaddr);
+       ether_ifattach(ifp, eaddr, NULL);
 
-       error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET, rl_intr,
-                              sc, &sc->rl_intrhand);
+       error = bus_setup_intr(dev, sc->rl_irq, INTR_NETSAFE, rl_intr,
+                              sc, &sc->rl_intrhand, ifp->if_serializer);
 
        if (error) {
                device_printf(dev, "couldn't set up irq\n");
@@ -958,12 +950,11 @@ rl_detach(device_t dev)
 {
        struct rl_softc *sc;
        struct ifnet *ifp;
-       int s;
 
        sc = device_get_softc(dev);
        ifp = &sc->arpcom.ac_if;
 
-       s = splimp();
+       lwkt_serialize_enter(ifp->if_serializer);
 
        if (device_is_attached(dev)) {
                rl_stop(sc);
@@ -976,7 +967,6 @@ rl_detach(device_t dev)
 
        if (sc->rl_intrhand)
                bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand);
-       splx(s);
 
        if (sc->rl_irq)
                bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq);
@@ -993,6 +983,8 @@ rl_detach(device_t dev)
        if (sc->rl_parent_tag)
                bus_dma_tag_destroy(sc->rl_parent_tag);
 
+       lwkt_serialize_exit(ifp->if_serializer);
+
        return(0);
 }
 
@@ -1162,7 +1154,7 @@ rl_rxeof(struct rl_softc *sc)
 
                ifp->if_ipackets++;
 
-               (*ifp->if_input)(ifp, m);
+               ifp->if_input(ifp, m);
        }
 }
 
@@ -1196,28 +1188,21 @@ rl_txeof(struct rl_softc *sc)
                bus_dmamap_destroy(sc->rl_tag, RL_LAST_DMAMAP(sc));
                m_freem(RL_LAST_TXMBUF(sc));
                RL_LAST_TXMBUF(sc) = NULL;
+               RL_INC(sc->rl_cdata.last_tx);
 
-               if ((txstat & RL_TXSTAT_TX_OK) == 0) {
-                       int oldthresh;
+               if (txstat & RL_TXSTAT_TX_UNDERRUN) {
+                       sc->rl_txthresh += 32;
+                       if (sc->rl_txthresh > RL_TX_THRESH_MAX)
+                               sc->rl_txthresh = RL_TX_THRESH_MAX;
+               }
 
+               if (txstat & RL_TXSTAT_TX_OK) {
+                       ifp->if_opackets++;
+               } else {
                        ifp->if_oerrors++;
-                       if ((txstat & RL_TXSTAT_TXABRT) ||
-                           (txstat & RL_TXSTAT_OUTOFWIN))
+                       if (txstat & (RL_TXSTAT_TXABRT | RL_TXSTAT_OUTOFWIN))
                                CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG);
-                       oldthresh = sc->rl_txthresh;
-                       /* error recovery */
-                       rl_reset(sc);
-                       rl_init(sc);
-                       /*
-                        * If there was a transmit underrun,
-                        * bump the TX threshold.
-                        */
-                       if (txstat & RL_TXSTAT_TX_UNDERRUN)
-                               sc->rl_txthresh = oldthresh + 32;
-                       return;
                }
-               ifp->if_opackets++;
-               RL_INC(sc->rl_cdata.last_tx);
                ifp->if_flags &= ~IFF_OACTIVE;
        } while (sc->rl_cdata.last_tx != sc->rl_cdata.cur_tx);
 
@@ -1232,58 +1217,59 @@ rl_tick(void *xsc)
 {
        struct rl_softc *sc = xsc;
        struct mii_data *mii;
-       int s;
 
-       s = splimp();
+       lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer);
 
        mii = device_get_softc(sc->rl_miibus);
        mii_tick(mii);
 
-       splx(s);
-
        callout_reset(&sc->rl_stat_timer, hz, rl_tick, sc);
+
+       lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer);
 }
 
 #ifdef DEVICE_POLLING
-static poll_handler_t rl_poll;
 
 static void
 rl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
 {
        struct rl_softc *sc = ifp->if_softc;
 
-       if ((ifp->if_capenable & IFCAP_POLLING) == 0) {
-               ether_poll_deregister(ifp);
-               cmd = POLL_DEREGISTER;
-       }
-       if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
+       switch(cmd) {
+       case POLL_REGISTER:
+               /* disable interrupts */
+                CSR_WRITE_2(sc, RL_IMR, 0x0000);
+               break;
+       case POLL_DEREGISTER:
+               /* enable interrupts */
                CSR_WRITE_2(sc, RL_IMR, RL_INTRS);
-               return;
-       }
-
-       sc->rxcycles = count;
-       rl_rxeof(sc);
-       rl_txeof(sc);
-       if (!ifq_is_empty(&ifp->if_snd))
-               rl_start(ifp);
-
-       if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
-               uint16_t status;
-               status = CSR_READ_2(sc, RL_ISR);
-               if (status == 0xffff)
-                       return;
-               if (status)
-                       CSR_WRITE_2(sc, RL_ISR, status);
-                 
-               /*
-                * XXX check behaviour on receiver stalls.
-                */
+               break;
+       default:
+               sc->rxcycles = count;
+               rl_rxeof(sc);
+               rl_txeof(sc);
+               if (!ifq_is_empty(&ifp->if_snd))
+                       rl_start(ifp);
+
+               if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
+                       uint16_t status;
+        
+                       status = CSR_READ_2(sc, RL_ISR);
+                       if (status == 0xffff)
+                               return;
+                       if (status)
+                               CSR_WRITE_2(sc, RL_ISR, status);
+                        
+                       /*
+                        * XXX check behaviour on receiver stalls.
+                        */
 
-               if (status & RL_ISR_SYSTEM_ERR) {
-                       rl_reset(sc);
-                       rl_init(sc);
+                       if (status & RL_ISR_SYSTEM_ERR) {
+                               rl_reset(sc);
+                               rl_init(sc);
+                       }
                }
+               break;
        }
 }
 #endif /* DEVICE_POLLING */
@@ -1301,16 +1287,6 @@ rl_intr(void *arg)
                return;
 
        ifp = &sc->arpcom.ac_if;
-#ifdef DEVICE_POLLING
-        if  (ifp->if_flags & IFF_POLLING)
-                return;
-        if ((ifp->if_capenable & IFCAP_POLLING) &&
-           ether_poll_register(rl_poll, ifp)) { /* ok, disable interrupts */
-                CSR_WRITE_2(sc, RL_IMR, 0x0000);
-                rl_poll(ifp, 0, 1);
-                return;
-        }
-#endif /* DEVICE_POLLING */
 
        for (;;) {
                status = CSR_READ_2(sc, RL_ISR);
@@ -1399,7 +1375,7 @@ rl_start(struct ifnet *ifp)
        sc = ifp->if_softc;
 
        while(RL_CUR_TXMBUF(sc) == NULL) {
-               m_head = ifq_dequeue(&ifp->if_snd);
+               m_head = ifq_dequeue(&ifp->if_snd, NULL);
                if (m_head == NULL)
                        break;
 
@@ -1449,11 +1425,8 @@ rl_init(void *xsc)
        struct rl_softc *sc = xsc;
        struct ifnet *ifp = &sc->arpcom.ac_if;
        struct mii_data *mii;
-       int s;
        uint32_t rxcfg = 0;
 
-       s = splimp();
-
        mii = device_get_softc(sc->rl_miibus);
 
        /*
@@ -1552,8 +1525,6 @@ rl_init(void *xsc)
        ifp->if_flags |= IFF_RUNNING;
        ifp->if_flags &= ~IFF_OACTIVE;
 
-       splx(s);
-
        callout_reset(&sc->rl_stat_timer, hz, rl_tick, sc);
 }
 
@@ -1593,9 +1564,7 @@ rl_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
        struct rl_softc *sc = ifp->if_softc;
        struct ifreq *ifr = (struct ifreq *) data;
        struct mii_data *mii;
-       int s, error = 0;
-
-       s = splimp();
+       int error = 0;
 
        switch (command) {
        case SIOCSIFFLAGS:
@@ -1618,16 +1587,12 @@ rl_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
                error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
                break;
        case SIOCSIFCAP:
-               ifp->if_capenable &= ~IFCAP_POLLING;
-               ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING;
                break;
        default:
                error = ether_ioctl(ifp, command, data);
                break;
        }
 
-       splx(s);
-
        return(error);
 }
 
@@ -1635,18 +1600,18 @@ static void
 rl_watchdog(struct ifnet *ifp)
 {
        struct rl_softc *sc = ifp->if_softc;
-       int s;
-
-       s = splimp();
 
        device_printf(sc->rl_dev, "watchdog timeout\n");
+
+       lwkt_serialize_enter(ifp->if_serializer);
+
        ifp->if_oerrors++;
 
        rl_txeof(sc);
        rl_rxeof(sc);
        rl_init(sc);
 
-       splx(s);
+       lwkt_serialize_exit(ifp->if_serializer);
 }
 
 /*
@@ -1663,9 +1628,6 @@ rl_stop(struct rl_softc *sc)
 
        callout_stop(&sc->rl_stat_timer);
        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
-#ifdef DEVICE_POLLING
-       ether_poll_deregister(ifp);
-#endif /* DEVICE_POLLING */
 
        CSR_WRITE_1(sc, RL_COMMAND, 0x00);
        CSR_WRITE_2(sc, RL_IMR, 0x0000);
@@ -1698,8 +1660,9 @@ rl_shutdown(device_t dev)
        struct rl_softc *sc;
 
        sc = device_get_softc(dev);
-
+       lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer);
        rl_stop(sc);
+       lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer);
 }
 
 /*
@@ -1713,6 +1676,7 @@ rl_suspend(device_t dev)
        struct rl_softc *sc = device_get_softc(dev);
        int i;
 
+       lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer);
        rl_stop(sc);
 
        for (i = 0; i < 5; i++)
@@ -1724,6 +1688,7 @@ rl_suspend(device_t dev)
 
        sc->suspended = 1;
 
+       lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer);
        return (0);
 }
 
@@ -1738,6 +1703,8 @@ static int rl_resume(device_t dev)
        struct ifnet *ifp = &sc->arpcom.ac_if;
        int             i;
 
+       lwkt_serialize_enter(ifp->if_serializer);
+
        /* better way to do this? */
        for (i = 0; i < 5; i++)
                pci_write_config(dev, PCIR_BAR(i), sc->saved_maps[i], 4);
@@ -1755,6 +1722,6 @@ static int rl_resume(device_t dev)
                 rl_init(sc);
 
        sc->suspended = 0;
-
+       lwkt_serialize_exit(ifp->if_serializer);
        return (0);
 }