Date: Sat, 14 Mar 2020 00:57:21 +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-12@freebsd.org Subject: svn commit: r358973 - in stable/12: share/man/man4 sys/dev/cxgbe sys/dev/cxgbe/common Message-ID: <202003140057.02E0vLKT016385@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: np Date: Sat Mar 14 00:57:20 2020 New Revision: 358973 URL: https://svnweb.freebsd.org/changeset/base/358973 Log: MFC r355107 and r355597. r355107: cxgbe(4): Allow the driver to specify multiple FECs that the firmware should try in order to link up with the peer. Various FEC variables within the driver can now have multiple bits set instead of being powers of 2. 0 and -1 in the user knobs still mean no FEC and auto (driver decides) respectively for backward compatibility, but no-FEC and auto now have their own bits in the internal representation. There is a new bit that can be set to request the FEC recommended by the cable/transceiver module. Add sysctls to display link related capabilities of the local side as well as the link partner. Note that all this needs a new firmware and the documentation for the driver FEC knobs will be updated after that firmware is added to the driver. r355597: cxgbe(4): Man page updates to go with r355107. Sponsored by: Chelsio Communications Modified: stable/12/share/man/man4/cxgbe.4 stable/12/sys/dev/cxgbe/common/common.h stable/12/sys/dev/cxgbe/common/t4_hw.c stable/12/sys/dev/cxgbe/t4_main.c Directory Properties: stable/12/ (props changed) Modified: stable/12/share/man/man4/cxgbe.4 ============================================================================== --- stable/12/share/man/man4/cxgbe.4 Sat Mar 14 00:49:59 2020 (r358972) +++ stable/12/share/man/man4/cxgbe.4 Sat Mar 14 00:57:20 2020 (r358973) @@ -31,7 +31,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Oct 25, 2019 +.Dd Dec 10, 2019 .Dt CXGBE 4 .Os .Sh NAME @@ -291,10 +291,14 @@ This tunable establishes the default PAUSE settings fo Settings can be displayed and controlled on a per-port basis via the dev.<port>.X.pause_settings sysctl. .It Va hw.cxgbe.fec -FEC (Forward Error Correction) settings. +Forward Error Correction settings. +-1 (default) means driver should automatically pick a value. 0 disables FEC. -Bit 0 enables RS FEC, bit 1 enables BASE-R FEC (aka Firecode FEC). -The default is -1 which lets the driver pick a value. +Finer grained control can be achieved by setting individual bits. +Bit 0 enables RS FEC, bit 1 enables BASE-R FEC (aka Firecode FEC), bit +2 enables NO FEC, and bit 6 enables the FEC that is recommended by the +transceiver/cable that is plugged in. +These bits can be set together in any combination. This tunable establishes the default FEC settings for all ports. Settings can be displayed and controlled on a per-port basis via the dev.<port>.X.fec sysctl. Modified: stable/12/sys/dev/cxgbe/common/common.h ============================================================================== --- stable/12/sys/dev/cxgbe/common/common.h Sat Mar 14 00:49:59 2020 (r358972) +++ stable/12/sys/dev/cxgbe/common/common.h Sat Mar 14 00:57:20 2020 (r358973) @@ -62,10 +62,21 @@ enum { }; enum { - FEC_NONE = 0, - FEC_RS = 1 << 0, - FEC_BASER_RS = 1 << 1, - FEC_AUTO = 1 << 5, /* M_FW_PORT_CAP32_FEC + 1 */ + /* + * Real FECs. In the same order as the FEC portion of caps32 so that + * the code can do (fec & M_FW_PORT_CAP32_FEC) to get all the real FECs. + */ + FEC_RS = 1 << 0, /* Reed-Solomon */ + FEC_BASER_RS = 1 << 1, /* BASE-R, aka Firecode */ + FEC_NONE = 1 << 2, /* no FEC */ + + /* + * Pseudo FECs that translate to real FECs. The firmware knows nothing + * about these and they start at M_FW_PORT_CAP32_FEC + 1. AUTO should + * be set all by itself. + */ + FEC_AUTO = 1 << 5, + FEC_MODULE = 1 << 6, /* FEC suggested by the cable/transceiver. */ }; enum t4_bar2_qtype { T4_BAR2_QTYPE_EGRESS, T4_BAR2_QTYPE_INGRESS }; @@ -409,20 +420,20 @@ struct trace_params { struct link_config { /* OS-specific code owns all the requested_* fields. */ - int8_t requested_aneg; /* link autonegotiation */ - int8_t requested_fc; /* flow control */ - int8_t requested_fec; /* FEC */ - u_int requested_speed; /* speed (Mbps) */ + int8_t requested_aneg; /* link autonegotiation */ + int8_t requested_fc; /* flow control */ + int8_t requested_fec; /* FEC */ + u_int requested_speed; /* speed (Mbps) */ - uint32_t supported; /* link capabilities */ - uint32_t advertising; /* advertised capabilities */ - uint32_t lp_advertising; /* peer advertised capabilities */ - uint32_t fec_hint; /* use this fec */ - u_int speed; /* actual link speed (Mbps) */ - int8_t fc; /* actual link flow control */ - int8_t fec; /* actual FEC */ - bool link_ok; /* link up? */ - uint8_t link_down_rc; /* link down reason */ + uint32_t pcaps; /* link capabilities */ + uint32_t acaps; /* advertised capabilities */ + uint32_t lpacaps; /* peer advertised capabilities */ + u_int speed; /* actual link speed (Mbps) */ + int8_t fc; /* actual link flow control */ + int8_t fec_hint; /* cable/transceiver recommended fec */ + int8_t fec; /* actual FEC */ + bool link_ok; /* link up? */ + uint8_t link_down_rc; /* link down reason */ }; #include "adapter.h" @@ -881,7 +892,7 @@ port_top_speed(const struct port_info *pi) { /* Mbps -> Gbps */ - return (fwcap_to_speed(pi->link_cfg.supported) / 1000); + return (fwcap_to_speed(pi->link_cfg.pcaps) / 1000); } #endif /* __CHELSIO_COMMON_H */ Modified: stable/12/sys/dev/cxgbe/common/t4_hw.c ============================================================================== --- stable/12/sys/dev/cxgbe/common/t4_hw.c Sat Mar 14 00:49:59 2020 (r358972) +++ stable/12/sys/dev/cxgbe/common/t4_hw.c Sat Mar 14 00:57:20 2020 (r358973) @@ -3841,6 +3841,43 @@ is_bt(struct port_info *pi) pi->port_type == FW_PORT_TYPE_BT_XAUI); } +static int8_t fwcap_to_fec(uint32_t caps, bool unset_means_none) +{ + int8_t fec = 0; + + if ((caps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC)) == 0) + return (unset_means_none ? FEC_NONE : 0); + + if (caps & FW_PORT_CAP32_FEC_RS) + fec |= FEC_RS; + if (caps & FW_PORT_CAP32_FEC_BASER_RS) + fec |= FEC_BASER_RS; + if (caps & FW_PORT_CAP32_FEC_NO_FEC) + fec |= FEC_NONE; + + return (fec); +} + +/* + * Note that 0 is not translated to NO_FEC. + */ +static uint32_t fec_to_fwcap(int8_t fec) +{ + uint32_t caps = 0; + + /* Only real FECs allowed. */ + MPASS((fec & ~M_FW_PORT_CAP32_FEC) == 0); + + if (fec & FEC_RS) + caps |= FW_PORT_CAP32_FEC_RS; + if (fec & FEC_BASER_RS) + caps |= FW_PORT_CAP32_FEC_BASER_RS; + if (fec & FEC_NONE) + caps |= FW_PORT_CAP32_FEC_NO_FEC; + + return (caps); +} + /** * t4_link_l1cfg - apply link configuration to MAC/PHY * @phy: the PHY to setup @@ -3869,41 +3906,61 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int m if (!(lc->requested_fc & PAUSE_AUTONEG)) fc |= FW_PORT_CAP32_FORCE_PAUSE; - fec = 0; - if (lc->requested_fec == FEC_AUTO) - fec = lc->fec_hint; - else { - if (lc->requested_fec & FEC_RS) - fec |= FW_PORT_CAP32_FEC_RS; - if (lc->requested_fec & FEC_BASER_RS) - fec |= FW_PORT_CAP32_FEC_BASER_RS; - } - if (lc->requested_aneg == AUTONEG_DISABLE) aneg = 0; else if (lc->requested_aneg == AUTONEG_ENABLE) aneg = FW_PORT_CAP32_ANEG; else - aneg = lc->supported & FW_PORT_CAP32_ANEG; + aneg = lc->pcaps & FW_PORT_CAP32_ANEG; if (aneg) { - speed = lc->supported & V_FW_PORT_CAP32_SPEED(M_FW_PORT_CAP32_SPEED); + speed = lc->pcaps & + V_FW_PORT_CAP32_SPEED(M_FW_PORT_CAP32_SPEED); } else if (lc->requested_speed != 0) speed = speed_to_fwcap(lc->requested_speed); else - speed = fwcap_top_speed(lc->supported); + speed = fwcap_top_speed(lc->pcaps); + fec = 0; + if (fec_supported(lc->pcaps)) { + if (lc->requested_fec == FEC_AUTO) { + if (lc->pcaps & FW_PORT_CAP32_FORCE_FEC) { + if (speed & FW_PORT_CAP32_SPEED_100G) { + fec |= FW_PORT_CAP32_FEC_RS; + fec |= FW_PORT_CAP32_FEC_NO_FEC; + } else { + fec |= FW_PORT_CAP32_FEC_RS; + fec |= FW_PORT_CAP32_FEC_BASER_RS; + fec |= FW_PORT_CAP32_FEC_NO_FEC; + } + } else { + /* Set only 1b with old firmwares. */ + fec |= fec_to_fwcap(lc->fec_hint); + } + } else { + fec |= fec_to_fwcap(lc->requested_fec & + M_FW_PORT_CAP32_FEC); + if (lc->requested_fec & FEC_MODULE) + fec |= fec_to_fwcap(lc->fec_hint); + } + + if (lc->pcaps & FW_PORT_CAP32_FORCE_FEC) + fec |= FW_PORT_CAP32_FORCE_FEC; + else if (fec == FW_PORT_CAP32_FEC_NO_FEC) + fec = 0; + } + /* Force AN on for BT cards. */ if (is_bt(adap->port[adap->chan_map[port]])) - aneg = lc->supported & FW_PORT_CAP32_ANEG; + aneg = lc->pcaps & FW_PORT_CAP32_ANEG; rcap = aneg | speed | fc | fec; - if ((rcap | lc->supported) != lc->supported) { + if ((rcap | lc->pcaps) != lc->pcaps) { #ifdef INVARIANTS - CH_WARN(adap, "rcap 0x%08x, pcap 0x%08x\n", rcap, - lc->supported); + CH_WARN(adap, "rcap 0x%08x, pcap 0x%08x, removed 0x%x\n", rcap, + lc->pcaps, rcap & (rcap ^ lc->pcaps)); #endif - rcap &= lc->supported; + rcap &= lc->pcaps; } rcap |= mdi; @@ -8470,7 +8527,6 @@ uint32_t fwcap_top_speed(uint32_t caps) return 0; } - /** * lstatus_to_fwcap - translate old lstatus to 32-bit Port Capabilities * @lstatus: old FW_PORT_ACTION_GET_PORT_INFO lstatus value @@ -8516,7 +8572,7 @@ static void handle_port_info(struct port_info *pi, con enum fw_port_action action, bool *mod_changed, bool *link_changed) { struct link_config old_lc, *lc = &pi->link_cfg; - unsigned char fc, fec; + unsigned char fc; u32 stat, linkattr; int old_ptype, old_mtype; @@ -8531,9 +8587,9 @@ static void handle_port_info(struct port_info *pi, con pi->mdio_addr = stat & F_FW_PORT_CMD_MDIOCAP ? G_FW_PORT_CMD_MDIOADDR(stat) : -1; - lc->supported = fwcaps16_to_caps32(be16_to_cpu(p->u.info.pcap)); - lc->advertising = fwcaps16_to_caps32(be16_to_cpu(p->u.info.acap)); - lc->lp_advertising = fwcaps16_to_caps32(be16_to_cpu(p->u.info.lpacap)); + lc->pcaps = fwcaps16_to_caps32(be16_to_cpu(p->u.info.pcap)); + lc->acaps = fwcaps16_to_caps32(be16_to_cpu(p->u.info.acap)); + lc->lpacaps = fwcaps16_to_caps32(be16_to_cpu(p->u.info.lpacap)); lc->link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0; lc->link_down_rc = G_FW_PORT_CMD_LINKDNRC(stat); @@ -8546,9 +8602,9 @@ static void handle_port_info(struct port_info *pi, con pi->mdio_addr = stat & F_FW_PORT_CMD_MDIOCAP32 ? G_FW_PORT_CMD_MDIOADDR32(stat) : -1; - lc->supported = be32_to_cpu(p->u.info32.pcaps32); - lc->advertising = be32_to_cpu(p->u.info32.acaps32); - lc->lp_advertising = be32_to_cpu(p->u.info32.lpacaps32); + lc->pcaps = be32_to_cpu(p->u.info32.pcaps32); + lc->acaps = be32_to_cpu(p->u.info32.acaps32); + lc->lpacaps = be32_to_cpu(p->u.info32.lpacaps32); lc->link_ok = (stat & F_FW_PORT_CMD_LSTATUS32) != 0; lc->link_down_rc = G_FW_PORT_CMD_LINKDNRC32(stat); @@ -8559,6 +8615,7 @@ static void handle_port_info(struct port_info *pi, con } lc->speed = fwcap_to_speed(linkattr); + lc->fec = fwcap_to_fec(linkattr, true); fc = 0; if (linkattr & FW_PORT_CAP32_FC_RX) @@ -8567,23 +8624,14 @@ static void handle_port_info(struct port_info *pi, con fc |= PAUSE_TX; lc->fc = fc; - fec = FEC_NONE; - if (linkattr & FW_PORT_CAP32_FEC_RS) - fec |= FEC_RS; - if (linkattr & FW_PORT_CAP32_FEC_BASER_RS) - fec |= FEC_BASER_RS; - lc->fec = fec; - if (mod_changed != NULL) *mod_changed = false; if (link_changed != NULL) *link_changed = false; if (old_ptype != pi->port_type || old_mtype != pi->mod_type || - old_lc.supported != lc->supported) { - if (pi->mod_type != FW_PORT_MOD_TYPE_NONE) { - lc->fec_hint = lc->advertising & - V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC); - } + old_lc.pcaps != lc->pcaps) { + if (pi->mod_type != FW_PORT_MOD_TYPE_NONE) + lc->fec_hint = fwcap_to_fec(lc->acaps, true); if (mod_changed != NULL) *mod_changed = true; } Modified: stable/12/sys/dev/cxgbe/t4_main.c ============================================================================== --- stable/12/sys/dev/cxgbe/t4_main.c Sat Mar 14 00:49:59 2020 (r358972) +++ stable/12/sys/dev/cxgbe/t4_main.c Sat Mar 14 00:57:20 2020 (r358973) @@ -642,6 +642,7 @@ 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_module_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); @@ -2243,7 +2244,7 @@ cxgbe_media_change(struct ifnet *ifp) PORT_LOCK(pi); if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { /* ifconfig .. media autoselect */ - if (!(lc->supported & FW_PORT_CAP32_ANEG)) { + if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) { rc = ENOTSUP; /* AN not supported by transceiver */ goto done; } @@ -4547,7 +4548,7 @@ set_current_media(struct port_info *pi) lc = &pi->link_cfg; if (lc->requested_aneg != AUTONEG_DISABLE && - lc->supported & FW_PORT_CAP32_ANEG) { + lc->pcaps & FW_PORT_CAP32_ANEG) { ifmedia_set(ifm, IFM_ETHER | IFM_AUTO); return; } @@ -4604,7 +4605,7 @@ build_medialist(struct port_info *pi) ifm = &pi->media; ifmedia_removeall(ifm); lc = &pi->link_cfg; - ss = G_FW_PORT_CAP32_SPEED(lc->supported); /* Supported Speeds */ + ss = G_FW_PORT_CAP32_SPEED(lc->pcaps); /* Supported Speeds */ if (__predict_false(ss == 0)) { /* not supposed to happen. */ MPASS(ss != 0); no_media: @@ -4630,7 +4631,7 @@ no_media: } 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_CAP32_ANEG) + if (lc->pcaps & FW_PORT_CAP32_ANEG) ifmedia_add(ifm, IFM_ETHER | IFM_AUTO, 0, NULL); set_current_media(pi); @@ -4658,14 +4659,16 @@ init_link_config(struct port_info *pi) lc->requested_fc = t4_pause_settings & (PAUSE_TX | PAUSE_RX | PAUSE_AUTONEG); - if (t4_fec == -1 || t4_fec & FEC_AUTO) + if (t4_fec & FEC_AUTO) lc->requested_fec = FEC_AUTO; - else { + else if (t4_fec == 0) lc->requested_fec = FEC_NONE; - if (t4_fec & FEC_RS) - lc->requested_fec |= FEC_RS; - if (t4_fec & FEC_BASER_RS) - lc->requested_fec |= FEC_BASER_RS; + else { + /* -1 is handled by the FEC_AUTO block above and not here. */ + lc->requested_fec = t4_fec & + (FEC_RS | FEC_BASER_RS | FEC_NONE | FEC_MODULE); + if (lc->requested_fec == 0) + lc->requested_fec = FEC_AUTO; } } @@ -4685,7 +4688,7 @@ fixup_link_config(struct port_info *pi) /* Speed (when not autonegotiating) */ if (lc->requested_speed != 0) { fwspeed = speed_to_fwcap(lc->requested_speed); - if ((fwspeed & lc->supported) == 0) { + if ((fwspeed & lc->pcaps) == 0) { n++; lc->requested_speed = 0; } @@ -4696,7 +4699,7 @@ fixup_link_config(struct port_info *pi) lc->requested_aneg == AUTONEG_DISABLE || lc->requested_aneg == AUTONEG_AUTO); if (lc->requested_aneg == AUTONEG_ENABLE && - !(lc->supported & FW_PORT_CAP32_ANEG)) { + !(lc->pcaps & FW_PORT_CAP32_ANEG)) { n++; lc->requested_aneg = AUTONEG_AUTO; } @@ -4704,26 +4707,26 @@ fixup_link_config(struct port_info *pi) /* Flow control */ MPASS((lc->requested_fc & ~(PAUSE_TX | PAUSE_RX | PAUSE_AUTONEG)) == 0); if (lc->requested_fc & PAUSE_TX && - !(lc->supported & FW_PORT_CAP32_FC_TX)) { + !(lc->pcaps & FW_PORT_CAP32_FC_TX)) { n++; lc->requested_fc &= ~PAUSE_TX; } if (lc->requested_fc & PAUSE_RX && - !(lc->supported & FW_PORT_CAP32_FC_RX)) { + !(lc->pcaps & FW_PORT_CAP32_FC_RX)) { n++; lc->requested_fc &= ~PAUSE_RX; } if (!(lc->requested_fc & PAUSE_AUTONEG) && - !(lc->supported & FW_PORT_CAP32_FORCE_PAUSE)) { + !(lc->pcaps & FW_PORT_CAP32_FORCE_PAUSE)) { n++; lc->requested_fc |= PAUSE_AUTONEG; } /* FEC */ if ((lc->requested_fec & FEC_RS && - !(lc->supported & FW_PORT_CAP32_FEC_RS)) || + !(lc->pcaps & FW_PORT_CAP32_FEC_RS)) || (lc->requested_fec & FEC_BASER_RS && - !(lc->supported & FW_PORT_CAP32_FEC_BASER_RS))) { + !(lc->pcaps & FW_PORT_CAP32_FEC_BASER_RS))) { n++; lc->requested_fec = FEC_AUTO; } @@ -4747,17 +4750,17 @@ apply_link_config(struct port_info *pi) PORT_LOCK_ASSERT_OWNED(pi); if (lc->requested_aneg == AUTONEG_ENABLE) - MPASS(lc->supported & FW_PORT_CAP32_ANEG); + MPASS(lc->pcaps & FW_PORT_CAP32_ANEG); if (!(lc->requested_fc & PAUSE_AUTONEG)) - MPASS(lc->supported & FW_PORT_CAP32_FORCE_PAUSE); + MPASS(lc->pcaps & FW_PORT_CAP32_FORCE_PAUSE); if (lc->requested_fc & PAUSE_TX) - MPASS(lc->supported & FW_PORT_CAP32_FC_TX); + MPASS(lc->pcaps & FW_PORT_CAP32_FC_TX); if (lc->requested_fc & PAUSE_RX) - MPASS(lc->supported & FW_PORT_CAP32_FC_RX); + MPASS(lc->pcaps & FW_PORT_CAP32_FC_RX); if (lc->requested_fec & FEC_RS) - MPASS(lc->supported & FW_PORT_CAP32_FEC_RS); + MPASS(lc->pcaps & FW_PORT_CAP32_FEC_RS); if (lc->requested_fec & FEC_BASER_RS) - MPASS(lc->supported & FW_PORT_CAP32_FEC_BASER_RS); + MPASS(lc->pcaps & FW_PORT_CAP32_FEC_BASER_RS); #endif rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc); if (rc != 0) { @@ -6469,11 +6472,21 @@ cxgbe_sysctls(struct port_info *pi) "PAUSE settings (bit 0 = rx_pause, 1 = tx_pause, 2 = pause_autoneg)"); 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)"); + "FECs to use (bit 0 = RS, 1 = FC, 2 = none, 5 = auto, 6 = module)"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "module_fec", + CTLTYPE_STRING, pi, 0, sysctl_module_fec, "A", + "FEC recommended by the cable/transceiver"); 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, "pcaps", CTLFLAG_RD, + &pi->link_cfg.pcaps, 0, "port capabilities"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, "acaps", CTLFLAG_RD, + &pi->link_cfg.acaps, 0, "advertised capabilities"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, "lpacaps", CTLFLAG_RD, + &pi->link_cfg.lpacaps, 0, "link partner advertised capabilities"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, "max_speed", CTLFLAG_RD, NULL, port_top_speed(pi), "max speed (in Gbps)"); SYSCTL_ADD_INT(ctx, children, OID_AUTO, "mps_bg_map", CTLFLAG_RD, NULL, @@ -6994,7 +7007,8 @@ sysctl_fec(SYSCTL_HANDLER_ARGS) if (req->newptr == NULL) { struct sbuf *sb; - static char *bits = "\20\1RS\2BASE-R\3RSVD1\4RSVD2\5RSVD3\6AUTO"; + static char *bits = "\20\1RS-FEC\2FC-FEC\3NO-FEC\4RSVD2" + "\5RSVD3\6auto\7module"; rc = sysctl_wire_old_buffer(req, 0); if (rc != 0) @@ -7010,19 +7024,20 @@ sysctl_fec(SYSCTL_HANDLER_ARGS) */ if (lc->link_ok) { sbuf_printf(sb, "%b", (lc->fec & M_FW_PORT_CAP32_FEC) | - (lc->requested_fec & FEC_AUTO), bits); + (lc->requested_fec & (FEC_AUTO | FEC_MODULE)), + bits); } else { sbuf_printf(sb, "%b", lc->requested_fec, bits); } rc = sbuf_finish(sb); sbuf_delete(sb); } else { - char s[3]; + char s[8]; int n; snprintf(s, sizeof(s), "%d", lc->requested_fec == FEC_AUTO ? -1 : - lc->requested_fec & M_FW_PORT_CAP32_FEC); + lc->requested_fec & (M_FW_PORT_CAP32_FEC | FEC_MODULE)); rc = sysctl_handle_string(oidp, s, sizeof(s), req); if (rc != 0) @@ -7031,12 +7046,8 @@ sysctl_fec(SYSCTL_HANDLER_ARGS) n = strtol(&s[0], NULL, 0); if (n < 0 || n & FEC_AUTO) n = FEC_AUTO; - else { - if (n & ~M_FW_PORT_CAP32_FEC) - return (EINVAL);/* some other bit is set too */ - if (!powerof2(n)) - return (EINVAL);/* one bit can be set at most */ - } + else if (n & ~(M_FW_PORT_CAP32_FEC | FEC_MODULE)) + return (EINVAL);/* some other bit is set too */ rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK, "t4fec"); @@ -7046,15 +7057,17 @@ sysctl_fec(SYSCTL_HANDLER_ARGS) old = lc->requested_fec; if (n == FEC_AUTO) lc->requested_fec = FEC_AUTO; - else if (n == 0) + else if (n == 0 || n == FEC_NONE) lc->requested_fec = FEC_NONE; else { - if ((lc->supported | V_FW_PORT_CAP32_FEC(n)) != - lc->supported) { + if ((lc->pcaps | + V_FW_PORT_CAP32_FEC(n & M_FW_PORT_CAP32_FEC)) != + lc->pcaps) { rc = ENOTSUP; goto done; } - lc->requested_fec = n; + lc->requested_fec = n & (M_FW_PORT_CAP32_FEC | + FEC_MODULE); } fixup_link_config(pi); if (pi->up_vis > 0) { @@ -7074,6 +7087,56 @@ done: } static int +sysctl_module_fec(SYSCTL_HANDLER_ARGS) +{ + struct port_info *pi = arg1; + struct adapter *sc = pi->adapter; + struct link_config *lc = &pi->link_cfg; + int rc; + int8_t fec; + struct sbuf *sb; + static char *bits = "\20\1RS-FEC\2FC-FEC\3NO-FEC\4RSVD2\5RSVD3"; + + 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); + + if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4mfec") != 0) + return (EBUSY); + 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. + * 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); + } + + fec = lc->fec_hint; + if (pi->mod_type == FW_PORT_MOD_TYPE_NONE || + !fec_supported(lc->pcaps)) { + sbuf_printf(sb, "n/a"); + } else { + if (fec == 0) + fec = FEC_NONE; + sbuf_printf(sb, "%b", fec & M_FW_PORT_CAP32_FEC, bits); + } + rc = sbuf_finish(sb); + sbuf_delete(sb); + + PORT_UNLOCK(pi); + end_synchronized_op(sc, 0); + + return (rc); +} + +static int sysctl_autoneg(SYSCTL_HANDLER_ARGS) { struct port_info *pi = arg1; @@ -7081,7 +7144,7 @@ sysctl_autoneg(SYSCTL_HANDLER_ARGS) struct link_config *lc = &pi->link_cfg; int rc, val; - if (lc->supported & FW_PORT_CAP32_ANEG) + if (lc->pcaps & FW_PORT_CAP32_ANEG) val = lc->requested_aneg == AUTONEG_DISABLE ? 0 : 1; else val = -1; @@ -7100,7 +7163,7 @@ sysctl_autoneg(SYSCTL_HANDLER_ARGS) if (rc) return (rc); PORT_LOCK(pi); - if (val == AUTONEG_ENABLE && !(lc->supported & FW_PORT_CAP32_ANEG)) { + if (val == AUTONEG_ENABLE && !(lc->pcaps & FW_PORT_CAP32_ANEG)) { rc = ENOTSUP; goto done; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202003140057.02E0vLKT016385>