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 rhead_ev_init( 82 __in efx_nic_t *enp) 83 { 84 _NOTE(ARGUNUSED(enp)) 85 86 return (0); 87 } 88 89 void 90 rhead_ev_fini( 91 __in efx_nic_t *enp) 92 { 93 _NOTE(ARGUNUSED(enp)) 94 } 95 96 __checkReturn efx_rc_t 97 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 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 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 EFSYS_ASSERT(desc_size != 0); 121 122 if (EFSYS_MEM_SIZE(esmp) < (ndescs * desc_size)) { 123 /* Buffer too small for event queue descriptors */ 124 rc = EINVAL; 125 goto fail1; 126 } 127 128 /* Set up the handler table */ 129 eep->ee_rx = rhead_ev_rx_packets; 130 eep->ee_tx = rhead_ev_tx_completion; 131 eep->ee_driver = NULL; /* FIXME */ 132 eep->ee_drv_gen = NULL; /* FIXME */ 133 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 if ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) == 143 EFX_EVQ_FLAGS_NOTIFY_INTERRUPT) { 144 /* IRQ number is specified by caller */ 145 } else if (index == EFX_RHEAD_ALWAYS_INTERRUPTING_EVQ_INDEX) { 146 /* Use the first interrupt for always interrupting EvQ */ 147 irq = 0; 148 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 rc = efx_mcdi_init_evq(enp, index, esmp, ndescs, irq, target_evq, us, 159 flags, B_FALSE); 160 if (rc != 0) 161 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 rhead_ev_qdestroy( 175 __in efx_evq_t *eep) 176 { 177 efx_nic_t *enp = eep->ee_enp; 178 179 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_RIVERHEAD); 180 181 (void) efx_mcdi_fini_evq(enp, eep->ee_index); 182 } 183 184 __checkReturn efx_rc_t 185 rhead_ev_qprime( 186 __in efx_evq_t *eep, 187 __in unsigned int count) 188 { 189 efx_nic_t *enp = eep->ee_enp; 190 uint32_t rptr; 191 efx_dword_t dword; 192 193 rptr = count & eep->ee_mask; 194 195 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 EFX_BAR_FCW_WRITED(enp, ER_GZ_EVQ_INT_PRIME, &dword); 199 200 return (0); 201 } 202 203 void 204 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 EFSYS_ASSERT(B_FALSE); 212 } 213 214 static __checkReturn boolean_t 215 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 code = EFX_QWORD_FIELD(*eventp, ESF_GZ_E_TYPE); 225 switch (code) { 226 case ESE_GZ_EF100_EV_RX_PKTS: 227 should_abort = eep->ee_rx(eep, eventp, eecp, arg); 228 break; 229 case ESE_GZ_EF100_EV_TX_COMPLETION: 230 should_abort = eep->ee_tx(eep, eventp, eecp, arg); 231 break; 232 case ESE_GZ_EF100_EV_MCDI: 233 should_abort = eep->ee_mcdi(eep, eventp, eecp, arg); 234 break; 235 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 EFSYS_ASSERT(eecp->eec_exception != NULL); 241 (void) eecp->eec_exception(arg, EFX_EXCEPTION_EV_ERROR, code); 242 should_abort = B_TRUE; 243 break; 244 } 245 246 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 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 EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 291 EFSYS_ASSERT(countp != NULL); 292 EFSYS_ASSERT(eecp != NULL); 293 294 count = *countp; 295 do { 296 /* Read up until the end of the batch period */ 297 batch = EF100_EV_BATCH - (count & (EF100_EV_BATCH - 1)); 298 phase_bit = (count & (eep->ee_mask + 1)) != 0; 299 offset = (count & eep->ee_mask) * sizeof (efx_qword_t); 300 for (total = 0; total < batch; ++total) { 301 EFSYS_MEM_READQ(eep->ee_esmp, offset, &(ev[total])); 302 303 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 offset += sizeof (efx_qword_t); 311 } 312 313 /* Process the batch of events */ 314 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 rhead_ev_dispatch(eep, &(ev[index]), eecp, arg); 321 322 if (should_abort) { 323 /* Ignore subsequent events */ 324 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 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 count += total; 344 345 } while (total == batch); 346 347 *countp = count; 348 } 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 rhead_ev_qmoderate( 499 __in efx_evq_t *eep, 500 __in unsigned int us) 501 { 502 _NOTE(ARGUNUSED(eep, us)) 503 504 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 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 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 if (enp->en_reset_flags & 541 (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR | EFX_RESET_HW_UNAVAIL)) 542 return (B_FALSE); 543 544 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 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 EFSYS_ASSERT(eecp->eec_rx_packets != NULL); 562 should_abort = eecp->eec_rx_packets(arg, label, num_packets, 563 EFX_PKT_PREFIX_LEN); 564 565 return (should_abort); 566 } 567 568 static __checkReturn boolean_t 569 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 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 if (enp->en_reset_flags & 584 (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR | EFX_RESET_HW_UNAVAIL)) 585 return (B_FALSE); 586 587 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 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 EFSYS_ASSERT(eecp->eec_tx_ndescs != NULL); 601 should_abort = eecp->eec_tx_ndescs(arg, label, num_descs); 602 603 return (should_abort); 604 } 605 606 static __checkReturn boolean_t 607 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 ret = ef10_ev_mcdi(eep, eqp, eecp, arg); 621 622 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 */ 690