diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c')
| -rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c | 295 |
1 files changed, 210 insertions, 85 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c index 89ec0667140..ca47665f94b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c @@ -1,12 +1,12 @@ /* bnx2x_stats.c: Broadcom Everest network driver. * - * Copyright (c) 2007-2012 Broadcom Corporation + * Copyright (c) 2007-2013 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * - * Maintained by: Eilon Greenstein <eilong@broadcom.com> + * Maintained by: Ariel Elior <ariel.elior@qlogic.com> * Written by: Eliezer Tamir * Based on code from Michael Chan's bnx2 driver * UDP CSUM errata workaround by Arik Gendelman @@ -19,7 +19,7 @@ #include "bnx2x_stats.h" #include "bnx2x_cmn.h" - +#include "bnx2x_sriov.h" /* Statistics */ @@ -79,6 +79,42 @@ static inline u16 bnx2x_get_port_stats_dma_len(struct bnx2x *bp) * Init service functions */ +static void bnx2x_dp_stats(struct bnx2x *bp) +{ + int i; + + DP(BNX2X_MSG_STATS, "dumping stats:\n" + "fw_stats_req\n" + " hdr\n" + " cmd_num %d\n" + " reserved0 %d\n" + " drv_stats_counter %d\n" + " reserved1 %d\n" + " stats_counters_addrs %x %x\n", + bp->fw_stats_req->hdr.cmd_num, + bp->fw_stats_req->hdr.reserved0, + bp->fw_stats_req->hdr.drv_stats_counter, + bp->fw_stats_req->hdr.reserved1, + bp->fw_stats_req->hdr.stats_counters_addrs.hi, + bp->fw_stats_req->hdr.stats_counters_addrs.lo); + + for (i = 0; i < bp->fw_stats_req->hdr.cmd_num; i++) { + DP(BNX2X_MSG_STATS, + "query[%d]\n" + " kind %d\n" + " index %d\n" + " funcID %d\n" + " reserved %d\n" + " address %x %x\n", + i, bp->fw_stats_req->query[i].kind, + bp->fw_stats_req->query[i].index, + bp->fw_stats_req->query[i].funcID, + bp->fw_stats_req->query[i].reserved, + bp->fw_stats_req->query[i].address.hi, + bp->fw_stats_req->query[i].address.lo); + } +} + /* Post the next statistics ramrod. Protect it with the spin in * order to ensure the strict order between statistics ramrods * (each ramrod has a sequence number passed in a @@ -103,7 +139,9 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp) DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n", bp->fw_stats_req->hdr.drv_stats_counter); - + /* adjust the ramrod to include VF queues statistics */ + bnx2x_iov_adjust_stats_req(bp); + bnx2x_dp_stats(bp); /* send FW stats ramrod */ rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0, @@ -158,7 +196,7 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp) } else if (bp->func_stx) { *stats_comp = 0; - bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); + bnx2x_issue_dmae_with_comp(bp, dmae, stats_comp); } } @@ -174,7 +212,7 @@ static int bnx2x_stats_comp(struct bnx2x *bp) break; } cnt--; - usleep_range(1000, 1000); + usleep_range(1000, 2000); } return 1; } @@ -183,7 +221,8 @@ static int bnx2x_stats_comp(struct bnx2x *bp) * Statistics service functions */ -static void bnx2x_stats_pmf_update(struct bnx2x *bp) +/* should be called under stats_sema */ +static void __bnx2x_stats_pmf_update(struct bnx2x *bp) { struct dmae_command *dmae; u32 opcode; @@ -480,29 +519,61 @@ static void bnx2x_func_stats_init(struct bnx2x *bp) *stats_comp = 0; } -static void bnx2x_stats_start(struct bnx2x *bp) +/* should be called under stats_sema */ +static void __bnx2x_stats_start(struct bnx2x *bp) { - if (bp->port.pmf) - bnx2x_port_stats_init(bp); + if (IS_PF(bp)) { + if (bp->port.pmf) + bnx2x_port_stats_init(bp); - else if (bp->func_stx) - bnx2x_func_stats_init(bp); + else if (bp->func_stx) + bnx2x_func_stats_init(bp); - bnx2x_hw_stats_post(bp); - bnx2x_storm_stats_post(bp); + bnx2x_hw_stats_post(bp); + bnx2x_storm_stats_post(bp); + } + + bp->stats_started = true; +} + +static void bnx2x_stats_start(struct bnx2x *bp) +{ + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); + __bnx2x_stats_start(bp); + up(&bp->stats_sema); } static void bnx2x_stats_pmf_start(struct bnx2x *bp) { + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); bnx2x_stats_comp(bp); - bnx2x_stats_pmf_update(bp); - bnx2x_stats_start(bp); + __bnx2x_stats_pmf_update(bp); + __bnx2x_stats_start(bp); + up(&bp->stats_sema); +} + +static void bnx2x_stats_pmf_update(struct bnx2x *bp) +{ + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); + __bnx2x_stats_pmf_update(bp); + up(&bp->stats_sema); } static void bnx2x_stats_restart(struct bnx2x *bp) { + /* vfs travel through here as part of the statistics FSM, but no action + * is required + */ + if (IS_VF(bp)) + return; + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); bnx2x_stats_comp(bp); - bnx2x_stats_start(bp); + __bnx2x_stats_start(bp); + up(&bp->stats_sema); } static void bnx2x_bmac_stats_update(struct bnx2x *bp) @@ -832,25 +903,14 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp) return 0; } -static int bnx2x_storm_stats_update(struct bnx2x *bp) +static int bnx2x_storm_stats_validate_counters(struct bnx2x *bp) { - struct tstorm_per_port_stats *tport = - &bp->fw_stats_data->port.tstorm_port_statistics; - struct tstorm_per_pf_stats *tfunc = - &bp->fw_stats_data->pf.tstorm_pf_statistics; - struct host_func_stats *fstats = &bp->func_stats; - struct bnx2x_eth_stats *estats = &bp->eth_stats; - struct bnx2x_eth_stats_old *estats_old = &bp->eth_stats_old; struct stats_counter *counters = &bp->fw_stats_data->storm_counters; - int i; u16 cur_stats_counter; - /* Make sure we use the value of the counter * used for sending the last stats ramrod. */ - spin_lock_bh(&bp->stats_lock); cur_stats_counter = bp->stats_counter - 1; - spin_unlock_bh(&bp->stats_lock); /* are storm stats valid? */ if (le16_to_cpu(counters->xstats_counter) != cur_stats_counter) { @@ -880,6 +940,23 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) le16_to_cpu(counters->tstats_counter), bp->stats_counter); return -EAGAIN; } + return 0; +} + +static int bnx2x_storm_stats_update(struct bnx2x *bp) +{ + struct tstorm_per_port_stats *tport = + &bp->fw_stats_data->port.tstorm_port_statistics; + struct tstorm_per_pf_stats *tfunc = + &bp->fw_stats_data->pf.tstorm_pf_statistics; + struct host_func_stats *fstats = &bp->func_stats; + struct bnx2x_eth_stats *estats = &bp->eth_stats; + struct bnx2x_eth_stats_old *estats_old = &bp->eth_stats_old; + int i; + + /* vfs stat counter is managed by pf */ + if (IS_PF(bp) && bnx2x_storm_stats_validate_counters(bp)) + return -EAGAIN; estats->error_bytes_received_hi = 0; estats->error_bytes_received_lo = 0; @@ -945,7 +1022,6 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) qstats->valid_bytes_received_lo = qstats->total_bytes_received_lo; - UPDATE_EXTEND_TSTAT(rcv_ucast_pkts, total_unicast_packets_received); UPDATE_EXTEND_TSTAT(rcv_mcast_pkts, @@ -953,8 +1029,8 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) UPDATE_EXTEND_TSTAT(rcv_bcast_pkts, total_broadcast_packets_received); UPDATE_EXTEND_E_TSTAT(pkts_too_big_discard, - etherstatsoverrsizepkts); - UPDATE_EXTEND_E_TSTAT(no_buff_discard, no_buff_discard); + etherstatsoverrsizepkts, 32); + UPDATE_EXTEND_E_TSTAT(no_buff_discard, no_buff_discard, 16); SUB_EXTEND_USTAT(ucast_no_buff_pkts, total_unicast_packets_received); @@ -1033,15 +1109,15 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) estats->total_bytes_received_lo, estats->rx_stat_ifhcinbadoctets_lo); - ADD_64(estats->total_bytes_received_hi, - le32_to_cpu(tfunc->rcv_error_bytes.hi), - estats->total_bytes_received_lo, - le32_to_cpu(tfunc->rcv_error_bytes.lo)); + ADD_64_LE(estats->total_bytes_received_hi, + tfunc->rcv_error_bytes.hi, + estats->total_bytes_received_lo, + tfunc->rcv_error_bytes.lo); - ADD_64(estats->error_bytes_received_hi, - le32_to_cpu(tfunc->rcv_error_bytes.hi), - estats->error_bytes_received_lo, - le32_to_cpu(tfunc->rcv_error_bytes.lo)); + ADD_64_LE(estats->error_bytes_received_hi, + tfunc->rcv_error_bytes.hi, + estats->error_bytes_received_lo, + tfunc->rcv_error_bytes.lo); UPDATE_ESTAT(etherstatsoverrsizepkts, rx_stat_dot3statsframestoolong); @@ -1171,26 +1247,43 @@ static void bnx2x_stats_update(struct bnx2x *bp) { u32 *stats_comp = bnx2x_sp(bp, stats_comp); - if (bnx2x_edebug_stats_stopped(bp)) + /* we run update from timer context, so give up + * if somebody is in the middle of transition + */ + if (down_trylock(&bp->stats_sema)) return; - if (*stats_comp != DMAE_COMP_VAL) - return; + if (bnx2x_edebug_stats_stopped(bp) || !bp->stats_started) + goto out; - if (bp->port.pmf) - bnx2x_hw_stats_update(bp); + if (IS_PF(bp)) { + if (*stats_comp != DMAE_COMP_VAL) + goto out; - if (bnx2x_storm_stats_update(bp)) { - if (bp->stats_pending++ == 3) { - BNX2X_ERR("storm stats were not updated for 3 times\n"); - bnx2x_panic(); + if (bp->port.pmf) + bnx2x_hw_stats_update(bp); + + if (bnx2x_storm_stats_update(bp)) { + if (bp->stats_pending++ == 3) { + BNX2X_ERR("storm stats were not updated for 3 times\n"); + bnx2x_panic(); + } + goto out; } - return; + } else { + /* vf doesn't collect HW statistics, and doesn't get completions + * perform only update + */ + bnx2x_storm_stats_update(bp); } bnx2x_net_stats_update(bp); bnx2x_drv_stats_update(bp); + /* vf is done */ + if (IS_VF(bp)) + goto out; + if (netif_msg_timer(bp)) { struct bnx2x_eth_stats *estats = &bp->eth_stats; @@ -1200,6 +1293,9 @@ static void bnx2x_stats_update(struct bnx2x *bp) bnx2x_hw_stats_post(bp); bnx2x_storm_stats_post(bp); + +out: + up(&bp->stats_sema); } static void bnx2x_port_stats_stop(struct bnx2x *bp) @@ -1265,6 +1361,11 @@ static void bnx2x_stats_stop(struct bnx2x *bp) { int update = 0; + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); + + bp->stats_started = false; + bnx2x_stats_comp(bp); if (bp->port.pmf) @@ -1281,6 +1382,8 @@ static void bnx2x_stats_stop(struct bnx2x *bp) bnx2x_hw_stats_post(bp); bnx2x_stats_comp(bp); } + + up(&bp->stats_sema); } static void bnx2x_stats_do_nothing(struct bnx2x *bp) @@ -1309,15 +1412,17 @@ static const struct { void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) { enum bnx2x_stats_state state; + void (*action)(struct bnx2x *bp); if (unlikely(bp->panic)) return; spin_lock_bh(&bp->stats_lock); state = bp->stats_state; bp->stats_state = bnx2x_stats_stm[state][event].next_state; + action = bnx2x_stats_stm[state][event].action; spin_unlock_bh(&bp->stats_lock); - bnx2x_stats_stm[state][event].action(bp); + action(bp); if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp)) DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n", @@ -1479,11 +1584,51 @@ static void bnx2x_prep_fw_stats_req(struct bnx2x *bp) } } +void bnx2x_memset_stats(struct bnx2x *bp) +{ + int i; + + /* function stats */ + for_each_queue(bp, i) { + struct bnx2x_fp_stats *fp_stats = &bp->fp_stats[i]; + + memset(&fp_stats->old_tclient, 0, + sizeof(fp_stats->old_tclient)); + memset(&fp_stats->old_uclient, 0, + sizeof(fp_stats->old_uclient)); + memset(&fp_stats->old_xclient, 0, + sizeof(fp_stats->old_xclient)); + if (bp->stats_init) { + memset(&fp_stats->eth_q_stats, 0, + sizeof(fp_stats->eth_q_stats)); + memset(&fp_stats->eth_q_stats_old, 0, + sizeof(fp_stats->eth_q_stats_old)); + } + } + + memset(&bp->dev->stats, 0, sizeof(bp->dev->stats)); + + if (bp->stats_init) { + memset(&bp->net_stats_old, 0, sizeof(bp->net_stats_old)); + memset(&bp->fw_stats_old, 0, sizeof(bp->fw_stats_old)); + memset(&bp->eth_stats_old, 0, sizeof(bp->eth_stats_old)); + memset(&bp->eth_stats, 0, sizeof(bp->eth_stats)); + memset(&bp->func_stats, 0, sizeof(bp->func_stats)); + } + + bp->stats_state = STATS_STATE_DISABLED; + + if (bp->port.pmf && bp->port.port_stx) + bnx2x_port_stats_base_init(bp); + + /* mark the end of statistics initializiation */ + bp->stats_init = false; +} + void bnx2x_stats_init(struct bnx2x *bp) { int /*abs*/port = BP_PORT(bp); int mb_idx = BP_FW_MB_IDX(bp); - int i; bp->stats_pending = 0; bp->executer_idx = 0; @@ -1519,36 +1664,11 @@ void bnx2x_stats_init(struct bnx2x *bp) &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2); } - /* function stats */ - for_each_queue(bp, i) { - struct bnx2x_fp_stats *fp_stats = &bp->fp_stats[i]; - - memset(&fp_stats->old_tclient, 0, - sizeof(fp_stats->old_tclient)); - memset(&fp_stats->old_uclient, 0, - sizeof(fp_stats->old_uclient)); - memset(&fp_stats->old_xclient, 0, - sizeof(fp_stats->old_xclient)); - if (bp->stats_init) { - memset(&fp_stats->eth_q_stats, 0, - sizeof(fp_stats->eth_q_stats)); - memset(&fp_stats->eth_q_stats_old, 0, - sizeof(fp_stats->eth_q_stats_old)); - } - } - /* Prepare statistics ramrod data */ bnx2x_prep_fw_stats_req(bp); - memset(&bp->dev->stats, 0, sizeof(bp->dev->stats)); + /* Clean SP from previous statistics */ if (bp->stats_init) { - memset(&bp->net_stats_old, 0, sizeof(bp->net_stats_old)); - memset(&bp->fw_stats_old, 0, sizeof(bp->fw_stats_old)); - memset(&bp->eth_stats_old, 0, sizeof(bp->eth_stats_old)); - memset(&bp->eth_stats, 0, sizeof(bp->eth_stats)); - memset(&bp->func_stats, 0, sizeof(bp->func_stats)); - - /* Clean SP from previous statistics */ if (bp->func_stx) { memset(bnx2x_sp(bp, func_stats), 0, sizeof(struct host_func_stats)); @@ -1558,13 +1678,7 @@ void bnx2x_stats_init(struct bnx2x *bp) } } - bp->stats_state = STATS_STATE_DISABLED; - - if (bp->port.pmf && bp->port.port_stx) - bnx2x_port_stats_base_init(bp); - - /* mark the end of statistics initializiation */ - bp->stats_init = false; + bnx2x_memset_stats(bp); } void bnx2x_save_statistics(struct bnx2x *bp) @@ -1879,3 +1993,14 @@ void bnx2x_afex_collect_stats(struct bnx2x *bp, void *void_afex_stats, estats->mac_discard); } } + +void bnx2x_stats_safe_exec(struct bnx2x *bp, + void (func_to_exec)(void *cookie), + void *cookie){ + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); + bnx2x_stats_comp(bp); + func_to_exec(cookie); + __bnx2x_stats_start(bp); + up(&bp->stats_sema); +} |
