net/qede/base: add EEE support

- Base driver EEE (Energy efficient ethernet) support.
 - Provide supported-speed mask to driver though shared memory.
 - Read/use eee-supported capabilities value from the shared memory.
 - Update qed_fill_link() to advertise the EEE capabilities.

Signed-off-by: Rasesh Mody <rasesh.mody@cavium.com>
This commit is contained in:
Rasesh Mody 2017-09-18 18:29:55 -07:00 committed by Ferruh Yigit
parent a064d7d28b
commit 3c6a3cf607
6 changed files with 164 additions and 3 deletions

View File

@ -3108,10 +3108,42 @@ ecore_hw_get_nvm_info(struct ecore_hwfn *p_hwfn,
NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX);
link->loopback_mode = 0;
if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) {
link_temp = ecore_rd(p_hwfn, p_ptt, port_cfg_addr +
OFFSETOF(struct nvm_cfg1_port, ext_phy));
link_temp &= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_MASK;
link_temp >>= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_OFFSET;
p_caps->default_eee = ECORE_MCP_EEE_ENABLED;
link->eee.enable = true;
switch (link_temp) {
case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_DISABLED:
p_caps->default_eee = ECORE_MCP_EEE_DISABLED;
link->eee.enable = false;
break;
case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_BALANCED:
p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_BALANCED_TIME;
break;
case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_AGGRESSIVE:
p_caps->eee_lpi_timer =
EEE_TX_TIMER_USEC_AGGRESSIVE_TIME;
break;
case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_LOW_LATENCY:
p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_LATENCY_TIME;
break;
}
link->eee.tx_lpi_timer = p_caps->eee_lpi_timer;
link->eee.tx_lpi_enable = link->eee.enable;
link->eee.adv_caps = ECORE_EEE_1G_ADV | ECORE_EEE_10G_ADV;
} else {
p_caps->default_eee = ECORE_MCP_EEE_UNSUPPORTED;
}
DP_VERBOSE(p_hwfn, ECORE_MSG_LINK,
"Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x\n",
"Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x\n EEE: %02x [%08x usec]",
link->speed.forced_speed, link->speed.advertised_speeds,
link->speed.autoneg, link->pause.autoneg);
link->speed.autoneg, link->pause.autoneg,
p_caps->default_eee, p_caps->eee_lpi_timer);
/* Read Multi-function information from shmem */
addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
@ -3317,6 +3349,27 @@ static void ecore_hw_info_port_num(struct ecore_hwfn *p_hwfn,
ecore_hw_info_port_num_ah_e5(p_hwfn, p_ptt);
}
static void ecore_mcp_get_eee_caps(struct ecore_hwfn *p_hwfn,
struct ecore_ptt *p_ptt)
{
struct ecore_mcp_link_capabilities *p_caps;
u32 eee_status;
p_caps = &p_hwfn->mcp_info->link_capabilities;
if (p_caps->default_eee == ECORE_MCP_EEE_UNSUPPORTED)
return;
p_caps->eee_speed_caps = 0;
eee_status = ecore_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr +
OFFSETOF(struct public_port, eee_status));
eee_status = (eee_status & EEE_SUPPORTED_SPEED_MASK) >>
EEE_SUPPORTED_SPEED_OFFSET;
if (eee_status & EEE_1G_SUPPORTED)
p_caps->eee_speed_caps |= ECORE_EEE_1G_ADV;
if (eee_status & EEE_10G_ADV)
p_caps->eee_speed_caps |= ECORE_EEE_10G_ADV;
}
static enum _ecore_status_t
ecore_get_hw_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
enum ecore_pci_personality personality,
@ -3386,6 +3439,8 @@ ecore_get_hw_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
p_hwfn->mcp_info->func_info.ovlan;
ecore_mcp_cmd_port_init(p_hwfn, p_ptt);
ecore_mcp_get_eee_caps(p_hwfn, p_ptt);
}
if (personality != ECORE_PCI_DEFAULT) {

View File

@ -1036,6 +1036,29 @@ static void ecore_mcp_handle_transceiver_change(struct ecore_hwfn *p_hwfn,
DP_NOTICE(p_hwfn, false, "Transceiver is unplugged.\n");
}
static void ecore_mcp_read_eee_config(struct ecore_hwfn *p_hwfn,
struct ecore_ptt *p_ptt,
struct ecore_mcp_link_state *p_link)
{
u32 eee_status, val;
p_link->eee_adv_caps = 0;
p_link->eee_lp_adv_caps = 0;
eee_status = ecore_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr +
OFFSETOF(struct public_port, eee_status));
p_link->eee_active = !!(eee_status & EEE_ACTIVE_BIT);
val = (eee_status & EEE_LD_ADV_STATUS_MASK) >> EEE_LD_ADV_STATUS_SHIFT;
if (val & EEE_1G_ADV)
p_link->eee_adv_caps |= ECORE_EEE_1G_ADV;
if (val & EEE_10G_ADV)
p_link->eee_adv_caps |= ECORE_EEE_10G_ADV;
val = (eee_status & EEE_LP_ADV_STATUS_MASK) >> EEE_LP_ADV_STATUS_SHIFT;
if (val & EEE_1G_ADV)
p_link->eee_lp_adv_caps |= ECORE_EEE_1G_ADV;
if (val & EEE_10G_ADV)
p_link->eee_lp_adv_caps |= ECORE_EEE_10G_ADV;
}
static void ecore_mcp_handle_link_change(struct ecore_hwfn *p_hwfn,
struct ecore_ptt *p_ptt,
bool b_reset)
@ -1170,6 +1193,9 @@ static void ecore_mcp_handle_link_change(struct ecore_hwfn *p_hwfn,
p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT);
if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE)
ecore_mcp_read_eee_config(p_hwfn, p_ptt, p_link);
OSAL_LINK_UPDATE(p_hwfn);
}
@ -1197,6 +1223,27 @@ enum _ecore_status_t ecore_mcp_set_link(struct ecore_hwfn *p_hwfn,
phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0;
phy_cfg.adv_speed = params->speed.advertised_speeds;
phy_cfg.loopback_mode = params->loopback_mode;
/* There are MFWs that share this capability regardless of whether
* this is feasible or not. And given that at the very least adv_caps
* would be set internally by ecore, we want to make sure LFA would
* still work.
*/
if ((p_hwfn->mcp_info->capabilities &
FW_MB_PARAM_FEATURE_SUPPORT_EEE) &&
params->eee.enable) {
phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED;
if (params->eee.tx_lpi_enable)
phy_cfg.eee_cfg |= EEE_CFG_TX_LPI;
if (params->eee.adv_caps & ECORE_EEE_1G_ADV)
phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_1G;
if (params->eee.adv_caps & ECORE_EEE_10G_ADV)
phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_10G;
phy_cfg.eee_cfg |= (params->eee.tx_lpi_timer <<
EEE_TX_TIMER_USEC_SHIFT) &
EEE_TX_TIMER_USEC_MASK;
}
p_hwfn->b_drv_link_init = b_up;
if (b_up)
@ -3331,7 +3378,8 @@ enum _ecore_status_t ecore_mcp_set_capabilities(struct ecore_hwfn *p_hwfn,
{
u32 mcp_resp, mcp_param, features;
features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_SMARTLINQ;
features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_SMARTLINQ |
DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE;
return ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT,
features, &mcp_resp, &mcp_param);

View File

@ -23,16 +23,37 @@ struct ecore_mcp_link_pause_params {
bool forced_tx;
};
enum ecore_mcp_eee_mode {
ECORE_MCP_EEE_DISABLED,
ECORE_MCP_EEE_ENABLED,
ECORE_MCP_EEE_UNSUPPORTED
};
struct ecore_link_eee_params {
u32 tx_lpi_timer;
#define ECORE_EEE_1G_ADV (1 << 0)
#define ECORE_EEE_10G_ADV (1 << 1)
/* Capabilities are represented using ECORE_EEE_*_ADV values */
u8 adv_caps;
u8 lp_adv_caps;
bool enable;
bool tx_lpi_enable;
};
struct ecore_mcp_link_params {
struct ecore_mcp_link_speed_params speed;
struct ecore_mcp_link_pause_params pause;
u32 loopback_mode; /* in PMM_LOOPBACK values */
struct ecore_link_eee_params eee;
};
struct ecore_mcp_link_capabilities {
u32 speed_capabilities;
bool default_speed_autoneg; /* In Mb/s */
u32 default_speed; /* In Mb/s */
enum ecore_mcp_eee_mode default_eee;
u32 eee_lpi_timer;
u8 eee_speed_caps;
};
struct ecore_mcp_link_state {
@ -67,6 +88,10 @@ struct ecore_mcp_link_state {
u8 partner_adv_pause;
bool sfp_tx_fault;
bool eee_active;
u8 eee_adv_caps;
u8 eee_lp_adv_caps;
};
struct ecore_mcp_function_info {

View File

@ -792,6 +792,12 @@ struct public_port {
#define EEE_LP_ADV_STATUS_MASK 0x00000f00
#define EEE_LP_ADV_STATUS_SHIFT 8
/* Supported speeds for EEE */
#define EEE_SUPPORTED_SPEED_MASK 0x0000f000
#define EEE_SUPPORTED_SPEED_OFFSET 12
#define EEE_1G_SUPPORTED (1 << 1)
#define EEE_10G_SUPPORTED (1 << 2)
u32 eee_remote; /* Used for EEE in LLDP */
#define EEE_REMOTE_TW_TX_MASK 0x0000ffff
#define EEE_REMOTE_TW_TX_SHIFT 0

View File

@ -83,6 +83,7 @@ struct qed_link_params {
#define QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS (1 << 1)
#define QED_LINK_OVERRIDE_SPEED_FORCED_SPEED (1 << 2)
#define QED_LINK_OVERRIDE_PAUSE_CONFIG (1 << 3)
#define QED_LINK_OVERRIDE_EEE_CONFIG (1 << 5)
uint32_t override_flags;
bool autoneg;
uint32_t adv_speeds;
@ -91,6 +92,7 @@ struct qed_link_params {
#define QED_LINK_PAUSE_RX_ENABLE (1 << 1)
#define QED_LINK_PAUSE_TX_ENABLE (1 << 2)
uint32_t pause_config;
struct ecore_link_eee_params eee;
};
struct qed_link_output {
@ -104,6 +106,12 @@ struct qed_link_output {
uint8_t port; /* In PORT defs */
bool autoneg;
uint32_t pause_config;
/* EEE - capability & param */
bool eee_supported;
bool eee_active;
u8 sup_caps;
struct ecore_link_eee_params eee;
};
struct qed_slowpath_params {

View File

@ -539,6 +539,21 @@ static void qed_fill_link(struct ecore_hwfn *hwfn,
if (params.pause.forced_tx)
if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE;
if (link_caps.default_eee == ECORE_MCP_EEE_UNSUPPORTED) {
if_link->eee_supported = false;
} else {
if_link->eee_supported = true;
if_link->eee_active = link.eee_active;
if_link->sup_caps = link_caps.eee_speed_caps;
/* MFW clears adv_caps on eee disable; use configured value */
if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps :
params.eee.adv_caps;
if_link->eee.lp_adv_caps = link.eee_lp_adv_caps;
if_link->eee.enable = params.eee.enable;
if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable;
if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer;
}
}
static void
@ -588,6 +603,10 @@ static int qed_set_link(struct ecore_dev *edev, struct qed_link_params *params)
link_params->pause.forced_tx = false;
}
if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG)
memcpy(&link_params->eee, &params->eee,
sizeof(link_params->eee));
rc = ecore_mcp_set_link(hwfn, ptt, params->link_up);
ecore_ptt_release(hwfn, ptt);