Loading drivers/net/ethernet/sfc/mae.c +111 −0 Original line number Diff line number Diff line Loading @@ -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); Loading drivers/net/ethernet/sfc/mae.h +4 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading drivers/net/ethernet/sfc/mcdi.h +5 −0 Original line number Diff line number Diff line Loading @@ -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))) Loading drivers/net/ethernet/sfc/tc.c +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading drivers/net/ethernet/sfc/tc.h +18 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,14 @@ #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)) Loading Loading @@ -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) Loading @@ -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; Loading Loading
drivers/net/ethernet/sfc/mae.c +111 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
drivers/net/ethernet/sfc/mae.h +4 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading
drivers/net/ethernet/sfc/mcdi.h +5 −0 Original line number Diff line number Diff line Loading @@ -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))) Loading
drivers/net/ethernet/sfc/tc.c +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
drivers/net/ethernet/sfc/tc.h +18 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,14 @@ #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)) Loading Loading @@ -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) Loading @@ -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; Loading