svn commit: r202112 - stable/8/sys/dev/mxge

Andrew Gallatin gallatin at FreeBSD.org
Mon Jan 11 20:32:51 UTC 2010


Author: gallatin
Date: Mon Jan 11 20:32:51 2010
New Revision: 202112
URL: http://svn.freebsd.org/changeset/base/202112

Log:
  Sync mxge(4) with head:
  r197391: Add support for TX throttling
  r198250: Move mxge(4)'s NIC watchdog reset handler from
  	 a callout to a taskqueue
  r198303: Make mxge do a better job recovering from NIC h/w faults
  r200845: Don't take the driver mutex in mxge_tick()
  r201758: Remove extraneous semicolons

Modified:
  stable/8/sys/dev/mxge/if_mxge.c
  stable/8/sys/dev/mxge/if_mxge_var.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/dev/mxge/if_mxge.c
==============================================================================
--- stable/8/sys/dev/mxge/if_mxge.c	Mon Jan 11 20:23:17 2010	(r202111)
+++ stable/8/sys/dev/mxge/if_mxge.c	Mon Jan 11 20:32:51 2010	(r202112)
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/socket.h>
 #include <sys/sysctl.h>
 #include <sys/sx.h>
+#include <sys/taskqueue.h>
 
 /* count xmits ourselves, rather than via drbr */
 #define NO_SLOW_STATS
@@ -106,6 +107,7 @@ static int mxge_max_slices = 1;
 static int mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_PORT;
 static int mxge_always_promisc = 0;
 static int mxge_initial_mtu = ETHERMTU_JUMBO;
+static int mxge_throttle = 0;
 static char *mxge_fw_unaligned = "mxge_ethp_z8e";
 static char *mxge_fw_aligned = "mxge_eth_z8e";
 static char *mxge_fw_rss_aligned = "mxge_rss_eth_z8e";
@@ -596,10 +598,13 @@ static int
 mxge_select_firmware(mxge_softc_t *sc)
 {
 	int aligned = 0;
+	int force_firmware = mxge_force_firmware;
 
+	if (sc->throttle)
+		force_firmware = sc->throttle;
 
-	if (mxge_force_firmware != 0) {
-		if (mxge_force_firmware == 1)
+	if (force_firmware != 0) {
+		if (force_firmware == 1)
 			aligned = 1;
 		else
 			aligned = 0;
@@ -1313,10 +1318,48 @@ mxge_reset(mxge_softc_t *sc, int interru
 	mxge_change_promisc(sc, sc->ifp->if_flags & IFF_PROMISC);
 	mxge_change_pause(sc, sc->pause);
 	mxge_set_multicast_list(sc);
+	if (sc->throttle) {
+		cmd.data0 = sc->throttle;
+		if (mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR,
+				  &cmd)) {
+			device_printf(sc->dev,
+				      "can't enable throttle\n");
+		}
+	}
 	return status;
 }
 
 static int
+mxge_change_throttle(SYSCTL_HANDLER_ARGS)
+{
+	mxge_cmd_t cmd;
+	mxge_softc_t *sc;
+	int err;
+	unsigned int throttle;
+
+	sc = arg1;
+	throttle = sc->throttle;
+	err = sysctl_handle_int(oidp, &throttle, arg2, req);
+        if (err != 0) {
+                return err;
+        }
+
+	if (throttle == sc->throttle)
+		return 0;
+
+        if (throttle < MXGE_MIN_THROTTLE || throttle > MXGE_MAX_THROTTLE)
+                return EINVAL;
+	
+	mtx_lock(&sc->driver_mtx);
+	cmd.data0 = throttle;
+	err = mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd);
+	if (err == 0)
+		sc->throttle = throttle;
+	mtx_unlock(&sc->driver_mtx);	
+	return err;
+}
+
+static int
 mxge_change_intr_coal(SYSCTL_HANDLER_ARGS)
 {
         mxge_softc_t *sc;
@@ -1508,6 +1551,12 @@ mxge_add_sysctls(mxge_softc_t *sc)
 			"I", "interrupt coalescing delay in usecs");
 
 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 
+			"throttle",
+			CTLTYPE_INT|CTLFLAG_RW, sc,
+			0, mxge_change_throttle, 
+			"I", "transmit throttling");
+
+	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 
 			"flow_control_enabled",
 			CTLTYPE_INT|CTLFLAG_RW, sc,
 			0, mxge_change_flow_control,
@@ -3591,7 +3640,6 @@ mxge_open(mxge_softc_t *sc)
 #endif
 	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-	callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
 
 	return 0;
 
@@ -3612,7 +3660,6 @@ mxge_close(mxge_softc_t *sc, int down)
 	int slice;
 #endif
 
-	callout_stop(&sc->co_hdl);
 #ifdef IFNET_BUF_RING
 	for (slice = 0; slice < sc->num_slices; slice++) {
 		ss = &sc->ss[slice];
@@ -3691,12 +3738,11 @@ mxge_read_reboot(mxge_softc_t *sc)
 	return (pci_read_config(dev, vs + 0x14, 4));
 }
 
-static int
-mxge_watchdog_reset(mxge_softc_t *sc, int slice)
+static void
+mxge_watchdog_reset(mxge_softc_t *sc)
 {
 	struct pci_devinfo *dinfo;
 	struct mxge_slice_state *ss;
-	mxge_tx_ring_t *tx;
 	int err, running, s, num_tx_slices = 1;
 	uint32_t reboot;
 	uint16_t cmd;
@@ -3723,7 +3769,6 @@ mxge_watchdog_reset(mxge_softc_t *sc, in
 		cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2);
 		if (cmd == 0xffff) {
 			device_printf(sc->dev, "NIC disappeared!\n");
-			return (err);
 		}
 	}
 	if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) {
@@ -3782,24 +3827,43 @@ mxge_watchdog_reset(mxge_softc_t *sc, in
 		}
 		sc->watchdog_resets++;
 	} else {
-		tx = &sc->ss[slice].tx;
 		device_printf(sc->dev,
-			      "NIC did not reboot, slice %d ring state:\n",
-			      slice);
-		device_printf(sc->dev,
-			      "tx.req=%d tx.done=%d, tx.queue_active=%d\n",
-			      tx->req, tx->done, tx->queue_active);
-		device_printf(sc->dev, "tx.activate=%d tx.deactivate=%d\n",
-			      tx->activate, tx->deactivate);
-		device_printf(sc->dev, "pkt_done=%d fw=%d\n",
-			      tx->pkt_done,
-			      be32toh(sc->ss->fw_stats->send_done_count));
-		device_printf(sc->dev, "not resetting\n");
+			      "NIC did not reboot, not resetting\n");
+		err = 0;
 	}
-	if (err)
+	if (err) {
 		device_printf(sc->dev, "watchdog reset failed\n");
+	} else {
+		if (sc->dying == 2)
+			sc->dying = 0;
+		callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
+	}
+}
 
-	return (err);
+static void
+mxge_watchdog_task(void *arg, int pending)
+{
+	mxge_softc_t *sc = arg;
+
+
+	mtx_lock(&sc->driver_mtx);
+	mxge_watchdog_reset(sc);
+	mtx_unlock(&sc->driver_mtx);
+}
+
+static void
+mxge_warn_stuck(mxge_softc_t *sc, mxge_tx_ring_t *tx, int slice)
+{
+	tx = &sc->ss[slice].tx;
+	device_printf(sc->dev, "slice %d struck? ring state:\n", slice);
+	device_printf(sc->dev,
+		      "tx.req=%d tx.done=%d, tx.queue_active=%d\n",
+		      tx->req, tx->done, tx->queue_active);
+	device_printf(sc->dev, "tx.activate=%d tx.deactivate=%d\n",
+			      tx->activate, tx->deactivate);
+	device_printf(sc->dev, "pkt_done=%d fw=%d\n",
+		      tx->pkt_done,
+		      be32toh(sc->ss->fw_stats->send_done_count));
 }
 
 static int
@@ -3823,8 +3887,11 @@ mxge_watchdog(mxge_softc_t *sc)
 		    tx->watchdog_req != tx->watchdog_done &&
 		    tx->done == tx->watchdog_done) {
 			/* check for pause blocking before resetting */
-			if (tx->watchdog_rx_pause == rx_pause)
-				err = mxge_watchdog_reset(sc, i);
+			if (tx->watchdog_rx_pause == rx_pause) {
+				mxge_warn_stuck(sc, tx, i);
+				taskqueue_enqueue(sc->tq, &sc->watchdog_task);
+				return (ENXIO);
+			}
 			else
 				device_printf(sc->dev, "Flow control blocking "
 					      "xmits, check link partner\n");
@@ -3840,10 +3907,11 @@ mxge_watchdog(mxge_softc_t *sc)
 	return (err);
 }
 
-static void
+static u_long
 mxge_update_stats(mxge_softc_t *sc)
 {
 	struct mxge_slice_state *ss;
+	u_long pkts = 0;
 	u_long ipackets = 0;
 	u_long opackets = 0;
 #ifdef IFNET_BUF_RING
@@ -3865,6 +3933,8 @@ mxge_update_stats(mxge_softc_t *sc)
 #endif
 		oerrors += ss->oerrors;
 	}
+	pkts = (ipackets - sc->ifp->if_ipackets);
+	pkts += (opackets - sc->ifp->if_opackets);
 	sc->ifp->if_ipackets = ipackets;
 	sc->ifp->if_opackets = opackets;
 #ifdef IFNET_BUF_RING
@@ -3873,23 +3943,43 @@ mxge_update_stats(mxge_softc_t *sc)
 	sc->ifp->if_snd.ifq_drops = odrops;
 #endif
 	sc->ifp->if_oerrors = oerrors;
+	return pkts;
 }
 
 static void
 mxge_tick(void *arg)
 {
 	mxge_softc_t *sc = arg;
+	u_long pkts = 0;
 	int err = 0;
+	int running, ticks;
+	uint16_t cmd;
 
-	/* aggregate stats from different slices */
-	mxge_update_stats(sc);
-	if (!sc->watchdog_countdown) {
-		err = mxge_watchdog(sc);
-		sc->watchdog_countdown = 4;
+	ticks = mxge_ticks;
+	running = sc->ifp->if_drv_flags & IFF_DRV_RUNNING;
+	if (running) {
+		/* aggregate stats from different slices */
+		pkts = mxge_update_stats(sc);
+		if (!sc->watchdog_countdown) {
+			err = mxge_watchdog(sc);
+			sc->watchdog_countdown = 4;
+		}
+		sc->watchdog_countdown--;
+	}
+	if (pkts == 0) {
+		/* ensure NIC did not suffer h/w fault while idle */
+		cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2);		
+		if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) {
+			sc->dying = 2;
+			taskqueue_enqueue(sc->tq, &sc->watchdog_task);
+			err = ENXIO;
+		}
+		/* look less often if NIC is idle */
+		ticks *= 4;
 	}
-	sc->watchdog_countdown--;
+
 	if (err == 0)
-		callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
+		callout_reset(&sc->co_hdl, ticks, mxge_tick, sc);
 
 }
 
@@ -4044,6 +4134,7 @@ mxge_ioctl(struct ifnet *ifp, u_long com
 	default:
 		err = ENOTTY;
         }
+
 	return err;
 }
 
@@ -4070,6 +4161,7 @@ mxge_fetch_tunables(mxge_softc_t *sc)
 	TUNABLE_INT_FETCH("hw.mxge.rss_hash_type", &mxge_rss_hash_type);
 	TUNABLE_INT_FETCH("hw.mxge.rss_hashtype", &mxge_rss_hash_type);
 	TUNABLE_INT_FETCH("hw.mxge.initial_mtu", &mxge_initial_mtu);
+	TUNABLE_INT_FETCH("hw.mxge.throttle", &mxge_throttle);
 	if (sc->lro_cnt != 0)
 		mxge_lro_cnt = sc->lro_cnt;
 
@@ -4087,6 +4179,12 @@ mxge_fetch_tunables(mxge_softc_t *sc)
 	if (mxge_initial_mtu > ETHERMTU_JUMBO ||
 	    mxge_initial_mtu < ETHER_MIN_LEN)
 		mxge_initial_mtu = ETHERMTU_JUMBO;
+
+	if (mxge_throttle && mxge_throttle > MXGE_MAX_THROTTLE)
+		mxge_throttle = MXGE_MAX_THROTTLE;
+	if (mxge_throttle && mxge_throttle < MXGE_MIN_THROTTLE)
+		mxge_throttle = MXGE_MIN_THROTTLE;
+	sc->throttle = mxge_throttle;
 }
 
 
@@ -4503,6 +4601,17 @@ mxge_attach(device_t dev)
 	sc->dev = dev;
 	mxge_fetch_tunables(sc);
 
+	TASK_INIT(&sc->watchdog_task, 1, mxge_watchdog_task, sc);
+	sc->tq = taskqueue_create_fast("mxge_taskq", M_WAITOK,
+				       taskqueue_thread_enqueue,
+				       &sc->tq);
+	if (sc->tq == NULL) {
+		err = ENOMEM;
+		goto abort_with_nothing;
+	}
+	taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
+				device_get_nameunit(sc->dev));
+
 	err = bus_dma_tag_create(NULL,			/* parent */
 				 1,			/* alignment */
 				 0,			/* boundary */
@@ -4519,7 +4628,7 @@ mxge_attach(device_t dev)
 	if (err != 0) {
 		device_printf(sc->dev, "Err %d allocating parent dmat\n",
 			      err);
-		goto abort_with_nothing;
+		goto abort_with_tq;
 	}
 
 	ifp = sc->ifp = if_alloc(IFT_ETHER);
@@ -4660,6 +4769,7 @@ mxge_attach(device_t dev)
 	ifp->if_transmit = mxge_transmit;
 	ifp->if_qflush = mxge_qflush;
 #endif
+	callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
 	return 0;
 
 abort_with_rings:
@@ -4681,7 +4791,12 @@ abort_with_lock:
 	if_free(ifp);
 abort_with_parent_dmat:
 	bus_dma_tag_destroy(sc->parent_dmat);
-
+abort_with_tq:
+	if (sc->tq != NULL) {
+		taskqueue_drain(sc->tq, &sc->watchdog_task);
+		taskqueue_free(sc->tq);
+		sc->tq = NULL;
+	}
 abort_with_nothing:
 	return err;
 }
@@ -4702,6 +4817,11 @@ mxge_detach(device_t dev)
 		mxge_close(sc, 0);
 	mtx_unlock(&sc->driver_mtx);
 	ether_ifdetach(sc->ifp);
+	if (sc->tq != NULL) {
+		taskqueue_drain(sc->tq, &sc->watchdog_task);
+		taskqueue_free(sc->tq);
+		sc->tq = NULL;
+	}
 	callout_drain(&sc->co_hdl);
 	ifmedia_removeall(&sc->media);
 	mxge_dummy_rdma(sc, 0);

Modified: stable/8/sys/dev/mxge/if_mxge_var.h
==============================================================================
--- stable/8/sys/dev/mxge/if_mxge_var.h	Mon Jan 11 20:23:17 2010	(r202111)
+++ stable/8/sys/dev/mxge/if_mxge_var.h	Mon Jan 11 20:32:51 2010	(r202112)
@@ -261,6 +261,7 @@ struct mxge_softc {
 	int fw_multicast_support;
 	int link_width;
 	int max_mtu;
+	int throttle;
 	int tx_defrag;
 	int media_flags;
 	int need_media_probe;
@@ -269,6 +270,8 @@ struct mxge_softc {
 	int dying;
 	mxge_dma_t dmabench_dma;
 	struct callout co_hdl;
+	struct taskqueue *tq;
+	struct task watchdog_task;
 	struct sysctl_oid *slice_sysctl_tree;
 	struct sysctl_ctx_list slice_sysctl_ctx;
 	char *mac_addr_string;
@@ -287,6 +290,8 @@ struct mxge_softc {
 #define MXGE_PCI_REV_Z8ES	1
 #define MXGE_XFP_COMPLIANCE_BYTE	131
 #define MXGE_SFP_COMPLIANCE_BYTE	  3
+#define MXGE_MIN_THROTTLE	416
+#define MXGE_MAX_THROTTLE	4096
 
 #define MXGE_HIGHPART_TO_U32(X) \
 (sizeof (X) == 8) ? ((uint32_t)((uint64_t)(X) >> 32)) : (0)


More information about the svn-src-all mailing list