svn commit: r201699 - stable/7/sys/dev/bge

Pyun YongHyeon yongari at FreeBSD.org
Thu Jan 7 00:04:29 UTC 2010


Author: yongari
Date: Thu Jan  7 00:04:29 2010
New Revision: 201699
URL: http://svn.freebsd.org/changeset/base/201699

Log:
  MFC r199667-199668
  
  r199667:
    Cache Rx producer/Tx consumer index as soon as we know status block
    update and then clear status block. Previously it used to access
    these index without synchronization which may cause problems when
    bounce buffers are used. Also add missing bus_dmamap_sync(9) in
    polling handler. Since we now update status block in driver, adjust
    bus_dmamap_sync(9) for status block.
  
  r199668:
    For MSI case, interrupt is not shared and we don't need to force
    PCI flush to get correct status block update. Add an optimized
    interrupt handler that is activated for MSI case. Actual interrupt
    handling is done by taskqueue such that the handler does not
    require driver lock for Rx path. The MSI capable bge(4) controllers
    automatically disables further interrupt once it enters interrupt
    state so we don't need PIO access to disable interrupt in interrupt
    handler.

Modified:
  stable/7/sys/dev/bge/if_bge.c
  stable/7/sys/dev/bge/if_bgereg.h
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/dev/bge/if_bge.c
==============================================================================
--- stable/7/sys/dev/bge/if_bge.c	Wed Jan  6 23:57:17 2010	(r201698)
+++ stable/7/sys/dev/bge/if_bge.c	Thu Jan  7 00:04:29 2010	(r201699)
@@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/module.h>
 #include <sys/socket.h>
 #include <sys/sysctl.h>
+#include <sys/taskqueue.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -361,8 +362,8 @@ static int bge_get_eaddr_nvram(struct bg
 static int bge_get_eaddr_eeprom(struct bge_softc *, uint8_t[]);
 static int bge_get_eaddr(struct bge_softc *, uint8_t[]);
 
-static void bge_txeof(struct bge_softc *);
-static void bge_rxeof(struct bge_softc *);
+static void bge_txeof(struct bge_softc *, uint16_t);
+static void bge_rxeof(struct bge_softc *, uint16_t, int);
 
 static void bge_asf_driver_up (struct bge_softc *);
 static void bge_tick(void *);
@@ -371,6 +372,8 @@ static void bge_stats_update_regs(struct
 static int bge_encap(struct bge_softc *, struct mbuf **, uint32_t *);
 
 static void bge_intr(void *);
+static int bge_msi_intr(void *);
+static void bge_intr_task(void *, int);
 static void bge_start_locked(struct ifnet *);
 static void bge_start(struct ifnet *);
 static int bge_ioctl(struct ifnet *, u_long, caddr_t);
@@ -2470,6 +2473,8 @@ bge_attach(device_t dev)
 	sc = device_get_softc(dev);
 	sc->bge_dev = dev;
 
+	TASK_INIT(&sc->bge_intr_task, 0, bge_intr_task, sc);
+
 	/*
 	 * Map control/status registers.
 	 */
@@ -2832,8 +2837,27 @@ again:
 	 * Hookup IRQ last.
 	 */
 #if __FreeBSD_version > 700030
-	error = bus_setup_intr(dev, sc->bge_irq, INTR_TYPE_NET | INTR_MPSAFE,
-	   NULL, bge_intr, sc, &sc->bge_intrhand);
+	if (BGE_IS_5755_PLUS(sc) && sc->bge_flags & BGE_FLAG_MSI) {
+		/* Take advantage of single-shot MSI. */
+		sc->bge_tq = taskqueue_create_fast("bge_taskq", M_WAITOK,
+		    taskqueue_thread_enqueue, &sc->bge_tq);
+		if (sc->bge_tq == NULL) {
+			device_printf(dev, "could not create taskqueue.\n");
+			ether_ifdetach(ifp);
+			error = ENXIO;
+			goto fail;
+		}
+		taskqueue_start_threads(&sc->bge_tq, 1, PI_NET, "%s taskq",
+		    device_get_nameunit(sc->bge_dev));
+		error = bus_setup_intr(dev, sc->bge_irq,
+		    INTR_TYPE_NET | INTR_MPSAFE, bge_msi_intr, NULL, sc,
+		    &sc->bge_intrhand);
+		if (error)
+			ether_ifdetach(ifp);
+	} else
+		error = bus_setup_intr(dev, sc->bge_irq,
+		    INTR_TYPE_NET | INTR_MPSAFE, NULL, bge_intr, sc,
+		    &sc->bge_intrhand);
 #else
 	error = bus_setup_intr(dev, sc->bge_irq, INTR_TYPE_NET | INTR_MPSAFE,
 	   bge_intr, sc, &sc->bge_intrhand);
@@ -2875,6 +2899,8 @@ bge_detach(device_t dev)
 
 	callout_drain(&sc->bge_stat_ch);
 
+	if (sc->bge_tq)
+		taskqueue_drain(sc->bge_tq, &sc->bge_intr_task);
 	ether_ifdetach(ifp);
 
 	if (sc->bge_flags & BGE_FLAG_TBI) {
@@ -2896,6 +2922,9 @@ bge_release_resources(struct bge_softc *
 
 	dev = sc->bge_dev;
 
+	if (sc->bge_tq != NULL)
+		taskqueue_free(sc->bge_tq);
+
 	if (sc->bge_intrhand != NULL)
 		bus_teardown_intr(dev, sc->bge_irq, sc->bge_intrhand);
 
@@ -3135,15 +3164,13 @@ bge_reset(struct bge_softc *sc)
  */
 
 static void
-bge_rxeof(struct bge_softc *sc)
+bge_rxeof(struct bge_softc *sc, uint16_t rx_prod, int holdlck)
 {
 	struct ifnet *ifp;
 	int stdcnt = 0, jumbocnt = 0;
-	uint16_t rx_prod, rx_cons;
+	uint16_t rx_cons;
 
-	BGE_LOCK_ASSERT(sc);
 	rx_cons = sc->bge_rx_saved_considx;
-	rx_prod = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx;
 
 	/* Nothing to do. */
 	if (rx_cons == rx_prod)
@@ -3259,9 +3286,12 @@ bge_rxeof(struct bge_softc *sc)
 #endif
 		}
 
-		BGE_UNLOCK(sc);
-		(*ifp->if_input)(ifp, m);
-		BGE_LOCK(sc);
+		if (holdlck != 0) {
+			BGE_UNLOCK(sc);
+			(*ifp->if_input)(ifp, m);
+			BGE_LOCK(sc);
+		} else
+			(*ifp->if_input)(ifp, m);
 
 		if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
 			return;
@@ -3294,7 +3324,7 @@ bge_rxeof(struct bge_softc *sc)
 }
 
 static void
-bge_txeof(struct bge_softc *sc)
+bge_txeof(struct bge_softc *sc, uint16_t tx_cons)
 {
 	struct bge_tx_bd *cur_tx = NULL;
 	struct ifnet *ifp;
@@ -3302,8 +3332,7 @@ bge_txeof(struct bge_softc *sc)
 	BGE_LOCK_ASSERT(sc);
 
 	/* Nothing to do. */
-	if (sc->bge_tx_saved_considx ==
-	    sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx)
+	if (sc->bge_tx_saved_considx == tx_cons)
 		return;
 
 	ifp = sc->bge_ifp;
@@ -3314,8 +3343,7 @@ bge_txeof(struct bge_softc *sc)
 	 * Go through our tx ring and free mbufs for those
 	 * frames that have been sent.
 	 */
-	while (sc->bge_tx_saved_considx !=
-	    sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx) {
+	while (sc->bge_tx_saved_considx != tx_cons) {
 		uint32_t		idx = 0;
 
 		idx = sc->bge_tx_saved_considx;
@@ -3346,6 +3374,7 @@ static void
 bge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
 {
 	struct bge_softc *sc = ifp->if_softc;
+	uint16_t rx_prod, tx_cons;
 	uint32_t statusword;
 	
 	BGE_LOCK(sc);
@@ -3355,13 +3384,17 @@ bge_poll(struct ifnet *ifp, enum poll_cm
 	}
 
 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
-	    sc->bge_cdata.bge_status_map, BUS_DMASYNC_POSTREAD);
+	    sc->bge_cdata.bge_status_map,
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+	rx_prod = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx;
+	tx_cons = sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx;
 
 	statusword = atomic_readandclear_32(
 	    &sc->bge_ldata.bge_status_block->bge_status);
 
 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
-	    sc->bge_cdata.bge_status_map, BUS_DMASYNC_PREREAD);
+	    sc->bge_cdata.bge_status_map,
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 
 	/* Note link event. It will be processed by POLL_AND_CHECK_STATUS. */
 	if (statusword & BGE_STATFLAG_LINKSTATE_CHANGED)
@@ -3374,12 +3407,12 @@ bge_poll(struct ifnet *ifp, enum poll_cm
 			bge_link_upd(sc);
 
 	sc->rxcycles = count;
-	bge_rxeof(sc);
+	bge_rxeof(sc, rx_prod, 1);
 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
 		BGE_UNLOCK(sc);
 		return;
 	}
-	bge_txeof(sc);
+	bge_txeof(sc, tx_cons);
 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 		bge_start_locked(ifp);
 
@@ -3387,12 +3420,76 @@ bge_poll(struct ifnet *ifp, enum poll_cm
 }
 #endif /* DEVICE_POLLING */
 
+static int
+bge_msi_intr(void *arg)
+{
+	struct bge_softc *sc;
+
+	sc = (struct bge_softc *)arg;
+	/*
+	 * This interrupt is not shared and controller already
+	 * disabled further interrupt.
+	 */
+	taskqueue_enqueue(sc->bge_tq, &sc->bge_intr_task);
+	return (FILTER_HANDLED);
+}
+
+static void
+bge_intr_task(void *arg, int pending)
+{
+	struct bge_softc *sc;
+	struct ifnet *ifp;
+	uint32_t status;
+	uint16_t rx_prod, tx_cons;
+
+	sc = (struct bge_softc *)arg;
+	ifp = sc->bge_ifp;
+
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return;
+
+	/* Get updated status block. */
+	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
+	    sc->bge_cdata.bge_status_map,
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+	/* Save producer/consumer indexess. */
+	rx_prod = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx;
+	tx_cons = sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx;
+	status = sc->bge_ldata.bge_status_block->bge_status;
+	sc->bge_ldata.bge_status_block->bge_status = 0;
+	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
+	    sc->bge_cdata.bge_status_map,
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+	/* Let controller work. */
+	bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
+
+	if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) != 0) {
+		BGE_LOCK(sc);
+		bge_link_upd(sc);
+		BGE_UNLOCK(sc);
+	}
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+		/* Check RX return ring producer/consumer. */
+		bge_rxeof(sc, rx_prod, 0);
+	}
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+		BGE_LOCK(sc);
+		/* Check TX ring producer/consumer. */
+		bge_txeof(sc, tx_cons);
+	    	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+			bge_start_locked(ifp);
+		BGE_UNLOCK(sc);
+	}
+}
+
 static void
 bge_intr(void *xsc)
 {
 	struct bge_softc *sc;
 	struct ifnet *ifp;
 	uint32_t statusword;
+	uint16_t rx_prod, tx_cons;
 
 	sc = xsc;
 
@@ -3436,7 +3533,14 @@ bge_intr(void *xsc)
 
 	/* Make sure the descriptor ring indexes are coherent. */
 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
-	    sc->bge_cdata.bge_status_map, BUS_DMASYNC_POSTREAD);
+	    sc->bge_cdata.bge_status_map,
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+	rx_prod = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx;
+	tx_cons = sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx;
+	sc->bge_ldata.bge_status_block->bge_status = 0;
+	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
+	    sc->bge_cdata.bge_status_map,
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 
 	if ((sc->bge_asicrev == BGE_ASICREV_BCM5700 &&
 	    sc->bge_chipid != BGE_CHIPID_BCM5700_B2) ||
@@ -3445,21 +3549,18 @@ bge_intr(void *xsc)
 
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
 		/* Check RX return ring producer/consumer. */
-		bge_rxeof(sc);
+		bge_rxeof(sc, rx_prod, 1);
 	}
 
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
 		/* Check TX ring producer/consumer. */
-		bge_txeof(sc);
+		bge_txeof(sc, tx_cons);
 	}
 
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
 	    !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 		bge_start_locked(ifp);
 
-	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
-	    sc->bge_cdata.bge_status_map, BUS_DMASYNC_PREREAD);
-
 	BGE_UNLOCK(sc);
 }
 

Modified: stable/7/sys/dev/bge/if_bgereg.h
==============================================================================
--- stable/7/sys/dev/bge/if_bgereg.h	Wed Jan  6 23:57:17 2010	(r201698)
+++ stable/7/sys/dev/bge/if_bgereg.h	Thu Jan  7 00:04:29 2010	(r201699)
@@ -2641,6 +2641,8 @@ struct bge_softc {
 #ifdef DEVICE_POLLING
 	int			rxcycles;
 #endif /* DEVICE_POLLING */
+	struct task		bge_intr_task;
+	struct taskqueue	*bge_tq;
 };
 
 #define	BGE_LOCK_INIT(_sc, _name) \


More information about the svn-src-all mailing list