Commit ae7e6937 authored by Alexander Lobakin's avatar Alexander Lobakin Committed by David S. Miller

qed: add support for Forward Error Correction

Add all necessary routines for reading supported FEC modes from NVM and
querying FEC control to the MFW (if the running version supports it).
Signed-off-by: default avatarAlexander Lobakin <alobakin@marvell.com>
Signed-off-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 37237b5b
......@@ -3968,7 +3968,7 @@ static int qed_hw_get_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
u32 port_cfg_addr, link_temp, nvm_cfg_addr, device_capabilities;
u32 port_cfg_addr, link_temp, nvm_cfg_addr, device_capabilities, fc;
u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, core_cfg;
struct qed_mcp_link_capabilities *p_caps;
struct qed_mcp_link_params *link;
......@@ -4081,16 +4081,38 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
p_hwfn->mcp_info->link_capabilities.default_speed_autoneg =
link->speed.autoneg;
link_temp &= NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK;
link_temp >>= NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET;
link->pause.autoneg = !!(link_temp &
NVM_CFG1_PORT_DRV_FLOW_CONTROL_AUTONEG);
link->pause.forced_rx = !!(link_temp &
NVM_CFG1_PORT_DRV_FLOW_CONTROL_RX);
link->pause.forced_tx = !!(link_temp &
NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX);
fc = GET_MFW_FIELD(link_temp, NVM_CFG1_PORT_DRV_FLOW_CONTROL);
link->pause.autoneg = !!(fc & NVM_CFG1_PORT_DRV_FLOW_CONTROL_AUTONEG);
link->pause.forced_rx = !!(fc & NVM_CFG1_PORT_DRV_FLOW_CONTROL_RX);
link->pause.forced_tx = !!(fc & NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX);
link->loopback_mode = 0;
if (p_hwfn->mcp_info->capabilities &
FW_MB_PARAM_FEATURE_SUPPORT_FEC_CONTROL) {
switch (GET_MFW_FIELD(link_temp,
NVM_CFG1_PORT_FEC_FORCE_MODE)) {
case NVM_CFG1_PORT_FEC_FORCE_MODE_NONE:
p_caps->fec_default |= QED_FEC_MODE_NONE;
break;
case NVM_CFG1_PORT_FEC_FORCE_MODE_FIRECODE:
p_caps->fec_default |= QED_FEC_MODE_FIRECODE;
break;
case NVM_CFG1_PORT_FEC_FORCE_MODE_RS:
p_caps->fec_default |= QED_FEC_MODE_RS;
break;
case NVM_CFG1_PORT_FEC_FORCE_MODE_AUTO:
p_caps->fec_default |= QED_FEC_MODE_AUTO;
break;
default:
DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
"unknown FEC mode in 0x%08x\n", link_temp);
}
} else {
p_caps->fec_default = QED_FEC_MODE_UNSUPPORTED;
}
link->fec = p_caps->fec_default;
if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) {
link_temp = qed_rd(p_hwfn, p_ptt, port_cfg_addr +
offsetof(struct nvm_cfg1_port, ext_phy));
......@@ -4122,14 +4144,12 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
p_caps->default_eee = QED_MCP_EEE_UNSUPPORTED;
}
DP_VERBOSE(p_hwfn,
NETIF_MSG_LINK,
"Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x EEE: %02x [%08x usec]\n",
link->speed.forced_speed,
link->speed.advertised_speeds,
link->speed.autoneg,
link->pause.autoneg,
p_caps->default_eee, p_caps->eee_lpi_timer);
DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
"Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x, EEE: 0x%02x [0x%08x usec], FEC: 0x%02x\n",
link->speed.forced_speed, link->speed.advertised_speeds,
link->speed.autoneg, link->pause.autoneg,
p_caps->default_eee, p_caps->eee_lpi_timer,
p_caps->fec_default);
if (IS_LEAD_HWFN(p_hwfn)) {
struct qed_dev *cdev = p_hwfn->cdev;
......
......@@ -11566,8 +11566,15 @@ struct eth_phy_cfg {
#define EEE_TX_TIMER_USEC_AGGRESSIVE_TIME 0x100
#define EEE_TX_TIMER_USEC_LATENCY_TIME 0x6000
u32 feature_config_flags;
#define ETH_EEE_MODE_ADV_LPI (1 << 0)
u32 deprecated;
u32 fec_mode;
#define FEC_FORCE_MODE_MASK 0x000000ff
#define FEC_FORCE_MODE_OFFSET 0
#define FEC_FORCE_MODE_NONE 0x00
#define FEC_FORCE_MODE_FIRECODE 0x01
#define FEC_FORCE_MODE_RS 0x02
#define FEC_FORCE_MODE_AUTO 0x07
};
struct port_mf_cfg {
......@@ -11934,6 +11941,11 @@ struct public_port {
#define LINK_STATUS_MAC_REMOTE_FAULT 0x02000000
#define LINK_STATUS_UNSUPPORTED_SPD_REQ 0x04000000
#define LINK_STATUS_FEC_MODE_MASK 0x38000000
#define LINK_STATUS_FEC_MODE_NONE (0 << 27)
#define LINK_STATUS_FEC_MODE_FIRECODE_CL74 (1 << 27)
#define LINK_STATUS_FEC_MODE_RS_CL91 (2 << 27)
u32 link_status1;
u32 ext_phy_fw_version;
u32 drv_phy_cfg_addr;
......@@ -12553,6 +12565,7 @@ struct public_drv_mb {
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_MASK 0x0000FFFF
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_OFFSET 0
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE 0x00000002
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_FEC_CONTROL 0x00000004
#define DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK 0x00010000
/* DRV_MSG_CODE_DEBUG_DATA_SEND parameters */
......@@ -12641,6 +12654,7 @@ struct public_drv_mb {
/* Get MFW feature support response */
#define FW_MB_PARAM_FEATURE_SUPPORT_SMARTLINQ 0x00000001
#define FW_MB_PARAM_FEATURE_SUPPORT_EEE 0x00000002
#define FW_MB_PARAM_FEATURE_SUPPORT_FEC_CONTROL 0x00000020
#define FW_MB_PARAM_FEATURE_SUPPORT_VLINK 0x00010000
#define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR BIT(0)
......@@ -13091,6 +13105,12 @@ struct nvm_cfg1_port {
#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_AUTONEG 0x1
#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_RX 0x2
#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX 0x4
#define NVM_CFG1_PORT_FEC_FORCE_MODE_MASK 0x000e0000
#define NVM_CFG1_PORT_FEC_FORCE_MODE_OFFSET 17
#define NVM_CFG1_PORT_FEC_FORCE_MODE_NONE 0x0
#define NVM_CFG1_PORT_FEC_FORCE_MODE_FIRECODE 0x1
#define NVM_CFG1_PORT_FEC_FORCE_MODE_RS 0x2
#define NVM_CFG1_PORT_FEC_FORCE_MODE_AUTO 0x7
u32 phy_cfg;
u32 mgmt_traffic;
......
......@@ -1597,6 +1597,9 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
memcpy(&link_params->eee, &params->eee,
sizeof(link_params->eee));
if (params->override_flags & QED_LINK_OVERRIDE_FEC_CONFIG)
link_params->fec = params->fec;
rc = qed_mcp_set_link(hwfn, ptt, params->link_up);
qed_ptt_release(hwfn, ptt);
......@@ -1938,6 +1941,9 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
else
phylink_clear(if_link->advertised_caps, Autoneg);
if_link->sup_fec = link_caps.fec_default;
if_link->active_fec = params.fec;
/* Fill link advertised capability */
qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds,
if_link->advertised_caps);
......
......@@ -1446,6 +1446,25 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE)
qed_mcp_read_eee_config(p_hwfn, p_ptt, p_link);
if (p_hwfn->mcp_info->capabilities &
FW_MB_PARAM_FEATURE_SUPPORT_FEC_CONTROL) {
switch (status & LINK_STATUS_FEC_MODE_MASK) {
case LINK_STATUS_FEC_MODE_NONE:
p_link->fec_active = QED_FEC_MODE_NONE;
break;
case LINK_STATUS_FEC_MODE_FIRECODE_CL74:
p_link->fec_active = QED_FEC_MODE_FIRECODE;
break;
case LINK_STATUS_FEC_MODE_RS_CL91:
p_link->fec_active = QED_FEC_MODE_RS;
break;
default:
p_link->fec_active = QED_FEC_MODE_AUTO;
}
} else {
p_link->fec_active = QED_FEC_MODE_UNSUPPORTED;
}
qed_link_update(p_hwfn, p_ptt);
out:
spin_unlock_bh(&p_hwfn->mcp_info->link_lock);
......@@ -1456,8 +1475,8 @@ int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up)
struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input;
struct qed_mcp_mb_params mb_params;
struct eth_phy_cfg phy_cfg;
u32 cmd, fec_bit = 0;
int rc = 0;
u32 cmd;
/* Set the shmem configuration according to params */
memset(&phy_cfg, 0, sizeof(phy_cfg));
......@@ -1489,16 +1508,27 @@ int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up)
EEE_TX_TIMER_USEC_MASK;
}
if (p_hwfn->mcp_info->capabilities &
FW_MB_PARAM_FEATURE_SUPPORT_FEC_CONTROL) {
if (params->fec & QED_FEC_MODE_NONE)
fec_bit |= FEC_FORCE_MODE_NONE;
else if (params->fec & QED_FEC_MODE_FIRECODE)
fec_bit |= FEC_FORCE_MODE_FIRECODE;
else if (params->fec & QED_FEC_MODE_RS)
fec_bit |= FEC_FORCE_MODE_RS;
else if (params->fec & QED_FEC_MODE_AUTO)
fec_bit |= FEC_FORCE_MODE_AUTO;
SET_MFW_FIELD(phy_cfg.fec_mode, FEC_FORCE_MODE, fec_bit);
}
p_hwfn->b_drv_link_init = b_up;
if (b_up) {
DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
"Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x, features 0x%08x\n",
phy_cfg.speed,
phy_cfg.pause,
phy_cfg.adv_speed,
phy_cfg.loopback_mode,
phy_cfg.feature_config_flags);
"Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x, FEC 0x%08x\n",
phy_cfg.speed, phy_cfg.pause, phy_cfg.adv_speed,
phy_cfg.loopback_mode, phy_cfg.fec_mode);
} else {
DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
"Resetting link\n");
......@@ -3805,7 +3835,8 @@ int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
u32 mcp_resp, mcp_param, features;
features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE |
DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK;
DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK |
DRV_MB_PARAM_FEATURE_SUPPORT_PORT_FEC_CONTROL;
return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT,
features, &mcp_resp, &mcp_param);
......
......@@ -38,11 +38,13 @@ struct qed_mcp_link_params {
struct qed_mcp_link_pause_params pause;
u32 loopback_mode;
struct qed_link_eee_params eee;
u32 fec;
};
struct qed_mcp_link_capabilities {
u32 speed_capabilities;
bool default_speed_autoneg;
u32 fec_default;
enum qed_mcp_eee_mode default_eee;
u32 eee_lpi_timer;
u8 eee_speed_caps;
......@@ -88,6 +90,8 @@ struct qed_mcp_link_state {
bool eee_active;
u8 eee_adv_caps;
u8 eee_lp_adv_caps;
u32 fec_active;
};
struct qed_mcp_function_info {
......
......@@ -661,6 +661,14 @@ enum qed_protocol {
QED_PROTOCOL_FCOE,
};
enum qed_fec_mode {
QED_FEC_MODE_NONE = BIT(0),
QED_FEC_MODE_FIRECODE = BIT(1),
QED_FEC_MODE_RS = BIT(2),
QED_FEC_MODE_AUTO = BIT(3),
QED_FEC_MODE_UNSUPPORTED = BIT(4),
};
struct qed_link_params {
bool link_up;
......@@ -671,6 +679,7 @@ struct qed_link_params {
#define QED_LINK_OVERRIDE_PAUSE_CONFIG BIT(3)
#define QED_LINK_OVERRIDE_LOOPBACK_MODE BIT(4)
#define QED_LINK_OVERRIDE_EEE_CONFIG BIT(5)
#define QED_LINK_OVERRIDE_FEC_CONFIG BIT(6)
bool autoneg;
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_speeds);
......@@ -689,6 +698,7 @@ struct qed_link_params {
#define QED_LINK_LOOPBACK_MAC BIT(4)
struct qed_link_eee_params eee;
u32 fec;
};
struct qed_link_output {
......@@ -709,6 +719,9 @@ struct qed_link_output {
bool eee_active;
u8 sup_caps;
struct qed_link_eee_params eee;
u32 sup_fec;
u32 active_fec;
};
struct qed_probe_params {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment