Date: Sun, 3 Jun 2018 15:12:40 +0000 (UTC) From: Navdeep Parhar <np@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r334562 - in stable/11/sys/dev/cxgbe: . common Message-ID: <201806031512.w53FCetu046392@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: np Date: Sun Jun 3 15:12:40 2018 New Revision: 334562 URL: https://svnweb.freebsd.org/changeset/base/334562 Log: MFC 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. Sponsored by: Chelsio Communications Modified: stable/11/sys/dev/cxgbe/adapter.h stable/11/sys/dev/cxgbe/common/common.h stable/11/sys/dev/cxgbe/common/t4_hw.c stable/11/sys/dev/cxgbe/t4_main.c Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/dev/cxgbe/adapter.h ============================================================================== --- stable/11/sys/dev/cxgbe/adapter.h Sun Jun 3 14:32:38 2018 (r334561) +++ stable/11/sys/dev/cxgbe/adapter.h Sun Jun 3 15:12:40 2018 (r334562) @@ -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: stable/11/sys/dev/cxgbe/common/common.h ============================================================================== --- stable/11/sys/dev/cxgbe/common/common.h Sun Jun 3 14:32:38 2018 (r334561) +++ stable/11/sys/dev/cxgbe/common/common.h Sun Jun 3 15:12:40 2018 (r334562) @@ -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: stable/11/sys/dev/cxgbe/common/t4_hw.c ============================================================================== --- stable/11/sys/dev/cxgbe/common/t4_hw.c Sun Jun 3 14:32:38 2018 (r334561) +++ stable/11/sys/dev/cxgbe/common/t4_hw.c Sun Jun 3 15:12:40 2018 (r334562) @@ -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: stable/11/sys/dev/cxgbe/t4_main.c ============================================================================== --- stable/11/sys/dev/cxgbe/t4_main.c Sun Jun 3 14:32:38 2018 (r334561) +++ stable/11/sys/dev/cxgbe/t4_main.c Sun Jun 3 15:12:40 2018 (r334562) @@ -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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806031512.w53FCetu046392>