Index: head/sys/dev/bnxt/bnxt.h =================================================================== --- head/sys/dev/bnxt/bnxt.h +++ head/sys/dev/bnxt/bnxt.h @@ -211,6 +211,10 @@ #define BNXT_HWRM_LOCK_DESTROY(_softc) mtx_destroy(&(_softc)->hwrm_lock) #define BNXT_HWRM_LOCK_ASSERT(_softc) mtx_assert(&(_softc)->hwrm_lock, \ MA_OWNED) +#define BNXT_IS_FLOW_CTRL_CHANGED(link_info) \ + ((link_info->last_flow_ctrl.tx != link_info->flow_ctrl.tx) || \ + (link_info->last_flow_ctrl.rx != link_info->flow_ctrl.rx) || \ + (link_info->last_flow_ctrl.autoneg != link_info->flow_ctrl.autoneg)) /* Chip info */ #define BNXT_TSO_SIZE UINT16_MAX @@ -288,6 +292,12 @@ int rid; }; +struct bnxt_flow_ctrl { + bool rx; + bool tx; + bool autoneg; +}; + struct bnxt_link_info { uint8_t media_type; uint8_t transceiver; @@ -299,10 +309,8 @@ uint8_t last_link_up; uint8_t duplex; uint8_t last_duplex; - uint8_t pause; - uint8_t last_pause; - uint8_t auto_pause; - uint8_t force_pause; + struct bnxt_flow_ctrl flow_ctrl; + struct bnxt_flow_ctrl last_flow_ctrl; uint8_t duplex_setting; uint8_t auto_mode; #define PHY_VER_LEN 3 @@ -320,7 +328,6 @@ #define BNXT_AUTONEG_SPEED 1 #define BNXT_AUTONEG_FLOW_CTRL 2 uint8_t req_duplex; - uint8_t req_flow_ctrl; uint16_t req_link_speed; }; @@ -596,6 +603,8 @@ struct sysctl_oid *hw_stats_oid; struct sysctl_ctx_list hw_lro_ctx; struct sysctl_oid *hw_lro_oid; + struct sysctl_ctx_list flow_ctrl_ctx; + struct sysctl_oid *flow_ctrl_oid; struct bnxt_ver_info *ver_info; struct bnxt_nvram_info *nvm_info; Index: head/sys/dev/bnxt/bnxt_hwrm.h =================================================================== --- head/sys/dev/bnxt/bnxt_hwrm.h +++ head/sys/dev/bnxt/bnxt_hwrm.h @@ -32,6 +32,11 @@ #ifndef _BNXT_HWRM_H #define _BNXT_HWRM_H +#define BNXT_PAUSE_TX (HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX) +#define BNXT_PAUSE_RX (HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX) +#define BNXT_AUTO_PAUSE_AUTONEG_PAUSE \ + (HWRM_PORT_PHY_QCFG_OUTPUT_AUTO_PAUSE_AUTONEG_PAUSE) + /* HWRM Function Prototypes */ int bnxt_alloc_hwrm_dma_mem(struct bnxt_softc *softc); void bnxt_free_hwrm_dma_mem(struct bnxt_softc *softc); @@ -45,8 +50,8 @@ int bnxt_hwrm_func_qcaps(struct bnxt_softc *softc); int bnxt_hwrm_func_qcfg(struct bnxt_softc *softc); int bnxt_hwrm_func_reset(struct bnxt_softc *softc); -int bnxt_hwrm_set_link_setting(struct bnxt_softc *, bool set_pause, - bool set_eee); +int bnxt_hwrm_set_link_setting(struct bnxt_softc *softc, bool set_pause, + bool set_eee, bool set_link); int bnxt_hwrm_set_pause(struct bnxt_softc *softc); int bnxt_hwrm_vnic_ctx_alloc(struct bnxt_softc *softc, uint16_t *ctx_id); int bnxt_hwrm_vnic_cfg(struct bnxt_softc *softc, struct bnxt_vnic_info *vnic); Index: head/sys/dev/bnxt/bnxt_hwrm.c =================================================================== --- head/sys/dev/bnxt/bnxt_hwrm.c +++ head/sys/dev/bnxt/bnxt_hwrm.c @@ -503,33 +503,28 @@ bnxt_hwrm_set_pause_common(struct bnxt_softc *softc, struct hwrm_port_phy_cfg_input *req) { - if (softc->link_info.autoneg & BNXT_AUTONEG_FLOW_CTRL) { + struct bnxt_link_info *link_info = &softc->link_info; + + if (link_info->flow_ctrl.autoneg) { req->auto_pause = HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_AUTONEG_PAUSE; - if (softc->link_info.req_flow_ctrl & - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX) + if (link_info->flow_ctrl.rx) req->auto_pause |= HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_RX; - if (softc->link_info.req_flow_ctrl & - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX) + if (link_info->flow_ctrl.tx) req->auto_pause |= - HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_RX; + HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_TX; req->enables |= htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_PAUSE); } else { - if (softc->link_info.req_flow_ctrl & - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX) + if (link_info->flow_ctrl.rx) req->force_pause |= HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_RX; - if (softc->link_info.req_flow_ctrl & - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX) + if (link_info->flow_ctrl.tx) req->force_pause |= HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_TX; req->enables |= htole32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_FORCE_PAUSE); - req->auto_pause = req->force_pause; - req->enables |= htole32( - HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_PAUSE); } } @@ -563,49 +558,41 @@ int bnxt_hwrm_set_link_setting(struct bnxt_softc *softc, bool set_pause, - bool set_eee) + bool set_eee, bool set_link) { struct hwrm_port_phy_cfg_input req = {0}; + int rc; if (softc->flags & BNXT_FLAG_NPAR) return ENOTSUP; bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_CFG); - if (set_pause) + + if (set_pause) { bnxt_hwrm_set_pause_common(softc, &req); - bnxt_hwrm_set_link_common(softc, &req); - if (set_eee) - bnxt_hwrm_set_eee(softc, &req); - return hwrm_send_message(softc, &req, sizeof(req)); -} + if (softc->link_info.flow_ctrl.autoneg) + set_link = true; + } - -int -bnxt_hwrm_set_pause(struct bnxt_softc *softc) -{ - struct hwrm_port_phy_cfg_input req = {0}; - int rc; - - if (softc->flags & BNXT_FLAG_NPAR) - return ENOTSUP; - - bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_PORT_PHY_CFG); - bnxt_hwrm_set_pause_common(softc, &req); - - if (softc->link_info.autoneg & BNXT_AUTONEG_FLOW_CTRL) + if (set_link) bnxt_hwrm_set_link_common(softc, &req); - + + if (set_eee) + bnxt_hwrm_set_eee(softc, &req); + BNXT_HWRM_LOCK(softc); rc = _hwrm_send_message(softc, &req, sizeof(req)); - if (!rc && !(softc->link_info.autoneg & BNXT_AUTONEG_FLOW_CTRL)) { - /* since changing of pause setting doesn't trigger any link - * change event, the driver needs to update the current pause - * result upon successfully return of the phy_cfg command */ - softc->link_info.pause = - softc->link_info.force_pause = softc->link_info.req_flow_ctrl; - softc->link_info.auto_pause = 0; - bnxt_report_link(softc); + + if (!rc) { + if (set_pause) { + /* since changing of 'force pause' setting doesn't + * trigger any link change event, the driver needs to + * update the current pause result upon successfully i + * return of the phy_cfg command */ + if (!softc->link_info.flow_ctrl.autoneg) + bnxt_report_link(softc); + } } BNXT_HWRM_UNLOCK(softc); return rc; @@ -1536,10 +1523,43 @@ link_info->phy_link_status = resp->link; link_info->duplex = resp->duplex_cfg; - link_info->pause = resp->pause; link_info->auto_mode = resp->auto_mode; - link_info->auto_pause = resp->auto_pause; - link_info->force_pause = resp->force_pause; + + /* + * When AUTO_PAUSE_AUTONEG_PAUSE bit is set to 1, + * the advertisement of pause is enabled. + * 1. When the auto_mode is not set to none and this flag is set to 1, + * then the auto_pause bits on this port are being advertised and + * autoneg pause results are being interpreted. + * 2. When the auto_mode is not set to none and this flag is set to 0, + * the pause is forced as indicated in force_pause, and also + * advertised as auto_pause bits, but the autoneg results are not + * interpreted since the pause configuration is being forced. + * 3. When the auto_mode is set to none and this flag is set to 1, + * auto_pause bits should be ignored and should be set to 0. + */ + + link_info->flow_ctrl.autoneg = false; + link_info->flow_ctrl.tx = false; + link_info->flow_ctrl.rx = false; + + if ((resp->auto_mode) && + (resp->auto_pause & BNXT_AUTO_PAUSE_AUTONEG_PAUSE)) { + link_info->flow_ctrl.autoneg = true; + } + + if (link_info->flow_ctrl.autoneg) { + if (resp->auto_pause & BNXT_PAUSE_TX) + link_info->flow_ctrl.tx = true; + if (resp->auto_pause & BNXT_PAUSE_RX) + link_info->flow_ctrl.rx = true; + } else { + if (resp->force_pause & BNXT_PAUSE_TX) + link_info->flow_ctrl.tx = true; + if (resp->force_pause & BNXT_PAUSE_RX) + link_info->flow_ctrl.rx = true; + } + link_info->duplex_setting = resp->duplex_cfg; if (link_info->phy_link_status == HWRM_PORT_PHY_QCFG_OUTPUT_LINK_LINK) link_info->link_speed = le16toh(resp->link_speed); Index: head/sys/dev/bnxt/bnxt_sysctl.h =================================================================== --- head/sys/dev/bnxt/bnxt_sysctl.h +++ head/sys/dev/bnxt/bnxt_sysctl.h @@ -41,3 +41,4 @@ int bnxt_create_config_sysctls_pre(struct bnxt_softc *softc); int bnxt_create_config_sysctls_post(struct bnxt_softc *softc); int bnxt_create_hw_lro_sysctls(struct bnxt_softc *softc); +int bnxt_create_pause_fc_sysctls(struct bnxt_softc *softc); Index: head/sys/dev/bnxt/bnxt_sysctl.c =================================================================== --- head/sys/dev/bnxt/bnxt_sysctl.c +++ head/sys/dev/bnxt/bnxt_sysctl.c @@ -94,6 +94,16 @@ return ENOMEM; } + sysctl_ctx_init(&softc->flow_ctrl_ctx); + ctx = device_get_sysctl_ctx(softc->dev); + softc->flow_ctrl_oid = SYSCTL_ADD_NODE(ctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev)), OID_AUTO, + "fc", CTLFLAG_RD, 0, "flow ctrl"); + if (!softc->flow_ctrl_oid) { + sysctl_ctx_free(&softc->flow_ctrl_ctx); + return ENOMEM; + } + return 0; } @@ -132,6 +142,14 @@ softc->hw_lro_oid = NULL; } + if (softc->flow_ctrl_oid != NULL) { + orc = sysctl_ctx_free(&softc->flow_ctrl_ctx); + if (orc) + rc = orc; + else + softc->flow_ctrl_oid = NULL; + } + return rc; } @@ -1257,6 +1275,62 @@ BNXT_HW_LRO_FN(bnxt_hw_lro_set_max_agg_segs, max_agg_segs) BNXT_HW_LRO_FN(bnxt_hw_lro_set_max_aggs, max_aggs) BNXT_HW_LRO_FN(bnxt_hw_lro_set_min_agg_len, min_agg_len) + +#define BNXT_FLOW_CTRL_FN(fn_name, arg) \ +static int \ +fn_name(SYSCTL_HANDLER_ARGS) { \ + struct bnxt_softc *softc = arg1; \ + int rc; \ + int val; \ + \ + if (softc == NULL) \ + return EBUSY; \ + \ + val = softc->link_info.flow_ctrl.arg; \ + rc = sysctl_handle_int(oidp, &val, 0, req); \ + if (rc || !req->newptr) \ + return rc; \ + \ + if (val) \ + val = 1; \ + \ + if (softc->link_info.flow_ctrl.arg != val) { \ + softc->link_info.flow_ctrl.arg = val; \ + rc = bnxt_hwrm_set_link_setting(softc, true, false, false);\ + rc = bnxt_hwrm_port_phy_qcfg(softc); \ + } \ + \ + return rc; \ +} + +BNXT_FLOW_CTRL_FN(bnxt_flow_ctrl_tx, tx) +BNXT_FLOW_CTRL_FN(bnxt_flow_ctrl_rx, rx) +BNXT_FLOW_CTRL_FN(bnxt_flow_ctrl_autoneg, autoneg) +int +bnxt_create_pause_fc_sysctls(struct bnxt_softc *softc) +{ + struct sysctl_oid *oid = softc->flow_ctrl_oid; + + if (!oid) + return ENOMEM; + + SYSCTL_ADD_PROC(&softc->flow_ctrl_ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "tx", CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, + bnxt_flow_ctrl_tx, "A", + "Enable or Disable Tx Flow Ctrl: 0 / 1"); + + SYSCTL_ADD_PROC(&softc->flow_ctrl_ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "rx", CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, + bnxt_flow_ctrl_rx, "A", + "Enable or Disable Tx Flow Ctrl: 0 / 1"); + + SYSCTL_ADD_PROC(&softc->flow_ctrl_ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "autoneg", CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, + bnxt_flow_ctrl_autoneg, "A", + "Enable or Disable Autoneg Flow Ctrl: 0 / 1"); + + return 0; +} int bnxt_create_hw_lro_sysctls(struct bnxt_softc *softc) Index: head/sys/dev/bnxt/if_bnxt.c =================================================================== --- head/sys/dev/bnxt/if_bnxt.c +++ head/sys/dev/bnxt/if_bnxt.c @@ -878,6 +878,10 @@ if (rc) goto failed; + rc = bnxt_create_pause_fc_sysctls(softc); + if (rc) + goto failed; + /* Initialize the vlan list */ SLIST_INIT(&softc->vnic_info.vlan_tags); softc->vnic_info.vlan_tag_list.idi_vaddr = NULL; @@ -1377,13 +1381,10 @@ return; } - if (link_info->pause == (HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX | - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX)) - ifmr->ifm_active |= (IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE); - else if (link_info->pause == HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX) - ifmr->ifm_active |= IFM_ETH_TXPAUSE; - else if (link_info->pause == HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX) + if (link_info->flow_ctrl.rx) ifmr->ifm_active |= IFM_ETH_RXPAUSE; + if (link_info->flow_ctrl.tx) + ifmr->ifm_active |= IFM_ETH_TXPAUSE; bnxt_report_link(softc); return; @@ -1471,7 +1472,7 @@ softc->link_info.autoneg |= BNXT_AUTONEG_SPEED; break; } - rc = bnxt_hwrm_set_link_setting(softc, true, true); + rc = bnxt_hwrm_set_link_setting(softc, true, true, true); bnxt_media_status(softc->ctx, &ifmr); return rc; } @@ -2096,18 +2097,6 @@ if (link_info->auto_mode != HWRM_PORT_PHY_QCFG_OUTPUT_AUTO_MODE_NONE) link_info->autoneg |= BNXT_AUTONEG_SPEED; - if (link_info->auto_pause & (HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX | - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX)) { - if (link_info->auto_pause == ( - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX | - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX)) - link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; - link_info->req_flow_ctrl = link_info->auto_pause; - } else if (link_info->force_pause & ( - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX | - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX)) { - link_info->req_flow_ctrl = link_info->force_pause; - } link_info->req_duplex = link_info->duplex_setting; if (link_info->autoneg & BNXT_AUTONEG_SPEED) link_info->req_link_speed = link_info->auto_link_speed; @@ -2352,47 +2341,46 @@ void bnxt_report_link(struct bnxt_softc *softc) { + struct bnxt_link_info *link_info = &softc->link_info; const char *duplex = NULL, *flow_ctrl = NULL; - if (softc->link_info.link_up == softc->link_info.last_link_up) { - if (!softc->link_info.link_up) + if (link_info->link_up == link_info->last_link_up) { + if (!link_info->link_up) return; - if (softc->link_info.pause == softc->link_info.last_pause && - softc->link_info.duplex == softc->link_info.last_duplex) + if ((link_info->duplex == link_info->last_duplex) && + (!(BNXT_IS_FLOW_CTRL_CHANGED(link_info)))) return; } - if (softc->link_info.link_up) { - if (softc->link_info.duplex == + if (link_info->link_up) { + if (link_info->duplex == HWRM_PORT_PHY_QCFG_OUTPUT_DUPLEX_CFG_FULL) duplex = "full duplex"; else duplex = "half duplex"; - if (softc->link_info.pause == ( - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX | - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX)) + if (link_info->flow_ctrl.tx & link_info->flow_ctrl.rx) flow_ctrl = "FC - receive & transmit"; - else if (softc->link_info.pause == - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_TX) + else if (link_info->flow_ctrl.tx) flow_ctrl = "FC - transmit"; - else if (softc->link_info.pause == - HWRM_PORT_PHY_QCFG_OUTPUT_PAUSE_RX) + else if (link_info->flow_ctrl.rx) flow_ctrl = "FC - receive"; else flow_ctrl = "FC - none"; iflib_link_state_change(softc->ctx, LINK_STATE_UP, IF_Gbps(100)); device_printf(softc->dev, "Link is UP %s, %s - %d Mbps \n", duplex, - flow_ctrl, (softc->link_info.link_speed * 100)); + flow_ctrl, (link_info->link_speed * 100)); } else { iflib_link_state_change(softc->ctx, LINK_STATE_DOWN, bnxt_get_baudrate(&softc->link_info)); device_printf(softc->dev, "Link is Down\n"); } - softc->link_info.last_link_up = softc->link_info.link_up; - softc->link_info.last_pause = softc->link_info.pause; - softc->link_info.last_duplex = softc->link_info.duplex; + link_info->last_link_up = link_info->link_up; + link_info->last_duplex = link_info->duplex; + link_info->last_flow_ctrl.tx = link_info->flow_ctrl.tx; + link_info->last_flow_ctrl.rx = link_info->flow_ctrl.rx; + link_info->last_flow_ctrl.autoneg = link_info->flow_ctrl.autoneg; } static int