Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : *
3 : : * Copyright(c) 2020-2021 Xilinx, Inc.
4 : : */
5 : :
6 : : #include <rte_common.h>
7 : : #include <rte_service_component.h>
8 : :
9 : : #include "efx.h"
10 : : #include "efx_regs_counters_pkt_format.h"
11 : :
12 : : #include "sfc_ev.h"
13 : : #include "sfc.h"
14 : : #include "sfc_rx.h"
15 : : #include "sfc_mae_counter.h"
16 : : #include "sfc_service.h"
17 : :
18 : : /**
19 : : * Approximate maximum number of counters per packet.
20 : : * In fact maximum depends on per-counter data offset which is specified
21 : : * in counter packet header.
22 : : */
23 : : #define SFC_MAE_COUNTERS_PER_PACKET_MAX \
24 : : ((SFC_MAE_COUNTER_STREAM_PACKET_SIZE - \
25 : : ER_RX_SL_PACKETISER_HEADER_WORD_SIZE) / \
26 : : ER_RX_SL_PACKETISER_PAYLOAD_WORD_SIZE)
27 : :
28 : : /**
29 : : * Minimum number of Rx buffers in counters only Rx queue.
30 : : */
31 : : #define SFC_MAE_COUNTER_RXQ_BUFS_MIN \
32 : : (SFC_COUNTER_RXQ_RX_DESC_COUNT - SFC_COUNTER_RXQ_REFILL_LEVEL)
33 : :
34 : : /**
35 : : * Approximate number of counter updates fit in counters only Rx queue.
36 : : * The number is inaccurate since SFC_MAE_COUNTERS_PER_PACKET_MAX is
37 : : * inaccurate (see above). However, it provides the gist for a number of
38 : : * counter updates which can fit in an Rx queue after empty poll.
39 : : *
40 : : * The define is not actually used, but provides calculations details.
41 : : */
42 : : #define SFC_MAE_COUNTERS_RXQ_SPACE \
43 : : (SFC_MAE_COUNTER_RXQ_BUFS_MIN * SFC_MAE_COUNTERS_PER_PACKET_MAX)
44 : :
45 : : static uint32_t
46 : 0 : sfc_mae_counter_get_service_lcore(struct sfc_adapter *sa)
47 : : {
48 : : uint32_t cid;
49 : :
50 : 0 : cid = sfc_get_service_lcore(sa->socket_id);
51 [ # # ]: 0 : if (cid != RTE_MAX_LCORE)
52 : : return cid;
53 : :
54 [ # # ]: 0 : if (sa->socket_id != SOCKET_ID_ANY)
55 : 0 : cid = sfc_get_service_lcore(SOCKET_ID_ANY);
56 : :
57 [ # # ]: 0 : if (cid == RTE_MAX_LCORE) {
58 : 0 : sfc_warn(sa, "failed to get service lcore for counter service");
59 [ # # ]: 0 : } else if (sa->socket_id != SOCKET_ID_ANY) {
60 : 0 : sfc_warn(sa,
61 : : "failed to get service lcore for counter service at socket %d, but got at socket %u",
62 : : sa->socket_id, rte_lcore_to_socket_id(cid));
63 : : }
64 : : return cid;
65 : : }
66 : :
67 : : bool
68 : 0 : sfc_mae_counter_rxq_required(struct sfc_adapter *sa)
69 : : {
70 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
71 : :
72 [ # # ]: 0 : if (encp->enc_mae_supported == B_FALSE)
73 : 0 : return false;
74 : :
75 : : return true;
76 : : }
77 : :
78 : : int
79 : 0 : sfc_mae_counter_fw_rsrc_enable(struct sfc_adapter *sa,
80 : : struct sfc_mae_counter *counterp)
81 : : {
82 : : struct sfc_mae_counter_registry *reg = &sa->mae.counter_registry;
83 : : struct sfc_mae_counter_records *counters;
84 : : struct sfc_mae_counter_record *p;
85 : : efx_counter_t mae_counter;
86 : : uint32_t generation_count;
87 : : uint32_t unused;
88 : : int rc;
89 : :
90 [ # # # ]: 0 : switch (counterp->type) {
91 : 0 : case EFX_COUNTER_TYPE_ACTION:
92 : 0 : counters = ®->action_counters;
93 : 0 : break;
94 : 0 : case EFX_COUNTER_TYPE_CONNTRACK:
95 : 0 : counters = ®->conntrack_counters;
96 : 0 : break;
97 : 0 : default:
98 : : rc = EINVAL;
99 : 0 : goto fail_counter_type_check;
100 : : }
101 : :
102 : : /*
103 : : * The actual count of counters allocated is ignored since a failure
104 : : * to allocate a single counter is indicated by non-zero return code.
105 : : */
106 : 0 : rc = efx_mae_counters_alloc_type(sa->nic, counterp->type, 1, &unused,
107 : : &mae_counter, &generation_count);
108 [ # # ]: 0 : if (rc != 0) {
109 : 0 : sfc_err(sa, "failed to alloc MAE counter: %s",
110 : : rte_strerror(rc));
111 : 0 : goto fail_mae_counter_alloc;
112 : : }
113 : :
114 [ # # ]: 0 : if (mae_counter.id >= counters->n_mae_counters) {
115 : : /*
116 : : * ID of a counter is expected to be within the range
117 : : * between 0 and the maximum count of counters to always
118 : : * fit into a pre-allocated array size of maximum counter ID.
119 : : */
120 : 0 : sfc_err(sa, "MAE counter ID is out of expected range");
121 : : rc = EFAULT;
122 : 0 : goto fail_counter_id_range;
123 : : }
124 : :
125 : 0 : counterp->fw_rsrc.counter_id.id = mae_counter.id;
126 : :
127 : 0 : p = &counters->mae_counters[mae_counter.id];
128 : :
129 : : /*
130 : : * Ordering is relaxed since it is the only operation on counter value.
131 : : * And it does not depend on different stores/loads in other threads.
132 : : * Paired with relaxed ordering in counter increment.
133 : : */
134 : 0 : __atomic_store(&p->reset.pkts_bytes.int128,
135 : : &p->value.pkts_bytes.int128, __ATOMIC_RELAXED);
136 : 0 : p->generation_count = generation_count;
137 : :
138 : 0 : p->ft_switch_hit_counter = counterp->ft_switch_hit_counter;
139 : :
140 : : /*
141 : : * The flag is set at the very end of add operation and reset
142 : : * at the beginning of delete operation. Release ordering is
143 : : * paired with acquire ordering on load in counter increment operation.
144 : : */
145 : 0 : __atomic_store_n(&p->inuse, true, __ATOMIC_RELEASE);
146 : :
147 : 0 : sfc_info(sa, "enabled MAE counter 0x%x-#%u with reset pkts=%" PRIu64
148 : : " bytes=%" PRIu64, counterp->type, mae_counter.id,
149 : : p->reset.pkts, p->reset.bytes);
150 : :
151 : 0 : return 0;
152 : :
153 : : fail_counter_id_range:
154 : 0 : (void)efx_mae_counters_free_type(sa->nic, counterp->type, 1, &unused,
155 : : &mae_counter, NULL);
156 : :
157 : 0 : fail_mae_counter_alloc:
158 : 0 : fail_counter_type_check:
159 : 0 : sfc_log_init(sa, "failed: %s", rte_strerror(rc));
160 : 0 : return rc;
161 : : }
162 : :
163 : : int
164 : 0 : sfc_mae_counter_fw_rsrc_disable(struct sfc_adapter *sa,
165 : : struct sfc_mae_counter *counter)
166 : : {
167 : : struct sfc_mae_counter_registry *reg = &sa->mae.counter_registry;
168 : 0 : efx_counter_t *mae_counter = &counter->fw_rsrc.counter_id;
169 : : struct sfc_mae_counter_records *counters;
170 : : struct sfc_mae_counter_record *p;
171 : : uint32_t unused;
172 : : int rc;
173 : :
174 [ # # # ]: 0 : switch (counter->type) {
175 : 0 : case EFX_COUNTER_TYPE_ACTION:
176 : 0 : counters = ®->action_counters;
177 : 0 : break;
178 : 0 : case EFX_COUNTER_TYPE_CONNTRACK:
179 : 0 : counters = ®->conntrack_counters;
180 : 0 : break;
181 : : default:
182 : : return EINVAL;
183 : : }
184 : :
185 : : SFC_ASSERT(mae_counter->id < counters->n_mae_counters);
186 : : /*
187 : : * The flag is set at the very end of add operation and reset
188 : : * at the beginning of delete operation. Release ordering is
189 : : * paired with acquire ordering on load in counter increment operation.
190 : : */
191 : 0 : p = &counters->mae_counters[mae_counter->id];
192 : 0 : __atomic_store_n(&p->inuse, false, __ATOMIC_RELEASE);
193 : :
194 : 0 : rc = efx_mae_counters_free_type(sa->nic, counter->type, 1, &unused,
195 : : mae_counter, NULL);
196 [ # # ]: 0 : if (rc != 0)
197 : 0 : sfc_err(sa, "failed to free MAE counter 0x%x-#%u: %s",
198 : : counter->type, mae_counter->id, rte_strerror(rc));
199 : :
200 : 0 : sfc_info(sa, "disabled MAE counter 0x%x-#%u with reset pkts=%" PRIu64
201 : : " bytes=%" PRIu64, counter->type, mae_counter->id,
202 : : p->reset.pkts, p->reset.bytes);
203 : :
204 : : /*
205 : : * Do this regardless of what efx_mae_counters_free() return value is.
206 : : * If there's some error, the resulting resource leakage is bad, but
207 : : * nothing sensible can be done in this case.
208 : : */
209 : 0 : mae_counter->id = EFX_MAE_RSRC_ID_INVALID;
210 : :
211 : 0 : return rc;
212 : : }
213 : :
214 : : static void
215 : 0 : sfc_mae_counter_increment(struct sfc_adapter *sa,
216 : : struct sfc_mae_counter_records *counters,
217 : : uint32_t mae_counter_id,
218 : : uint32_t generation_count,
219 : : uint64_t pkts, uint64_t bytes)
220 : : {
221 : 0 : struct sfc_mae_counter_record *p =
222 : 0 : &counters->mae_counters[mae_counter_id];
223 : : struct sfc_mae_counters_xstats *xstats = &counters->xstats;
224 : : union sfc_pkts_bytes cnt_val;
225 : : bool inuse;
226 : :
227 : : /*
228 : : * Acquire ordering is paired with release ordering in counter add
229 : : * and delete operations.
230 : : */
231 : 0 : __atomic_load(&p->inuse, &inuse, __ATOMIC_ACQUIRE);
232 [ # # ]: 0 : if (!inuse) {
233 : : /*
234 : : * Two possible cases include:
235 : : * 1) Counter is just allocated. Too early counter update
236 : : * cannot be processed properly.
237 : : * 2) Stale update of freed and not reallocated counter.
238 : : * There is no point in processing that update.
239 : : */
240 : 0 : xstats->not_inuse_update++;
241 : 0 : return;
242 : : }
243 : :
244 [ # # ]: 0 : if (unlikely(generation_count < p->generation_count)) {
245 : : /*
246 : : * It is a stale update for the reallocated counter
247 : : * (i.e., freed and the same ID allocated again).
248 : : */
249 : 0 : xstats->realloc_update++;
250 : 0 : return;
251 : : }
252 : :
253 : 0 : cnt_val.pkts = p->value.pkts + pkts;
254 : 0 : cnt_val.bytes = p->value.bytes + bytes;
255 : :
256 : : /*
257 : : * Ordering is relaxed since it is the only operation on counter value.
258 : : * And it does not depend on different stores/loads in other threads.
259 : : * Paired with relaxed ordering on counter reset.
260 : : */
261 : 0 : __atomic_store(&p->value.pkts_bytes,
262 : : &cnt_val.pkts_bytes, __ATOMIC_RELAXED);
263 : :
264 [ # # ]: 0 : if (p->ft_switch_hit_counter != NULL) {
265 : : uint64_t ft_switch_hit_counter;
266 : :
267 : 0 : ft_switch_hit_counter = *p->ft_switch_hit_counter + pkts;
268 : 0 : __atomic_store_n(p->ft_switch_hit_counter, ft_switch_hit_counter,
269 : : __ATOMIC_RELAXED);
270 : : }
271 : :
272 : 0 : sfc_info(sa, "update MAE counter 0x%x-#%u: pkts+%" PRIu64 "=%" PRIu64
273 : : ", bytes+%" PRIu64 "=%" PRIu64, counters->type, mae_counter_id,
274 : : pkts, cnt_val.pkts, bytes, cnt_val.bytes);
275 : : }
276 : :
277 : : static void
278 : 0 : sfc_mae_parse_counter_packet(struct sfc_adapter *sa,
279 : : struct sfc_mae_counter_registry *counter_registry,
280 : : const struct rte_mbuf *m)
281 : : {
282 : : struct sfc_mae_counter_records *counters;
283 : : uint32_t generation_count;
284 : : const efx_xword_t *hdr;
285 : : const efx_oword_t *counters_data;
286 : : unsigned int version;
287 : : unsigned int id;
288 : : unsigned int header_offset;
289 : : unsigned int payload_offset;
290 : : unsigned int counter_count;
291 : : unsigned int required_len;
292 : : unsigned int i;
293 : :
294 [ # # ]: 0 : if (unlikely(m->nb_segs != 1)) {
295 : 0 : sfc_err(sa, "unexpectedly scattered MAE counters packet (%u segments)",
296 : : m->nb_segs);
297 : 0 : return;
298 : : }
299 : :
300 [ # # ]: 0 : if (unlikely(m->data_len < ER_RX_SL_PACKETISER_HEADER_WORD_SIZE)) {
301 : 0 : sfc_err(sa, "too short MAE counters packet (%u bytes)",
302 : : m->data_len);
303 : 0 : return;
304 : : }
305 : :
306 : : /*
307 : : * The generation count is located in the Rx prefix in the USER_MARK
308 : : * field which is written into hash.fdir.hi field of an mbuf. See
309 : : * SF-123581-TC SmartNIC Datapath Offloads section 4.7.5 Counters.
310 : : */
311 : 0 : generation_count = m->hash.fdir.hi;
312 : :
313 : 0 : hdr = rte_pktmbuf_mtod(m, const efx_xword_t *);
314 : :
315 : 0 : version = EFX_XWORD_FIELD(*hdr, ERF_SC_PACKETISER_HEADER_VERSION);
316 [ # # ]: 0 : if (unlikely(version != ERF_SC_PACKETISER_HEADER_VERSION_2)) {
317 : 0 : sfc_err(sa, "unexpected MAE counters packet version %u",
318 : : version);
319 : 0 : return;
320 : : }
321 : :
322 : 0 : id = EFX_XWORD_FIELD(*hdr, ERF_SC_PACKETISER_HEADER_IDENTIFIER);
323 : :
324 [ # # # ]: 0 : switch (id) {
325 : 0 : case ERF_SC_PACKETISER_HEADER_IDENTIFIER_AR:
326 : 0 : counters = &counter_registry->action_counters;
327 : 0 : break;
328 : 0 : case ERF_SC_PACKETISER_HEADER_IDENTIFIER_CT:
329 : 0 : counters = &counter_registry->conntrack_counters;
330 : 0 : break;
331 : 0 : default:
332 : 0 : sfc_err(sa, "unexpected MAE counters source identifier %u", id);
333 : 0 : return;
334 : : }
335 : :
336 : : /* Packet layout definitions assume fixed header offset in fact */
337 : 0 : header_offset =
338 : 0 : EFX_XWORD_FIELD(*hdr, ERF_SC_PACKETISER_HEADER_HEADER_OFFSET);
339 [ # # ]: 0 : if (unlikely(header_offset !=
340 : : ERF_SC_PACKETISER_HEADER_HEADER_OFFSET_DEFAULT)) {
341 : 0 : sfc_err(sa, "unexpected MAE counters packet header offset %u",
342 : : header_offset);
343 : 0 : return;
344 : : }
345 : :
346 : 0 : payload_offset =
347 : 0 : EFX_XWORD_FIELD(*hdr, ERF_SC_PACKETISER_HEADER_PAYLOAD_OFFSET);
348 : :
349 : 0 : counter_count = EFX_XWORD_FIELD(*hdr, ERF_SC_PACKETISER_HEADER_COUNT);
350 : :
351 : 0 : required_len = payload_offset +
352 : 0 : counter_count * sizeof(counters_data[0]);
353 [ # # ]: 0 : if (unlikely(required_len > m->data_len)) {
354 : 0 : sfc_err(sa, "truncated MAE counters packet: %u counters, packet length is %u vs %u required",
355 : : counter_count, m->data_len, required_len);
356 : : /*
357 : : * In theory it is possible process available counters data,
358 : : * but such condition is really unexpected and it is
359 : : * better to treat entire packet as corrupted.
360 : : */
361 : 0 : return;
362 : : }
363 : :
364 : : /* Ensure that counters data is 32-bit aligned */
365 [ # # ]: 0 : if (unlikely(payload_offset % sizeof(uint32_t) != 0)) {
366 : 0 : sfc_err(sa, "unsupported MAE counters payload offset %u, must be 32-bit aligned",
367 : : payload_offset);
368 : 0 : return;
369 : : }
370 : : RTE_BUILD_BUG_ON(sizeof(counters_data[0]) !=
371 : : ER_RX_SL_PACKETISER_PAYLOAD_WORD_SIZE);
372 : :
373 : 0 : counters_data =
374 : 0 : rte_pktmbuf_mtod_offset(m, const efx_oword_t *, payload_offset);
375 : :
376 : 0 : sfc_info(sa, "update %u MAE counters with gc=%u",
377 : : counter_count, generation_count);
378 : :
379 [ # # ]: 0 : for (i = 0; i < counter_count; ++i) {
380 : : uint32_t packet_count_lo;
381 : : uint32_t packet_count_hi;
382 : : uint32_t byte_count_lo;
383 : : uint32_t byte_count_hi;
384 : :
385 : : /*
386 : : * Use 32-bit field accessors below since counters data
387 : : * is not 64-bit aligned.
388 : : * 32-bit alignment is checked above taking into account
389 : : * that start of packet data is 32-bit aligned
390 : : * (cache-line size aligned in fact).
391 : : */
392 : 0 : packet_count_lo =
393 : 0 : EFX_OWORD_FIELD32(counters_data[i],
394 : : ERF_SC_PACKETISER_PAYLOAD_PACKET_COUNT_LO);
395 : 0 : packet_count_hi =
396 : 0 : EFX_OWORD_FIELD32(counters_data[i],
397 : : ERF_SC_PACKETISER_PAYLOAD_PACKET_COUNT_HI);
398 : 0 : byte_count_lo =
399 : : EFX_OWORD_FIELD32(counters_data[i],
400 : : ERF_SC_PACKETISER_PAYLOAD_BYTE_COUNT_LO);
401 : 0 : byte_count_hi =
402 : : EFX_OWORD_FIELD32(counters_data[i],
403 : : ERF_SC_PACKETISER_PAYLOAD_BYTE_COUNT_HI);
404 : :
405 [ # # ]: 0 : if (id == ERF_SC_PACKETISER_HEADER_IDENTIFIER_CT) {
406 : : /*
407 : : * FIXME:
408 : : *
409 : : * CT counters are 1-bit saturating counters.
410 : : * There is no way to express this in DPDK
411 : : * currently, so increment the hit count
412 : : * by one to let the application know
413 : : * that the flow is still effective.
414 : : */
415 : : packet_count_lo = 1;
416 : : packet_count_hi = 0;
417 : : byte_count_lo = 0;
418 : : byte_count_hi = 0;
419 : : }
420 : :
421 : 0 : sfc_mae_counter_increment(sa,
422 : : counters,
423 : 0 : EFX_OWORD_FIELD32(counters_data[i],
424 : : ERF_SC_PACKETISER_PAYLOAD_COUNTER_INDEX),
425 : : generation_count,
426 : 0 : (uint64_t)packet_count_lo |
427 : 0 : ((uint64_t)packet_count_hi <<
428 : : ERF_SC_PACKETISER_PAYLOAD_PACKET_COUNT_LO_WIDTH),
429 : 0 : (uint64_t)byte_count_lo |
430 : 0 : ((uint64_t)byte_count_hi <<
431 : : ERF_SC_PACKETISER_PAYLOAD_BYTE_COUNT_LO_WIDTH));
432 : : }
433 : : }
434 : :
435 : : static int32_t
436 : 0 : sfc_mae_counter_poll_packets(struct sfc_adapter *sa)
437 : : {
438 : 0 : struct sfc_mae_counter_registry *counter_registry =
439 : : &sa->mae.counter_registry;
440 : : struct rte_mbuf *mbufs[SFC_MAE_COUNTER_RX_BURST];
441 : : unsigned int pushed_diff;
442 : : unsigned int pushed;
443 : : unsigned int i;
444 : : uint16_t n;
445 : : int rc;
446 : :
447 : 0 : n = counter_registry->rx_pkt_burst(counter_registry->rx_dp, mbufs,
448 : : SFC_MAE_COUNTER_RX_BURST);
449 : :
450 [ # # ]: 0 : for (i = 0; i < n; i++)
451 : 0 : sfc_mae_parse_counter_packet(sa, counter_registry, mbufs[i]);
452 : :
453 : 0 : rte_pktmbuf_free_bulk(mbufs, n);
454 : :
455 [ # # ]: 0 : if (!counter_registry->use_credits)
456 : 0 : return n;
457 : :
458 : 0 : pushed = sfc_rx_get_pushed(sa, counter_registry->rx_dp);
459 : 0 : pushed_diff = pushed - counter_registry->pushed_n_buffers;
460 : :
461 [ # # ]: 0 : if (pushed_diff >= SFC_COUNTER_RXQ_REFILL_LEVEL) {
462 : 0 : rc = efx_mae_counters_stream_give_credits(sa->nic, pushed_diff);
463 [ # # ]: 0 : if (rc == 0) {
464 : 0 : counter_registry->pushed_n_buffers = pushed;
465 : : } else {
466 : : /*
467 : : * FIXME: counters might be important for the
468 : : * application. Handle the error in order to recover
469 : : * from the failure
470 : : */
471 : 0 : SFC_GENERIC_LOG(DEBUG, "Give credits failed: %s",
472 : : rte_strerror(rc));
473 : : }
474 : : }
475 : :
476 : 0 : return n;
477 : : }
478 : :
479 : : static int32_t
480 : 0 : sfc_mae_counter_service_routine(void *arg)
481 : : {
482 : : struct sfc_adapter *sa = arg;
483 : :
484 : : /*
485 : : * We cannot propagate any errors and we don't need to know
486 : : * the number of packets we've received.
487 : : */
488 : 0 : (void)sfc_mae_counter_poll_packets(sa);
489 : :
490 : 0 : return 0;
491 : : }
492 : :
493 : : static uint32_t
494 : 0 : sfc_mae_counter_thread(void *data)
495 : : {
496 : : struct sfc_adapter *sa = data;
497 : : struct sfc_mae_counter_registry *counter_registry =
498 : : &sa->mae.counter_registry;
499 : : int32_t rc;
500 : :
501 [ # # ]: 0 : while (__atomic_load_n(&counter_registry->polling.thread.run,
502 : : __ATOMIC_ACQUIRE)) {
503 : 0 : rc = sfc_mae_counter_poll_packets(sa);
504 [ # # ]: 0 : if (rc == 0) {
505 : : /*
506 : : * The queue is empty. Do not burn CPU.
507 : : * An empty queue has just enough space for about
508 : : * SFC_MAE_COUNTERS_RXQ_SPACE counter updates which is
509 : : * more than 100K, so we can sleep a bit. The queue uses
510 : : * a credit-based flow control anyway, so firmware will
511 : : * not enqueue more counter updates until the host
512 : : * supplies it with additional credits. The counters are
513 : : * 48bits wide, so the timeout need only be short enough
514 : : * to ensure that the counter values do not overflow
515 : : * before the next counter update. Also we should not
516 : : * delay counter updates for a long time, otherwise
517 : : * application may decide that flow is idle and should
518 : : * be removed.
519 : : */
520 : : rte_delay_ms(1);
521 : : }
522 : : }
523 : :
524 : 0 : return 0;
525 : : }
526 : :
527 : : static void
528 : 0 : sfc_mae_counter_service_unregister(struct sfc_adapter *sa)
529 : : {
530 : : struct sfc_mae_counter_registry *registry =
531 : : &sa->mae.counter_registry;
532 : : const unsigned int wait_ms = 10000;
533 : : unsigned int i;
534 : :
535 : 0 : rte_service_runstate_set(registry->polling.service.id, 0);
536 : 0 : rte_service_component_runstate_set(registry->polling.service.id, 0);
537 : :
538 : : /*
539 : : * Wait for the counter routine to finish the last iteration.
540 : : * Give up on timeout.
541 : : */
542 [ # # ]: 0 : for (i = 0; i < wait_ms; i++) {
543 [ # # ]: 0 : if (rte_service_may_be_active(registry->polling.service.id) == 0)
544 : : break;
545 : :
546 : : rte_delay_ms(1);
547 : : }
548 [ # # ]: 0 : if (i == wait_ms)
549 : 0 : sfc_warn(sa, "failed to wait for counter service to stop");
550 : :
551 : 0 : rte_service_map_lcore_set(registry->polling.service.id,
552 : : registry->polling.service.core_id, 0);
553 : :
554 : 0 : rte_service_component_unregister(registry->polling.service.id);
555 : 0 : }
556 : :
557 : : static struct sfc_rxq_info *
558 : : sfc_counter_rxq_info_get(struct sfc_adapter *sa)
559 : : {
560 : 0 : return &sfc_sa2shared(sa)->rxq_info[sa->counter_rxq.sw_index];
561 : : }
562 : :
563 : : static void
564 : : sfc_mae_counter_registry_prepare(struct sfc_mae_counter_registry *registry,
565 : : struct sfc_adapter *sa,
566 : : uint32_t counter_stream_flags)
567 : : {
568 : 0 : registry->rx_pkt_burst = sa->eth_dev->rx_pkt_burst;
569 : 0 : registry->rx_dp = sfc_counter_rxq_info_get(sa)->dp;
570 : 0 : registry->pushed_n_buffers = 0;
571 : 0 : registry->use_credits = counter_stream_flags &
572 : : EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS;
573 : : }
574 : :
575 : : static int
576 : 0 : sfc_mae_counter_service_register(struct sfc_adapter *sa,
577 : : uint32_t counter_stream_flags)
578 : : {
579 : : struct rte_service_spec service;
580 : 0 : char counter_service_name[sizeof(service.name)] = "counter_service";
581 : : struct sfc_mae_counter_registry *counter_registry =
582 : : &sa->mae.counter_registry;
583 : : uint32_t cid;
584 : : uint32_t sid;
585 : : int rc;
586 : :
587 : 0 : sfc_log_init(sa, "entry");
588 : :
589 : : /* Prepare service info */
590 : : memset(&service, 0, sizeof(service));
591 : 0 : rte_strscpy(service.name, counter_service_name, sizeof(service.name));
592 : 0 : service.socket_id = sa->socket_id;
593 : 0 : service.callback = sfc_mae_counter_service_routine;
594 : 0 : service.callback_userdata = sa;
595 : : sfc_mae_counter_registry_prepare(counter_registry, sa,
596 : : counter_stream_flags);
597 : :
598 : 0 : cid = sfc_get_service_lcore(sa->socket_id);
599 [ # # # # ]: 0 : if (cid == RTE_MAX_LCORE && sa->socket_id != SOCKET_ID_ANY) {
600 : : /* Warn and try to allocate on any NUMA node */
601 : 0 : sfc_warn(sa,
602 : : "failed to get service lcore for counter service at socket %d",
603 : : sa->socket_id);
604 : :
605 : 0 : cid = sfc_get_service_lcore(SOCKET_ID_ANY);
606 : : }
607 [ # # ]: 0 : if (cid == RTE_MAX_LCORE) {
608 : : rc = ENOTSUP;
609 : 0 : sfc_err(sa, "failed to get service lcore for counter service");
610 : 0 : goto fail_get_service_lcore;
611 : : }
612 : :
613 : : /* Service core may be in "stopped" state, start it */
614 : 0 : rc = rte_service_lcore_start(cid);
615 [ # # ]: 0 : if (rc != 0 && rc != -EALREADY) {
616 : 0 : sfc_err(sa, "failed to start service core for counter service: %s",
617 : : rte_strerror(-rc));
618 : : rc = ENOTSUP;
619 : 0 : goto fail_start_core;
620 : : }
621 : :
622 : : /* Register counter service */
623 : 0 : rc = rte_service_component_register(&service, &sid);
624 [ # # ]: 0 : if (rc != 0) {
625 : : rc = ENOEXEC;
626 : 0 : sfc_err(sa, "failed to register counter service component");
627 : 0 : goto fail_register;
628 : : }
629 : :
630 : : /* Map the service with the service core */
631 : 0 : rc = rte_service_map_lcore_set(sid, cid, 1);
632 [ # # ]: 0 : if (rc != 0) {
633 : 0 : rc = -rc;
634 : 0 : sfc_err(sa, "failed to map lcore for counter service: %s",
635 : : rte_strerror(rc));
636 : 0 : goto fail_map_lcore;
637 : : }
638 : :
639 : : /* Run the service */
640 : 0 : rc = rte_service_component_runstate_set(sid, 1);
641 [ # # ]: 0 : if (rc < 0) {
642 : 0 : rc = -rc;
643 : 0 : sfc_err(sa, "failed to run counter service component: %s",
644 : : rte_strerror(rc));
645 : 0 : goto fail_component_runstate_set;
646 : : }
647 : 0 : rc = rte_service_runstate_set(sid, 1);
648 [ # # ]: 0 : if (rc < 0) {
649 : 0 : rc = -rc;
650 : 0 : sfc_err(sa, "failed to run counter service");
651 : 0 : goto fail_runstate_set;
652 : : }
653 : :
654 : 0 : counter_registry->polling_mode = SFC_MAE_COUNTER_POLLING_SERVICE;
655 : 0 : counter_registry->polling.service.core_id = cid;
656 : 0 : counter_registry->polling.service.id = sid;
657 : :
658 : 0 : sfc_log_init(sa, "done");
659 : :
660 : 0 : return 0;
661 : :
662 : : fail_runstate_set:
663 : 0 : rte_service_component_runstate_set(sid, 0);
664 : :
665 : 0 : fail_component_runstate_set:
666 : 0 : rte_service_map_lcore_set(sid, cid, 0);
667 : :
668 : 0 : fail_map_lcore:
669 : 0 : rte_service_component_unregister(sid);
670 : :
671 : 0 : fail_register:
672 : 0 : fail_start_core:
673 : 0 : fail_get_service_lcore:
674 : 0 : sfc_log_init(sa, "failed: %s", rte_strerror(rc));
675 : :
676 : 0 : return rc;
677 : : }
678 : :
679 : : static void
680 : 0 : sfc_mae_counter_thread_stop(struct sfc_adapter *sa)
681 : : {
682 : 0 : struct sfc_mae_counter_registry *counter_registry =
683 : : &sa->mae.counter_registry;
684 : : int rc;
685 : :
686 : : /* Ensure that flag is set before attempting to join thread */
687 : 0 : __atomic_store_n(&counter_registry->polling.thread.run, false,
688 : : __ATOMIC_RELEASE);
689 : :
690 : 0 : rc = rte_thread_join(counter_registry->polling.thread.id, NULL);
691 [ # # ]: 0 : if (rc != 0)
692 : 0 : sfc_err(sa, "failed to join the MAE counter polling thread");
693 : :
694 : 0 : counter_registry->polling_mode = SFC_MAE_COUNTER_POLLING_OFF;
695 : 0 : }
696 : :
697 : : static int
698 : 0 : sfc_mae_counter_thread_spawn(struct sfc_adapter *sa,
699 : : uint32_t counter_stream_flags)
700 : : {
701 : : struct sfc_mae_counter_registry *counter_registry =
702 : : &sa->mae.counter_registry;
703 : : int rc;
704 : :
705 : 0 : sfc_log_init(sa, "entry");
706 : :
707 : : sfc_mae_counter_registry_prepare(counter_registry, sa,
708 : : counter_stream_flags);
709 : :
710 : 0 : counter_registry->polling_mode = SFC_MAE_COUNTER_POLLING_THREAD;
711 : 0 : counter_registry->polling.thread.run = true;
712 : :
713 : 0 : rc = rte_thread_create_internal_control(&sa->mae.counter_registry.polling.thread.id,
714 : : "sfc-maecnt", sfc_mae_counter_thread, sa);
715 : :
716 : 0 : return rc;
717 : : }
718 : :
719 : : int
720 : 0 : sfc_mae_counters_init(struct sfc_mae_counter_records *counters,
721 : : uint32_t nb_counters_max)
722 : : {
723 : : int rc;
724 : :
725 : 0 : SFC_GENERIC_LOG(DEBUG, "%s: entry", __func__);
726 : :
727 : 0 : counters->mae_counters = rte_zmalloc("sfc_mae_counters",
728 : : sizeof(*counters->mae_counters) * nb_counters_max, 0);
729 [ # # ]: 0 : if (counters->mae_counters == NULL) {
730 : : rc = ENOMEM;
731 : 0 : SFC_GENERIC_LOG(ERR, "%s: failed: %s", __func__,
732 : : rte_strerror(rc));
733 : 0 : return rc;
734 : : }
735 : :
736 : 0 : counters->n_mae_counters = nb_counters_max;
737 : :
738 : 0 : SFC_GENERIC_LOG(DEBUG, "%s: done", __func__);
739 : :
740 : 0 : return 0;
741 : : }
742 : :
743 : : void
744 : 0 : sfc_mae_counters_fini(struct sfc_mae_counter_records *counters)
745 : : {
746 : 0 : rte_free(counters->mae_counters);
747 : 0 : counters->mae_counters = NULL;
748 : 0 : }
749 : :
750 : : int
751 : 0 : sfc_mae_counter_rxq_attach(struct sfc_adapter *sa)
752 : : {
753 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
754 : : char name[RTE_MEMPOOL_NAMESIZE];
755 : : struct rte_mempool *mp;
756 : : unsigned int n_elements;
757 : : unsigned int cache_size;
758 : : /* The mempool is internal and private area is not required */
759 : : const uint16_t priv_size = 0;
760 : : const uint16_t data_room_size = RTE_PKTMBUF_HEADROOM +
761 : : SFC_MAE_COUNTER_STREAM_PACKET_SIZE;
762 : : int rc;
763 : :
764 : 0 : sfc_log_init(sa, "entry");
765 : :
766 [ # # ]: 0 : if (!sas->counters_rxq_allocated) {
767 : 0 : sfc_log_init(sa, "counter queue is not supported - skip");
768 : 0 : return 0;
769 : : }
770 : :
771 : : /*
772 : : * At least one element in the ring is always unused to distinguish
773 : : * between empty and full ring cases.
774 : : */
775 : : n_elements = SFC_COUNTER_RXQ_RX_DESC_COUNT - 1;
776 : :
777 : : /*
778 : : * The cache must have sufficient space to put received buckets
779 : : * before they're reused on refill.
780 : : */
781 : : cache_size = rte_align32pow2(SFC_COUNTER_RXQ_REFILL_LEVEL +
782 : : SFC_MAE_COUNTER_RX_BURST - 1);
783 : :
784 [ # # ]: 0 : if (snprintf(name, sizeof(name), "counter_rxq-pool-%u", sas->port_id) >=
785 : : (int)sizeof(name)) {
786 : 0 : sfc_err(sa, "failed: counter RxQ mempool name is too long");
787 : : rc = ENAMETOOLONG;
788 : 0 : goto fail_long_name;
789 : : }
790 : :
791 : : /*
792 : : * It could be single-producer single-consumer ring mempool which
793 : : * requires minimal barriers. However, cache size and refill/burst
794 : : * policy are aligned, therefore it does not matter which
795 : : * mempool backend is chosen since backend is unused.
796 : : */
797 : 0 : mp = rte_pktmbuf_pool_create(name, n_elements, cache_size,
798 : : priv_size, data_room_size, sa->socket_id);
799 [ # # ]: 0 : if (mp == NULL) {
800 : 0 : sfc_err(sa, "failed to create counter RxQ mempool");
801 : 0 : rc = rte_errno;
802 : 0 : goto fail_mp_create;
803 : : }
804 : :
805 : 0 : sa->counter_rxq.sw_index = sfc_counters_rxq_sw_index(sas);
806 : 0 : sa->counter_rxq.mp = mp;
807 : 0 : sa->counter_rxq.state |= SFC_COUNTER_RXQ_ATTACHED;
808 : :
809 : 0 : sfc_log_init(sa, "done");
810 : :
811 : 0 : return 0;
812 : :
813 : : fail_mp_create:
814 : 0 : fail_long_name:
815 : 0 : sfc_log_init(sa, "failed: %s", rte_strerror(rc));
816 : :
817 : 0 : return rc;
818 : : }
819 : :
820 : : void
821 : 0 : sfc_mae_counter_rxq_detach(struct sfc_adapter *sa)
822 : : {
823 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
824 : :
825 : 0 : sfc_log_init(sa, "entry");
826 : :
827 [ # # ]: 0 : if (!sas->counters_rxq_allocated) {
828 : 0 : sfc_log_init(sa, "counter queue is not supported - skip");
829 : 0 : return;
830 : : }
831 : :
832 [ # # ]: 0 : if ((sa->counter_rxq.state & SFC_COUNTER_RXQ_ATTACHED) == 0) {
833 : 0 : sfc_log_init(sa, "counter queue is not attached - skip");
834 : 0 : return;
835 : : }
836 : :
837 : 0 : rte_mempool_free(sa->counter_rxq.mp);
838 : 0 : sa->counter_rxq.mp = NULL;
839 : 0 : sa->counter_rxq.state &= ~SFC_COUNTER_RXQ_ATTACHED;
840 : :
841 : 0 : sfc_log_init(sa, "done");
842 : : }
843 : :
844 : : int
845 : 0 : sfc_mae_counter_rxq_init(struct sfc_adapter *sa)
846 : : {
847 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
848 : 0 : const struct rte_eth_rxconf rxconf = {
849 : : .rx_free_thresh = SFC_COUNTER_RXQ_REFILL_LEVEL,
850 : : .rx_drop_en = 1,
851 : : };
852 : : uint16_t nb_rx_desc = SFC_COUNTER_RXQ_RX_DESC_COUNT;
853 : : int rc;
854 : :
855 : 0 : sfc_log_init(sa, "entry");
856 : :
857 [ # # ]: 0 : if (!sas->counters_rxq_allocated) {
858 : 0 : sfc_log_init(sa, "counter queue is not supported - skip");
859 : 0 : return 0;
860 : : }
861 : :
862 [ # # ]: 0 : if ((sa->counter_rxq.state & SFC_COUNTER_RXQ_ATTACHED) == 0) {
863 : 0 : sfc_log_init(sa, "counter queue is not attached - skip");
864 : 0 : return 0;
865 : : }
866 : :
867 : 0 : nb_rx_desc = RTE_MIN(nb_rx_desc, sa->rxq_max_entries);
868 : 0 : nb_rx_desc = RTE_MAX(nb_rx_desc, sa->rxq_min_entries);
869 : :
870 : 0 : rc = sfc_rx_qinit_info(sa, sa->counter_rxq.sw_index,
871 : : EFX_RXQ_FLAG_USER_MARK);
872 [ # # ]: 0 : if (rc != 0)
873 : 0 : goto fail_counter_rxq_init_info;
874 : :
875 : 0 : rc = sfc_rx_qinit(sa, sa->counter_rxq.sw_index, nb_rx_desc,
876 : 0 : sa->socket_id, &rxconf, sa->counter_rxq.mp);
877 [ # # ]: 0 : if (rc != 0) {
878 : 0 : sfc_err(sa, "failed to init counter RxQ");
879 : 0 : goto fail_counter_rxq_init;
880 : : }
881 : :
882 : 0 : sa->counter_rxq.state |= SFC_COUNTER_RXQ_INITIALIZED;
883 : :
884 : 0 : sfc_log_init(sa, "done");
885 : :
886 : 0 : return 0;
887 : :
888 : : fail_counter_rxq_init:
889 : 0 : fail_counter_rxq_init_info:
890 : 0 : sfc_log_init(sa, "failed: %s", rte_strerror(rc));
891 : :
892 : 0 : return rc;
893 : : }
894 : :
895 : : void
896 : 0 : sfc_mae_counter_rxq_fini(struct sfc_adapter *sa)
897 : : {
898 : : struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
899 : :
900 : 0 : sfc_log_init(sa, "entry");
901 : :
902 [ # # ]: 0 : if (!sas->counters_rxq_allocated) {
903 : 0 : sfc_log_init(sa, "counter queue is not supported - skip");
904 : 0 : return;
905 : : }
906 : :
907 [ # # ]: 0 : if ((sa->counter_rxq.state & SFC_COUNTER_RXQ_INITIALIZED) == 0) {
908 : 0 : sfc_log_init(sa, "counter queue is not initialized - skip");
909 : 0 : return;
910 : : }
911 : :
912 : 0 : sfc_rx_qfini(sa, sa->counter_rxq.sw_index);
913 : :
914 : 0 : sfc_log_init(sa, "done");
915 : : }
916 : :
917 : : void
918 : 0 : sfc_mae_counter_stop(struct sfc_adapter *sa)
919 : : {
920 : : struct sfc_mae *mae = &sa->mae;
921 : :
922 : 0 : sfc_log_init(sa, "entry");
923 : :
924 [ # # ]: 0 : if (!mae->counter_rxq_running) {
925 : 0 : sfc_log_init(sa, "counter queue is not running - skip");
926 : 0 : return;
927 : : }
928 : :
929 : : SFC_ASSERT(mae->counter_registry.polling_mode !=
930 : : SFC_MAE_COUNTER_POLLING_OFF);
931 : :
932 [ # # ]: 0 : if (mae->counter_registry.polling_mode ==
933 : : SFC_MAE_COUNTER_POLLING_SERVICE)
934 : 0 : sfc_mae_counter_service_unregister(sa);
935 : : else
936 : 0 : sfc_mae_counter_thread_stop(sa);
937 : :
938 : 0 : efx_mae_counters_stream_stop(sa->nic, sa->counter_rxq.sw_index, NULL);
939 : :
940 : 0 : mae->counter_rxq_running = false;
941 : :
942 : 0 : sfc_log_init(sa, "done");
943 : : }
944 : :
945 : : int
946 : 0 : sfc_mae_counter_start(struct sfc_adapter *sa)
947 : : {
948 : : struct sfc_mae *mae = &sa->mae;
949 : : uint32_t flags;
950 : : int rc;
951 : :
952 : : SFC_ASSERT(sa->counter_rxq.state & SFC_COUNTER_RXQ_ATTACHED);
953 : :
954 [ # # ]: 0 : if (mae->counter_rxq_running)
955 : : return 0;
956 : :
957 : 0 : sfc_log_init(sa, "entry");
958 : :
959 : 0 : rc = efx_mae_counters_stream_start(sa->nic, sa->counter_rxq.sw_index,
960 : : SFC_MAE_COUNTER_STREAM_PACKET_SIZE,
961 : : 0 /* No flags required */, &flags);
962 [ # # ]: 0 : if (rc != 0) {
963 : 0 : sfc_err(sa, "failed to start MAE counters stream: %s",
964 : : rte_strerror(rc));
965 : 0 : goto fail_counter_stream;
966 : : }
967 : :
968 : 0 : sfc_log_init(sa, "stream start flags: 0x%x", flags);
969 : :
970 [ # # ]: 0 : if (sfc_mae_counter_get_service_lcore(sa) != RTE_MAX_LCORE) {
971 : 0 : rc = sfc_mae_counter_service_register(sa, flags);
972 [ # # ]: 0 : if (rc != 0)
973 : 0 : goto fail_service_register;
974 : : } else {
975 : 0 : rc = sfc_mae_counter_thread_spawn(sa, flags);
976 [ # # ]: 0 : if (rc != 0)
977 : 0 : goto fail_thread_spawn;
978 : : }
979 : :
980 : 0 : mae->counter_rxq_running = true;
981 : :
982 : 0 : return 0;
983 : :
984 : : fail_service_register:
985 : 0 : fail_thread_spawn:
986 : 0 : efx_mae_counters_stream_stop(sa->nic, sa->counter_rxq.sw_index, NULL);
987 : :
988 : 0 : fail_counter_stream:
989 : 0 : sfc_log_init(sa, "failed: %s", rte_strerror(rc));
990 : :
991 : 0 : return rc;
992 : : }
993 : :
994 : : int
995 : 0 : sfc_mae_counter_get(struct sfc_adapter *sa,
996 : : const struct sfc_mae_counter *counter,
997 : : struct rte_flow_query_count *data)
998 : : {
999 : 0 : struct sfc_ft_ctx *ft_ctx = counter->ft_ctx;
1000 : : struct sfc_mae_counter_records *counters;
1001 : : uint64_t non_reset_tunnel_hit_counter;
1002 : : struct sfc_mae_counter_record *p;
1003 : : union sfc_pkts_bytes value;
1004 : : bool need_byte_count;
1005 : :
1006 [ # # # ]: 0 : switch (counter->type) {
1007 : 0 : case EFX_COUNTER_TYPE_ACTION:
1008 : 0 : counters = &sa->mae.counter_registry.action_counters;
1009 : : need_byte_count = true;
1010 : 0 : break;
1011 : 0 : case EFX_COUNTER_TYPE_CONNTRACK:
1012 : 0 : counters = &sa->mae.counter_registry.conntrack_counters;
1013 : : need_byte_count = false;
1014 : 0 : break;
1015 : : default:
1016 : : return EINVAL;
1017 : : }
1018 : :
1019 : : SFC_ASSERT(counter->fw_rsrc.counter_id.id < counters->n_mae_counters);
1020 : 0 : p = &counters->mae_counters[counter->fw_rsrc.counter_id.id];
1021 : :
1022 : : /*
1023 : : * Ordering is relaxed since it is the only operation on counter value.
1024 : : * And it does not depend on different stores/loads in other threads.
1025 : : * Paired with relaxed ordering in counter increment.
1026 : : */
1027 : 0 : value.pkts_bytes.int128 = __atomic_load_n(&p->value.pkts_bytes.int128,
1028 : : __ATOMIC_RELAXED);
1029 : :
1030 : 0 : data->hits_set = 1;
1031 : 0 : data->hits = value.pkts - p->reset.pkts;
1032 : :
1033 [ # # ]: 0 : if (ft_ctx != NULL) {
1034 : 0 : data->hits += ft_ctx->switch_hit_counter;
1035 : : non_reset_tunnel_hit_counter = data->hits;
1036 : 0 : data->hits -= ft_ctx->reset_tunnel_hit_counter;
1037 [ # # ]: 0 : } else if (need_byte_count) {
1038 : 0 : data->bytes_set = 1;
1039 : 0 : data->bytes = value.bytes - p->reset.bytes;
1040 : : }
1041 : :
1042 [ # # ]: 0 : if (data->reset != 0) {
1043 [ # # ]: 0 : if (ft_ctx != NULL) {
1044 : 0 : ft_ctx->reset_tunnel_hit_counter =
1045 : : non_reset_tunnel_hit_counter;
1046 : : } else {
1047 : 0 : p->reset.pkts = value.pkts;
1048 : :
1049 [ # # ]: 0 : if (need_byte_count)
1050 : 0 : p->reset.bytes = value.bytes;
1051 : : }
1052 : : }
1053 : :
1054 : : return 0;
1055 : : }
1056 : :
1057 : : bool
1058 : 0 : sfc_mae_counter_stream_enabled(struct sfc_adapter *sa)
1059 : : {
1060 [ # # # # ]: 0 : if ((sa->counter_rxq.state & SFC_COUNTER_RXQ_INITIALIZED) == 0 ||
1061 : 0 : sfc_get_service_lcore(SOCKET_ID_ANY) == RTE_MAX_LCORE)
1062 : 0 : return B_FALSE;
1063 : : else
1064 : : return B_TRUE;
1065 : : }
|