]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
mlxsw: spectrum: Collect tclass related stats periodically
authorNogah Frankel <nogahf@mellanox.com>
Mon, 6 Nov 2017 06:23:47 +0000 (07:23 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 8 Nov 2017 03:23:38 +0000 (12:23 +0900)
Add more statistics to be collected from the HW periodically. These stats
are tclass based (beside ECN marked packet, that exist only port based).
They are needed to expose RED qdisc stats and xstats correctly.

Signed-off-by: Nogah Frankel <nogahf@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h

index e42b3e7bd588cb849badb9ca6fc4ce58ff6ea2bb..1497b436be781b23a0b3986a1a409c8330223e31 100644 (file)
@@ -1324,6 +1324,38 @@ static int mlxsw_sp_port_get_hw_stats(struct net_device *dev,
        return err;
 }
 
+static void
+mlxsw_sp_port_get_hw_xstats(struct net_device *dev,
+                           struct mlxsw_sp_port_xstats *xstats)
+{
+       char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
+       int err, i;
+
+       err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_EXT_CNT, 0,
+                                         ppcnt_pl);
+       if (!err)
+               xstats->ecn = mlxsw_reg_ppcnt_ecn_marked_get(ppcnt_pl);
+
+       for (i = 0; i < TC_MAX_QUEUE; i++) {
+               err = mlxsw_sp_port_get_stats_raw(dev,
+                                                 MLXSW_REG_PPCNT_TC_CONG_TC,
+                                                 i, ppcnt_pl);
+               if (!err)
+                       xstats->wred_drop[i] =
+                               mlxsw_reg_ppcnt_wred_discard_get(ppcnt_pl);
+
+               err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_TC_CNT,
+                                                 i, ppcnt_pl);
+               if (err)
+                       continue;
+
+               xstats->backlog[i] =
+                       mlxsw_reg_ppcnt_tc_transmit_queue_get(ppcnt_pl);
+               xstats->tail_drop[i] =
+                       mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get(ppcnt_pl);
+       }
+}
+
 static void update_stats_cache(struct work_struct *work)
 {
        struct mlxsw_sp_port *mlxsw_sp_port =
@@ -1335,6 +1367,8 @@ static void update_stats_cache(struct work_struct *work)
 
        mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev,
                                   &mlxsw_sp_port->periodic_hw_stats.stats);
+       mlxsw_sp_port_get_hw_xstats(mlxsw_sp_port->dev,
+                                   &mlxsw_sp_port->periodic_hw_stats.xstats);
 
 out:
        mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw,
index 76ebd58b6248af2c660ed06063d6e7b407be6c9f..e68299e6a9632419f4025fdd1527575f0ac723b8 100644 (file)
@@ -213,6 +213,14 @@ struct mlxsw_sp_qdisc {
        enum mlxsw_sp_qdisc_type type;
 };
 
+/* No need an internal lock; At worse - miss a single periodic iteration */
+struct mlxsw_sp_port_xstats {
+       u64 ecn;
+       u64 wred_drop[TC_MAX_QUEUE];
+       u64 tail_drop[TC_MAX_QUEUE];
+       u64 backlog[TC_MAX_QUEUE];
+};
+
 struct mlxsw_sp_port {
        struct net_device *dev;
        struct mlxsw_sp_port_pcpu_stats __percpu *pcpu_stats;
@@ -242,6 +250,7 @@ struct mlxsw_sp_port {
        struct {
                #define MLXSW_HW_STATS_UPDATE_TIME HZ
                struct rtnl_link_stats64 stats;
+               struct mlxsw_sp_port_xstats xstats;
                struct delayed_work update_dw;
        } periodic_hw_stats;
        struct mlxsw_sp_port_sample *sample;