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