Commit c8c60d88 authored by Yuval Mintz's avatar Yuval Mintz Committed by David S. Miller
Browse files

bnx2x: Added EEE support



This patch adds energy efficient energy support (802.3az) to bnx2x
boards with 84833 phys (and sufficiently new BC and external FW).
Signed-off-by: default avatarYuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 80f12ecc
......@@ -1067,8 +1067,18 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */
uses the same defines as link_config */
u32 mfw_wol_link_cfg2; /* 0x480 */
u32 Reserved2[17]; /* 0x484 */
/* EEE power saving mode */
u32 eee_power_mode; /* 0x484 */
#define PORT_FEAT_CFG_EEE_POWER_MODE_MASK 0x000000FF
#define PORT_FEAT_CFG_EEE_POWER_MODE_SHIFT 0
#define PORT_FEAT_CFG_EEE_POWER_MODE_DISABLED 0x00000000
#define PORT_FEAT_CFG_EEE_POWER_MODE_BALANCED 0x00000001
#define PORT_FEAT_CFG_EEE_POWER_MODE_AGGRESSIVE 0x00000002
#define PORT_FEAT_CFG_EEE_POWER_MODE_LOW_LATENCY 0x00000003
u32 Reserved2[16]; /* 0x488 */
};
......@@ -1255,6 +1265,8 @@ struct drv_func_mb {
#define DRV_MSG_CODE_DRV_INFO_ACK 0xd8000000
#define DRV_MSG_CODE_DRV_INFO_NACK 0xd9000000
#define DRV_MSG_CODE_EEE_RESULTS_ACK 0xda000000
#define DRV_MSG_CODE_SET_MF_BW 0xe0000000
#define REQ_BC_VER_4_SET_MF_BW 0x00060202
#define DRV_MSG_CODE_SET_MF_BW_ACK 0xe1000000
......@@ -1320,6 +1332,8 @@ struct drv_func_mb {
#define FW_MSG_CODE_DRV_INFO_ACK 0xd8100000
#define FW_MSG_CODE_DRV_INFO_NACK 0xd9100000
#define FW_MSG_CODE_EEE_RESULS_ACK 0xda100000
#define FW_MSG_CODE_SET_MF_BW_SENT 0xe0000000
#define FW_MSG_CODE_SET_MF_BW_DONE 0xe1000000
......@@ -1383,6 +1397,8 @@ struct drv_func_mb {
#define DRV_STATUS_DRV_INFO_REQ 0x04000000
#define DRV_STATUS_EEE_NEGOTIATION_RESULTS 0x08000000
u32 virt_mac_upper;
#define VIRT_MAC_SIGN_MASK 0xffff0000
#define VIRT_MAC_SIGNATURE 0x564d0000
......@@ -1613,6 +1629,11 @@ struct fw_flr_mb {
struct fw_flr_ack ack;
};
struct eee_remote_vals {
u32 tx_tw;
u32 rx_tw;
};
/**** SUPPORT FOR SHMEM ARRRAYS ***
* The SHMEM HSI is aligned on 32 bit boundaries which makes it difficult to
* define arrays with storage types smaller then unsigned dwords.
......@@ -2053,6 +2074,41 @@ struct shmem2_region {
#define DRV_INFO_CONTROL_OP_CODE_MASK 0x0000ff00
#define DRV_INFO_CONTROL_OP_CODE_SHIFT 8
u32 ibft_host_addr; /* initialized by option ROM */
struct eee_remote_vals eee_remote_vals[PORT_MAX];
u32 reserved[E2_FUNC_MAX];
/* the status of EEE auto-negotiation
* bits 15:0 the configured tx-lpi entry timer value. Depends on bit 31.
* bits 19:16 the supported modes for EEE.
* bits 23:20 the speeds advertised for EEE.
* bits 27:24 the speeds the Link partner advertised for EEE.
* The supported/adv. modes in bits 27:19 originate from the
* SHMEM_EEE_XXX_ADV definitions (where XXX is replaced by speed).
* bit 28 when 1'b1 EEE was requested.
* bit 29 when 1'b1 tx lpi was requested.
* bit 30 when 1'b1 EEE was negotiated. Tx lpi will be asserted iff
* 30:29 are 2'b11.
* bit 31 when 1'b0 bits 15:0 contain a PORT_FEAT_CFG_EEE_ define as
* value. When 1'b1 those bits contains a value times 16 microseconds.
*/
u32 eee_status[PORT_MAX];
#define SHMEM_EEE_TIMER_MASK 0x0000ffff
#define SHMEM_EEE_SUPPORTED_MASK 0x000f0000
#define SHMEM_EEE_SUPPORTED_SHIFT 16
#define SHMEM_EEE_ADV_STATUS_MASK 0x00f00000
#define SHMEM_EEE_100M_ADV (1<<0)
#define SHMEM_EEE_1G_ADV (1<<1)
#define SHMEM_EEE_10G_ADV (1<<2)
#define SHMEM_EEE_ADV_STATUS_SHIFT 20
#define SHMEM_EEE_LP_ADV_STATUS_MASK 0x0f000000
#define SHMEM_EEE_LP_ADV_STATUS_SHIFT 24
#define SHMEM_EEE_REQUESTED_BIT 0x10000000
#define SHMEM_EEE_LPI_REQUESTED_BIT 0x20000000
#define SHMEM_EEE_ACTIVE_BIT 0x40000000
#define SHMEM_EEE_TIME_OUTPUT_BIT 0x80000000
u32 sizeof_port_stats;
};
......@@ -2599,6 +2655,9 @@ struct host_port_stats {
u32 pfc_frames_tx_lo;
u32 pfc_frames_rx_hi;
u32 pfc_frames_rx_lo;
u32 eee_lpi_count_hi;
u32 eee_lpi_count_lo;
};
......
......@@ -1305,6 +1305,94 @@ int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
return 0;
}
/******************************************************************/
/* EEE section */
/******************************************************************/
static u8 bnx2x_eee_has_cap(struct link_params *params)
{
struct bnx2x *bp = params->bp;
if (REG_RD(bp, params->shmem2_base) <=
offsetof(struct shmem2_region, eee_status[params->port]))
return 0;
return 1;
}
static int bnx2x_eee_nvram_to_time(u32 nvram_mode, u32 *idle_timer)
{
switch (nvram_mode) {
case PORT_FEAT_CFG_EEE_POWER_MODE_BALANCED:
*idle_timer = EEE_MODE_NVRAM_BALANCED_TIME;
break;
case PORT_FEAT_CFG_EEE_POWER_MODE_AGGRESSIVE:
*idle_timer = EEE_MODE_NVRAM_AGGRESSIVE_TIME;
break;
case PORT_FEAT_CFG_EEE_POWER_MODE_LOW_LATENCY:
*idle_timer = EEE_MODE_NVRAM_LATENCY_TIME;
break;
default:
*idle_timer = 0;
break;
}
return 0;
}
static int bnx2x_eee_time_to_nvram(u32 idle_timer, u32 *nvram_mode)
{
switch (idle_timer) {
case EEE_MODE_NVRAM_BALANCED_TIME:
*nvram_mode = PORT_FEAT_CFG_EEE_POWER_MODE_BALANCED;
break;
case EEE_MODE_NVRAM_AGGRESSIVE_TIME:
*nvram_mode = PORT_FEAT_CFG_EEE_POWER_MODE_AGGRESSIVE;
break;
case EEE_MODE_NVRAM_LATENCY_TIME:
*nvram_mode = PORT_FEAT_CFG_EEE_POWER_MODE_LOW_LATENCY;
break;
default:
*nvram_mode = PORT_FEAT_CFG_EEE_POWER_MODE_DISABLED;
break;
}
return 0;
}
static u32 bnx2x_eee_calc_timer(struct link_params *params)
{
u32 eee_mode, eee_idle;
struct bnx2x *bp = params->bp;
if (params->eee_mode & EEE_MODE_OVERRIDE_NVRAM) {
if (params->eee_mode & EEE_MODE_OUTPUT_TIME) {
/* time value in eee_mode --> used directly*/
eee_idle = params->eee_mode & EEE_MODE_TIMER_MASK;
} else {
/* hsi value in eee_mode --> time */
if (bnx2x_eee_nvram_to_time(params->eee_mode &
EEE_MODE_NVRAM_MASK,
&eee_idle))
return 0;
}
} else {
/* hsi values in nvram --> time*/
eee_mode = ((REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_feature_config[params->port].
eee_power_mode)) &
PORT_FEAT_CFG_EEE_POWER_MODE_MASK) >>
PORT_FEAT_CFG_EEE_POWER_MODE_SHIFT);
if (bnx2x_eee_nvram_to_time(eee_mode, &eee_idle))
return 0;
}
return eee_idle;
}
/******************************************************************/
/* PFC section */
/******************************************************************/
......@@ -1729,6 +1817,14 @@ static int bnx2x_xmac_enable(struct link_params *params,
/* update PFC */
bnx2x_update_pfc_xmac(params, vars, 0);
if (vars->eee_status & SHMEM_EEE_ADV_STATUS_MASK) {
DP(NETIF_MSG_LINK, "Setting XMAC for EEE\n");
REG_WR(bp, xmac_base + XMAC_REG_EEE_TIMERS_HI, 0x1380008);
REG_WR(bp, xmac_base + XMAC_REG_EEE_CTRL, 0x1);
} else {
REG_WR(bp, xmac_base + XMAC_REG_EEE_CTRL, 0x0);
}
/* Enable TX and RX */
val = XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN;
......@@ -2439,6 +2535,16 @@ static void bnx2x_update_mng(struct link_params *params, u32 link_status)
port_mb[params->port].link_status), link_status);
}
static void bnx2x_update_mng_eee(struct link_params *params, u32 eee_status)
{
struct bnx2x *bp = params->bp;
if (bnx2x_eee_has_cap(params))
REG_WR(bp, params->shmem2_base +
offsetof(struct shmem2_region,
eee_status[params->port]), eee_status);
}
static void bnx2x_update_pfc_nig(struct link_params *params,
struct link_vars *vars,
struct bnx2x_nig_brb_pfc_port_params *nig_params)
......@@ -3950,6 +4056,20 @@ static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_DIGITAL4_MISC3, val | 0x8080);
/* Enable LPI pass through */
if ((params->eee_mode & EEE_MODE_ADV_LPI) &&
(phy->flags & FLAGS_EEE_10GBT) &&
(!(params->eee_mode & EEE_MODE_ENABLE_LPI) ||
bnx2x_eee_calc_timer(params)) &&
(params->req_duplex[bnx2x_phy_selection(params)] == DUPLEX_FULL)) {
DP(NETIF_MSG_LINK, "Configure WC for LPI pass through\n");
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_EEE_COMBO_CONTROL0,
0x7c);
bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_DIGITAL4_MISC5, 0xc000);
}
/* 10G XFI Full Duplex */
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x100);
......@@ -6462,6 +6582,15 @@ static int bnx2x_update_link_down(struct link_params *params,
(MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
}
if (CHIP_IS_E3(bp)) {
REG_WR(bp, MISC_REG_CPMU_LP_FW_ENABLE_P0 + (params->port << 2),
0);
REG_WR(bp, MISC_REG_CPMU_LP_DR_ENABLE, 0);
REG_WR(bp, MISC_REG_CPMU_LP_MASK_ENT_P0 + (params->port << 2),
0);
vars->eee_status &= ~(SHMEM_EEE_LP_ADV_STATUS_MASK |
SHMEM_EEE_ACTIVE_BIT);
bnx2x_update_mng_eee(params, vars->eee_status);
bnx2x_xmac_disable(params);
bnx2x_umac_disable(params);
}
......@@ -6501,6 +6630,16 @@ static int bnx2x_update_link_up(struct link_params *params,
bnx2x_umac_enable(params, vars, 0);
bnx2x_set_led(params, vars,
LED_MODE_OPER, vars->line_speed);
if ((vars->eee_status & SHMEM_EEE_ACTIVE_BIT) &&
(vars->eee_status & SHMEM_EEE_LPI_REQUESTED_BIT)) {
DP(NETIF_MSG_LINK, "Enabling LPI assertion\n");
REG_WR(bp, MISC_REG_CPMU_LP_FW_ENABLE_P0 +
(params->port << 2), 1);
REG_WR(bp, MISC_REG_CPMU_LP_DR_ENABLE, 1);
REG_WR(bp, MISC_REG_CPMU_LP_MASK_ENT_P0 +
(params->port << 2), 0xfc20);
}
}
if ((CHIP_IS_E1x(bp) ||
CHIP_IS_E2(bp))) {
......@@ -6538,7 +6677,7 @@ static int bnx2x_update_link_up(struct link_params *params,
/* update shared memory */
bnx2x_update_mng(params, vars->link_status);
bnx2x_update_mng_eee(params, vars->eee_status);
/* Check remote fault */
for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) {
......@@ -6582,6 +6721,8 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
phy_vars[phy_index].phy_link_up = 0;
phy_vars[phy_index].link_up = 0;
phy_vars[phy_index].fault_detected = 0;
/* different consideration, since vars holds inner state */
phy_vars[phy_index].eee_status = vars->eee_status;
}
if (USES_WARPCORE(bp))
......@@ -6711,6 +6852,9 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
vars->link_status |= LINK_STATUS_SERDES_LINK;
else
vars->link_status &= ~LINK_STATUS_SERDES_LINK;
vars->eee_status = phy_vars[active_external_phy].eee_status;
DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
active_external_phy);
}
......@@ -9579,9 +9723,9 @@ static int bnx2x_8481_config_init(struct bnx2x_phy *phy,
static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
struct link_params *params,
u16 fw_cmd,
u16 cmd_args[])
u16 cmd_args[], int argc)
{
u32 idx;
int idx;
u16 val;
struct bnx2x *bp = params->bp;
/* Write CMD_OPEN_OVERRIDE to STATUS reg */
......@@ -9601,7 +9745,7 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
}
/* Prepare argument(s) and issue command */
for (idx = 0; idx < PHY84833_CMDHDLR_MAX_ARGS; idx++) {
for (idx = 0; idx < argc; idx++) {
bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
MDIO_84833_CMD_HDLR_DATA1 + idx,
cmd_args[idx]);
......@@ -9622,7 +9766,7 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
return -EINVAL;
}
/* Gather returning data */
for (idx = 0; idx < PHY84833_CMDHDLR_MAX_ARGS; idx++) {
for (idx = 0; idx < argc; idx++) {
bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
MDIO_84833_CMD_HDLR_DATA1 + idx,
&cmd_args[idx]);
......@@ -9656,7 +9800,7 @@ static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy,
data[1] = (u16)pair_swap;
status = bnx2x_84833_cmd_hdlr(phy, params,
PHY84833_CMD_SET_PAIR_SWAP, data);
PHY84833_CMD_SET_PAIR_SWAP, data, PHY84833_CMDHDLR_MAX_ARGS);
if (status == 0)
DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data[1]);
......@@ -9734,6 +9878,95 @@ static int bnx2x_84833_hw_reset_phy(struct bnx2x_phy *phy,
return 0;
}
static int bnx2x_8483x_eee_timers(struct link_params *params,
struct link_vars *vars)
{
u32 eee_idle = 0, eee_mode;
struct bnx2x *bp = params->bp;
eee_idle = bnx2x_eee_calc_timer(params);
if (eee_idle) {
REG_WR(bp, MISC_REG_CPMU_LP_IDLE_THR_P0 + (params->port << 2),
eee_idle);
} else if ((params->eee_mode & EEE_MODE_ENABLE_LPI) &&
(params->eee_mode & EEE_MODE_OVERRIDE_NVRAM) &&
(params->eee_mode & EEE_MODE_OUTPUT_TIME)) {
DP(NETIF_MSG_LINK, "Error: Tx LPI is enabled with timer 0\n");
return -EINVAL;
}
vars->eee_status &= ~(SHMEM_EEE_TIMER_MASK | SHMEM_EEE_TIME_OUTPUT_BIT);
if (params->eee_mode & EEE_MODE_OUTPUT_TIME) {
/* eee_idle in 1u --> eee_status in 16u */
eee_idle >>= 4;
vars->eee_status |= (eee_idle & SHMEM_EEE_TIMER_MASK) |
SHMEM_EEE_TIME_OUTPUT_BIT;
} else {
if (bnx2x_eee_time_to_nvram(eee_idle, &eee_mode))
return -EINVAL;
vars->eee_status |= eee_mode;
}
return 0;
}
static int bnx2x_8483x_disable_eee(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
int rc;
struct bnx2x *bp = params->bp;
u16 cmd_args = 0;
DP(NETIF_MSG_LINK, "Don't Advertise 10GBase-T EEE\n");
/* Make Certain LPI is disabled */
REG_WR(bp, MISC_REG_CPMU_LP_FW_ENABLE_P0 + (params->port << 2), 0);
REG_WR(bp, MISC_REG_CPMU_LP_DR_ENABLE, 0);
/* Prevent Phy from working in EEE and advertising it */
rc = bnx2x_84833_cmd_hdlr(phy, params,
PHY84833_CMD_SET_EEE_MODE, &cmd_args, 1);
if (rc != 0) {
DP(NETIF_MSG_LINK, "EEE disable failed.\n");
return rc;
}
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_EEE_ADV, 0);
vars->eee_status &= ~SHMEM_EEE_ADV_STATUS_MASK;
return 0;
}
static int bnx2x_8483x_enable_eee(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
int rc;
struct bnx2x *bp = params->bp;
u16 cmd_args = 1;
DP(NETIF_MSG_LINK, "Advertise 10GBase-T EEE\n");
rc = bnx2x_84833_cmd_hdlr(phy, params,
PHY84833_CMD_SET_EEE_MODE, &cmd_args, 1);
if (rc != 0) {
DP(NETIF_MSG_LINK, "EEE enable failed.\n");
return rc;
}
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_EEE_ADV, 0x8);
/* Mask events preventing LPI generation */
REG_WR(bp, MISC_REG_CPMU_LP_MASK_EXT_P0 + (params->port << 2), 0xfc20);
vars->eee_status &= ~SHMEM_EEE_ADV_STATUS_MASK;
vars->eee_status |= (SHMEM_EEE_10G_ADV << SHMEM_EEE_ADV_STATUS_SHIFT);
return 0;
}
#define PHY84833_CONSTANT_LATENCY 1193
static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
struct link_params *params,
......@@ -9833,7 +10066,8 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
cmd_args[2] = PHY84833_CONSTANT_LATENCY + 1;
cmd_args[3] = PHY84833_CONSTANT_LATENCY;
rc = bnx2x_84833_cmd_hdlr(phy, params,
PHY84833_CMD_SET_EEE_MODE, cmd_args);
PHY84833_CMD_SET_EEE_MODE, cmd_args,
PHY84833_CMDHDLR_MAX_ARGS);
if (rc != 0)
DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n");
}
......@@ -9858,6 +10092,48 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
MDIO_CTL_REG_84823_USER_CTRL_REG, val);
}
bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
MDIO_84833_TOP_CFG_FW_REV, &val);
/* Configure EEE support */
if ((val >= MDIO_84833_TOP_CFG_FW_EEE) && bnx2x_eee_has_cap(params)) {
phy->flags |= FLAGS_EEE_10GBT;
vars->eee_status |= SHMEM_EEE_10G_ADV <<
SHMEM_EEE_SUPPORTED_SHIFT;
/* Propogate params' bits --> vars (for migration exposure) */
if (params->eee_mode & EEE_MODE_ENABLE_LPI)
vars->eee_status |= SHMEM_EEE_LPI_REQUESTED_BIT;
else
vars->eee_status &= ~SHMEM_EEE_LPI_REQUESTED_BIT;
if (params->eee_mode & EEE_MODE_ADV_LPI)
vars->eee_status |= SHMEM_EEE_REQUESTED_BIT;
else
vars->eee_status &= ~SHMEM_EEE_REQUESTED_BIT;
rc = bnx2x_8483x_eee_timers(params, vars);
if (rc != 0) {
DP(NETIF_MSG_LINK, "Failed to configure EEE timers\n");
bnx2x_8483x_disable_eee(phy, params, vars);
return rc;
}
if ((params->req_duplex[actual_phy_selection] == DUPLEX_FULL) &&
(params->eee_mode & EEE_MODE_ADV_LPI) &&
(bnx2x_eee_calc_timer(params) ||
!(params->eee_mode & EEE_MODE_ENABLE_LPI)))
rc = bnx2x_8483x_enable_eee(phy, params, vars);
else
rc = bnx2x_8483x_disable_eee(phy, params, vars);
if (rc != 0) {
DP(NETIF_MSG_LINK, "Failed to set EEE advertisment\n");
return rc;
}
} else {
phy->flags &= ~FLAGS_EEE_10GBT;
vars->eee_status &= ~SHMEM_EEE_SUPPORTED_MASK;
}
if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
/* Bring PHY out of super isolate mode as the final step. */
bnx2x_cl45_read(bp, phy,
......@@ -9989,6 +10265,31 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
if (val & (1<<11))
vars->link_status |=
LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
/* Determine if EEE was negotiated */
if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
u32 eee_shmem = 0;
bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
MDIO_AN_REG_EEE_ADV, &val1);
bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
MDIO_AN_REG_LP_EEE_ADV, &val2);
if ((val1 & val2) & 0x8) {
DP(NETIF_MSG_LINK, "EEE negotiated\n");
vars->eee_status |= SHMEM_EEE_ACTIVE_BIT;
}
if (val2 & 0x12)
eee_shmem |= SHMEM_EEE_100M_ADV;
if (val2 & 0x4)
eee_shmem |= SHMEM_EEE_1G_ADV;
if (val2 & 0x68)
eee_shmem |= SHMEM_EEE_10G_ADV;
vars->eee_status &= ~SHMEM_EEE_LP_ADV_STATUS_MASK;
vars->eee_status |= (eee_shmem <<
SHMEM_EEE_LP_ADV_STATUS_SHIFT);
}
}
return link_up;
......@@ -11243,7 +11544,8 @@ static struct bnx2x_phy phy_84833 = {
.def_md_devad = 0,
.flags = (FLAGS_FAN_FAILURE_DET_REQ |
FLAGS_REARM_LATCH_SIGNAL |
FLAGS_TX_ERROR_CHECK),
FLAGS_TX_ERROR_CHECK |
FLAGS_EEE_10GBT),
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
......@@ -12011,6 +12313,8 @@ int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
break;
}
bnx2x_update_mng(params, vars->link_status);
bnx2x_update_mng_eee(params, vars->eee_status);
return 0;
}
......@@ -12023,6 +12327,9 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
/* disable attentions */
vars->link_status = 0;
bnx2x_update_mng(params, vars->link_status);
vars->eee_status &= ~(SHMEM_EEE_LP_ADV_STATUS_MASK |
SHMEM_EEE_ACTIVE_BIT);
bnx2x_update_mng_eee(params, vars->eee_status);
bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
(NIG_MASK_XGXS0_LINK_STATUS |
NIG_MASK_XGXS0_LINK10G |
......
......@@ -149,6 +149,7 @@ struct bnx2x_phy {
#define FLAGS_DUMMY_READ (1<<9)
#define FLAGS_MDC_MDIO_WA_B0 (1<<10)
#define FLAGS_TX_ERROR_CHECK (1<<12)
#define FLAGS_EEE_10GBT (1<<13)
/* preemphasis values for the rx side */
u16 rx_preemphasis[4];
......@@ -265,6 +266,30 @@ struct link_params {
u8 num_phys;
u8 rsrv;
/* Used to configure the EEE Tx LPI timer, has several modes of
* operation, according to bits 29:28 -
* 2'b00: Timer will be configured by nvram, output will be the value
* from nvram.
* 2'b01: Timer will be configured by nvram, output will be in
* microseconds.
* 2'b10: bits 1:0 contain an nvram value which will be used instead
* of the one located in the nvram. Output will be that value.
* 2'b11: bits 19:0 contain the idle timer in microseconds; output
* will be in microseconds.
* Bits 31:30 should be 2'b11 in order for EEE to be enabled.
*/
u32 eee_mode;
#define EEE_MODE_NVRAM_BALANCED_TIME (0xa00)
#define EEE_MODE_NVRAM_AGGRESSIVE_TIME (0x100)
#define EEE_MODE_NVRAM_LATENCY_TIME (0x6000)
#define EEE_MODE_NVRAM_MASK (0x3)
#define EEE_MODE_TIMER_MASK (0xfffff)
#define EEE_MODE_OUTPUT_TIME (1<<28)
#define EEE_MODE_OVERRIDE_NVRAM (1<<29)
#define EEE_MODE_ENABLE_LPI (1<<30)
#define EEE_MODE_ADV_LPI (1<<31)
u16 hw_led_mode; /* part of the hw_config read from the shmem */
u32 multi_phy_config;
......@@ -301,6 +326,7 @@ struct link_vars {
/* The same definitions as the shmem parameter */
u32 link_status;
u32 eee_status;
u8 fault_detected;
u8 rsrv1;
u16 periodic_flags;
......
......@@ -3176,6 +3176,12 @@ static void bnx2x_set_mf_bw(struct bnx2x *bp)
bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW_ACK, 0);
}
static void bnx2x_handle_eee_event(struct bnx2x *bp)
{
DP(BNX2X_MSG_MCP, "EEE - LLDP event\n");
bnx2x_fw_command(bp, DRV_MSG_CODE_EEE_RESULTS_ACK, 0);
}
static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
{
enum drv_info_opcode op_code;
......@@ -3742,6 +3748,8 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
if (val & DRV_STATUS_AFEX_EVENT_MASK)
bnx2x_handle_afex_cmd(bp,
val & DRV_STATUS_AFEX_EVENT_MASK);
if (val & DRV_STATUS_EEE_NEGOTIATION_RESULTS)
bnx2x_handle_eee_event(bp);
if (bp->link_vars.periodic_flags &
PERIODIC_FLAGS_LINK_EVENT) {
/* sync with link */
......@@ -10082,7 +10090,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
{
int port = BP_PORT(bp);
u32 config;
u32 ext_phy_type, ext_phy_config;
u32 ext_phy_type, ext_phy_config, eee_mode;