sfc: add ef100 MAE counter support functions
authorEdward Cree <ecree.xilinx@gmail.com>
Mon, 14 Nov 2022 13:15:54 +0000 (13:15 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Nov 2022 09:07:02 +0000 (09:07 +0000)
Start and stop MAE counter streaming, and grant credits.

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/mae.h
drivers/net/ethernet/sfc/mcdi.h
drivers/net/ethernet/sfc/tc.c
drivers/net/ethernet/sfc/tc.h

index 1e605e2..3772234 100644 (file)
@@ -112,6 +112,117 @@ int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
        return 0;
 }
 
+int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
+{
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_START_V2_IN_LEN);
+       MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
+       u32 out_flags;
+       size_t outlen;
+       int rc;
+
+       MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_QID,
+                     efx_rx_queue_index(rx_queue));
+       MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_PACKET_SIZE,
+                     efx->net_dev->mtu);
+       MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_COUNTER_TYPES_MASK,
+                      BIT(MAE_COUNTER_TYPE_AR) | BIT(MAE_COUNTER_TYPE_CT) |
+                      BIT(MAE_COUNTER_TYPE_OR));
+       rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_START,
+                         inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               return rc;
+       if (outlen < sizeof(outbuf))
+               return -EIO;
+       out_flags = MCDI_DWORD(outbuf, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
+       if (out_flags & BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST)) {
+               netif_dbg(efx, drv, efx->net_dev,
+                         "MAE counter stream uses credits\n");
+               rx_queue->grant_credits = true;
+               out_flags &= ~BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST);
+       }
+       if (out_flags) {
+               netif_err(efx, drv, efx->net_dev,
+                         "MAE counter stream start: unrecognised flags %x\n",
+                         out_flags);
+               goto out_stop;
+       }
+       return 0;
+out_stop:
+       efx_mae_stop_counters(efx, rx_queue);
+       return -EOPNOTSUPP;
+}
+
+static bool efx_mae_counters_flushed(u32 *flush_gen, u32 *seen_gen)
+{
+       int i;
+
+       for (i = 0; i < EFX_TC_COUNTER_TYPE_MAX; i++)
+               if ((s32)(flush_gen[i] - seen_gen[i]) > 0)
+                       return false;
+       return true;
+}
+
+int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
+{
+       MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_V2_OUT_LENMAX);
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN);
+       size_t outlen;
+       int rc, i;
+
+       MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_STOP_IN_QID,
+                     efx_rx_queue_index(rx_queue));
+       rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_STOP,
+                         inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
+
+       if (rc)
+               return rc;
+
+       netif_dbg(efx, drv, efx->net_dev, "Draining counters:\n");
+       /* Only process received generation counts */
+       for (i = 0; (i < (outlen / 4)) && (i < EFX_TC_COUNTER_TYPE_MAX); i++) {
+               efx->tc->flush_gen[i] = MCDI_ARRAY_DWORD(outbuf,
+                                                        MAE_COUNTERS_STREAM_STOP_V2_OUT_GENERATION_COUNT,
+                                                        i);
+               netif_dbg(efx, drv, efx->net_dev,
+                         "\ttype %u, awaiting gen %u\n", i,
+                         efx->tc->flush_gen[i]);
+       }
+
+       efx->tc->flush_counters = true;
+
+       /* Drain can take up to 2 seconds owing to FWRIVERHD-2884; whatever
+        * timeout we use, that delay is added to unload on nonresponsive
+        * hardware, so 2500ms seems like a reasonable compromise.
+        */
+       if (!wait_event_timeout(efx->tc->flush_wq,
+                               efx_mae_counters_flushed(efx->tc->flush_gen,
+                                                        efx->tc->seen_gen),
+                               msecs_to_jiffies(2500)))
+               netif_warn(efx, drv, efx->net_dev,
+                          "Failed to drain counters RXQ, FW may be unhappy\n");
+
+       efx->tc->flush_counters = false;
+
+       return rc;
+}
+
+void efx_mae_counters_grant_credits(struct work_struct *work)
+{
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN);
+       struct efx_rx_queue *rx_queue = container_of(work, struct efx_rx_queue,
+                                                    grant_work);
+       struct efx_nic *efx = rx_queue->efx;
+       unsigned int credits;
+
+       BUILD_BUG_ON(MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
+       credits = READ_ONCE(rx_queue->notified_count) - rx_queue->granted_count;
+       MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
+                      credits);
+       if (!efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS,
+                         inbuf, sizeof(inbuf), NULL, 0, NULL))
+               rx_queue->granted_count += credits;
+}
+
 static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps)
 {
        MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN);
index 3e0cd23..8f5de01 100644 (file)
@@ -27,6 +27,10 @@ void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out);
 
 int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
 
+int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
+int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
+void efx_mae_counters_grant_credits(struct work_struct *work);
+
 #define MAE_NUM_FIELDS (MAE_FIELD_ENC_VNET_ID + 1)
 
 struct mae_caps {
index fbeb581..7e35fec 100644 (file)
@@ -221,6 +221,11 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
 #define MCDI_BYTE(_buf, _field)                                                \
        ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1),       \
         *MCDI_PTR(_buf, _field))
+#define MCDI_SET_WORD(_buf, _field, _value) do {                       \
+       BUILD_BUG_ON(MC_CMD_ ## _field ## _LEN != 2);                   \
+       BUILD_BUG_ON(MC_CMD_ ## _field ## _OFST & 1);                   \
+       *(__force __le16 *)MCDI_PTR(_buf, _field) = cpu_to_le16(_value);\
+       } while (0)
 #define MCDI_WORD(_buf, _field)                                                \
        ((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) +       \
         le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))
index 17e1a34..894f578 100644 (file)
@@ -751,6 +751,7 @@ int efx_init_struct_tc(struct efx_nic *efx)
        INIT_LIST_HEAD(&efx->tc->block_list);
 
        mutex_init(&efx->tc->mutex);
+       init_waitqueue_head(&efx->tc->flush_wq);
        rc = rhashtable_init(&efx->tc->match_action_ht, &efx_tc_match_action_ht_params);
        if (rc < 0)
                goto fail_match_action_ht;
index 4240c37..464fc92 100644 (file)
 #include <net/flow_offload.h>
 #include <linux/rhashtable.h>
 #include "net_driver.h"
+#include "mcdi_pcol.h" /* for MAE_COUNTER_TYPE_* */
+
+enum efx_tc_counter_type {
+       EFX_TC_COUNTER_TYPE_AR = MAE_COUNTER_TYPE_AR,
+       EFX_TC_COUNTER_TYPE_CT = MAE_COUNTER_TYPE_CT,
+       EFX_TC_COUNTER_TYPE_OR = MAE_COUNTER_TYPE_OR,
+       EFX_TC_COUNTER_TYPE_MAX
+};
 
 #define IS_ALL_ONES(v) (!(typeof (v))~(v))
 
@@ -79,6 +87,12 @@ enum efx_tc_rule_prios {
  * @reps_filter_uc: VNIC filter for representor unicast RX (promisc)
  * @reps_filter_mc: VNIC filter for representor multicast RX (allmulti)
  * @reps_mport_vport_id: vport_id for representor RX filters
+ * @flush_counters: counters have been stopped, waiting for drain
+ * @flush_gen: final generation count per type array as reported by
+ *             MC_CMD_MAE_COUNTERS_STREAM_STOP
+ * @seen_gen: most recent generation count per type as seen by efx_tc_rx()
+ * @flush_wq: wait queue used by efx_mae_stop_counters() to wait for
+ *     MAE counters RXQ to finish draining
  * @dflt: Match-action rules for default switching; at priority
  *     %EFX_TC_PRIO_DFLT.  Named by *ingress* port
  * @dflt.pf: rule for traffic ingressing from PF (egresses to wire)
@@ -92,6 +106,10 @@ struct efx_tc_state {
        struct rhashtable match_action_ht;
        u32 reps_mport_id, reps_mport_vport_id;
        s32 reps_filter_uc, reps_filter_mc;
+       bool flush_counters;
+       u32 flush_gen[EFX_TC_COUNTER_TYPE_MAX];
+       u32 seen_gen[EFX_TC_COUNTER_TYPE_MAX];
+       wait_queue_head_t flush_wq;
        struct {
                struct efx_tc_flow_rule pf;
                struct efx_tc_flow_rule wire;