@@ -112,6 +112,117 @@ int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
112
112
return 0 ;
113
113
}
114
114
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
+
115
226
static int efx_mae_get_basic_caps (struct efx_nic * efx , struct mae_caps * caps )
116
227
{
117
228
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,
323
434
#undef CHECK_BIT
324
435
#undef CHECK
325
436
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
+
326
488
static bool efx_mae_asl_id (u32 id )
327
489
{
328
490
return !!(id & BIT (31 ));
@@ -339,8 +501,12 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
339
501
MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL );
340
502
MCDI_SET_DWORD (inbuf , MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID ,
341
503
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 );
344
510
MCDI_SET_DWORD (inbuf , MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID ,
345
511
MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL );
346
512
MCDI_SET_DWORD (inbuf , MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID ,
0 commit comments