mlxsw: spectrum: Add support for generic flow counter allocation
authorArkadi Sharshevsky <arkadis@mellanox.com>
Sat, 11 Mar 2017 08:42:53 +0000 (09:42 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 13 Mar 2017 06:50:13 +0000 (23:50 -0700)
Add support for allocating generic flow counter. Generic flow counter
can count packets or packets and bytes and can be assigned to different
hardware processes. First use will be for counting packets and bytes of
ACL rules, and will be introduced in the following patches.

Signed-off-by: Arkadi Sharshevsky <arkadis@mellanox.com>
Reviewed-by: Ido schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/resources.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.h

index 15b808693f00cc4e11c26773cfb7bf0ee86b9aa9..905a8e269f874882630d2a45161c40fca02d49b4 100644 (file)
@@ -45,6 +45,7 @@ enum mlxsw_res_id {
        MLXSW_RES_ID_MAX_TRAP_GROUPS,
        MLXSW_RES_ID_COUNTER_POOL_SIZE,
        MLXSW_RES_ID_MAX_SPAN,
+       MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES,
        MLXSW_RES_ID_MAX_SYSTEM_PORT,
        MLXSW_RES_ID_MAX_LAG,
        MLXSW_RES_ID_MAX_LAG_MEMBERS,
@@ -78,6 +79,7 @@ static u16 mlxsw_res_ids[] = {
        [MLXSW_RES_ID_MAX_TRAP_GROUPS] = 0x2201,
        [MLXSW_RES_ID_COUNTER_POOL_SIZE] = 0x2410,
        [MLXSW_RES_ID_MAX_SPAN] = 0x2420,
+       [MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES] = 0x2443,
        [MLXSW_RES_ID_MAX_SYSTEM_PORT] = 0x2502,
        [MLXSW_RES_ID_MAX_LAG] = 0x2520,
        [MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521,
index b8237f98d47038873e3ea70d81586adcf591de3a..af430484ed2f6287509a6f179814d60a00f7d530 100644 (file)
@@ -139,6 +139,60 @@ MLXSW_ITEM32(tx, hdr, fid, 0x08, 0, 16);
  */
 MLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4);
 
+int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,
+                             unsigned int counter_index, u64 *packets,
+                             u64 *bytes)
+{
+       char mgpc_pl[MLXSW_REG_MGPC_LEN];
+       int err;
+
+       mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_NOP,
+                           MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS_BYTES);
+       err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);
+       if (err)
+               return err;
+       *packets = mlxsw_reg_mgpc_packet_counter_get(mgpc_pl);
+       *bytes = mlxsw_reg_mgpc_byte_counter_get(mgpc_pl);
+       return 0;
+}
+
+static int mlxsw_sp_flow_counter_clear(struct mlxsw_sp *mlxsw_sp,
+                                      unsigned int counter_index)
+{
+       char mgpc_pl[MLXSW_REG_MGPC_LEN];
+
+       mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_CLEAR,
+                           MLXSW_REG_MGPC_COUNTER_SET_TYPE_PACKETS_BYTES);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);
+}
+
+int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp,
+                               unsigned int *p_counter_index)
+{
+       int err;
+
+       err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,
+                                    p_counter_index);
+       if (err)
+               return err;
+       err = mlxsw_sp_flow_counter_clear(mlxsw_sp, *p_counter_index);
+       if (err)
+               goto err_counter_clear;
+       return 0;
+
+err_counter_clear:
+       mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,
+                             *p_counter_index);
+       return err;
+}
+
+void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp,
+                               unsigned int counter_index)
+{
+        mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,
+                              counter_index);
+}
+
 static void mlxsw_sp_txhdr_construct(struct sk_buff *skb,
                                     const struct mlxsw_tx_info *tx_info)
 {
index dd59a9bf9085e5c688e9b24c95b1f6f16b82cc30..b0500b878fb4663d3951fccfb7e4db77edeb47ba 100644 (file)
@@ -679,5 +679,12 @@ int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
                            __be16 protocol, struct tc_cls_flower_offload *f);
 void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
                             struct tc_cls_flower_offload *f);
+int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,
+                             unsigned int counter_index, u64 *packets,
+                             u64 *bytes);
+int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp,
+                               unsigned int *p_counter_index);
+void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp,
+                               unsigned int counter_index);
 
 #endif
index 0cae75c415d46d356e7fed5c02ab2f8ffc634fff..1631e01908c066a68dcc399b43fd79a7b337bc45 100644 (file)
@@ -52,7 +52,11 @@ struct mlxsw_sp_counter_pool {
        struct mlxsw_sp_counter_sub_pool *sub_pools;
 };
 
-static struct mlxsw_sp_counter_sub_pool mlxsw_sp_counter_sub_pools[] = {};
+static struct mlxsw_sp_counter_sub_pool mlxsw_sp_counter_sub_pools[] = {
+       [MLXSW_SP_COUNTER_SUB_POOL_FLOW] = {
+               .bank_count = 6,
+       },
+};
 
 static int mlxsw_sp_counter_pool_validate(struct mlxsw_sp *mlxsw_sp)
 {
@@ -69,6 +73,19 @@ static int mlxsw_sp_counter_pool_validate(struct mlxsw_sp *mlxsw_sp)
        return 0;
 }
 
+static int mlxsw_sp_counter_sub_pools_prepare(struct mlxsw_sp *mlxsw_sp)
+{
+       struct mlxsw_sp_counter_sub_pool *sub_pool;
+
+       /* Prepare generic flow pool*/
+       sub_pool = &mlxsw_sp_counter_sub_pools[MLXSW_SP_COUNTER_SUB_POOL_FLOW];
+       if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, COUNTER_SIZE_PACKETS_BYTES))
+               return -EIO;
+       sub_pool->entry_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
+                                                 COUNTER_SIZE_PACKETS_BYTES);
+       return 0;
+}
+
 int mlxsw_sp_counter_pool_init(struct mlxsw_sp *mlxsw_sp)
 {
        struct mlxsw_sp_counter_sub_pool *sub_pool;
@@ -85,6 +102,10 @@ int mlxsw_sp_counter_pool_init(struct mlxsw_sp *mlxsw_sp)
        if (err)
                return err;
 
+       err = mlxsw_sp_counter_sub_pools_prepare(mlxsw_sp);
+       if (err)
+               return err;
+
        pool = kzalloc(sizeof(*pool), GFP_KERNEL);
        if (!pool)
                return -ENOMEM;
index 5bf42d923edfe3d16ebb1cb70cf4de1f68ef7f79..031bc4abbe2dd634fe6111ad568227dce8a60d15 100644 (file)
@@ -38,8 +38,7 @@
 #include "spectrum.h"
 
 enum mlxsw_sp_counter_sub_pool_id {
-       /* Placeholder before first pool registered */
-       MLXSW_SP_COUNTER_SUB_POOL_PLACEHOLDER,
+       MLXSW_SP_COUNTER_SUB_POOL_FLOW,
 };
 
 int mlxsw_sp_counter_alloc(struct mlxsw_sp *mlxsw_sp,