bnx2x: link report improvements
To avoid link notification duplication Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com> Signed-off-by: Vladislav Zolotarov <vladz@broadcom.com> Signed-off-by: Eilon Greenstein <eilong@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
34da9e50e9
commit
2ae17f6660
4 changed files with 141 additions and 35 deletions
|
@ -893,6 +893,22 @@ typedef enum {
|
|||
(&bp->def_status_blk->sp_sb.\
|
||||
index_values[HC_SP_INDEX_EQ_CONS])
|
||||
|
||||
/* This is a data that will be used to create a link report message.
|
||||
* We will keep the data used for the last link report in order
|
||||
* to prevent reporting the same link parameters twice.
|
||||
*/
|
||||
struct bnx2x_link_report_data {
|
||||
u16 line_speed; /* Effective line speed */
|
||||
unsigned long link_report_flags;/* BNX2X_LINK_REPORT_XXX flags */
|
||||
};
|
||||
|
||||
enum {
|
||||
BNX2X_LINK_REPORT_FD, /* Full DUPLEX */
|
||||
BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
BNX2X_LINK_REPORT_RX_FC_ON,
|
||||
BNX2X_LINK_REPORT_TX_FC_ON,
|
||||
};
|
||||
|
||||
struct bnx2x {
|
||||
/* Fields used in the tx and intr/napi performance paths
|
||||
* are grouped together in the beginning of the structure
|
||||
|
@ -1025,6 +1041,9 @@ struct bnx2x {
|
|||
|
||||
struct link_params link_params;
|
||||
struct link_vars link_vars;
|
||||
u32 link_cnt;
|
||||
struct bnx2x_link_report_data last_reported_link;
|
||||
|
||||
struct mdio_if_info mdio;
|
||||
|
||||
struct bnx2x_common common;
|
||||
|
@ -1441,6 +1460,8 @@ struct bnx2x_func_init_params {
|
|||
#define WAIT_RAMROD_POLL 0x01
|
||||
#define WAIT_RAMROD_COMMON 0x02
|
||||
|
||||
void bnx2x_read_mf_cfg(struct bnx2x *bp);
|
||||
|
||||
/* dmae */
|
||||
void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32);
|
||||
void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
|
||||
|
|
|
@ -758,35 +758,119 @@ u16 bnx2x_get_mf_speed(struct bnx2x *bp)
|
|||
return line_speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* bnx2x_fill_report_data - fill link report data to report
|
||||
*
|
||||
* @bp: driver handle
|
||||
* @data: link state to update
|
||||
*
|
||||
* It uses a none-atomic bit operations because is called under the mutex.
|
||||
*/
|
||||
static inline void bnx2x_fill_report_data(struct bnx2x *bp,
|
||||
struct bnx2x_link_report_data *data)
|
||||
{
|
||||
u16 line_speed = bnx2x_get_mf_speed(bp);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
|
||||
/* Fill the report data: efective line speed */
|
||||
data->line_speed = line_speed;
|
||||
|
||||
/* Link is down */
|
||||
if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS))
|
||||
__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&data->link_report_flags);
|
||||
|
||||
/* Full DUPLEX */
|
||||
if (bp->link_vars.duplex == DUPLEX_FULL)
|
||||
__set_bit(BNX2X_LINK_REPORT_FD, &data->link_report_flags);
|
||||
|
||||
/* Rx Flow Control is ON */
|
||||
if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX)
|
||||
__set_bit(BNX2X_LINK_REPORT_RX_FC_ON, &data->link_report_flags);
|
||||
|
||||
/* Tx Flow Control is ON */
|
||||
if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
|
||||
__set_bit(BNX2X_LINK_REPORT_TX_FC_ON, &data->link_report_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* bnx2x_link_report - report link status to OS.
|
||||
*
|
||||
* @bp: driver handle
|
||||
*
|
||||
* Calls the __bnx2x_link_report() under the same locking scheme
|
||||
* as a link/PHY state managing code to ensure a consistent link
|
||||
* reporting.
|
||||
*/
|
||||
|
||||
void bnx2x_link_report(struct bnx2x *bp)
|
||||
{
|
||||
if (bp->flags & MF_FUNC_DIS) {
|
||||
bnx2x_acquire_phy_lock(bp);
|
||||
__bnx2x_link_report(bp);
|
||||
bnx2x_release_phy_lock(bp);
|
||||
}
|
||||
|
||||
/**
|
||||
* __bnx2x_link_report - report link status to OS.
|
||||
*
|
||||
* @bp: driver handle
|
||||
*
|
||||
* None atomic inmlementation.
|
||||
* Should be called under the phy_lock.
|
||||
*/
|
||||
void __bnx2x_link_report(struct bnx2x *bp)
|
||||
{
|
||||
struct bnx2x_link_report_data cur_data;
|
||||
|
||||
/* reread mf_cfg */
|
||||
if (!CHIP_IS_E1(bp))
|
||||
bnx2x_read_mf_cfg(bp);
|
||||
|
||||
/* Read the current link report info */
|
||||
bnx2x_fill_report_data(bp, &cur_data);
|
||||
|
||||
/* Don't report link down or exactly the same link status twice */
|
||||
if (!memcmp(&cur_data, &bp->last_reported_link, sizeof(cur_data)) ||
|
||||
(test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&bp->last_reported_link.link_report_flags) &&
|
||||
test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&cur_data.link_report_flags)))
|
||||
return;
|
||||
|
||||
bp->link_cnt++;
|
||||
|
||||
/* We are going to report a new link parameters now -
|
||||
* remember the current data for the next time.
|
||||
*/
|
||||
memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data));
|
||||
|
||||
if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&cur_data.link_report_flags)) {
|
||||
netif_carrier_off(bp->dev);
|
||||
netdev_err(bp->dev, "NIC Link is Down\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bp->link_vars.link_up) {
|
||||
u16 line_speed;
|
||||
|
||||
if (bp->state == BNX2X_STATE_OPEN)
|
||||
} else {
|
||||
netif_carrier_on(bp->dev);
|
||||
netdev_info(bp->dev, "NIC Link is Up, ");
|
||||
pr_cont("%d Mbps ", cur_data.line_speed);
|
||||
|
||||
line_speed = bnx2x_get_mf_speed(bp);
|
||||
|
||||
pr_cont("%d Mbps ", line_speed);
|
||||
|
||||
if (bp->link_vars.duplex == DUPLEX_FULL)
|
||||
if (test_and_clear_bit(BNX2X_LINK_REPORT_FD,
|
||||
&cur_data.link_report_flags))
|
||||
pr_cont("full duplex");
|
||||
else
|
||||
pr_cont("half duplex");
|
||||
|
||||
if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) {
|
||||
if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) {
|
||||
/* Handle the FC at the end so that only these flags would be
|
||||
* possibly set. This way we may easily check if there is no FC
|
||||
* enabled.
|
||||
*/
|
||||
if (cur_data.link_report_flags) {
|
||||
if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON,
|
||||
&cur_data.link_report_flags)) {
|
||||
pr_cont(", receive ");
|
||||
if (bp->link_vars.flow_ctrl &
|
||||
BNX2X_FLOW_CTRL_TX)
|
||||
if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON,
|
||||
&cur_data.link_report_flags))
|
||||
pr_cont("& transmit ");
|
||||
} else {
|
||||
pr_cont(", transmit ");
|
||||
|
@ -794,10 +878,6 @@ void bnx2x_link_report(struct bnx2x *bp)
|
|||
pr_cont("flow control ON");
|
||||
}
|
||||
pr_cont("\n");
|
||||
|
||||
} else { /* link_down */
|
||||
netif_carrier_off(bp->dev);
|
||||
netdev_err(bp->dev, "NIC Link is Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1345,6 +1425,13 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
|||
|
||||
bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
|
||||
|
||||
/* Set the initial link reported state to link down */
|
||||
bnx2x_acquire_phy_lock(bp);
|
||||
memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link));
|
||||
__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
|
||||
&bp->last_reported_link.link_report_flags);
|
||||
bnx2x_release_phy_lock(bp);
|
||||
|
||||
/* must be called before memory allocation and HW init */
|
||||
bnx2x_ilt_set_info(bp);
|
||||
|
||||
|
|
|
@ -67,11 +67,12 @@ void bnx2x__link_status_update(struct bnx2x *bp);
|
|||
* Report link status to upper layer
|
||||
*
|
||||
* @param bp
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
void bnx2x_link_report(struct bnx2x *bp);
|
||||
|
||||
/* None-atomic version of bnx2x_link_report() */
|
||||
void __bnx2x_link_report(struct bnx2x *bp);
|
||||
|
||||
/**
|
||||
* calculates MF speed according to current linespeed and MF
|
||||
* configuration
|
||||
|
|
|
@ -2036,7 +2036,7 @@ static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp)
|
|||
return CMNG_FNS_NONE;
|
||||
}
|
||||
|
||||
static void bnx2x_read_mf_cfg(struct bnx2x *bp)
|
||||
void bnx2x_read_mf_cfg(struct bnx2x *bp)
|
||||
{
|
||||
int vn, n = (CHIP_MODE_IS_4_PORT(bp) ? 2 : 1);
|
||||
|
||||
|
@ -2123,7 +2123,6 @@ static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
|
|||
/* This function is called upon link interrupt */
|
||||
static void bnx2x_link_attn(struct bnx2x *bp)
|
||||
{
|
||||
u32 prev_link_status = bp->link_vars.link_status;
|
||||
/* Make sure that we are synced with the current statistics */
|
||||
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
|
||||
|
||||
|
@ -2168,17 +2167,15 @@ static void bnx2x_link_attn(struct bnx2x *bp)
|
|||
"single function mode without fairness\n");
|
||||
}
|
||||
|
||||
__bnx2x_link_report(bp);
|
||||
|
||||
if (IS_MF(bp))
|
||||
bnx2x_link_sync_notify(bp);
|
||||
|
||||
/* indicate link status only if link status actually changed */
|
||||
if (prev_link_status != bp->link_vars.link_status)
|
||||
bnx2x_link_report(bp);
|
||||
}
|
||||
|
||||
void bnx2x__link_status_update(struct bnx2x *bp)
|
||||
{
|
||||
if ((bp->state != BNX2X_STATE_OPEN) || (bp->flags & MF_FUNC_DIS))
|
||||
if (bp->state != BNX2X_STATE_OPEN)
|
||||
return;
|
||||
|
||||
bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
|
||||
|
@ -2188,10 +2185,6 @@ void bnx2x__link_status_update(struct bnx2x *bp)
|
|||
else
|
||||
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
|
||||
|
||||
/* the link status update could be the result of a DCC event
|
||||
hence re-read the shmem mf configuration */
|
||||
bnx2x_read_mf_cfg(bp);
|
||||
|
||||
/* indicate link status */
|
||||
bnx2x_link_report(bp);
|
||||
}
|
||||
|
@ -3120,10 +3113,14 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
|
|||
if (val & DRV_STATUS_SET_MF_BW)
|
||||
bnx2x_set_mf_bw(bp);
|
||||
|
||||
bnx2x__link_status_update(bp);
|
||||
if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
|
||||
bnx2x_pmf_update(bp);
|
||||
|
||||
/* Always call it here: bnx2x_link_report() will
|
||||
* prevent the link indication duplication.
|
||||
*/
|
||||
bnx2x__link_status_update(bp);
|
||||
|
||||
if (bp->port.pmf &&
|
||||
(val & DRV_STATUS_DCBX_NEGOTIATION_RESULTS) &&
|
||||
bp->dcbx_enabled > 0)
|
||||
|
|
Loading…
Reference in a new issue