Date: Tue, 25 Sep 2018 05:52:43 +0000 (UTC) From: Navdeep Parhar <np@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r338924 - in head: share/man/man4 sys/dev/cxgbe sys/dev/cxgbe/common sys/dev/cxgbe/tom Message-ID: <201809250552.w8P5qh4a004298@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: np Date: Tue Sep 25 05:52:42 2018 New Revision: 338924 URL: https://svnweb.freebsd.org/changeset/base/338924 Log: cxgbe(4): Link related changes. - Switch to using 32b port/link capabilities in the driver. The 32b format is used internally by firmwares > 1.16.45.0 and the driver will now interact with the firmware in its native format, whether it's 16b or 32b. Note that the 16b format doesn't have room for 50G, 200G, or 400G speeds. - Add a bit in the pause_settings knobs to allow negotiated PAUSE settings to override manual settings. - Ensure that manual link settings persist across an administrative down/up as well as transceiver unplug/replug. - Remove unused is_*G_port() functions. Approved by: re@ (gjb@) MFC after: 1 month Sponsored by: Chelsio Communications Modified: head/share/man/man4/cxgbe.4 head/sys/dev/cxgbe/adapter.h head/sys/dev/cxgbe/common/common.h head/sys/dev/cxgbe/common/t4_hw.c head/sys/dev/cxgbe/osdep.h head/sys/dev/cxgbe/t4_main.c head/sys/dev/cxgbe/tom/t4_cpl_io.c Modified: head/share/man/man4/cxgbe.4 ============================================================================== --- head/share/man/man4/cxgbe.4 Tue Sep 25 05:18:20 2018 (r338923) +++ head/share/man/man4/cxgbe.4 Tue Sep 25 05:52:42 2018 (r338924) @@ -31,7 +31,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Aug 9, 2018 +.Dd Sep 24, 2018 .Dt CXGBE 4 .Os .Sh NAME @@ -279,19 +279,21 @@ This usually results in the port emitting PAUSE frames 1 instructs the hardware to drop frames destined for congested queues. .It Va hw.cxgbe.pause_settings PAUSE frame settings. -Bit 0 is rx_pause, bit 1 is tx_pause. +Bit 0 is rx_pause, bit 1 is tx_pause, bit 2 is pause_autoneg. rx_pause = 1 instructs the hardware to heed incoming PAUSE frames, 0 instructs it to ignore them. tx_pause = 1 allows the hardware to emit PAUSE frames when its receive FIFO reaches a high threshold, 0 prohibits the hardware from emitting PAUSE frames. -The default is 3 (both rx_pause and tx_pause = 1). +pause_autoneg = 1 overrides the rx_pause and tx_pause bits and instructs the +hardware to negotiate PAUSE settings with the link peer. +The default is 7 (all three = 1). This tunable establishes the default PAUSE settings for all ports. 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. 0 diables FEC. -Bit 0 enables RS FEC, bit 1 enables BASE-R RS, bit 3 is reserved. +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. This tunable establishes the default FEC settings for all ports. Settings can be displayed and controlled on a per-port basis via the Modified: head/sys/dev/cxgbe/adapter.h ============================================================================== --- head/sys/dev/cxgbe/adapter.h Tue Sep 25 05:18:20 2018 (r338923) +++ head/sys/dev/cxgbe/adapter.h Tue Sep 25 05:52:42 2018 (r338924) @@ -289,7 +289,6 @@ struct port_info { uint8_t rx_e_chan_map; /* rx TP e-channel bitmap */ struct link_config link_cfg; - struct link_config old_link_cfg; struct ifmedia media; struct timeval last_refreshed; @@ -1071,52 +1070,6 @@ t4_os_set_hw_addr(struct port_info *pi, uint8_t hw_add { bcopy(hw_addr, pi->vi[0].hw_addr, ETHER_ADDR_LEN); -} - -static inline bool -is_10G_port(const struct port_info *pi) -{ - - return ((pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) != 0); -} - -static inline bool -is_25G_port(const struct port_info *pi) -{ - - return ((pi->link_cfg.supported & FW_PORT_CAP_SPEED_25G) != 0); -} - -static inline bool -is_40G_port(const struct port_info *pi) -{ - - return ((pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G) != 0); -} - -static inline bool -is_100G_port(const struct port_info *pi) -{ - - return ((pi->link_cfg.supported & FW_PORT_CAP_SPEED_100G) != 0); -} - -static inline int -port_top_speed(const struct port_info *pi) -{ - - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100G) - return (100); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G) - return (40); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_25G) - return (25); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) - return (10); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G) - return (1); - - return (0); } static inline int Modified: head/sys/dev/cxgbe/common/common.h ============================================================================== --- head/sys/dev/cxgbe/common/common.h Tue Sep 25 05:18:20 2018 (r338923) +++ head/sys/dev/cxgbe/common/common.h Tue Sep 25 05:52:42 2018 (r338924) @@ -66,9 +66,10 @@ enum { }; enum { + FEC_NONE = 0, FEC_RS = 1 << 0, FEC_BASER_RS = 1 << 1, - FEC_RESERVED = 1 << 2, + FEC_AUTO = 1 << 5, /* M_FW_PORT_CAP32_FEC + 1 */ }; enum t4_bar2_qtype { T4_BAR2_QTYPE_EGRESS, T4_BAR2_QTYPE_INGRESS }; @@ -368,6 +369,7 @@ struct adapter_params { unsigned int ethoffload:1; unsigned int hash_filter:1; unsigned int filter2_wr_support:1; + unsigned int port_caps32:1; unsigned int ofldq_wr_cred; unsigned int eo_wr_cred; @@ -409,20 +411,21 @@ struct trace_params { }; struct link_config { - /* OS-specific code owns all the requested_* fields */ - 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 (Mbps) */ + /* 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) */ - unsigned short supported; /* link capabilities */ - unsigned short advertising; /* advertised capabilities */ - unsigned short lp_advertising; /* peer advertised capabilities */ - 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? */ - unsigned char link_down_rc; /* link down reason */ + 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 */ }; #include "adapter.h" @@ -874,5 +877,16 @@ int t4vf_prep_adapter(struct adapter *adapter); int t4_bar2_sge_qregs(struct adapter *adapter, unsigned int qid, enum t4_bar2_qtype qtype, int user, u64 *pbar2_qoffset, unsigned int *pbar2_qid); +unsigned int fwcap_to_speed(uint32_t caps); +uint32_t speed_to_fwcap(unsigned int speed); +uint32_t fwcap_top_speed(uint32_t caps); + +static inline int +port_top_speed(const struct port_info *pi) +{ + + /* Mbps -> Gbps */ + return (fwcap_to_speed(pi->link_cfg.supported) / 1000); +} #endif /* __CHELSIO_COMMON_H */ Modified: head/sys/dev/cxgbe/common/t4_hw.c ============================================================================== --- head/sys/dev/cxgbe/common/t4_hw.c Tue Sep 25 05:18:20 2018 (r338923) +++ head/sys/dev/cxgbe/common/t4_hw.c Tue Sep 25 05:52:42 2018 (r338924) @@ -3756,6 +3756,93 @@ void t4_ulprx_read_la(struct adapter *adap, u32 *la_bu } /** + * fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits + * @caps16: a 16-bit Port Capabilities value + * + * Returns the equivalent 32-bit Port Capabilities value. + */ +static uint32_t fwcaps16_to_caps32(uint16_t caps16) +{ + uint32_t caps32 = 0; + + #define CAP16_TO_CAP32(__cap) \ + do { \ + if (caps16 & FW_PORT_CAP_##__cap) \ + caps32 |= FW_PORT_CAP32_##__cap; \ + } while (0) + + CAP16_TO_CAP32(SPEED_100M); + CAP16_TO_CAP32(SPEED_1G); + CAP16_TO_CAP32(SPEED_25G); + CAP16_TO_CAP32(SPEED_10G); + CAP16_TO_CAP32(SPEED_40G); + CAP16_TO_CAP32(SPEED_100G); + CAP16_TO_CAP32(FC_RX); + CAP16_TO_CAP32(FC_TX); + CAP16_TO_CAP32(ANEG); + CAP16_TO_CAP32(FORCE_PAUSE); + CAP16_TO_CAP32(MDIAUTO); + CAP16_TO_CAP32(MDISTRAIGHT); + CAP16_TO_CAP32(FEC_RS); + CAP16_TO_CAP32(FEC_BASER_RS); + CAP16_TO_CAP32(802_3_PAUSE); + CAP16_TO_CAP32(802_3_ASM_DIR); + + #undef CAP16_TO_CAP32 + + return caps32; +} + +/** + * fwcaps32_to_caps16 - convert 32-bit Port Capabilities to 16-bits + * @caps32: a 32-bit Port Capabilities value + * + * Returns the equivalent 16-bit Port Capabilities value. Note that + * not all 32-bit Port Capabilities can be represented in the 16-bit + * Port Capabilities and some fields/values may not make it. + */ +static uint16_t fwcaps32_to_caps16(uint32_t caps32) +{ + uint16_t caps16 = 0; + + #define CAP32_TO_CAP16(__cap) \ + do { \ + if (caps32 & FW_PORT_CAP32_##__cap) \ + caps16 |= FW_PORT_CAP_##__cap; \ + } while (0) + + CAP32_TO_CAP16(SPEED_100M); + CAP32_TO_CAP16(SPEED_1G); + CAP32_TO_CAP16(SPEED_10G); + CAP32_TO_CAP16(SPEED_25G); + CAP32_TO_CAP16(SPEED_40G); + CAP32_TO_CAP16(SPEED_100G); + CAP32_TO_CAP16(FC_RX); + CAP32_TO_CAP16(FC_TX); + CAP32_TO_CAP16(802_3_PAUSE); + CAP32_TO_CAP16(802_3_ASM_DIR); + CAP32_TO_CAP16(ANEG); + CAP32_TO_CAP16(FORCE_PAUSE); + CAP32_TO_CAP16(MDIAUTO); + CAP32_TO_CAP16(MDISTRAIGHT); + CAP32_TO_CAP16(FEC_RS); + CAP32_TO_CAP16(FEC_BASER_RS); + + #undef CAP32_TO_CAP16 + + return caps16; +} + +static bool +is_bt(struct port_info *pi) +{ + + return (pi->port_type == FW_PORT_TYPE_BT_SGMII || + pi->port_type == FW_PORT_TYPE_BT_XFI || + pi->port_type == FW_PORT_TYPE_BT_XAUI); +} + +/** * t4_link_l1cfg - apply link configuration to MAC/PHY * @phy: the PHY to setup * @mac: the MAC to setup @@ -3772,53 +3859,45 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int m struct link_config *lc) { struct fw_port_cmd c; - unsigned int mdi = V_FW_PORT_CAP_MDI(FW_PORT_CAP_MDI_AUTO); + unsigned int mdi = V_FW_PORT_CAP32_MDI(FW_PORT_CAP32_MDI_AUTO); unsigned int aneg, fc, fec, speed, rcap; fc = 0; if (lc->requested_fc & PAUSE_RX) - fc |= FW_PORT_CAP_FC_RX; + fc |= FW_PORT_CAP32_FC_RX; if (lc->requested_fc & PAUSE_TX) - fc |= FW_PORT_CAP_FC_TX; + fc |= FW_PORT_CAP32_FC_TX; + if (!(lc->requested_fc & PAUSE_AUTONEG)) + fc |= FW_PORT_CAP32_FORCE_PAUSE; fec = 0; - if (lc->requested_fec & FEC_RS) - fec = FW_PORT_CAP_FEC_RS; - else if (lc->requested_fec & FEC_BASER_RS) - fec = FW_PORT_CAP_FEC_BASER_RS; + 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->supported & FW_PORT_CAP_ANEG) || - lc->requested_aneg == AUTONEG_DISABLE) { + if (lc->requested_aneg == AUTONEG_DISABLE) aneg = 0; - switch (lc->requested_speed) { - case 100000: - speed = FW_PORT_CAP_SPEED_100G; - break; - case 40000: - speed = FW_PORT_CAP_SPEED_40G; - break; - case 25000: - speed = FW_PORT_CAP_SPEED_25G; - break; - case 10000: - speed = FW_PORT_CAP_SPEED_10G; - break; - case 1000: - speed = FW_PORT_CAP_SPEED_1G; - break; - case 100: - speed = FW_PORT_CAP_SPEED_100M; - break; - default: - return -EINVAL; - break; - } - } else { - aneg = FW_PORT_CAP_ANEG; - speed = lc->supported & - V_FW_PORT_CAP_SPEED(M_FW_PORT_CAP_SPEED); - } + else if (lc->requested_aneg == AUTONEG_ENABLE) + aneg = FW_PORT_CAP32_ANEG; + else + aneg = lc->supported & FW_PORT_CAP32_ANEG; + if (aneg) { + speed = lc->supported & 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); + + /* Force AN on for BT cards. */ + if (is_bt(adap->port[port])) + aneg = lc->supported & FW_PORT_CAP32_ANEG; + rcap = aneg | speed | fc | fec; if ((rcap | lc->supported) != lc->supported) { #ifdef INVARIANTS @@ -3833,10 +3912,17 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int m c.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST | F_FW_CMD_EXEC | V_FW_PORT_CMD_PORTID(port)); - c.action_to_len16 = - cpu_to_be32(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | + if (adap->params.port_caps32) { + c.action_to_len16 = + cpu_to_be32(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG32) | + FW_LEN16(c)); + c.u.l1cfg32.rcap32 = cpu_to_be32(rcap); + } else { + c.action_to_len16 = + cpu_to_be32(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | FW_LEN16(c)); - c.u.l1cfg.rcap = cpu_to_be32(rcap); + c.u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(rcap)); + } return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL); } @@ -7736,56 +7822,205 @@ const char *t4_link_down_rc_str(unsigned char link_dow } /* + * Return the highest speed set in the port capabilities, in Mb/s. + */ +unsigned int fwcap_to_speed(uint32_t caps) +{ + #define TEST_SPEED_RETURN(__caps_speed, __speed) \ + do { \ + if (caps & FW_PORT_CAP32_SPEED_##__caps_speed) \ + return __speed; \ + } while (0) + + TEST_SPEED_RETURN(400G, 400000); + TEST_SPEED_RETURN(200G, 200000); + TEST_SPEED_RETURN(100G, 100000); + TEST_SPEED_RETURN(50G, 50000); + TEST_SPEED_RETURN(40G, 40000); + TEST_SPEED_RETURN(25G, 25000); + TEST_SPEED_RETURN(10G, 10000); + TEST_SPEED_RETURN(1G, 1000); + TEST_SPEED_RETURN(100M, 100); + + #undef TEST_SPEED_RETURN + + return 0; +} + +/* + * Return the port capabilities bit for the given speed, which is in Mb/s. + */ +uint32_t speed_to_fwcap(unsigned int speed) +{ + #define TEST_SPEED_RETURN(__caps_speed, __speed) \ + do { \ + if (speed == __speed) \ + return FW_PORT_CAP32_SPEED_##__caps_speed; \ + } while (0) + + TEST_SPEED_RETURN(400G, 400000); + TEST_SPEED_RETURN(200G, 200000); + TEST_SPEED_RETURN(100G, 100000); + TEST_SPEED_RETURN(50G, 50000); + TEST_SPEED_RETURN(40G, 40000); + TEST_SPEED_RETURN(25G, 25000); + TEST_SPEED_RETURN(10G, 10000); + TEST_SPEED_RETURN(1G, 1000); + TEST_SPEED_RETURN(100M, 100); + + #undef TEST_SPEED_RETURN + + return 0; +} + +/* + * Return the port capabilities bit for the highest speed in the capabilities. + */ +uint32_t fwcap_top_speed(uint32_t caps) +{ + #define TEST_SPEED_RETURN(__caps_speed) \ + do { \ + if (caps & FW_PORT_CAP32_SPEED_##__caps_speed) \ + return FW_PORT_CAP32_SPEED_##__caps_speed; \ + } while (0) + + TEST_SPEED_RETURN(400G); + TEST_SPEED_RETURN(200G); + TEST_SPEED_RETURN(100G); + TEST_SPEED_RETURN(50G); + TEST_SPEED_RETURN(40G); + TEST_SPEED_RETURN(25G); + TEST_SPEED_RETURN(10G); + TEST_SPEED_RETURN(1G); + TEST_SPEED_RETURN(100M); + + #undef TEST_SPEED_RETURN + + return 0; +} + + +/** + * lstatus_to_fwcap - translate old lstatus to 32-bit Port Capabilities + * @lstatus: old FW_PORT_ACTION_GET_PORT_INFO lstatus value + * + * Translates old FW_PORT_ACTION_GET_PORT_INFO lstatus field into new + * 32-bit Port Capabilities value. + */ +static uint32_t lstatus_to_fwcap(u32 lstatus) +{ + uint32_t linkattr = 0; + + /* + * Unfortunately the format of the Link Status in the old + * 16-bit Port Information message isn't the same as the + * 16-bit Port Capabilities bitfield used everywhere else ... + */ + if (lstatus & F_FW_PORT_CMD_RXPAUSE) + linkattr |= FW_PORT_CAP32_FC_RX; + if (lstatus & F_FW_PORT_CMD_TXPAUSE) + linkattr |= FW_PORT_CAP32_FC_TX; + if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) + linkattr |= FW_PORT_CAP32_SPEED_100M; + if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) + linkattr |= FW_PORT_CAP32_SPEED_1G; + if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) + linkattr |= FW_PORT_CAP32_SPEED_10G; + if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_25G)) + linkattr |= FW_PORT_CAP32_SPEED_25G; + if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G)) + linkattr |= FW_PORT_CAP32_SPEED_40G; + if (lstatus & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100G)) + linkattr |= FW_PORT_CAP32_SPEED_100G; + + return linkattr; +} + +/* * Updates all fields owned by the common code in port_info and link_config * based on information provided by the firmware. Does not touch any * requested_* field. */ -static void handle_port_info(struct port_info *pi, const struct fw_port_info *p) +static void handle_port_info(struct port_info *pi, const struct fw_port_cmd *p, + enum fw_port_action action, bool *mod_changed, bool *link_changed) { - struct link_config *lc = &pi->link_cfg; - int speed; + struct link_config old_lc, *lc = &pi->link_cfg; unsigned char fc, fec; - u32 stat = be32_to_cpu(p->lstatus_to_modtype); + u32 stat, linkattr; + int old_ptype, old_mtype; - pi->port_type = G_FW_PORT_CMD_PTYPE(stat); - pi->mod_type = G_FW_PORT_CMD_MODTYPE(stat); - pi->mdio_addr = stat & F_FW_PORT_CMD_MDIOCAP ? - G_FW_PORT_CMD_MDIOADDR(stat) : -1; + old_ptype = pi->port_type; + old_mtype = pi->mod_type; + old_lc = *lc; + if (action == FW_PORT_ACTION_GET_PORT_INFO) { + stat = be32_to_cpu(p->u.info.lstatus_to_modtype); - lc->supported = be16_to_cpu(p->pcap); - lc->advertising = be16_to_cpu(p->acap); - lc->lp_advertising = be16_to_cpu(p->lpacap); - lc->link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0; - lc->link_down_rc = G_FW_PORT_CMD_LINKDNRC(stat); + pi->port_type = G_FW_PORT_CMD_PTYPE(stat); + pi->mod_type = G_FW_PORT_CMD_MODTYPE(stat); + pi->mdio_addr = stat & F_FW_PORT_CMD_MDIOCAP ? + G_FW_PORT_CMD_MDIOADDR(stat) : -1; - speed = 0; - if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) - speed = 100; - else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) - speed = 1000; - else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) - speed = 10000; - else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_25G)) - speed = 25000; - else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G)) - speed = 40000; - else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100G)) - speed = 100000; - lc->speed = speed; + 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->link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0; + lc->link_down_rc = G_FW_PORT_CMD_LINKDNRC(stat); + linkattr = lstatus_to_fwcap(stat); + } else if (action == FW_PORT_ACTION_GET_PORT_INFO32) { + stat = be32_to_cpu(p->u.info32.lstatus32_to_cbllen32); + + pi->port_type = G_FW_PORT_CMD_PORTTYPE32(stat); + pi->mod_type = G_FW_PORT_CMD_MODTYPE32(stat); + 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 = be16_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); + + linkattr = be32_to_cpu(p->u.info32.linkattr32); + } else { + CH_ERR(pi->adapter, "bad port_info action 0x%x\n", action); + return; + } + + lc->speed = fwcap_to_speed(linkattr); + fc = 0; - if (stat & F_FW_PORT_CMD_RXPAUSE) + if (linkattr & FW_PORT_CAP32_FC_RX) fc |= PAUSE_RX; - if (stat & F_FW_PORT_CMD_TXPAUSE) + if (linkattr & FW_PORT_CAP32_FC_TX) fc |= PAUSE_TX; lc->fc = fc; - fec = 0; - if (lc->advertising & FW_PORT_CAP_FEC_RS) - fec = FEC_RS; - else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS) - fec = FEC_BASER_RS; + 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); + } + if (mod_changed != NULL) + *mod_changed = true; + } + if (old_lc.link_ok != lc->link_ok || old_lc.speed != lc->speed || + old_lc.fec != lc->fec || old_lc.fc != lc->fc) { + if (link_changed != NULL) + *link_changed = true; + } } /** @@ -7798,22 +8033,24 @@ static void handle_port_info(struct port_info *pi, con */ int t4_update_port_info(struct port_info *pi) { - struct fw_port_cmd port_cmd; + struct adapter *sc = pi->adapter; + struct fw_port_cmd cmd; + enum fw_port_action action; int ret; - memset(&port_cmd, 0, sizeof port_cmd); - port_cmd.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) | - F_FW_CMD_REQUEST | F_FW_CMD_READ | - V_FW_PORT_CMD_PORTID(pi->tx_chan)); - port_cmd.action_to_len16 = cpu_to_be32( - V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) | - FW_LEN16(port_cmd)); - ret = t4_wr_mbox_ns(pi->adapter, pi->adapter->mbox, - &port_cmd, sizeof(port_cmd), &port_cmd); + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_READ | + V_FW_PORT_CMD_PORTID(pi->tx_chan)); + action = sc->params.port_caps32 ? FW_PORT_ACTION_GET_PORT_INFO32 : + FW_PORT_ACTION_GET_PORT_INFO; + cmd.action_to_len16 = cpu_to_be32(V_FW_PORT_CMD_ACTION(action) | + FW_LEN16(cmd)); + ret = t4_wr_mbox_ns(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); if (ret) return ret; - handle_port_info(pi, &port_cmd.u.info); + handle_port_info(pi, &cmd, action, NULL, NULL); return 0; } @@ -7828,15 +8065,18 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be6 { u8 opcode = *(const u8 *)rpl; const struct fw_port_cmd *p = (const void *)rpl; - unsigned int action = - G_FW_PORT_CMD_ACTION(be32_to_cpu(p->action_to_len16)); + enum fw_port_action action = + G_FW_PORT_CMD_ACTION(be32_to_cpu(p->action_to_len16)); + bool mod_changed, link_changed; - if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO) { + if (opcode == FW_PORT_CMD && + (action == FW_PORT_ACTION_GET_PORT_INFO || + action == FW_PORT_ACTION_GET_PORT_INFO32)) { /* link/module state change message */ - int i, old_ptype, old_mtype; + int i; int chan = G_FW_PORT_CMD_PORTID(be32_to_cpu(p->op_to_portid)); struct port_info *pi = NULL; - struct link_config *lc, *old_lc; + struct link_config *lc; for_each_port(adap, i) { pi = adap2pinfo(adap, i); @@ -7846,23 +8086,15 @@ 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); + handle_port_info(pi, p, action, &mod_changed, &link_changed); PORT_UNLOCK(pi); - if (old_ptype != pi->port_type || old_mtype != pi->mod_type) { + if (mod_changed) 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 || - old_lc->fc != lc->fc) { + if (link_changed) { + PORT_LOCK(pi); t4_os_link_changed(pi); - *old_lc = *lc; + PORT_UNLOCK(pi); } - PORT_UNLOCK(pi); } else { CH_WARN_RATELIMIT(adap, "Unknown firmware reply %d\n", opcode); return -EINVAL; @@ -8595,6 +8827,11 @@ int t4_port_init(struct adapter *adap, int mbox, int p } while ((adap->params.portvec & (1 << j)) == 0); } + p->tx_chan = j; + p->mps_bg_map = t4_get_mps_bg_map(adap, j); + p->rx_e_chan_map = t4_get_rx_e_chan_map(adap, j); + p->lport = j; + if (!(adap->flags & IS_VF) || adap->params.vfres.r_caps & FW_CMD_CAP_PORT) { t4_update_port_info(p); @@ -8609,10 +8846,6 @@ int t4_port_init(struct adapter *adap, int mbox, int p p->vi[0].smt_idx = (ret & 0x7f) << 1; else p->vi[0].smt_idx = (ret & 0x7f); - p->tx_chan = j; - p->mps_bg_map = t4_get_mps_bg_map(adap, j); - p->rx_e_chan_map = t4_get_rx_e_chan_map(adap, j); - p->lport = j; p->vi[0].rss_size = rss_size; t4_os_set_hw_addr(p, addr); Modified: head/sys/dev/cxgbe/osdep.h ============================================================================== --- head/sys/dev/cxgbe/osdep.h Tue Sep 25 05:18:20 2018 (r338923) +++ head/sys/dev/cxgbe/osdep.h Tue Sep 25 05:52:42 2018 (r338924) @@ -108,6 +108,7 @@ typedef boolean_t bool; #define DUPLEX_HALF 0 #define DUPLEX_FULL 1 +#define AUTONEG_AUTO (-1) #define AUTONEG_DISABLE 0 #define AUTONEG_ENABLE 1 Modified: head/sys/dev/cxgbe/t4_main.c ============================================================================== --- head/sys/dev/cxgbe/t4_main.c Tue Sep 25 05:18:20 2018 (r338923) +++ head/sys/dev/cxgbe/t4_main.c Tue Sep 25 05:52:42 2018 (r338924) @@ -390,18 +390,20 @@ static char t4_cfg_file[32] = DEFAULT_CF; TUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file)); /* - * PAUSE settings (bit 0, 1 = rx_pause, tx_pause respectively). + * PAUSE settings (bit 0, 1, 2 = rx_pause, tx_pause, pause_autoneg respectively). * rx_pause = 1 to heed incoming PAUSE frames, 0 to ignore them. * tx_pause = 1 to emit PAUSE frames when the rx FIFO reaches its high water * mark or when signalled to do so, 0 to never emit PAUSE. + * pause_autoneg = 1 means PAUSE will be negotiated if possible and the + * negotiated settings will override rx_pause/tx_pause. + * Otherwise rx_pause/tx_pause are applied forcibly. */ -static int t4_pause_settings = PAUSE_TX | PAUSE_RX; +static int t4_pause_settings = PAUSE_RX | PAUSE_TX | PAUSE_AUTONEG; 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. + * Forward Error Correction settings (bit 0, 1 = RS, BASER respectively). + * -1 to run with the firmware default. Same as FEC_AUTO (bit 5) * 0 to disable FEC. */ static int t4_fec = -1; @@ -526,9 +528,11 @@ static int get_params__pre_init(struct adapter *); static int get_params__post_init(struct adapter *); 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 bool fixed_ifmedia(struct port_info *); +static void build_medialist(struct port_info *); +static void init_link_config(struct port_info *); +static int fixup_link_config(struct port_info *); +static int apply_link_config(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 *); @@ -1018,6 +1022,14 @@ t4_attach(device_t dev) ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, cxgbe_media_status); + PORT_LOCK(pi); + init_link_config(pi); + fixup_link_config(pi); + build_medialist(pi); + if (fixed_ifmedia(pi)) + pi->flags |= FIXED_IFMEDIA; + PORT_UNLOCK(pi); + pi->dev = device_add_child(dev, sc->names->ifnet_name, -1); if (pi->dev == NULL) { device_printf(dev, @@ -1885,7 +1897,7 @@ cxgbe_transmit(struct ifnet *ifp, struct mbuf *m) M_ASSERTPKTHDR(m); MPASS(m->m_nextpkt == NULL); /* not quite ready for this yet */ - if (__predict_false(pi->link_cfg.link_ok == 0)) { + if (__predict_false(pi->link_cfg.link_ok == false)) { m_freem(m); return (ENETDOWN); } @@ -2063,8 +2075,8 @@ 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. + * The kernel picks a media from the list we had provided but we still validate + * the requeste. */ int cxgbe_media_change(struct ifnet *ifp) @@ -2081,8 +2093,14 @@ cxgbe_media_change(struct ifnet *ifp) return (rc); PORT_LOCK(pi); if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { - MPASS(lc->supported & FW_PORT_CAP_ANEG); + /* ifconfig .. media autoselect */ + if (!(lc->supported & FW_PORT_CAP32_ANEG)) { + rc = ENOTSUP; /* AN not supported by transceiver */ + goto done; + } lc->requested_aneg = AUTONEG_ENABLE; + lc->requested_speed = 0; + lc->requested_fc |= PAUSE_AUTONEG; } else { lc->requested_aneg = AUTONEG_DISABLE; lc->requested_speed = @@ -2093,47 +2111,25 @@ cxgbe_media_change(struct ifnet *ifp) if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE) lc->requested_fc |= PAUSE_TX; } - if (pi->up_vis > 0) - rc = apply_l1cfg(pi); + if (pi->up_vis > 0) { + fixup_link_config(pi); + rc = apply_link_config(pi); + } +done: PORT_UNLOCK(pi); end_synchronized_op(sc, 0); return (rc); } /* - * 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) +port_mword(struct port_info *pi, uint32_t speed) { - MPASS(speed & M_FW_PORT_CAP_SPEED); + MPASS(speed & M_FW_PORT_CAP32_SPEED); MPASS(powerof2(speed)); switch(pi->port_type) { @@ -2142,24 +2138,24 @@ port_mword(struct port_info *pi, uint16_t speed) case FW_PORT_TYPE_BT_XAUI: /* BaseT */ switch (speed) { - case FW_PORT_CAP_SPEED_100M: + case FW_PORT_CAP32_SPEED_100M: return (IFM_100_T); - case FW_PORT_CAP_SPEED_1G: + case FW_PORT_CAP32_SPEED_1G: return (IFM_1000_T); - case FW_PORT_CAP_SPEED_10G: + case FW_PORT_CAP32_SPEED_10G: return (IFM_10G_T); } break; case FW_PORT_TYPE_KX4: - if (speed == FW_PORT_CAP_SPEED_10G) + if (speed == FW_PORT_CAP32_SPEED_10G) return (IFM_10G_KX4); break; case FW_PORT_TYPE_CX4: - if (speed == FW_PORT_CAP_SPEED_10G) + if (speed == FW_PORT_CAP32_SPEED_10G) return (IFM_10G_CX4); break; case FW_PORT_TYPE_KX: - if (speed == FW_PORT_CAP_SPEED_1G) + if (speed == FW_PORT_CAP32_SPEED_1G) return (IFM_1000_KX); break; case FW_PORT_TYPE_KR: @@ -2170,15 +2166,17 @@ port_mword(struct port_info *pi, uint16_t speed) case FW_PORT_TYPE_KR_SFP28: case FW_PORT_TYPE_KR_XLAUI: switch (speed) { - case FW_PORT_CAP_SPEED_1G: + case FW_PORT_CAP32_SPEED_1G: return (IFM_1000_KX); - case FW_PORT_CAP_SPEED_10G: + case FW_PORT_CAP32_SPEED_10G: return (IFM_10G_KR); - case FW_PORT_CAP_SPEED_25G: + case FW_PORT_CAP32_SPEED_25G: return (IFM_25G_KR); - case FW_PORT_CAP_SPEED_40G: + case FW_PORT_CAP32_SPEED_40G: return (IFM_40G_KR4); - case FW_PORT_CAP_SPEED_100G: + case FW_PORT_CAP32_SPEED_50G: + return (IFM_50G_KR2); + case FW_PORT_CAP32_SPEED_100G: return (IFM_100G_KR4); } break; @@ -2196,53 +2194,59 @@ port_mword(struct port_info *pi, uint16_t speed) switch (pi->mod_type) { case FW_PORT_MOD_TYPE_LR: switch (speed) { - case FW_PORT_CAP_SPEED_1G: + case FW_PORT_CAP32_SPEED_1G: return (IFM_1000_LX); - case FW_PORT_CAP_SPEED_10G: + case FW_PORT_CAP32_SPEED_10G: return (IFM_10G_LR); - case FW_PORT_CAP_SPEED_25G: + case FW_PORT_CAP32_SPEED_25G: return (IFM_25G_LR); - case FW_PORT_CAP_SPEED_40G: + case FW_PORT_CAP32_SPEED_40G: return (IFM_40G_LR4); - case FW_PORT_CAP_SPEED_100G: + case FW_PORT_CAP32_SPEED_50G: + return (IFM_50G_LR2); + case FW_PORT_CAP32_SPEED_100G: return (IFM_100G_LR4); } break; case FW_PORT_MOD_TYPE_SR: switch (speed) { - case FW_PORT_CAP_SPEED_1G: + case FW_PORT_CAP32_SPEED_1G: return (IFM_1000_SX); - case FW_PORT_CAP_SPEED_10G: + case FW_PORT_CAP32_SPEED_10G: return (IFM_10G_SR); - case FW_PORT_CAP_SPEED_25G: + case FW_PORT_CAP32_SPEED_25G: return (IFM_25G_SR); - case FW_PORT_CAP_SPEED_40G: + case FW_PORT_CAP32_SPEED_40G: return (IFM_40G_SR4); - case FW_PORT_CAP_SPEED_100G: + case FW_PORT_CAP32_SPEED_50G: + return (IFM_50G_SR2); + case FW_PORT_CAP32_SPEED_100G: return (IFM_100G_SR4); } break; case FW_PORT_MOD_TYPE_ER: - if (speed == FW_PORT_CAP_SPEED_10G) + if (speed == FW_PORT_CAP32_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: + case FW_PORT_CAP32_SPEED_1G: return (IFM_1000_CX); - case FW_PORT_CAP_SPEED_10G: + case FW_PORT_CAP32_SPEED_10G: return (IFM_10G_TWINAX); - case FW_PORT_CAP_SPEED_25G: + case FW_PORT_CAP32_SPEED_25G: return (IFM_25G_CR); - case FW_PORT_CAP_SPEED_40G: *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201809250552.w8P5qh4a004298>