summaryrefslogtreecommitdiffstats
path: root/sys/dev/mxge/if_mxge.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mxge/if_mxge.c')
-rw-r--r--sys/dev/mxge/if_mxge.c158
1 files changed, 129 insertions, 29 deletions
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index 88c3489..6e8ca67 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -106,6 +106,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";
@@ -143,7 +144,7 @@ MODULE_DEPEND(mxge, zlib, 1, 1, 1);
static int mxge_load_firmware(mxge_softc_t *sc, int adopt);
static int mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data);
-static int mxge_close(mxge_softc_t *sc);
+static int mxge_close(mxge_softc_t *sc, int down);
static int mxge_open(mxge_softc_t *sc);
static void mxge_tick(void *arg);
@@ -596,10 +597,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;
@@ -1305,8 +1309,7 @@ mxge_reset(mxge_softc_t *sc, int interrupts_setup)
ss->lro_queued = 0;
ss->lro_flushed = 0;
if (ss->fw_stats != NULL) {
- ss->fw_stats->valid = 0;
- ss->fw_stats->send_done_count = 0;
+ bzero(ss->fw_stats, sizeof *ss->fw_stats);
}
}
sc->rdma_tags_available = 15;
@@ -1314,10 +1317,48 @@ mxge_reset(mxge_softc_t *sc, int interrupts_setup)
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;
@@ -1379,7 +1420,7 @@ mxge_change_lro_locked(mxge_softc_t *sc, int lro_cnt)
ifp->if_capenable |= IFCAP_LRO;
sc->lro_cnt = lro_cnt;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- mxge_close(sc);
+ mxge_close(sc, 0);
err = mxge_open(sc);
}
return err;
@@ -1495,6 +1536,10 @@ mxge_add_sysctls(mxge_softc_t *sc)
"read_write_dma_MBs",
CTLFLAG_RD, &sc->read_write_dma,
0, "DMA concurrent Read/Write speed in MB/s");
+ SYSCTL_ADD_INT(ctx, children, OID_AUTO,
+ "watchdog_resets",
+ CTLFLAG_RD, &sc->watchdog_resets,
+ 0, "Number of times NIC was reset");
/* performance related tunables */
@@ -1505,6 +1550,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,
@@ -3600,7 +3651,7 @@ abort:
}
static int
-mxge_close(mxge_softc_t *sc)
+mxge_close(mxge_softc_t *sc, int down)
{
mxge_cmd_t cmd;
int err, old_down_cnt;
@@ -3617,21 +3668,23 @@ mxge_close(mxge_softc_t *sc)
}
#endif
sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
- old_down_cnt = sc->down_cnt;
- wmb();
- err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd);
- if (err) {
- device_printf(sc->dev, "Couldn't bring down link\n");
- }
- if (old_down_cnt == sc->down_cnt) {
- /* wait for down irq */
- DELAY(10 * sc->intr_coal_delay);
- }
- wmb();
- if (old_down_cnt == sc->down_cnt) {
- device_printf(sc->dev, "never got down irq\n");
+ if (!down) {
+ old_down_cnt = sc->down_cnt;
+ wmb();
+ err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd);
+ if (err) {
+ device_printf(sc->dev,
+ "Couldn't bring down link\n");
+ }
+ if (old_down_cnt == sc->down_cnt) {
+ /* wait for down irq */
+ DELAY(10 * sc->intr_coal_delay);
+ }
+ wmb();
+ if (old_down_cnt == sc->down_cnt) {
+ device_printf(sc->dev, "never got down irq\n");
+ }
}
-
mxge_free_mbufs(sc);
return 0;
@@ -3684,8 +3737,9 @@ static int
mxge_watchdog_reset(mxge_softc_t *sc, int slice)
{
struct pci_devinfo *dinfo;
+ struct mxge_slice_state *ss;
mxge_tx_ring_t *tx;
- int err;
+ int err, running, s, num_tx_slices = 1;
uint32_t reboot;
uint16_t cmd;
@@ -3719,6 +3773,30 @@ mxge_watchdog_reset(mxge_softc_t *sc, int slice)
reboot = mxge_read_reboot(sc);
device_printf(sc->dev, "NIC rebooted, status = 0x%x\n",
reboot);
+ running = sc->ifp->if_drv_flags & IFF_DRV_RUNNING;
+ if (running) {
+
+ /*
+ * quiesce NIC so that TX routines will not try to
+ * xmit after restoration of BAR
+ */
+
+ /* Mark the link as down */
+ if (sc->link_state) {
+ sc->link_state = 0;
+ if_link_state_change(sc->ifp,
+ LINK_STATE_DOWN);
+ }
+#ifdef IFNET_BUF_RING
+ num_tx_slices = sc->num_slices;
+#endif
+ /* grab all TX locks to ensure no tx */
+ for (s = 0; s < num_tx_slices; s++) {
+ ss = &sc->ss[s];
+ mtx_lock(&ss->tx.mtx);
+ }
+ mxge_close(sc, 1);
+ }
/* restore PCI configuration space */
dinfo = device_get_ivars(sc->dev);
pci_cfg_restore(sc->dev, dinfo);
@@ -3726,10 +3804,22 @@ mxge_watchdog_reset(mxge_softc_t *sc, int slice)
/* and redo any changes we made to our config space */
mxge_setup_cfg_space(sc);
- if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) {
- mxge_close(sc);
- err = mxge_open(sc);
+ /* reload f/w */
+ err = mxge_load_firmware(sc, 0);
+ if (err) {
+ device_printf(sc->dev,
+ "Unable to re-load f/w\n");
}
+ if (running) {
+ if (!err)
+ err = mxge_open(sc);
+ /* release all TX locks */
+ for (s = 0; s < num_tx_slices; s++) {
+ ss = &sc->ss[s];
+ mtx_unlock(&ss->tx.mtx);
+ }
+ }
+ sc->watchdog_resets++;
} else {
tx = &sc->ss[slice].tx;
device_printf(sc->dev,
@@ -3745,6 +3835,9 @@ mxge_watchdog_reset(mxge_softc_t *sc, int slice)
be32toh(sc->ss->fw_stats->send_done_count));
device_printf(sc->dev, "not resetting\n");
}
+ if (err)
+ device_printf(sc->dev, "watchdog reset failed\n");
+
return (err);
}
@@ -3860,11 +3953,11 @@ mxge_change_mtu(mxge_softc_t *sc, int mtu)
old_mtu = ifp->if_mtu;
ifp->if_mtu = mtu;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- mxge_close(sc);
+ mxge_close(sc, 0);
err = mxge_open(sc);
if (err != 0) {
ifp->if_mtu = old_mtu;
- mxge_close(sc);
+ mxge_close(sc, 0);
(void) mxge_open(sc);
}
}
@@ -3922,7 +4015,7 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- mxge_close(sc);
+ mxge_close(sc, 0);
}
}
mtx_unlock(&sc->driver_mtx);
@@ -4016,6 +4109,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;
@@ -4033,6 +4127,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;
}
@@ -4645,7 +4745,7 @@ mxge_detach(device_t dev)
mtx_lock(&sc->driver_mtx);
sc->dying = 1;
if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING)
- mxge_close(sc);
+ mxge_close(sc, 0);
mtx_unlock(&sc->driver_mtx);
ether_ifdetach(sc->ifp);
callout_drain(&sc->co_hdl);
OpenPOWER on IntegriCloud