From owner-svn-src-stable-8@FreeBSD.ORG Mon Jan 11 20:32:51 2010 Return-Path: Delivered-To: svn-src-stable-8@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6F0451065672; Mon, 11 Jan 2010 20:32:51 +0000 (UTC) (envelope-from gallatin@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 5C7828FC18; Mon, 11 Jan 2010 20:32:51 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o0BKWpat068677; Mon, 11 Jan 2010 20:32:51 GMT (envelope-from gallatin@svn.freebsd.org) Received: (from gallatin@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o0BKWpV6068674; Mon, 11 Jan 2010 20:32:51 GMT (envelope-from gallatin@svn.freebsd.org) Message-Id: <201001112032.o0BKWpV6068674@svn.freebsd.org> From: Andrew Gallatin Date: Mon, 11 Jan 2010 20:32:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r202112 - stable/8/sys/dev/mxge X-BeenThere: svn-src-stable-8@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 8-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jan 2010 20:32:51 -0000 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 #include #include +#include /* 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)