lkml.org 
[lkml]   [2021]   [Dec]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 101/130] atlantic: Fix statistics logic for production hardware
    Date
    From: Dmitry Bogdanov <dbezrukov@marvell.com>

    commit 2087ced0fc3a6d45203925750a2b1bcd5402e639 upstream.

    B0 is the main and widespread device revision of atlantic2 HW. In the
    current state, driver will incorrectly fetch the statistics for this
    revision.

    Fixes: 5cfd54d7dc186 ("net: atlantic: minimal A2 fw_ops")
    Signed-off-by: Dmitry Bogdanov <dbezrukov@marvell.com>
    Signed-off-by: Sudarsana Reddy Kalluru <skalluru@marvell.com>
    Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 2
    drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 10
    drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c | 15 +
    drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h | 38 +++
    drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c | 101 ++++++++--
    5 files changed, 139 insertions(+), 27 deletions(-)

    --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
    +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
    @@ -80,6 +80,8 @@ struct aq_hw_link_status_s {
    };

    struct aq_stats_s {
    + u64 brc;
    + u64 btc;
    u64 uprc;
    u64 mprc;
    u64 bprc;
    --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
    +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
    @@ -903,8 +903,14 @@ u64 *aq_nic_get_stats(struct aq_nic_s *s
    data[++i] = stats->mbtc;
    data[++i] = stats->bbrc;
    data[++i] = stats->bbtc;
    - data[++i] = stats->ubrc + stats->mbrc + stats->bbrc;
    - data[++i] = stats->ubtc + stats->mbtc + stats->bbtc;
    + if (stats->brc)
    + data[++i] = stats->brc;
    + else
    + data[++i] = stats->ubrc + stats->mbrc + stats->bbrc;
    + if (stats->btc)
    + data[++i] = stats->btc;
    + else
    + data[++i] = stats->ubtc + stats->mbtc + stats->bbtc;
    data[++i] = stats->dma_pkt_rc;
    data[++i] = stats->dma_pkt_tc;
    data[++i] = stats->dma_oct_rc;
    --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
    +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
    @@ -867,12 +867,20 @@ static int hw_atl_fw1x_deinit(struct aq_
    int hw_atl_utils_update_stats(struct aq_hw_s *self)
    {
    struct aq_stats_s *cs = &self->curr_stats;
    + struct aq_stats_s curr_stats = *cs;
    struct hw_atl_utils_mbox mbox;
    + bool corrupted_stats = false;

    hw_atl_utils_mpi_read_stats(self, &mbox);

    -#define AQ_SDELTA(_N_) (self->curr_stats._N_ += \
    - mbox.stats._N_ - self->last_stats._N_)
    +#define AQ_SDELTA(_N_) \
    +do { \
    + if (!corrupted_stats && \
    + ((s64)(mbox.stats._N_ - self->last_stats._N_)) >= 0) \
    + curr_stats._N_ += mbox.stats._N_ - self->last_stats._N_; \
    + else \
    + corrupted_stats = true; \
    +} while (0)

    if (self->aq_link_status.mbps) {
    AQ_SDELTA(uprc);
    @@ -892,6 +900,9 @@ int hw_atl_utils_update_stats(struct aq_
    AQ_SDELTA(bbrc);
    AQ_SDELTA(bbtc);
    AQ_SDELTA(dpc);
    +
    + if (!corrupted_stats)
    + *cs = curr_stats;
    }
    #undef AQ_SDELTA

    --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h
    +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.h
    @@ -239,7 +239,8 @@ struct version_s {
    u8 minor;
    u16 build;
    } phy;
    - u32 rsvd;
    + u32 drv_iface_ver:4;
    + u32 rsvd:28;
    };

    struct link_status_s {
    @@ -424,7 +425,7 @@ struct cable_diag_status_s {
    u16 rsvd2;
    };

    -struct statistics_s {
    +struct statistics_a0_s {
    struct {
    u32 link_up;
    u32 link_down;
    @@ -457,6 +458,33 @@ struct statistics_s {
    u32 reserve_fw_gap;
    };

    +struct __packed statistics_b0_s {
    + u64 rx_good_octets;
    + u64 rx_pause_frames;
    + u64 rx_good_frames;
    + u64 rx_errors;
    + u64 rx_unicast_frames;
    + u64 rx_multicast_frames;
    + u64 rx_broadcast_frames;
    +
    + u64 tx_good_octets;
    + u64 tx_pause_frames;
    + u64 tx_good_frames;
    + u64 tx_errors;
    + u64 tx_unicast_frames;
    + u64 tx_multicast_frames;
    + u64 tx_broadcast_frames;
    +
    + u32 main_loop_cycles;
    +};
    +
    +struct __packed statistics_s {
    + union __packed {
    + struct statistics_a0_s a0;
    + struct statistics_b0_s b0;
    + };
    +};
    +
    struct filter_caps_s {
    u8 l2_filters_base_index:6;
    u8 flexible_filter_mask:2;
    @@ -545,7 +573,7 @@ struct management_status_s {
    u32 rsvd5;
    };

    -struct fw_interface_out {
    +struct __packed fw_interface_out {
    struct transaction_counter_s transaction_id;
    struct version_s version;
    struct link_status_s link_status;
    @@ -569,7 +597,6 @@ struct fw_interface_out {
    struct core_dump_s core_dump;
    u32 rsvd11;
    struct statistics_s stats;
    - u32 rsvd12;
    struct filter_caps_s filter_caps;
    struct device_caps_s device_caps;
    u32 rsvd13;
    @@ -592,6 +619,9 @@ struct fw_interface_out {
    #define AQ_HOST_MODE_LOW_POWER 3U
    #define AQ_HOST_MODE_SHUTDOWN 4U

    +#define AQ_A2_FW_INTERFACE_A0 0
    +#define AQ_A2_FW_INTERFACE_B0 1
    +
    int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops);

    int hw_atl2_utils_soft_reset(struct aq_hw_s *self);
    --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
    +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
    @@ -333,18 +333,22 @@ static int aq_a2_fw_get_mac_permanent(st
    return 0;
    }

    -static int aq_a2_fw_update_stats(struct aq_hw_s *self)
    +static void aq_a2_fill_a0_stats(struct aq_hw_s *self,
    + struct statistics_s *stats)
    {
    struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
    - struct statistics_s stats;
    - int err;
    -
    - err = hw_atl2_shared_buffer_read_safe(self, stats, &stats);
    - if (err)
    - return err;
    -
    -#define AQ_SDELTA(_N_, _F_) (self->curr_stats._N_ += \
    - stats.msm._F_ - priv->last_stats.msm._F_)
    + struct aq_stats_s *cs = &self->curr_stats;
    + struct aq_stats_s curr_stats = *cs;
    + bool corrupted_stats = false;
    +
    +#define AQ_SDELTA(_N, _F) \
    +do { \
    + if (!corrupted_stats && \
    + ((s64)(stats->a0.msm._F - priv->last_stats.a0.msm._F)) >= 0) \
    + curr_stats._N += stats->a0.msm._F - priv->last_stats.a0.msm._F;\
    + else \
    + corrupted_stats = true; \
    +} while (0)

    if (self->aq_link_status.mbps) {
    AQ_SDELTA(uprc, rx_unicast_frames);
    @@ -363,17 +367,76 @@ static int aq_a2_fw_update_stats(struct
    AQ_SDELTA(mbtc, tx_multicast_octets);
    AQ_SDELTA(bbrc, rx_broadcast_octets);
    AQ_SDELTA(bbtc, tx_broadcast_octets);
    +
    + if (!corrupted_stats)
    + *cs = curr_stats;
    + }
    +#undef AQ_SDELTA
    +
    +}
    +
    +static void aq_a2_fill_b0_stats(struct aq_hw_s *self,
    + struct statistics_s *stats)
    +{
    + struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
    + struct aq_stats_s *cs = &self->curr_stats;
    + struct aq_stats_s curr_stats = *cs;
    + bool corrupted_stats = false;
    +
    +#define AQ_SDELTA(_N, _F) \
    +do { \
    + if (!corrupted_stats && \
    + ((s64)(stats->b0._F - priv->last_stats.b0._F)) >= 0) \
    + curr_stats._N += stats->b0._F - priv->last_stats.b0._F; \
    + else \
    + corrupted_stats = true; \
    +} while (0)
    +
    + if (self->aq_link_status.mbps) {
    + AQ_SDELTA(uprc, rx_unicast_frames);
    + AQ_SDELTA(mprc, rx_multicast_frames);
    + AQ_SDELTA(bprc, rx_broadcast_frames);
    + AQ_SDELTA(erpr, rx_errors);
    + AQ_SDELTA(brc, rx_good_octets);
    +
    + AQ_SDELTA(uptc, tx_unicast_frames);
    + AQ_SDELTA(mptc, tx_multicast_frames);
    + AQ_SDELTA(bptc, tx_broadcast_frames);
    + AQ_SDELTA(erpt, tx_errors);
    + AQ_SDELTA(btc, tx_good_octets);
    +
    + if (!corrupted_stats)
    + *cs = curr_stats;
    }
    #undef AQ_SDELTA
    - self->curr_stats.dma_pkt_rc =
    - hw_atl_stats_rx_dma_good_pkt_counter_get(self);
    - self->curr_stats.dma_pkt_tc =
    - hw_atl_stats_tx_dma_good_pkt_counter_get(self);
    - self->curr_stats.dma_oct_rc =
    - hw_atl_stats_rx_dma_good_octet_counter_get(self);
    - self->curr_stats.dma_oct_tc =
    - hw_atl_stats_tx_dma_good_octet_counter_get(self);
    - self->curr_stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
    +}
    +
    +static int aq_a2_fw_update_stats(struct aq_hw_s *self)
    +{
    + struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
    + struct aq_stats_s *cs = &self->curr_stats;
    + struct statistics_s stats;
    + struct version_s version;
    + int err;
    +
    + err = hw_atl2_shared_buffer_read_safe(self, version, &version);
    + if (err)
    + return err;
    +
    + err = hw_atl2_shared_buffer_read_safe(self, stats, &stats);
    + if (err)
    + return err;
    +
    + if (version.drv_iface_ver == AQ_A2_FW_INTERFACE_A0)
    + aq_a2_fill_a0_stats(self, &stats);
    + else
    + aq_a2_fill_b0_stats(self, &stats);
    +
    + cs->dma_pkt_rc = hw_atl_stats_rx_dma_good_pkt_counter_get(self);
    + cs->dma_pkt_tc = hw_atl_stats_tx_dma_good_pkt_counter_get(self);
    + cs->dma_oct_rc = hw_atl_stats_rx_dma_good_octet_counter_get(self);
    + cs->dma_oct_tc = hw_atl_stats_tx_dma_good_octet_counter_get(self);
    + cs->dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);

    memcpy(&priv->last_stats, &stats, sizeof(stats));


    \
     
     \ /
      Last update: 2021-12-06 16:41    [W:4.039 / U:0.172 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site