Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : *
3 : : * Copyright(c) 2019-2021 Xilinx, Inc.
4 : : * Copyright(c) 2018-2019 Solarflare Communications Inc.
5 : : */
6 : :
7 : : #include "efx.h"
8 : : #include "efx_impl.h"
9 : :
10 : : #if EFSYS_OPT_RIVERHEAD
11 : :
12 : : /*
13 : : * Non-interrupting event queue requires interrupting event queue to
14 : : * refer to for wake-up events even if wake ups are never used.
15 : : * It could be even non-allocated event queue.
16 : : */
17 : : #define EFX_RHEAD_ALWAYS_INTERRUPTING_EVQ_INDEX (0)
18 : :
19 : : static boolean_t
20 : : rhead_ev_dispatch(
21 : : __in efx_evq_t *eep,
22 : : __in efx_qword_t *eventp,
23 : : __in const efx_ev_callbacks_t *eecp,
24 : : __in_opt void *arg);
25 : :
26 : : static __checkReturn boolean_t
27 : : rhead_ev_rx_packets(
28 : : __in efx_evq_t *eep,
29 : : __in efx_qword_t *eqp,
30 : : __in const efx_ev_callbacks_t *eecp,
31 : : __in_opt void *arg);
32 : :
33 : : static __checkReturn boolean_t
34 : : rhead_ev_tx_completion(
35 : : __in efx_evq_t *eep,
36 : : __in efx_qword_t *eqp,
37 : : __in const efx_ev_callbacks_t *eecp,
38 : : __in_opt void *arg);
39 : :
40 : : static __checkReturn boolean_t
41 : : rhead_ev_mcdi(
42 : : __in efx_evq_t *eep,
43 : : __in efx_qword_t *eqp,
44 : : __in const efx_ev_callbacks_t *eecp,
45 : : __in_opt void *arg);
46 : :
47 : : #if EFSYS_OPT_EV_EXTENDED_WIDTH
48 : : static boolean_t
49 : : rhead_ev_ew_dispatch(
50 : : __in efx_evq_t *eep,
51 : : __in efx_xword_t *eventp,
52 : : __in const efx_ev_callbacks_t *eecp,
53 : : __in_opt void *arg);
54 : :
55 : : static void
56 : : rhead_ev_ew_qpoll(
57 : : __in efx_evq_t *eep,
58 : : __inout unsigned int *countp,
59 : : __in const efx_ev_callbacks_t *eecp,
60 : : __in_opt void *arg);
61 : :
62 : : #if EFSYS_OPT_DESC_PROXY
63 : : static boolean_t
64 : : rhead_ev_ew_txq_desc(
65 : : __in efx_evq_t *eep,
66 : : __in efx_xword_t *eventp,
67 : : __in const efx_ev_callbacks_t *eecp,
68 : : __in_opt void *arg);
69 : :
70 : : static boolean_t
71 : : rhead_ev_ew_virtq_desc(
72 : : __in efx_evq_t *eep,
73 : : __in efx_xword_t *eventp,
74 : : __in const efx_ev_callbacks_t *eecp,
75 : : __in_opt void *arg);
76 : : #endif /* EFSYS_OPT_DESC_PROXY */
77 : : #endif /* EFSYS_OPT_EV_EXTENDED_WIDTH */
78 : :
79 : :
80 : : __checkReturn efx_rc_t
81 : 0 : rhead_ev_init(
82 : : __in efx_nic_t *enp)
83 : : {
84 : : _NOTE(ARGUNUSED(enp))
85 : :
86 : 0 : return (0);
87 : : }
88 : :
89 : : void
90 : 0 : rhead_ev_fini(
91 : : __in efx_nic_t *enp)
92 : : {
93 : : _NOTE(ARGUNUSED(enp))
94 : 0 : }
95 : :
96 : : __checkReturn efx_rc_t
97 : 0 : rhead_ev_qcreate(
98 : : __in efx_nic_t *enp,
99 : : __in unsigned int index,
100 : : __in efsys_mem_t *esmp,
101 : : __in size_t ndescs,
102 : : __in uint32_t id,
103 : : __in uint32_t us,
104 : : __in uint32_t flags,
105 : : __in uint32_t irq,
106 : : __in efx_evq_t *eep)
107 : : {
108 : 0 : const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
109 : : size_t desc_size;
110 : : uint32_t target_evq = 0;
111 : : efx_rc_t rc;
112 : :
113 : : _NOTE(ARGUNUSED(id)) /* buftbl id managed by MC */
114 : :
115 : 0 : desc_size = encp->enc_ev_desc_size;
116 : : #if EFSYS_OPT_EV_EXTENDED_WIDTH
117 : : if (flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH)
118 : : desc_size = encp->enc_ev_ew_desc_size;
119 : : #endif
120 [ # # ]: 0 : EFSYS_ASSERT(desc_size != 0);
121 : :
122 [ # # ]: 0 : if (EFSYS_MEM_SIZE(esmp) < (ndescs * desc_size)) {
123 : : /* Buffer too small for event queue descriptors */
124 : : rc = EINVAL;
125 : 0 : goto fail1;
126 : : }
127 : :
128 : : /* Set up the handler table */
129 : 0 : eep->ee_rx = rhead_ev_rx_packets;
130 : 0 : eep->ee_tx = rhead_ev_tx_completion;
131 : 0 : eep->ee_driver = NULL; /* FIXME */
132 : 0 : eep->ee_drv_gen = NULL; /* FIXME */
133 : 0 : eep->ee_mcdi = rhead_ev_mcdi;
134 : :
135 : : #if EFSYS_OPT_DESC_PROXY
136 : : eep->ee_ew_txq_desc = rhead_ev_ew_txq_desc;
137 : : eep->ee_ew_virtq_desc = rhead_ev_ew_virtq_desc;
138 : : #endif /* EFSYS_OPT_DESC_PROXY */
139 : :
140 : : /* Set up the event queue */
141 : : /* INIT_EVQ expects function-relative vector number */
142 [ # # ]: 0 : if ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
143 : : EFX_EVQ_FLAGS_NOTIFY_INTERRUPT) {
144 : : /* IRQ number is specified by caller */
145 [ # # ]: 0 : } else if (index == EFX_RHEAD_ALWAYS_INTERRUPTING_EVQ_INDEX) {
146 : : /* Use the first interrupt for always interrupting EvQ */
147 : : irq = 0;
148 : 0 : flags = (flags & ~EFX_EVQ_FLAGS_NOTIFY_MASK) |
149 : : EFX_EVQ_FLAGS_NOTIFY_INTERRUPT;
150 : : } else {
151 : : target_evq = EFX_RHEAD_ALWAYS_INTERRUPTING_EVQ_INDEX;
152 : : }
153 : :
154 : : /*
155 : : * Interrupts may be raised for events immediately after the queue is
156 : : * created. See bug58606.
157 : : */
158 : 0 : rc = efx_mcdi_init_evq(enp, index, esmp, ndescs, irq, target_evq, us,
159 : : flags, B_FALSE);
160 [ # # ]: 0 : if (rc != 0)
161 : 0 : goto fail2;
162 : :
163 : : return (0);
164 : :
165 : : fail2:
166 : : EFSYS_PROBE(fail2);
167 : : fail1:
168 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
169 : :
170 : : return (rc);
171 : : }
172 : :
173 : : void
174 : 0 : rhead_ev_qdestroy(
175 : : __in efx_evq_t *eep)
176 : : {
177 : 0 : efx_nic_t *enp = eep->ee_enp;
178 : :
179 [ # # ]: 0 : EFSYS_ASSERT(enp->en_family == EFX_FAMILY_RIVERHEAD);
180 : :
181 : 0 : (void) efx_mcdi_fini_evq(enp, eep->ee_index);
182 : 0 : }
183 : :
184 : : __checkReturn efx_rc_t
185 : 0 : rhead_ev_qprime(
186 : : __in efx_evq_t *eep,
187 : : __in unsigned int count)
188 : : {
189 : 0 : efx_nic_t *enp = eep->ee_enp;
190 : : uint32_t rptr;
191 : : efx_dword_t dword;
192 : :
193 : 0 : rptr = count & eep->ee_mask;
194 : :
195 : 0 : EFX_POPULATE_DWORD_2(dword, ERF_GZ_EVQ_ID, eep->ee_index,
196 : : ERF_GZ_IDX, rptr);
197 : : /* EVQ_INT_PRIME lives function control window only on Riverhead */
198 [ # # # # : 0 : EFX_BAR_FCW_WRITED(enp, ER_GZ_EVQ_INT_PRIME, &dword);
# # ]
199 : :
200 : 0 : return (0);
201 : : }
202 : :
203 : : void
204 : 0 : rhead_ev_qpost(
205 : : __in efx_evq_t *eep,
206 : : __in uint16_t data)
207 : : {
208 : : _NOTE(ARGUNUSED(eep, data))
209 : :
210 : : /* Not implemented yet */
211 : 0 : EFSYS_ASSERT(B_FALSE);
212 : : }
213 : :
214 : : static __checkReturn boolean_t
215 : 0 : rhead_ev_dispatch(
216 : : __in efx_evq_t *eep,
217 : : __in efx_qword_t *eventp,
218 : : __in const efx_ev_callbacks_t *eecp,
219 : : __in_opt void *arg)
220 : : {
221 : : boolean_t should_abort;
222 : : uint32_t code;
223 : :
224 : 0 : code = EFX_QWORD_FIELD(*eventp, ESF_GZ_E_TYPE);
225 [ # # # # ]: 0 : switch (code) {
226 : 0 : case ESE_GZ_EF100_EV_RX_PKTS:
227 : 0 : should_abort = eep->ee_rx(eep, eventp, eecp, arg);
228 : 0 : break;
229 : 0 : case ESE_GZ_EF100_EV_TX_COMPLETION:
230 : 0 : should_abort = eep->ee_tx(eep, eventp, eecp, arg);
231 : 0 : break;
232 : 0 : case ESE_GZ_EF100_EV_MCDI:
233 : 0 : should_abort = eep->ee_mcdi(eep, eventp, eecp, arg);
234 : 0 : break;
235 : 0 : default:
236 : : EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index,
237 : : uint32_t, EFX_QWORD_FIELD(*eventp, EFX_DWORD_1),
238 : : uint32_t, EFX_QWORD_FIELD(*eventp, EFX_DWORD_0));
239 : :
240 [ # # ]: 0 : EFSYS_ASSERT(eecp->eec_exception != NULL);
241 : 0 : (void) eecp->eec_exception(arg, EFX_EXCEPTION_EV_ERROR, code);
242 : : should_abort = B_TRUE;
243 : 0 : break;
244 : : }
245 : :
246 : 0 : return (should_abort);
247 : : }
248 : :
249 : : /*
250 : : * Poll event queue in batches. Size of the batch is equal to cache line
251 : : * size divided by event size.
252 : : *
253 : : * Event queue is written by NIC and read by CPU. If CPU starts reading
254 : : * of events on the cache line, read all remaining events in a tight
255 : : * loop while event is present.
256 : : */
257 : : #define EF100_EV_BATCH 8
258 : :
259 : : /*
260 : : * Check if event is present.
261 : : *
262 : : * Riverhead EvQs use a phase bit to indicate the presence of valid events,
263 : : * by flipping the phase bit on each wrap of the write index.
264 : : */
265 : : #define EF100_EV_PRESENT(_qword, _phase_bit) \
266 : : (EFX_QWORD_FIELD((_qword), ESF_GZ_EV_EVQ_PHASE) == _phase_bit)
267 : :
268 : : void
269 : 0 : rhead_ev_qpoll(
270 : : __in efx_evq_t *eep,
271 : : __inout unsigned int *countp,
272 : : __in const efx_ev_callbacks_t *eecp,
273 : : __in_opt void *arg)
274 : : {
275 : : efx_qword_t ev[EF100_EV_BATCH];
276 : : unsigned int batch;
277 : : unsigned int phase_bit;
278 : : unsigned int total;
279 : : unsigned int count;
280 : : unsigned int index;
281 : : size_t offset;
282 : :
283 : : #if EFSYS_OPT_EV_EXTENDED_WIDTH
284 : : if (eep->ee_flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH) {
285 : : rhead_ev_ew_qpoll(eep, countp, eecp, arg);
286 : : return;
287 : : }
288 : : #endif /* EFSYS_OPT_EV_EXTENDED_WIDTH */
289 : :
290 [ # # ]: 0 : EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
291 [ # # ]: 0 : EFSYS_ASSERT(countp != NULL);
292 [ # # ]: 0 : EFSYS_ASSERT(eecp != NULL);
293 : :
294 : 0 : count = *countp;
295 : : do {
296 : : /* Read up until the end of the batch period */
297 : 0 : batch = EF100_EV_BATCH - (count & (EF100_EV_BATCH - 1));
298 : 0 : phase_bit = (count & (eep->ee_mask + 1)) != 0;
299 : 0 : offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
300 [ # # ]: 0 : for (total = 0; total < batch; ++total) {
301 : 0 : EFSYS_MEM_READQ(eep->ee_esmp, offset, &(ev[total]));
302 : :
303 [ # # ]: 0 : if (!EF100_EV_PRESENT(ev[total], phase_bit))
304 : : break;
305 : :
306 : : EFSYS_PROBE3(event, unsigned int, eep->ee_index,
307 : : uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_1),
308 : : uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_0));
309 : :
310 : 0 : offset += sizeof (efx_qword_t);
311 : : }
312 : :
313 : : /* Process the batch of events */
314 [ # # ]: 0 : for (index = 0; index < total; ++index) {
315 : : boolean_t should_abort;
316 : :
317 : : EFX_EV_QSTAT_INCR(eep, EV_ALL);
318 : :
319 : : should_abort =
320 : 0 : rhead_ev_dispatch(eep, &(ev[index]), eecp, arg);
321 : :
322 [ # # ]: 0 : if (should_abort) {
323 : : /* Ignore subsequent events */
324 : 0 : total = index + 1;
325 : :
326 : : /*
327 : : * Poison batch to ensure the outer
328 : : * loop is broken out of.
329 : : */
330 : : EFSYS_ASSERT(batch <= EF100_EV_BATCH);
331 : 0 : batch += (EF100_EV_BATCH << 1);
332 : : EFSYS_ASSERT(total != batch);
333 : : break;
334 : : }
335 : : }
336 : :
337 : : /*
338 : : * There is no necessity to clear processed events since
339 : : * phase bit which is flipping on each write index wrap
340 : : * is used for event presence indication.
341 : : */
342 : :
343 : 0 : count += total;
344 : :
345 [ # # ]: 0 : } while (total == batch);
346 : :
347 : 0 : *countp = count;
348 : 0 : }
349 : :
350 : : #if EFSYS_OPT_EV_EXTENDED_WIDTH
351 : : static boolean_t
352 : : rhead_ev_ew_dispatch(
353 : : __in efx_evq_t *eep,
354 : : __in efx_xword_t *eventp,
355 : : __in const efx_ev_callbacks_t *eecp,
356 : : __in_opt void *arg)
357 : : {
358 : : boolean_t should_abort;
359 : : uint32_t code;
360 : :
361 : : EFSYS_ASSERT((eep->ee_flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH) != 0);
362 : :
363 : : code = EFX_XWORD_FIELD(*eventp, ESF_GZ_EV_256_EV32_TYPE);
364 : : switch (code) {
365 : : case ESE_GZ_EF100_EVEW_64BIT:
366 : : /* NOTE: ignore phase bit in encapsulated 64bit event. */
367 : : should_abort =
368 : : rhead_ev_dispatch(eep, &eventp->ex_qword[0], eecp, arg);
369 : : break;
370 : :
371 : : #if EFSYS_OPT_DESC_PROXY
372 : : case ESE_GZ_EF100_EVEW_TXQ_DESC:
373 : : should_abort = eep->ee_ew_txq_desc(eep, eventp, eecp, arg);
374 : : break;
375 : :
376 : : case ESE_GZ_EF100_EVEW_VIRTQ_DESC:
377 : : should_abort = eep->ee_ew_virtq_desc(eep, eventp, eecp, arg);
378 : : break;
379 : : #endif /* EFSYS_OPT_DESC_PROXY */
380 : :
381 : : default:
382 : : /* Omit currently unused reserved bits from the probe. */
383 : : EFSYS_PROBE7(ew_bad_event, unsigned int, eep->ee_index,
384 : : uint32_t, EFX_XWORD_FIELD(*eventp, EFX_DWORD_7),
385 : : uint32_t, EFX_XWORD_FIELD(*eventp, EFX_DWORD_4),
386 : : uint32_t, EFX_XWORD_FIELD(*eventp, EFX_DWORD_3),
387 : : uint32_t, EFX_XWORD_FIELD(*eventp, EFX_DWORD_2),
388 : : uint32_t, EFX_XWORD_FIELD(*eventp, EFX_DWORD_1),
389 : : uint32_t, EFX_XWORD_FIELD(*eventp, EFX_DWORD_0));
390 : :
391 : : EFSYS_ASSERT(eecp->eec_exception != NULL);
392 : : (void) eecp->eec_exception(arg, EFX_EXCEPTION_EV_ERROR, code);
393 : : should_abort = B_TRUE;
394 : : }
395 : :
396 : : return (should_abort);
397 : : }
398 : :
399 : : /*
400 : : * Poll extended width event queue. Size of the batch is equal to cache line
401 : : * size divided by event size.
402 : : */
403 : : #define EF100_EV_EW_BATCH 2
404 : :
405 : : /*
406 : : * Check if event is present.
407 : : *
408 : : * Riverhead EvQs use a phase bit to indicate the presence of valid events,
409 : : * by flipping the phase bit on each wrap of the write index.
410 : : */
411 : : #define EF100_EV_EW_PRESENT(_xword, _phase_bit) \
412 : : (EFX_XWORD_FIELD((_xword), ESF_GZ_EV_256_EV32_PHASE) == (_phase_bit))
413 : :
414 : : static void
415 : : rhead_ev_ew_qpoll(
416 : : __in efx_evq_t *eep,
417 : : __inout unsigned int *countp,
418 : : __in const efx_ev_callbacks_t *eecp,
419 : : __in_opt void *arg)
420 : : {
421 : : efx_xword_t ev[EF100_EV_EW_BATCH];
422 : : unsigned int batch;
423 : : unsigned int phase_bit;
424 : : unsigned int total;
425 : : unsigned int count;
426 : : unsigned int index;
427 : : size_t offset;
428 : :
429 : : EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
430 : : EFSYS_ASSERT((eep->ee_flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH) != 0);
431 : : EFSYS_ASSERT(countp != NULL);
432 : : EFSYS_ASSERT(eecp != NULL);
433 : :
434 : : count = *countp;
435 : : do {
436 : : /* Read up until the end of the batch period */
437 : : batch = EF100_EV_EW_BATCH - (count & (EF100_EV_EW_BATCH - 1));
438 : : phase_bit = (count & (eep->ee_mask + 1)) != 0;
439 : : offset = (count & eep->ee_mask) * sizeof (efx_xword_t);
440 : : for (total = 0; total < batch; ++total) {
441 : : EFSYS_MEM_READX(eep->ee_esmp, offset, &(ev[total]));
442 : :
443 : : if (!EF100_EV_EW_PRESENT(ev[total], phase_bit))
444 : : break;
445 : :
446 : : /* Omit unused reserved bits from the probe. */
447 : : EFSYS_PROBE7(ew_event, unsigned int, eep->ee_index,
448 : : uint32_t, EFX_XWORD_FIELD(ev[total], EFX_DWORD_7),
449 : : uint32_t, EFX_XWORD_FIELD(ev[total], EFX_DWORD_4),
450 : : uint32_t, EFX_XWORD_FIELD(ev[total], EFX_DWORD_3),
451 : : uint32_t, EFX_XWORD_FIELD(ev[total], EFX_DWORD_2),
452 : : uint32_t, EFX_XWORD_FIELD(ev[total], EFX_DWORD_1),
453 : : uint32_t, EFX_XWORD_FIELD(ev[total], EFX_DWORD_0));
454 : :
455 : : offset += sizeof (efx_xword_t);
456 : : }
457 : :
458 : : /* Process the batch of events */
459 : : for (index = 0; index < total; ++index) {
460 : : boolean_t should_abort;
461 : :
462 : : EFX_EV_QSTAT_INCR(eep, EV_ALL);
463 : :
464 : : should_abort =
465 : : rhead_ev_ew_dispatch(eep, &(ev[index]), eecp, arg);
466 : :
467 : : if (should_abort) {
468 : : /* Ignore subsequent events */
469 : : total = index + 1;
470 : :
471 : : /*
472 : : * Poison batch to ensure the outer
473 : : * loop is broken out of.
474 : : */
475 : : EFSYS_ASSERT(batch <= EF100_EV_EW_BATCH);
476 : : batch += (EF100_EV_EW_BATCH << 1);
477 : : EFSYS_ASSERT(total != batch);
478 : : break;
479 : : }
480 : : }
481 : :
482 : : /*
483 : : * There is no necessity to clear processed events since
484 : : * phase bit which is flipping on each write index wrap
485 : : * is used for event presence indication.
486 : : */
487 : :
488 : : count += total;
489 : :
490 : : } while (total == batch);
491 : :
492 : : *countp = count;
493 : : }
494 : : #endif /* EFSYS_OPT_EV_EXTENDED_WIDTH */
495 : :
496 : :
497 : : __checkReturn efx_rc_t
498 : 0 : rhead_ev_qmoderate(
499 : : __in efx_evq_t *eep,
500 : : __in unsigned int us)
501 : : {
502 : : _NOTE(ARGUNUSED(eep, us))
503 : :
504 : 0 : return (ENOTSUP);
505 : : }
506 : :
507 : :
508 : : #if EFSYS_OPT_QSTATS
509 : : void
510 : : rhead_ev_qstats_update(
511 : : __in efx_evq_t *eep,
512 : : __inout_ecount(EV_NQSTATS) efsys_stat_t *stat)
513 : : {
514 : : unsigned int id;
515 : :
516 : : for (id = 0; id < EV_NQSTATS; id++) {
517 : : efsys_stat_t *essp = &stat[id];
518 : :
519 : : EFSYS_STAT_INCR(essp, eep->ee_stat[id]);
520 : : eep->ee_stat[id] = 0;
521 : : }
522 : : }
523 : : #endif /* EFSYS_OPT_QSTATS */
524 : :
525 : : static __checkReturn boolean_t
526 : 0 : rhead_ev_rx_packets(
527 : : __in efx_evq_t *eep,
528 : : __in efx_qword_t *eqp,
529 : : __in const efx_ev_callbacks_t *eecp,
530 : : __in_opt void *arg)
531 : : {
532 : 0 : efx_nic_t *enp = eep->ee_enp;
533 : : uint32_t label;
534 : : uint32_t num_packets;
535 : : boolean_t should_abort;
536 : :
537 : : EFX_EV_QSTAT_INCR(eep, EV_RX);
538 : :
539 : : /* Discard events after RXQ/TXQ errors, or hardware not available */
540 [ # # ]: 0 : if (enp->en_reset_flags &
541 : : (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR | EFX_RESET_HW_UNAVAIL))
542 : : return (B_FALSE);
543 : :
544 : 0 : label = EFX_QWORD_FIELD(*eqp, ESF_GZ_EV_RXPKTS_Q_LABEL);
545 : :
546 : : /*
547 : : * On EF100 the EV_RX event reports the number of received
548 : : * packets (unlike EF10 which reports a descriptor index).
549 : : * The client driver is responsible for maintaining the Rx
550 : : * descriptor index, and computing how many descriptors are
551 : : * occupied by each received packet (based on the Rx buffer size
552 : : * and the packet length from the Rx prefix).
553 : : */
554 : 0 : num_packets = EFX_QWORD_FIELD(*eqp, ESF_GZ_EV_RXPKTS_NUM_PKT);
555 : :
556 : : /*
557 : : * The receive event may indicate more than one packet, and so
558 : : * does not contain the packet length. Read the packet length
559 : : * from the prefix when handling each packet.
560 : : */
561 [ # # ]: 0 : EFSYS_ASSERT(eecp->eec_rx_packets != NULL);
562 : 0 : should_abort = eecp->eec_rx_packets(arg, label, num_packets,
563 : : EFX_PKT_PREFIX_LEN);
564 : :
565 : 0 : return (should_abort);
566 : : }
567 : :
568 : : static __checkReturn boolean_t
569 : 0 : rhead_ev_tx_completion(
570 : : __in efx_evq_t *eep,
571 : : __in efx_qword_t *eqp,
572 : : __in const efx_ev_callbacks_t *eecp,
573 : : __in_opt void *arg)
574 : : {
575 : 0 : efx_nic_t *enp = eep->ee_enp;
576 : : uint32_t num_descs;
577 : : uint32_t label;
578 : : boolean_t should_abort;
579 : :
580 : : EFX_EV_QSTAT_INCR(eep, EV_TX);
581 : :
582 : : /* Discard events after RXQ/TXQ errors, or hardware not available */
583 [ # # ]: 0 : if (enp->en_reset_flags &
584 : : (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR | EFX_RESET_HW_UNAVAIL))
585 : : return (B_FALSE);
586 : :
587 : 0 : label = EFX_QWORD_FIELD(*eqp, ESF_GZ_EV_TXCMPL_Q_LABEL);
588 : :
589 : : /*
590 : : * On EF100 the EV_TX event reports the number of completed Tx
591 : : * descriptors (on EF10, the event reports the low bits of the
592 : : * index of the last completed descriptor).
593 : : * The client driver completion callback will compute the
594 : : * descriptor index, so that is not needed here.
595 : : */
596 : 0 : num_descs = EFX_QWORD_FIELD(*eqp, ESF_GZ_EV_TXCMPL_NUM_DESC);
597 : :
598 : : EFSYS_PROBE2(tx_ndescs, uint32_t, label, unsigned int, num_descs);
599 : :
600 [ # # ]: 0 : EFSYS_ASSERT(eecp->eec_tx_ndescs != NULL);
601 : 0 : should_abort = eecp->eec_tx_ndescs(arg, label, num_descs);
602 : :
603 : 0 : return (should_abort);
604 : : }
605 : :
606 : : static __checkReturn boolean_t
607 : 0 : rhead_ev_mcdi(
608 : : __in efx_evq_t *eep,
609 : : __in efx_qword_t *eqp,
610 : : __in const efx_ev_callbacks_t *eecp,
611 : : __in_opt void *arg)
612 : : {
613 : : boolean_t ret;
614 : :
615 : : /*
616 : : * Event format was changed post Riverhead R1 and now
617 : : * MCDI event layout on EF100 is exactly the same as on EF10
618 : : * except added QDMA phase bit which is unused on EF10.
619 : : */
620 : 0 : ret = ef10_ev_mcdi(eep, eqp, eecp, arg);
621 : :
622 : 0 : return (ret);
623 : : }
624 : :
625 : : #if EFSYS_OPT_DESC_PROXY
626 : : static boolean_t
627 : : rhead_ev_ew_txq_desc(
628 : : __in efx_evq_t *eep,
629 : : __in efx_xword_t *eventp,
630 : : __in const efx_ev_callbacks_t *eecp,
631 : : __in_opt void *arg)
632 : : {
633 : : efx_oword_t txq_desc;
634 : : uint16_t vi_id;
635 : : boolean_t should_abort;
636 : :
637 : : _NOTE(ARGUNUSED(eep))
638 : :
639 : : vi_id = EFX_XWORD_FIELD(*eventp, ESF_GZ_EV_TXQ_DP_VI_ID);
640 : :
641 : : /*
642 : : * NOTE: This is the raw descriptor data, and has not been converted
643 : : * to host endian. The handler callback must use the EFX_OWORD macros
644 : : * to extract the descriptor fields as host endian values.
645 : : */
646 : : txq_desc = eventp->ex_oword[0];
647 : :
648 : : EFSYS_ASSERT(eecp->eec_desc_proxy_txq_desc != NULL);
649 : : should_abort = eecp->eec_desc_proxy_txq_desc(arg, vi_id, txq_desc);
650 : :
651 : : return (should_abort);
652 : : }
653 : : #endif /* EFSYS_OPT_DESC_PROXY */
654 : :
655 : :
656 : : #if EFSYS_OPT_DESC_PROXY
657 : : static boolean_t
658 : : rhead_ev_ew_virtq_desc(
659 : : __in efx_evq_t *eep,
660 : : __in efx_xword_t *eventp,
661 : : __in const efx_ev_callbacks_t *eecp,
662 : : __in_opt void *arg)
663 : : {
664 : : efx_oword_t virtq_desc;
665 : : uint16_t vi_id;
666 : : uint16_t avail;
667 : : boolean_t should_abort;
668 : :
669 : : _NOTE(ARGUNUSED(eep))
670 : :
671 : : vi_id = EFX_XWORD_FIELD(*eventp, ESF_GZ_EV_VQ_DP_VI_ID);
672 : : avail = EFX_XWORD_FIELD(*eventp, ESF_GZ_EV_VQ_DP_AVAIL_ENTRY);
673 : :
674 : : /*
675 : : * NOTE: This is the raw descriptor data, and has not been converted
676 : : * to host endian. The handler callback must use the EFX_OWORD macros
677 : : * to extract the descriptor fields as host endian values.
678 : : */
679 : : virtq_desc = eventp->ex_oword[0];
680 : :
681 : : EFSYS_ASSERT(eecp->eec_desc_proxy_virtq_desc != NULL);
682 : : should_abort =
683 : : eecp->eec_desc_proxy_virtq_desc(arg, vi_id, avail, virtq_desc);
684 : :
685 : : return (should_abort);
686 : : }
687 : : #endif /* EFSYS_OPT_DESC_PROXY */
688 : :
689 : : #endif /* EFSYS_OPT_RIVERHEAD */
|