summaryrefslogtreecommitdiffstats
path: root/sys/dev/cxgbe/t4_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/cxgbe/t4_main.c')
-rw-r--r--sys/dev/cxgbe/t4_main.c185
1 files changed, 149 insertions, 36 deletions
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 2a8305d..d976313 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -348,6 +348,24 @@ static int t4_pause_settings = PAUSE_TX | PAUSE_RX;
TUNABLE_INT("hw.cxgbe.pause_settings", &t4_pause_settings);
/*
+ * Forward Error Correction settings (bit 0, 1, 2 = FEC_RS, FEC_BASER_RS,
+ * FEC_RESERVED respectively).
+ * -1 to run with the firmware default.
+ * 0 to disable FEC.
+ */
+static int t4_fec = -1;
+TUNABLE_INT("hw.cxgbe.fec", &t4_fec);
+
+/*
+ * Link autonegotiation.
+ * -1 to run with the firmware default.
+ * 0 to disable.
+ * 1 to enable.
+ */
+static int t4_autoneg = -1;
+TUNABLE_INT("hw.cxgbe.autoneg", &t4_autoneg);
+
+/*
* Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed,
* encouraged respectively).
*/
@@ -482,6 +500,8 @@ static int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS);
static int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS);
static int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS);
static int sysctl_pause_settings(SYSCTL_HANDLER_ARGS);
+static int sysctl_fec(SYSCTL_HANDLER_ARGS);
+static int sysctl_autoneg(SYSCTL_HANDLER_ARGS);
static int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS);
static int sysctl_temperature(SYSCTL_HANDLER_ARGS);
#ifdef SBUF_DRAIN
@@ -910,6 +930,7 @@ t4_attach(device_t dev)
n10g = n1g = 0;
for_each_port(sc, i) {
struct port_info *pi;
+ struct link_config *lc;
pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK);
sc->port[i] = pi;
@@ -938,12 +959,19 @@ t4_attach(device_t dev)
goto done;
}
- pi->link_cfg.requested_fc &= ~(PAUSE_TX | PAUSE_RX);
- pi->link_cfg.requested_fc |= t4_pause_settings;
- pi->link_cfg.fc &= ~(PAUSE_TX | PAUSE_RX);
- pi->link_cfg.fc |= t4_pause_settings;
+ lc = &pi->link_cfg;
+ lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
+ lc->requested_fc |= t4_pause_settings;
+ if (t4_fec != -1) {
+ lc->requested_fec = t4_fec &
+ G_FW_PORT_CAP_FEC(lc->supported);
+ }
+ if (lc->supported & FW_PORT_CAP_ANEG && t4_autoneg != -1) {
+ lc->autoneg = t4_autoneg ? AUTONEG_ENABLE :
+ AUTONEG_DISABLE;
+ }
- rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, &pi->link_cfg);
+ rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
if (rc != 0) {
device_printf(dev, "port %d l1cfg failed: %d\n", i, rc);
free(pi->vi, M_CXGBE);
@@ -966,8 +994,6 @@ t4_attach(device_t dev)
n1g++;
}
- pi->linkdnrc = -1;
-
pi->dev = device_add_child(dev, sc->names->ifnet_name, -1);
if (pi->dev == NULL) {
device_printf(dev,
@@ -3867,8 +3893,8 @@ cxgbe_uninit_synchronized(struct vi_info *vi)
pi->link_cfg.link_ok = 0;
pi->link_cfg.speed = 0;
- pi->linkdnrc = -1;
- t4_os_link_changed(sc, pi->port_id, 0, -1);
+ pi->link_cfg.link_down_rc = 255;
+ t4_os_link_changed(sc, pi->port_id, 0);
return (0);
}
@@ -5124,8 +5150,14 @@ cxgbe_sysctls(struct port_info *pi)
}
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pause_settings",
- CTLTYPE_STRING | CTLFLAG_RW, pi, PAUSE_TX, sysctl_pause_settings,
- "A", "PAUSE settings (bit 0 = rx_pause, bit 1 = tx_pause)");
+ CTLTYPE_STRING | CTLFLAG_RW, pi, 0, sysctl_pause_settings, "A",
+ "PAUSE settings (bit 0 = rx_pause, bit 1 = tx_pause)");
+ SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fec",
+ CTLTYPE_STRING | CTLFLAG_RW, pi, 0, sysctl_fec, "A",
+ "Forward Error Correction (bit 0 = RS, bit 1 = BASER_RS)");
+ SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "autoneg",
+ CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_autoneg, "I",
+ "autonegotiation (-1 = not supported)");
SYSCTL_ADD_INT(ctx, children, OID_AUTO, "max_speed", CTLFLAG_RD, NULL,
port_top_speed(pi), "max speed (in Gbps)");
@@ -5586,12 +5618,9 @@ sysctl_pause_settings(SYSCTL_HANDLER_ARGS)
if (rc)
return (rc);
if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) {
- int link_ok = lc->link_ok;
-
lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
lc->requested_fc |= n;
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
- lc->link_ok = link_ok; /* restore */
}
end_synchronized_op(sc, 0);
}
@@ -5600,6 +5629,97 @@ sysctl_pause_settings(SYSCTL_HANDLER_ARGS)
}
static int
+sysctl_fec(SYSCTL_HANDLER_ARGS)
+{
+ struct port_info *pi = arg1;
+ struct adapter *sc = pi->adapter;
+ struct link_config *lc = &pi->link_cfg;
+ int rc;
+
+ if (req->newptr == NULL) {
+ struct sbuf *sb;
+ static char *bits = "\20\1RS\2BASER_RS\3RESERVED";
+
+ rc = sysctl_wire_old_buffer(req, 0);
+ if (rc != 0)
+ return(rc);
+
+ sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
+ if (sb == NULL)
+ return (ENOMEM);
+
+ sbuf_printf(sb, "%b", lc->fec & M_FW_PORT_CAP_FEC, bits);
+ rc = sbuf_finish(sb);
+ sbuf_delete(sb);
+ } else {
+ char s[2];
+ int n;
+
+ s[0] = '0' + (lc->requested_fec & M_FW_PORT_CAP_FEC);
+ s[1] = 0;
+
+ rc = sysctl_handle_string(oidp, s, sizeof(s), req);
+ if (rc != 0)
+ return(rc);
+
+ if (s[1] != 0)
+ return (EINVAL);
+ if (s[0] < '0' || s[0] > '9')
+ return (EINVAL); /* not a number */
+ n = s[0] - '0';
+ if (n & ~M_FW_PORT_CAP_FEC)
+ return (EINVAL); /* some other bit is set too */
+
+ rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
+ "t4fec");
+ if (rc)
+ return (rc);
+ if ((lc->requested_fec & M_FW_PORT_CAP_FEC) != n) {
+ lc->requested_fec = n &
+ G_FW_PORT_CAP_FEC(lc->supported);
+ rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
+ }
+ end_synchronized_op(sc, 0);
+ }
+
+ return (rc);
+}
+
+static int
+sysctl_autoneg(SYSCTL_HANDLER_ARGS)
+{
+ struct port_info *pi = arg1;
+ struct adapter *sc = pi->adapter;
+ struct link_config *lc = &pi->link_cfg;
+ int rc, val, old;
+
+ if (lc->supported & FW_PORT_CAP_ANEG)
+ val = lc->autoneg == AUTONEG_ENABLE ? 1 : 0;
+ else
+ val = -1;
+ rc = sysctl_handle_int(oidp, &val, 0, req);
+ if (rc != 0 || req->newptr == NULL)
+ return (rc);
+ if ((lc->supported & FW_PORT_CAP_ANEG) == 0)
+ return (ENOTSUP);
+
+ val = val ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ if (lc->autoneg == val)
+ return (0); /* no change */
+
+ rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
+ "t4aneg");
+ if (rc)
+ return (rc);
+ old = lc->autoneg;
+ lc->autoneg = val;
+ rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
+ if (rc != 0)
+ lc->autoneg = old;
+ return (rc);
+}
+
+static int
sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS)
{
struct adapter *sc = arg1;
@@ -6344,6 +6464,7 @@ sysctl_linkdnrc(SYSCTL_HANDLER_ARGS)
{
int rc = 0;
struct port_info *pi = arg1;
+ struct link_config *lc = &pi->link_cfg;
struct sbuf *sb;
rc = sysctl_wire_old_buffer(req, 0);
@@ -6353,10 +6474,10 @@ sysctl_linkdnrc(SYSCTL_HANDLER_ARGS)
if (sb == NULL)
return (ENOMEM);
- if (pi->linkdnrc < 0)
+ if (lc->link_ok || lc->link_down_rc == 255)
sbuf_printf(sb, "n/a");
else
- sbuf_printf(sb, "%s", t4_link_down_rc_str(pi->linkdnrc));
+ sbuf_printf(sb, "%s", t4_link_down_rc_str(lc->link_down_rc));
rc = sbuf_finish(sb);
sbuf_delete(sb);
@@ -7070,25 +7191,23 @@ sysctl_tids(SYSCTL_HANDLER_ARGS)
}
if (t->ntids) {
+ sbuf_printf(sb, "TID range: ");
if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) {
- uint32_t b;
+ uint32_t b, hb;
- if (chip_id(sc) <= CHELSIO_T5)
+ if (chip_id(sc) <= CHELSIO_T5) {
b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4;
- else
- b = t4_read_reg(sc, A_LE_DB_SRVR_START_INDEX);
-
- if (b) {
- sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1,
- t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4,
- t->ntids - 1);
+ hb = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4;
} else {
- sbuf_printf(sb, "TID range: %u-%u",
- t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4,
- t->ntids - 1);
+ b = t4_read_reg(sc, A_LE_DB_SRVR_START_INDEX);
+ hb = t4_read_reg(sc, A_T6_LE_DB_HASH_TID_BASE);
}
+
+ if (b)
+ sbuf_printf(sb, "0-%u, ", b - 1);
+ sbuf_printf(sb, "%u-%u", hb, t->ntids - 1);
} else
- sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1);
+ sbuf_printf(sb, "0-%u", t->ntids - 1);
sbuf_printf(sb, ", in use: %u\n",
atomic_load_acq_int(&t->tids_in_use));
}
@@ -8826,19 +8945,13 @@ t4_os_portmod_changed(const struct adapter *sc, int idx)
}
void
-t4_os_link_changed(struct adapter *sc, int idx, int link_stat, int reason)
+t4_os_link_changed(struct adapter *sc, int idx, int link_stat)
{
struct port_info *pi = sc->port[idx];
struct vi_info *vi;
struct ifnet *ifp;
int v;
- if (link_stat)
- pi->linkdnrc = -1;
- else {
- if (reason >= 0)
- pi->linkdnrc = reason;
- }
for_each_vi(pi, v, vi) {
ifp = vi->ifp;
if (ifp == NULL)
OpenPOWER on IntegriCloud