svn commit: r334631 - in releng/11.2/sys/dev/cxgbe: . common
Navdeep Parhar
np at FreeBSD.org
Mon Jun 4 20:34:55 UTC 2018
Author: np
Date: Mon Jun 4 20:34:53 2018
New Revision: 334631
URL: https://svnweb.freebsd.org/changeset/base/334631
Log:
Merge r334562 from stable/11 to releng/11.2. r334562 MFC'd the
following revisions to stable/11: r333650, r333652, r333682, r334406,
r334409-r334410, and r334489.
r333650:
cxgbe(4): Claim some more T5 and T6 boards.
r333652:
cxgbe(4): Add support for two more flash parts.
r333682:
cxgbe(4): Fall back to a failsafe configuration built into the firmware
if an error is reported while pre-processing the configuration file that
the driver attempted to use.
Also, allow the user to explicitly use the built-in configuration with
hw.cxgbe.config_file="built-in"
r334406:
cxgbe(4): Consider all supported speeds when building the ifmedia list
for a port. Fix other related issues while here:
- Require port lock for access to link_config.
- Allow 100Mbps operation by tracking the speed in Mbps. Yes, really.
- New port flag to indicate that the media list is immutable. It will
be used in future refinements.
This also fixes a bug where the driver reports incorrect media with
recent firmwares.
r334409:
cxgbe(4): Implement ifm_change callback.
r334410:
cxgbe(4): Use ifm for ifmedia just like the rest of the kernel.
No functional change.
r334489:
cxgbe(4): Include full duplex mediaopt in media that can be reported as
active. Always report full duplex in active media.
Approved by: re@ (gjb@, kib@)
Sponsored by: Chelsio Communications
Modified:
releng/11.2/sys/dev/cxgbe/adapter.h
releng/11.2/sys/dev/cxgbe/common/common.h
releng/11.2/sys/dev/cxgbe/common/t4_hw.c
releng/11.2/sys/dev/cxgbe/t4_main.c
Directory Properties:
releng/11.2/ (props changed)
Modified: releng/11.2/sys/dev/cxgbe/adapter.h
==============================================================================
--- releng/11.2/sys/dev/cxgbe/adapter.h Mon Jun 4 20:24:31 2018 (r334630)
+++ releng/11.2/sys/dev/cxgbe/adapter.h Mon Jun 4 20:34:53 2018 (r334631)
@@ -162,6 +162,7 @@ enum {
/* port flags */
HAS_TRACEQ = (1 << 3),
+ FIXED_IFMEDIA = (1 << 4), /* ifmedia list doesn't change. */
/* VI flags */
DOOMED = (1 << 0),
Modified: releng/11.2/sys/dev/cxgbe/common/common.h
==============================================================================
--- releng/11.2/sys/dev/cxgbe/common/common.h Mon Jun 4 20:24:31 2018 (r334630)
+++ releng/11.2/sys/dev/cxgbe/common/common.h Mon Jun 4 20:34:53 2018 (r334631)
@@ -413,12 +413,12 @@ struct link_config {
unsigned char requested_aneg; /* link aneg user has requested */
unsigned char requested_fc; /* flow control user has requested */
unsigned char requested_fec; /* FEC user has requested */
- unsigned int requested_speed; /* speed user has requested */
+ unsigned int requested_speed; /* speed user has requested (Mbps) */
unsigned short supported; /* link capabilities */
unsigned short advertising; /* advertised capabilities */
unsigned short lp_advertising; /* peer advertised capabilities */
- unsigned int speed; /* actual link speed */
+ unsigned int speed; /* actual link speed (Mbps) */
unsigned char fc; /* actual link flow control */
unsigned char fec; /* actual FEC */
unsigned char link_ok; /* link up? */
Modified: releng/11.2/sys/dev/cxgbe/common/t4_hw.c
==============================================================================
--- releng/11.2/sys/dev/cxgbe/common/t4_hw.c Mon Jun 4 20:24:31 2018 (r334630)
+++ releng/11.2/sys/dev/cxgbe/common/t4_hw.c Mon Jun 4 20:34:53 2018 (r334631)
@@ -3725,21 +3725,24 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int m
lc->requested_aneg == AUTONEG_DISABLE) {
aneg = 0;
switch (lc->requested_speed) {
- case 100:
+ case 100000:
speed = FW_PORT_CAP_SPEED_100G;
break;
- case 40:
+ case 40000:
speed = FW_PORT_CAP_SPEED_40G;
break;
- case 25:
+ case 25000:
speed = FW_PORT_CAP_SPEED_25G;
break;
- case 10:
+ case 10000:
speed = FW_PORT_CAP_SPEED_10G;
break;
- case 1:
+ case 1000:
speed = FW_PORT_CAP_SPEED_1G;
break;
+ case 100:
+ speed = FW_PORT_CAP_SPEED_100M;
+ break;
default:
return -EINVAL;
break;
@@ -7713,9 +7716,9 @@ static void handle_port_info(struct port_info *pi, con
fec = 0;
if (lc->advertising & FW_PORT_CAP_FEC_RS)
- fec |= FEC_RS;
- if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
- fec |= FEC_BASER_RS;
+ fec = FEC_RS;
+ else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
+ fec = FEC_BASER_RS;
lc->fec = fec;
}
@@ -7776,14 +7779,16 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be6
}
lc = &pi->link_cfg;
+ PORT_LOCK(pi);
old_lc = &pi->old_link_cfg;
old_ptype = pi->port_type;
old_mtype = pi->mod_type;
-
handle_port_info(pi, &p->u.info);
+ PORT_UNLOCK(pi);
if (old_ptype != pi->port_type || old_mtype != pi->mod_type) {
t4_os_portmod_changed(pi);
}
+ PORT_LOCK(pi);
if (old_lc->link_ok != lc->link_ok ||
old_lc->speed != lc->speed ||
old_lc->fec != lc->fec ||
@@ -7791,6 +7796,7 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be6
t4_os_link_changed(pi);
*old_lc = *lc;
}
+ PORT_UNLOCK(pi);
} else {
CH_WARN_RATELIMIT(adap, "Unknown firmware reply %d\n", opcode);
return -EINVAL;
@@ -7896,6 +7902,44 @@ int t4_get_flash_params(struct adapter *adapter)
default:
CH_ERR(adapter, "Micron Flash Part has bad size, "
+ "ID = %#x, Density code = %#x\n",
+ flashid, density);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case 0x9d: { /* ISSI -- Integrated Silicon Solution, Inc. */
+ /*
+ * This Density -> Size decoding table is taken from ISSI
+ * Data Sheets.
+ */
+ density = (flashid >> 16) & 0xff;
+ switch (density) {
+ case 0x16: size = 1 << 25; break; /* 32MB */
+ case 0x17: size = 1 << 26; break; /* 64MB */
+
+ default:
+ CH_ERR(adapter, "ISSI Flash Part has bad size, "
+ "ID = %#x, Density code = %#x\n",
+ flashid, density);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case 0xc2: { /* Macronix */
+ /*
+ * This Density -> Size decoding table is taken from Macronix
+ * Data Sheets.
+ */
+ density = (flashid >> 16) & 0xff;
+ switch (density) {
+ case 0x17: size = 1 << 23; break; /* 8MB */
+ case 0x18: size = 1 << 24; break; /* 16MB */
+
+ default:
+ CH_ERR(adapter, "Macronix Flash Part has bad size, "
"ID = %#x, Density code = %#x\n",
flashid, density);
return -EINVAL;
Modified: releng/11.2/sys/dev/cxgbe/t4_main.c
==============================================================================
--- releng/11.2/sys/dev/cxgbe/t4_main.c Mon Jun 4 20:24:31 2018 (r334630)
+++ releng/11.2/sys/dev/cxgbe/t4_main.c Mon Jun 4 20:34:53 2018 (r334631)
@@ -376,9 +376,10 @@ int t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX;
TUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types);
/*
- * Configuration file.
+ * Configuration file. All the _CF names here are special.
*/
#define DEFAULT_CF "default"
+#define BUILTIN_CF "built-in"
#define FLASH_CF "flash"
#define UWIRE_CF "uwire"
#define FPGA_CF "fpga"
@@ -528,6 +529,7 @@ static int set_params__post_init(struct adapter *);
static void t4_set_desc(struct adapter *);
static void build_medialist(struct port_info *, struct ifmedia *);
static void init_l1cfg(struct port_info *);
+static int apply_l1cfg(struct port_info *);
static int cxgbe_init_synchronized(struct vi_info *);
static int cxgbe_uninit_synchronized(struct vi_info *);
static void quiesce_txq(struct adapter *, struct sge_txq *);
@@ -659,16 +661,10 @@ struct {
{0x5412, "Chelsio T560-CR"}, /* 1 x 40G, 2 x 10G */
{0x5414, "Chelsio T580-LP-SO-CR"}, /* 2 x 40G, nomem */
{0x5415, "Chelsio T502-BT"}, /* 2 x 1G */
-#ifdef notyet
- {0x5404, "Chelsio T520-BCH"},
- {0x5405, "Chelsio T540-BCH"},
- {0x5406, "Chelsio T540-CH"},
- {0x5408, "Chelsio T520-CX"},
- {0x540b, "Chelsio B520-SR"},
- {0x540c, "Chelsio B504-BT"},
- {0x540f, "Chelsio Amsterdam"},
- {0x5413, "Chelsio T580-CHR"},
-#endif
+ {0x5418, "Chelsio T540-BT"}, /* 4 x 10GBaseT */
+ {0x5419, "Chelsio T540-LP-BT"}, /* 4 x 10GBaseT */
+ {0x541a, "Chelsio T540-SO-BT"}, /* 4 x 10GBaseT, nomem */
+ {0x541b, "Chelsio T540-SO-CR"}, /* 4 x 10G, nomem */
}, t6_pciids[] = {
{0xc006, "Chelsio Terminator 6 FPGA"}, /* T6 PE10K6 FPGA (PF0) */
{0x6400, "Chelsio T6-DBG-25"}, /* 2 x 10/25G, debug */
@@ -688,9 +684,14 @@ struct {
{0x6415, "Chelsio T6201-BT"}, /* 2 x 1000BASE-T */
/* Custom */
- {0x6480, "Chelsio T6225 80"},
- {0x6481, "Chelsio T62100 81"},
- {0x6484, "Chelsio T62100 84"},
+ {0x6480, "Custom T6225-CR"},
+ {0x6481, "Custom T62100-CR"},
+ {0x6482, "Custom T6225-CR"},
+ {0x6483, "Custom T62100-CR"},
+ {0x6484, "Custom T64100-CR"},
+ {0x6485, "Custom T6240-SO"},
+ {0x6486, "Custom T6225-SO-CR"},
+ {0x6487, "Custom T6225-CR"},
};
#ifdef TCP_OFFLOAD
@@ -2008,78 +2009,248 @@ cxgbe_get_counter(struct ifnet *ifp, ift_counter c)
}
}
+/*
+ * The kernel picks a media from the list we had provided so we do not have to
+ * validate the request.
+ */
static int
cxgbe_media_change(struct ifnet *ifp)
{
struct vi_info *vi = ifp->if_softc;
+ struct port_info *pi = vi->pi;
+ struct ifmedia *ifm = &pi->media;
+ struct link_config *lc = &pi->link_cfg;
+ struct adapter *sc = pi->adapter;
+ int rc;
- device_printf(vi->dev, "%s unimplemented.\n", __func__);
+ rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4mec");
+ if (rc != 0)
+ return (rc);
+ PORT_LOCK(pi);
+ if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
+ MPASS(lc->supported & FW_PORT_CAP_ANEG);
+ lc->requested_aneg = AUTONEG_ENABLE;
+ } else {
+ lc->requested_aneg = AUTONEG_DISABLE;
+ lc->requested_speed =
+ ifmedia_baudrate(ifm->ifm_media) / 1000000;
+ lc->requested_fc = 0;
+ if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_RXPAUSE)
+ lc->requested_fc |= PAUSE_RX;
+ if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE)
+ lc->requested_fc |= PAUSE_TX;
+ }
+ if (pi->up_vis > 0)
+ rc = apply_l1cfg(pi);
+ PORT_UNLOCK(pi);
+ end_synchronized_op(sc, 0);
+ return (rc);
+}
- return (EOPNOTSUPP);
+/*
+ * Mbps to FW_PORT_CAP_SPEED_* bit.
+ */
+static uint16_t
+speed_to_fwspeed(int speed)
+{
+
+ switch (speed) {
+ case 100000:
+ return (FW_PORT_CAP_SPEED_100G);
+ case 40000:
+ return (FW_PORT_CAP_SPEED_40G);
+ case 25000:
+ return (FW_PORT_CAP_SPEED_25G);
+ case 10000:
+ return (FW_PORT_CAP_SPEED_10G);
+ case 1000:
+ return (FW_PORT_CAP_SPEED_1G);
+ case 100:
+ return (FW_PORT_CAP_SPEED_100M);
+ }
+
+ return (0);
}
+/*
+ * Base media word (without ETHER, pause, link active, etc.) for the port at the
+ * given speed.
+ */
+static int
+port_mword(struct port_info *pi, uint16_t speed)
+{
+
+ MPASS(speed & M_FW_PORT_CAP_SPEED);
+ MPASS(powerof2(speed));
+
+ switch(pi->port_type) {
+ case FW_PORT_TYPE_BT_SGMII:
+ case FW_PORT_TYPE_BT_XFI:
+ case FW_PORT_TYPE_BT_XAUI:
+ /* BaseT */
+ switch (speed) {
+ case FW_PORT_CAP_SPEED_100M:
+ return (IFM_100_T);
+ case FW_PORT_CAP_SPEED_1G:
+ return (IFM_1000_T);
+ case FW_PORT_CAP_SPEED_10G:
+ return (IFM_10G_T);
+ }
+ break;
+ case FW_PORT_TYPE_KX4:
+ if (speed == FW_PORT_CAP_SPEED_10G)
+ return (IFM_10G_KX4);
+ break;
+ case FW_PORT_TYPE_CX4:
+ if (speed == FW_PORT_CAP_SPEED_10G)
+ return (IFM_10G_CX4);
+ break;
+ case FW_PORT_TYPE_KX:
+ if (speed == FW_PORT_CAP_SPEED_1G)
+ return (IFM_1000_KX);
+ break;
+ case FW_PORT_TYPE_KR:
+ case FW_PORT_TYPE_BP_AP:
+ case FW_PORT_TYPE_BP4_AP:
+ case FW_PORT_TYPE_BP40_BA:
+ case FW_PORT_TYPE_KR4_100G:
+ case FW_PORT_TYPE_KR_SFP28:
+ case FW_PORT_TYPE_KR_XLAUI:
+ switch (speed) {
+ case FW_PORT_CAP_SPEED_1G:
+ return (IFM_1000_KX);
+ case FW_PORT_CAP_SPEED_10G:
+ return (IFM_10G_KR);
+ case FW_PORT_CAP_SPEED_25G:
+ return (IFM_25G_KR);
+ case FW_PORT_CAP_SPEED_40G:
+ return (IFM_40G_KR4);
+ case FW_PORT_CAP_SPEED_100G:
+ return (IFM_100G_KR4);
+ }
+ break;
+ case FW_PORT_TYPE_FIBER_XFI:
+ case FW_PORT_TYPE_FIBER_XAUI:
+ case FW_PORT_TYPE_SFP:
+ case FW_PORT_TYPE_QSFP_10G:
+ case FW_PORT_TYPE_QSA:
+ case FW_PORT_TYPE_QSFP:
+ case FW_PORT_TYPE_CR4_QSFP:
+ case FW_PORT_TYPE_CR_QSFP:
+ case FW_PORT_TYPE_CR2_QSFP:
+ case FW_PORT_TYPE_SFP28:
+ /* Pluggable transceiver */
+ switch (pi->mod_type) {
+ case FW_PORT_MOD_TYPE_LR:
+ switch (speed) {
+ case FW_PORT_CAP_SPEED_1G:
+ return (IFM_1000_LX);
+ case FW_PORT_CAP_SPEED_10G:
+ return (IFM_10G_LR);
+ case FW_PORT_CAP_SPEED_25G:
+ return (IFM_25G_LR);
+ case FW_PORT_CAP_SPEED_40G:
+ return (IFM_40G_LR4);
+ case FW_PORT_CAP_SPEED_100G:
+ return (IFM_100G_LR4);
+ }
+ break;
+ case FW_PORT_MOD_TYPE_SR:
+ switch (speed) {
+ case FW_PORT_CAP_SPEED_1G:
+ return (IFM_1000_SX);
+ case FW_PORT_CAP_SPEED_10G:
+ return (IFM_10G_SR);
+ case FW_PORT_CAP_SPEED_25G:
+ return (IFM_25G_SR);
+ case FW_PORT_CAP_SPEED_40G:
+ return (IFM_40G_SR4);
+ case FW_PORT_CAP_SPEED_100G:
+ return (IFM_100G_SR4);
+ }
+ break;
+ case FW_PORT_MOD_TYPE_ER:
+ if (speed == FW_PORT_CAP_SPEED_10G)
+ return (IFM_10G_ER);
+ break;
+ case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
+ case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
+ switch (speed) {
+ case FW_PORT_CAP_SPEED_1G:
+ return (IFM_1000_CX);
+ case FW_PORT_CAP_SPEED_10G:
+ return (IFM_10G_TWINAX);
+ case FW_PORT_CAP_SPEED_25G:
+ return (IFM_25G_CR);
+ case FW_PORT_CAP_SPEED_40G:
+ return (IFM_40G_CR4);
+ case FW_PORT_CAP_SPEED_100G:
+ return (IFM_100G_CR4);
+ }
+ break;
+ case FW_PORT_MOD_TYPE_LRM:
+ if (speed == FW_PORT_CAP_SPEED_10G)
+ return (IFM_10G_LRM);
+ break;
+ case FW_PORT_MOD_TYPE_NA:
+ MPASS(0); /* Not pluggable? */
+ /* fall throough */
+ case FW_PORT_MOD_TYPE_ERROR:
+ case FW_PORT_MOD_TYPE_UNKNOWN:
+ case FW_PORT_MOD_TYPE_NOTSUPPORTED:
+ break;
+ case FW_PORT_MOD_TYPE_NONE:
+ return (IFM_NONE);
+ }
+ break;
+ case FW_PORT_TYPE_NONE:
+ return (IFM_NONE);
+ }
+
+ return (IFM_UNKNOWN);
+}
+
static void
cxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
{
struct vi_info *vi = ifp->if_softc;
struct port_info *pi = vi->pi;
- struct ifmedia_entry *cur;
+ struct adapter *sc = pi->adapter;
struct link_config *lc = &pi->link_cfg;
- /*
- * If all the interfaces are administratively down the firmware does not
- * report transceiver changes. Refresh port info here so that ifconfig
- * displays accurate information at all times.
- */
- if (begin_synchronized_op(pi->adapter, NULL, SLEEP_OK | INTR_OK,
- "t4med") == 0) {
- PORT_LOCK(pi);
- if (pi->up_vis == 0) {
- t4_update_port_info(pi);
- build_medialist(pi, &pi->media);
- }
- PORT_UNLOCK(pi);
- end_synchronized_op(pi->adapter, 0);
+ if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4med") != 0)
+ return;
+ PORT_LOCK(pi);
+
+ if (pi->up_vis == 0) {
+ /*
+ * If all the interfaces are administratively down the firmware
+ * does not report transceiver changes. Refresh port info here
+ * so that ifconfig displays accurate ifmedia at all times.
+ * This is the only reason we have a synchronized op in this
+ * function. Just PORT_LOCK would have been enough otherwise.
+ */
+ t4_update_port_info(pi);
+ build_medialist(pi, &pi->media);
}
+ /* ifm_status */
ifmr->ifm_status = IFM_AVALID;
if (lc->link_ok == 0)
- return;
-
+ goto done;
ifmr->ifm_status |= IFM_ACTIVE;
- ifmr->ifm_active &= ~(IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
- if (lc->fc & PAUSE_RX)
- ifmr->ifm_active |= IFM_ETH_RXPAUSE;
- if (lc->fc & PAUSE_TX)
- ifmr->ifm_active |= IFM_ETH_TXPAUSE;
- /* active and current will differ iff current media is autoselect. */
- cur = pi->media.ifm_cur;
- if (cur != NULL && IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
- return;
-
+ /* ifm_active */
ifmr->ifm_active = IFM_ETHER | IFM_FDX;
+ ifmr->ifm_active &= ~(IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
if (lc->fc & PAUSE_RX)
ifmr->ifm_active |= IFM_ETH_RXPAUSE;
if (lc->fc & PAUSE_TX)
ifmr->ifm_active |= IFM_ETH_TXPAUSE;
- switch (lc->speed) {
- case 10000:
- ifmr->ifm_active |= IFM_10G_T;
- break;
- case 1000:
- ifmr->ifm_active |= IFM_1000_T;
- break;
- case 100:
- ifmr->ifm_active |= IFM_100_TX;
- break;
- case 10:
- ifmr->ifm_active |= IFM_10_T;
- break;
- default:
- device_printf(vi->dev, "link up but speed unknown (%u)\n",
- lc->speed);
- }
+ ifmr->ifm_active |= port_mword(pi, speed_to_fwspeed(lc->speed));
+done:
+ PORT_UNLOCK(pi);
+ end_synchronized_op(sc, 0);
}
static int
@@ -3247,7 +3418,8 @@ partition_resources(struct adapter *sc, const struct f
snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF);
if (is_fpga(sc))
snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF);
- }
+ } else if (strncmp(t4_cfg_file, BUILTIN_CF, sizeof(t4_cfg_file)) == 0)
+ goto use_built_in_config; /* go straight to config. */
/*
* We need to load another module if the profile is anything except
@@ -3358,8 +3530,31 @@ use_config_on_flash:
if (rc != 0) {
device_printf(sc->dev,
"failed to pre-process config file: %d "
- "(mtype %d, moff 0x%x).\n", rc, mtype, moff);
- goto done;
+ "(mtype %d, moff 0x%x). Will reset the firmware and retry "
+ "with the built-in configuration.\n", rc, mtype, moff);
+
+ rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST);
+ if (rc != 0) {
+ device_printf(sc->dev,
+ "firmware reset failed: %d.\n", rc);
+ if (rc != ETIMEDOUT && rc != EIO) {
+ t4_fw_bye(sc, sc->mbox);
+ sc->flags &= ~FW_OK;
+ }
+ goto done;
+ }
+ snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", "built-in");
+use_built_in_config:
+ bzero(&caps, sizeof(caps));
+ caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+ F_FW_CMD_REQUEST | F_FW_CMD_READ);
+ caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps));
+ rc = t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps);
+ if (rc != 0) {
+ device_printf(sc->dev,
+ "built-in configuration failed: %d.\n", rc);
+ goto done;
+ }
}
finicsum = be32toh(caps.finicsum);
@@ -3759,214 +3954,114 @@ t4_set_desc(struct adapter *sc)
device_set_desc_copy(sc->dev, buf);
}
+static inline void
+ifmedia_add4(struct ifmedia *ifm, int m)
+{
+
+ ifmedia_add(ifm, m, 0, NULL);
+ ifmedia_add(ifm, m | IFM_ETH_TXPAUSE, 0, NULL);
+ ifmedia_add(ifm, m | IFM_ETH_RXPAUSE, 0, NULL);
+ ifmedia_add(ifm, m | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE, 0, NULL);
+}
+
static void
-build_medialist(struct port_info *pi, struct ifmedia *media)
+set_current_media(struct port_info *pi, struct ifmedia *ifm)
{
- int m;
+ struct link_config *lc;
+ int mword;
PORT_LOCK_ASSERT_OWNED(pi);
- ifmedia_removeall(media);
+ /* Leave current media alone if it's already set to IFM_NONE. */
+ if (ifm->ifm_cur != NULL &&
+ IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_NONE)
+ return;
- /*
- * XXX: Would it be better to ifmedia_add all 4 combinations of pause
- * settings for every speed instead of just txpause|rxpause? ifconfig
- * media display looks much better if autoselect is the only case where
- * ifm_current is different from ifm_active. If the user picks anything
- * except txpause|rxpause the display is ugly.
- */
- m = IFM_ETHER | IFM_FDX | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE;
+ lc = &pi->link_cfg;
+ if (lc->requested_aneg == AUTONEG_ENABLE &&
+ lc->supported & FW_PORT_CAP_ANEG) {
+ ifmedia_set(ifm, IFM_ETHER | IFM_AUTO);
+ return;
+ }
+ mword = IFM_ETHER | IFM_FDX;
+ if (lc->requested_fc & PAUSE_TX)
+ mword |= IFM_ETH_TXPAUSE;
+ if (lc->requested_fc & PAUSE_RX)
+ mword |= IFM_ETH_RXPAUSE;
+ mword |= port_mword(pi, speed_to_fwspeed(lc->requested_speed));
+ ifmedia_set(ifm, mword);
+}
- switch(pi->port_type) {
- case FW_PORT_TYPE_BT_XFI:
- case FW_PORT_TYPE_BT_XAUI:
- ifmedia_add(media, m | IFM_10G_T, 0, NULL);
- /* fall through */
+static void
+build_medialist(struct port_info *pi, struct ifmedia *ifm)
+{
+ uint16_t ss, speed;
+ int unknown, mword, bit;
+ struct link_config *lc;
- case FW_PORT_TYPE_BT_SGMII:
- ifmedia_add(media, m | IFM_1000_T, 0, NULL);
- ifmedia_add(media, m | IFM_100_TX, 0, NULL);
- ifmedia_add(media, IFM_ETHER | IFM_AUTO, 0, NULL);
- ifmedia_set(media, IFM_ETHER | IFM_AUTO);
- break;
+ PORT_LOCK_ASSERT_OWNED(pi);
- case FW_PORT_TYPE_CX4:
- ifmedia_add(media, m | IFM_10G_CX4, 0, NULL);
- ifmedia_set(media, m | IFM_10G_CX4);
- break;
+ if (pi->flags & FIXED_IFMEDIA)
+ return;
- case FW_PORT_TYPE_QSFP_10G:
- case FW_PORT_TYPE_SFP:
- case FW_PORT_TYPE_FIBER_XFI:
- case FW_PORT_TYPE_FIBER_XAUI:
- switch (pi->mod_type) {
+ /*
+ * First setup all the requested_ fields so that they comply with what's
+ * supported by the port + transceiver. Note that this clobbers any
+ * user preferences set via sysctl_pause_settings or sysctl_autoneg.
+ */
+ init_l1cfg(pi);
- case FW_PORT_MOD_TYPE_LR:
- ifmedia_add(media, m | IFM_10G_LR, 0, NULL);
- ifmedia_set(media, m | IFM_10G_LR);
- break;
+ /*
+ * Now (re)build the ifmedia list.
+ */
+ ifmedia_removeall(ifm);
+ lc = &pi->link_cfg;
+ ss = G_FW_PORT_CAP_SPEED(lc->supported); /* Supported Speeds */
+ if (__predict_false(ss == 0)) { /* not supposed to happen. */
+ MPASS(ss != 0);
+no_media:
+ MPASS(LIST_EMPTY(&ifm->ifm_list));
+ ifmedia_add(ifm, IFM_ETHER | IFM_NONE, 0, NULL);
+ ifmedia_set(ifm, IFM_ETHER | IFM_NONE);
+ return;
+ }
- case FW_PORT_MOD_TYPE_SR:
- ifmedia_add(media, m | IFM_10G_SR, 0, NULL);
- ifmedia_set(media, m | IFM_10G_SR);
- break;
-
- case FW_PORT_MOD_TYPE_LRM:
- ifmedia_add(media, m | IFM_10G_LRM, 0, NULL);
- ifmedia_set(media, m | IFM_10G_LRM);
- break;
-
- case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
- case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
- ifmedia_add(media, m | IFM_10G_TWINAX, 0, NULL);
- ifmedia_set(media, m | IFM_10G_TWINAX);
- break;
-
- case FW_PORT_MOD_TYPE_NONE:
- m &= ~IFM_FDX;
- ifmedia_add(media, m | IFM_NONE, 0, NULL);
- ifmedia_set(media, m | IFM_NONE);
- break;
-
- case FW_PORT_MOD_TYPE_NA:
- case FW_PORT_MOD_TYPE_ER:
- default:
- device_printf(pi->dev,
- "unknown port_type (%d), mod_type (%d)\n",
- pi->port_type, pi->mod_type);
- ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
- ifmedia_set(media, m | IFM_UNKNOWN);
- break;
+ unknown = 0;
+ for (bit = 0; bit < fls(ss); bit++) {
+ speed = 1 << bit;
+ MPASS(speed & M_FW_PORT_CAP_SPEED);
+ if (ss & speed) {
+ mword = port_mword(pi, speed);
+ if (mword == IFM_NONE) {
+ goto no_media;
+ } else if (mword == IFM_UNKNOWN)
+ unknown++;
+ else
+ ifmedia_add4(ifm, IFM_ETHER | IFM_FDX | mword);
}
- break;
-
- case FW_PORT_TYPE_CR_QSFP:
- case FW_PORT_TYPE_SFP28:
- case FW_PORT_TYPE_KR_SFP28:
- switch (pi->mod_type) {
-
- case FW_PORT_MOD_TYPE_SR:
- ifmedia_add(media, m | IFM_25G_SR, 0, NULL);
- ifmedia_set(media, m | IFM_25G_SR);
- break;
-
- case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
- case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
- ifmedia_add(media, m | IFM_25G_CR, 0, NULL);
- ifmedia_set(media, m | IFM_25G_CR);
- break;
-
- case FW_PORT_MOD_TYPE_NONE:
- m &= ~IFM_FDX;
- ifmedia_add(media, m | IFM_NONE, 0, NULL);
- ifmedia_set(media, m | IFM_NONE);
- break;
-
- default:
- device_printf(pi->dev,
- "unknown port_type (%d), mod_type (%d)\n",
- pi->port_type, pi->mod_type);
- ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
- ifmedia_set(media, m | IFM_UNKNOWN);
- break;
- }
- break;
-
- case FW_PORT_TYPE_QSFP:
- switch (pi->mod_type) {
-
- case FW_PORT_MOD_TYPE_LR:
- ifmedia_add(media, m | IFM_40G_LR4, 0, NULL);
- ifmedia_set(media, m | IFM_40G_LR4);
- break;
-
- case FW_PORT_MOD_TYPE_SR:
- ifmedia_add(media, m | IFM_40G_SR4, 0, NULL);
- ifmedia_set(media, m | IFM_40G_SR4);
- break;
-
- case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
- case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
- ifmedia_add(media, m | IFM_40G_CR4, 0, NULL);
- ifmedia_set(media, m | IFM_40G_CR4);
- break;
-
- case FW_PORT_MOD_TYPE_NONE:
- m &= ~IFM_FDX;
- ifmedia_add(media, m | IFM_NONE, 0, NULL);
- ifmedia_set(media, m | IFM_NONE);
- break;
-
- default:
- device_printf(pi->dev,
- "unknown port_type (%d), mod_type (%d)\n",
- pi->port_type, pi->mod_type);
- ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
- ifmedia_set(media, m | IFM_UNKNOWN);
- break;
- }
- break;
-
- case FW_PORT_TYPE_KR4_100G:
- case FW_PORT_TYPE_CR4_QSFP:
- switch (pi->mod_type) {
-
- case FW_PORT_MOD_TYPE_LR:
- ifmedia_add(media, m | IFM_100G_LR4, 0, NULL);
- ifmedia_set(media, m | IFM_100G_LR4);
- break;
-
- case FW_PORT_MOD_TYPE_SR:
- ifmedia_add(media, m | IFM_100G_SR4, 0, NULL);
- ifmedia_set(media, m | IFM_100G_SR4);
- break;
-
- case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
- case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
- ifmedia_add(media, m | IFM_100G_CR4, 0, NULL);
- ifmedia_set(media, m | IFM_100G_CR4);
- break;
-
- case FW_PORT_MOD_TYPE_NONE:
- m &= ~IFM_FDX;
- ifmedia_add(media, m | IFM_NONE, 0, NULL);
- ifmedia_set(media, m | IFM_NONE);
- break;
-
- default:
- device_printf(pi->dev,
- "unknown port_type (%d), mod_type (%d)\n",
- pi->port_type, pi->mod_type);
- ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
- ifmedia_set(media, m | IFM_UNKNOWN);
- break;
- }
- break;
-
- default:
- device_printf(pi->dev,
- "unknown port_type (%d), mod_type (%d)\n", pi->port_type,
- pi->mod_type);
- ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
- ifmedia_set(media, m | IFM_UNKNOWN);
- break;
}
+ if (unknown > 0) /* Add one unknown for all unknown media types. */
+ ifmedia_add4(ifm, IFM_ETHER | IFM_FDX | IFM_UNKNOWN);
+ if (lc->supported & FW_PORT_CAP_ANEG)
+ ifmedia_add(ifm, IFM_ETHER | IFM_AUTO, 0, NULL);
+
+ set_current_media(pi, ifm);
}
/*
- * Update all the requested_* fields in the link config and then send a mailbox
- * command to apply the settings.
+ * Update all the requested_* fields in the link config to something valid (and
+ * reasonable).
*/
static void
init_l1cfg(struct port_info *pi)
{
- struct adapter *sc = pi->adapter;
struct link_config *lc = &pi->link_cfg;
- int rc;
- ASSERT_SYNCHRONIZED_OP(sc);
+ PORT_LOCK_ASSERT_OWNED(pi);
- lc->requested_speed = port_top_speed(pi); /* in Gbps */
+ /* Gbps -> Mbps */
+ lc->requested_speed = port_top_speed(pi) * 1000;
+
if (t4_autoneg != 0 && lc->supported & FW_PORT_CAP_ANEG) {
lc->requested_aneg = AUTONEG_ENABLE;
} else {
@@ -3976,18 +4071,58 @@ init_l1cfg(struct port_info *pi)
lc->requested_fc = t4_pause_settings & (PAUSE_TX | PAUSE_RX);
if (t4_fec != -1) {
- lc->requested_fec = t4_fec & (FEC_RS | FEC_BASER_RS |
- FEC_RESERVED);
+ if (t4_fec & FEC_RS && lc->supported & FW_PORT_CAP_FEC_RS) {
+ lc->requested_fec = FEC_RS;
+ } else if (t4_fec & FEC_BASER_RS &&
+ lc->supported & FW_PORT_CAP_FEC_BASER_RS) {
+ lc->requested_fec = FEC_BASER_RS;
+ } else {
+ lc->requested_fec = 0;
+ }
} else {
/* Use the suggested value provided by the firmware in acaps */
- if (lc->advertising & FW_PORT_CAP_FEC_RS)
+ if (lc->advertising & FW_PORT_CAP_FEC_RS &&
+ lc->supported & FW_PORT_CAP_FEC_RS) {
lc->requested_fec = FEC_RS;
- else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
+ } else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS &&
+ lc->supported & FW_PORT_CAP_FEC_BASER_RS) {
lc->requested_fec = FEC_BASER_RS;
- else
+ } else {
lc->requested_fec = 0;
+ }
}
+}
+/*
+ * Apply the settings in requested_* to the hardware. The parameters are
+ * expected to be sane.
+ */
+static int
+apply_l1cfg(struct port_info *pi)
+{
+ struct adapter *sc = pi->adapter;
+ struct link_config *lc = &pi->link_cfg;
+ int rc;
+#ifdef INVARIANTS
+ uint16_t fwspeed;
+
+ ASSERT_SYNCHRONIZED_OP(sc);
+ PORT_LOCK_ASSERT_OWNED(pi);
+
+ if (lc->requested_aneg == AUTONEG_ENABLE)
+ MPASS(lc->supported & FW_PORT_CAP_ANEG);
+ if (lc->requested_fc & PAUSE_TX)
+ MPASS(lc->supported & FW_PORT_CAP_FC_TX);
+ if (lc->requested_fc & PAUSE_RX)
+ MPASS(lc->supported & FW_PORT_CAP_FC_RX);
+ if (lc->requested_fec == FEC_RS)
+ MPASS(lc->supported & FW_PORT_CAP_FEC_RS);
+ if (lc->requested_fec == FEC_BASER_RS)
+ MPASS(lc->supported & FW_PORT_CAP_FEC_BASER_RS);
+ fwspeed = speed_to_fwspeed(lc->requested_speed);
+ MPASS(fwspeed != 0);
+ MPASS(lc->supported & fwspeed);
+#endif
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
if (rc != 0) {
device_printf(pi->dev, "l1cfg failed: %d\n", rc);
@@ -3995,6 +4130,7 @@ init_l1cfg(struct port_info *pi)
lc->fc = lc->requested_fc;
lc->fec = lc->requested_fec;
}
+ return (rc);
}
#define FW_MAC_EXACT_CHUNK 7
@@ -4279,7 +4415,7 @@ cxgbe_init_synchronized(struct vi_info *vi)
if (pi->up_vis++ == 0) {
t4_update_port_info(pi);
build_medialist(pi, &pi->media);
- init_l1cfg(pi);
+ apply_l1cfg(pi);
}
ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -4354,13 +4490,13 @@ cxgbe_uninit_synchronized(struct vi_info *vi)
PORT_UNLOCK(pi);
return (0);
}
- PORT_UNLOCK(pi);
pi->link_cfg.link_ok = 0;
pi->link_cfg.speed = 0;
pi->link_cfg.link_down_rc = 255;
t4_os_link_changed(pi);
pi->old_link_cfg = pi->link_cfg;
+ PORT_UNLOCK(pi);
return (0);
}
@@ -6083,14 +6219,17 @@ sysctl_pause_settings(SYSCTL_HANDLER_ARGS)
"t4PAUSE");
if (rc)
return (rc);
+ PORT_LOCK(pi);
if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) {
lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
lc->requested_fc |= n;
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
if (rc == 0) {
lc->fc = lc->requested_fc;
+ set_current_media(pi, &pi->media);
}
}
+ PORT_UNLOCK(pi);
end_synchronized_op(sc, 0);
}
@@ -6138,11 +6277,14 @@ sysctl_fec(SYSCTL_HANDLER_ARGS)
n = s[0] - '0';
if (n & ~M_FW_PORT_CAP_FEC)
return (EINVAL); /* some other bit is set too */
+ if (!powerof2(n))
+ return (EINVAL); /* one bit can be set at most */
rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
"t4fec");
if (rc)
return (rc);
+ PORT_LOCK(pi);
if ((lc->requested_fec & M_FW_PORT_CAP_FEC) != n) {
lc->requested_fec = n &
G_FW_PORT_CAP_FEC(lc->supported);
@@ -6151,6 +6293,7 @@ sysctl_fec(SYSCTL_HANDLER_ARGS)
lc->fec = lc->requested_fec;
}
}
+ PORT_UNLOCK(pi);
end_synchronized_op(sc, 0);
}
@@ -6172,27 +6315,35 @@ sysctl_autoneg(SYSCTL_HANDLER_ARGS)
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);
-
if (val == 0)
val = AUTONEG_DISABLE;
else if (val == 1)
val = AUTONEG_ENABLE;
else
return (EINVAL);
- if (lc->requested_aneg == val)
- return (0); /* no change */
rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
"t4aneg");
if (rc)
return (rc);
+ PORT_LOCK(pi);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-releng
mailing list