@@ -112,6 +112,117 @@ int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
112112 return 0 ;
113113}
114114
115+ int efx_mae_start_counters (struct efx_nic * efx , struct efx_rx_queue * rx_queue )
116+ {
117+ MCDI_DECLARE_BUF (inbuf , MC_CMD_MAE_COUNTERS_STREAM_START_V2_IN_LEN );
118+ MCDI_DECLARE_BUF (outbuf , MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN );
119+ u32 out_flags ;
120+ size_t outlen ;
121+ int rc ;
122+
123+ MCDI_SET_WORD (inbuf , MAE_COUNTERS_STREAM_START_V2_IN_QID ,
124+ efx_rx_queue_index (rx_queue ));
125+ MCDI_SET_WORD (inbuf , MAE_COUNTERS_STREAM_START_V2_IN_PACKET_SIZE ,
126+ efx -> net_dev -> mtu );
127+ MCDI_SET_DWORD (inbuf , MAE_COUNTERS_STREAM_START_V2_IN_COUNTER_TYPES_MASK ,
128+ BIT (MAE_COUNTER_TYPE_AR ) | BIT (MAE_COUNTER_TYPE_CT ) |
129+ BIT (MAE_COUNTER_TYPE_OR ));
130+ rc = efx_mcdi_rpc (efx , MC_CMD_MAE_COUNTERS_STREAM_START ,
131+ inbuf , sizeof (inbuf ), outbuf , sizeof (outbuf ), & outlen );
132+ if (rc )
133+ return rc ;
134+ if (outlen < sizeof (outbuf ))
135+ return - EIO ;
136+ out_flags = MCDI_DWORD (outbuf , MAE_COUNTERS_STREAM_START_OUT_FLAGS );
137+ if (out_flags & BIT (MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST )) {
138+ netif_dbg (efx , drv , efx -> net_dev ,
139+ "MAE counter stream uses credits\n" );
140+ rx_queue -> grant_credits = true;
141+ out_flags &= ~BIT (MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST );
142+ }
143+ if (out_flags ) {
144+ netif_err (efx , drv , efx -> net_dev ,
145+ "MAE counter stream start: unrecognised flags %x\n" ,
146+ out_flags );
147+ goto out_stop ;
148+ }
149+ return 0 ;
150+ out_stop :
151+ efx_mae_stop_counters (efx , rx_queue );
152+ return - EOPNOTSUPP ;
153+ }
154+
155+ static bool efx_mae_counters_flushed (u32 * flush_gen , u32 * seen_gen )
156+ {
157+ int i ;
158+
159+ for (i = 0 ; i < EFX_TC_COUNTER_TYPE_MAX ; i ++ )
160+ if ((s32 )(flush_gen [i ] - seen_gen [i ]) > 0 )
161+ return false;
162+ return true;
163+ }
164+
165+ int efx_mae_stop_counters (struct efx_nic * efx , struct efx_rx_queue * rx_queue )
166+ {
167+ MCDI_DECLARE_BUF (outbuf , MC_CMD_MAE_COUNTERS_STREAM_STOP_V2_OUT_LENMAX );
168+ MCDI_DECLARE_BUF (inbuf , MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN );
169+ size_t outlen ;
170+ int rc , i ;
171+
172+ MCDI_SET_WORD (inbuf , MAE_COUNTERS_STREAM_STOP_IN_QID ,
173+ efx_rx_queue_index (rx_queue ));
174+ rc = efx_mcdi_rpc (efx , MC_CMD_MAE_COUNTERS_STREAM_STOP ,
175+ inbuf , sizeof (inbuf ), outbuf , sizeof (outbuf ), & outlen );
176+
177+ if (rc )
178+ return rc ;
179+
180+ netif_dbg (efx , drv , efx -> net_dev , "Draining counters:\n" );
181+ /* Only process received generation counts */
182+ for (i = 0 ; (i < (outlen / 4 )) && (i < EFX_TC_COUNTER_TYPE_MAX ); i ++ ) {
183+ efx -> tc -> flush_gen [i ] = MCDI_ARRAY_DWORD (outbuf ,
184+ MAE_COUNTERS_STREAM_STOP_V2_OUT_GENERATION_COUNT ,
185+ i );
186+ netif_dbg (efx , drv , efx -> net_dev ,
187+ "\ttype %u, awaiting gen %u\n" , i ,
188+ efx -> tc -> flush_gen [i ]);
189+ }
190+
191+ efx -> tc -> flush_counters = true;
192+
193+ /* Drain can take up to 2 seconds owing to FWRIVERHD-2884; whatever
194+ * timeout we use, that delay is added to unload on nonresponsive
195+ * hardware, so 2500ms seems like a reasonable compromise.
196+ */
197+ if (!wait_event_timeout (efx -> tc -> flush_wq ,
198+ efx_mae_counters_flushed (efx -> tc -> flush_gen ,
199+ efx -> tc -> seen_gen ),
200+ msecs_to_jiffies (2500 )))
201+ netif_warn (efx , drv , efx -> net_dev ,
202+ "Failed to drain counters RXQ, FW may be unhappy\n" );
203+
204+ efx -> tc -> flush_counters = false;
205+
206+ return rc ;
207+ }
208+
209+ void efx_mae_counters_grant_credits (struct work_struct * work )
210+ {
211+ MCDI_DECLARE_BUF (inbuf , MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN );
212+ struct efx_rx_queue * rx_queue = container_of (work , struct efx_rx_queue ,
213+ grant_work );
214+ struct efx_nic * efx = rx_queue -> efx ;
215+ unsigned int credits ;
216+
217+ BUILD_BUG_ON (MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN );
218+ credits = READ_ONCE (rx_queue -> notified_count ) - rx_queue -> granted_count ;
219+ MCDI_SET_DWORD (inbuf , MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS ,
220+ credits );
221+ if (!efx_mcdi_rpc (efx , MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS ,
222+ inbuf , sizeof (inbuf ), NULL , 0 , NULL ))
223+ rx_queue -> granted_count += credits ;
224+ }
225+
115226static int efx_mae_get_basic_caps (struct efx_nic * efx , struct mae_caps * caps )
116227{
117228 MCDI_DECLARE_BUF (outbuf , MC_CMD_MAE_GET_CAPS_OUT_LEN );
@@ -323,6 +434,57 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
323434#undef CHECK_BIT
324435#undef CHECK
325436
437+ int efx_mae_allocate_counter (struct efx_nic * efx , struct efx_tc_counter * cnt )
438+ {
439+ MCDI_DECLARE_BUF (outbuf , MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN (1 ));
440+ MCDI_DECLARE_BUF (inbuf , MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN );
441+ size_t outlen ;
442+ int rc ;
443+
444+ if (!cnt )
445+ return - EINVAL ;
446+
447+ MCDI_SET_DWORD (inbuf , MAE_COUNTER_ALLOC_V2_IN_REQUESTED_COUNT , 1 );
448+ MCDI_SET_DWORD (inbuf , MAE_COUNTER_ALLOC_V2_IN_COUNTER_TYPE , cnt -> type );
449+ rc = efx_mcdi_rpc (efx , MC_CMD_MAE_COUNTER_ALLOC , inbuf , sizeof (inbuf ),
450+ outbuf , sizeof (outbuf ), & outlen );
451+ if (rc )
452+ return rc ;
453+ /* pcol says this can't happen, since count is 1 */
454+ if (outlen < sizeof (outbuf ))
455+ return - EIO ;
456+ cnt -> fw_id = MCDI_DWORD (outbuf , MAE_COUNTER_ALLOC_OUT_COUNTER_ID );
457+ cnt -> gen = MCDI_DWORD (outbuf , MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT );
458+ return 0 ;
459+ }
460+
461+ int efx_mae_free_counter (struct efx_nic * efx , struct efx_tc_counter * cnt )
462+ {
463+ MCDI_DECLARE_BUF (outbuf , MC_CMD_MAE_COUNTER_FREE_OUT_LEN (1 ));
464+ MCDI_DECLARE_BUF (inbuf , MC_CMD_MAE_COUNTER_FREE_V2_IN_LEN );
465+ size_t outlen ;
466+ int rc ;
467+
468+ MCDI_SET_DWORD (inbuf , MAE_COUNTER_FREE_V2_IN_COUNTER_ID_COUNT , 1 );
469+ MCDI_SET_DWORD (inbuf , MAE_COUNTER_FREE_V2_IN_FREE_COUNTER_ID , cnt -> fw_id );
470+ MCDI_SET_DWORD (inbuf , MAE_COUNTER_FREE_V2_IN_COUNTER_TYPE , cnt -> type );
471+ rc = efx_mcdi_rpc (efx , MC_CMD_MAE_COUNTER_FREE , inbuf , sizeof (inbuf ),
472+ outbuf , sizeof (outbuf ), & outlen );
473+ if (rc )
474+ return rc ;
475+ /* pcol says this can't happen, since count is 1 */
476+ if (outlen < sizeof (outbuf ))
477+ return - EIO ;
478+ /* FW freed a different ID than we asked for, should also never happen.
479+ * Warn because it means we've now got a different idea to the FW of
480+ * what counters exist, which could cause mayhem later.
481+ */
482+ if (WARN_ON (MCDI_DWORD (outbuf , MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID ) !=
483+ cnt -> fw_id ))
484+ return - EIO ;
485+ return 0 ;
486+ }
487+
326488static bool efx_mae_asl_id (u32 id )
327489{
328490 return !!(id & BIT (31 ));
@@ -339,8 +501,12 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
339501 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL );
340502 MCDI_SET_DWORD (inbuf , MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID ,
341503 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL );
342- MCDI_SET_DWORD (inbuf , MAE_ACTION_SET_ALLOC_IN_COUNTER_ID ,
343- MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL );
504+ if (act -> count && !WARN_ON (!act -> count -> cnt ))
505+ MCDI_SET_DWORD (inbuf , MAE_ACTION_SET_ALLOC_IN_COUNTER_ID ,
506+ act -> count -> cnt -> fw_id );
507+ else
508+ MCDI_SET_DWORD (inbuf , MAE_ACTION_SET_ALLOC_IN_COUNTER_ID ,
509+ MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL );
344510 MCDI_SET_DWORD (inbuf , MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID ,
345511 MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL );
346512 MCDI_SET_DWORD (inbuf , MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID ,
0 commit comments