sfc: attach an MAE counter to TC actions that need it
authorEdward Cree <ecree.xilinx@gmail.com>
Mon, 14 Nov 2022 13:15:59 +0000 (13:15 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Nov 2022 09:07:03 +0000 (09:07 +0000)
The only actions that expect stats (that sfc HW supports) are gact shot
 (drop), mirred redirect and mirred mirror.  Since these are 'deliverish'
 actions that end an action-set, we only require at most one counter per
 action-set.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/mae.c
drivers/net/ethernet/sfc/tc.c
drivers/net/ethernet/sfc/tc.h

index f227b4f..583baf6 100644 (file)
@@ -501,8 +501,12 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
                       MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
        MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
                       MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
-       MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
-                      MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
+       if (act->count && !WARN_ON(!act->count->cnt))
+               MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
+                              act->count->cnt->fw_id);
+       else
+               MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
+                              MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
        MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID,
                       MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL);
        MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
index 8ea7f52..1cfc50f 100644 (file)
@@ -77,6 +77,8 @@ static void efx_tc_free_action_set(struct efx_nic *efx,
                 */
                list_del(&act->list);
        }
+       if (act->count)
+               efx_tc_flower_put_counter_index(efx, act->count);
        kfree(act);
 }
 
@@ -376,6 +378,28 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
                        goto release;
                }
 
+               if ((fa->id == FLOW_ACTION_REDIRECT ||
+                    fa->id == FLOW_ACTION_MIRRED ||
+                    fa->id == FLOW_ACTION_DROP) && fa->hw_stats) {
+                       struct efx_tc_counter_index *ctr;
+
+                       if (!(fa->hw_stats & FLOW_ACTION_HW_STATS_DELAYED)) {
+                               NL_SET_ERR_MSG_FMT_MOD(extack, "hw_stats_type %u not supported (only 'delayed')",
+                                                      fa->hw_stats);
+                               rc = -EOPNOTSUPP;
+                               goto release;
+                       }
+
+                       ctr = efx_tc_flower_get_counter_index(efx, tc->cookie,
+                                                             EFX_TC_COUNTER_TYPE_AR);
+                       if (IS_ERR(ctr)) {
+                               rc = PTR_ERR(ctr);
+                               NL_SET_ERR_MSG_MOD(extack, "Failed to obtain a counter");
+                               goto release;
+                       }
+                       act->count = ctr;
+               }
+
                switch (fa->id) {
                case FLOW_ACTION_DROP:
                        rc = efx_mae_alloc_action_set(efx, act);
@@ -412,6 +436,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
                        if (fa->id == FLOW_ACTION_REDIRECT)
                                break; /* end of the line */
                        /* Mirror, so continue on with saved act */
+                       save.count = NULL;
                        act = kzalloc(sizeof(*act), GFP_USER);
                        if (!act) {
                                rc = -ENOMEM;
index 6c8ebb2..418ce8c 100644 (file)
@@ -20,6 +20,7 @@
 
 struct efx_tc_action_set {
        u16 deliver:1;
+       struct efx_tc_counter_index *count;
        u32 dest_mport;
        u32 fw_id; /* index of this entry in firmware actions table */
        struct list_head list;