common/sfc_efx: remove GENEVE from supported tunnels
[dpdk.git] / drivers / common / sfc_efx / base / rhead_nic.c
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
11 #if EFSYS_OPT_RIVERHEAD
12
13         __checkReturn   efx_rc_t
14 rhead_board_cfg(
15         __in            efx_nic_t *enp)
16 {
17         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
18         uint32_t end_padding;
19         uint32_t bandwidth;
20         efx_rc_t rc;
21
22         if ((rc = efx_mcdi_nic_board_cfg(enp)) != 0)
23                 goto fail1;
24
25         /*
26          * The tunnel encapsulation initialization happens unconditionally
27          * for now.
28          */
29         encp->enc_tunnel_encapsulations_supported =
30             (1u << EFX_TUNNEL_PROTOCOL_VXLAN) |
31             (1u << EFX_TUNNEL_PROTOCOL_NVGRE);
32
33         /*
34          * Software limitation inherited from EF10. This limit is not
35          * increased since the hardware does not report this limit, it is
36          * handled internally resulting in a tunnel add error when there is no
37          * space for more UDP tunnels.
38          */
39         encp->enc_tunnel_config_udp_entries_max = EFX_TUNNEL_MAXNENTRIES;
40
41         encp->enc_clk_mult = 1; /* not used for Riverhead */
42
43         /*
44          * FIXME There are TxSend and TxSeg descriptors on Riverhead.
45          * TxSeg is bigger than TxSend.
46          */
47         encp->enc_tx_dma_desc_size_max = EFX_MASK32(ESF_GZ_TX_SEND_LEN);
48         /* No boundary crossing limits */
49         encp->enc_tx_dma_desc_boundary = 0;
50
51         /*
52          * Initialise design parameters to either a runtime value read from
53          * the design parameters area or the well known default value
54          * (see SF-119689-TC section 4.4 for details).
55          * FIXME: Read design parameters area values.
56          */
57         encp->enc_tx_tso_max_header_ndescs =
58             ESE_EF100_DP_GZ_TSO_MAX_HDR_NUM_SEGS_DEFAULT;
59         encp->enc_tx_tso_max_header_length =
60             ESE_EF100_DP_GZ_TSO_MAX_HDR_LEN_DEFAULT;
61         encp->enc_tx_tso_max_payload_ndescs =
62             ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_NUM_SEGS_DEFAULT;
63         encp->enc_tx_tso_max_payload_length =
64             ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_LEN_DEFAULT;
65         encp->enc_tx_tso_max_nframes =
66             ESE_EF100_DP_GZ_TSO_MAX_NUM_FRAMES_DEFAULT;
67
68         /*
69          * Riverhead does not put any restrictions on TCP header offset limit.
70          */
71         encp->enc_tx_tso_tcp_header_offset_limit = UINT32_MAX;
72
73         /*
74          * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use
75          * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available
76          * resources (allocated to this PCIe function), which is zero until
77          * after we have allocated VIs.
78          */
79         encp->enc_evq_limit = 1024;
80         encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET;
81         encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET;
82
83         encp->enc_buftbl_limit = UINT32_MAX;
84
85         /*
86          * Riverhead event queue creation completes
87          * immediately (no initial event).
88          */
89         encp->enc_evq_init_done_ev_supported = B_FALSE;
90
91         /*
92          * Enable firmware workarounds for hardware errata.
93          * Expected responses are:
94          *  - 0 (zero):
95          *      Success: workaround enabled or disabled as requested.
96          *  - MC_CMD_ERR_ENOSYS (reported as ENOTSUP):
97          *      Firmware does not support the MC_CMD_WORKAROUND request.
98          *      (assume that the workaround is not supported).
99          *  - MC_CMD_ERR_ENOENT (reported as ENOENT):
100          *      Firmware does not support the requested workaround.
101          *  - MC_CMD_ERR_EPERM  (reported as EACCES):
102          *      Unprivileged function cannot enable/disable workarounds.
103          *
104          * See efx_mcdi_request_errcode() for MCDI error translations.
105          */
106
107         /*
108          * Replay engine on Riverhead should suppress duplicate packets
109          * (e.g. because of exact multicast and all-multicast filters
110          * match) to the same RxQ.
111          */
112         encp->enc_bug26807_workaround = B_FALSE;
113
114         /*
115          * Checksums for TSO sends should always be correct on Riverhead.
116          * FIXME: revisit when TSO support is implemented.
117          */
118         encp->enc_bug61297_workaround = B_FALSE;
119
120         encp->enc_evq_max_nevs = RHEAD_EVQ_MAXNEVS;
121         encp->enc_evq_min_nevs = RHEAD_EVQ_MINNEVS;
122         encp->enc_rxq_max_ndescs = RHEAD_RXQ_MAXNDESCS;
123         encp->enc_rxq_min_ndescs = RHEAD_RXQ_MINNDESCS;
124         encp->enc_txq_max_ndescs = RHEAD_TXQ_MAXNDESCS;
125         encp->enc_txq_min_ndescs = RHEAD_TXQ_MINNDESCS;
126
127         /* Riverhead FW does not support event queue timers yet. */
128         encp->enc_evq_timer_quantum_ns = 0;
129         encp->enc_evq_timer_max_us = 0;
130
131 #if EFSYS_OPT_EV_EXTENDED_WIDTH
132         encp->enc_ev_ew_desc_size = RHEAD_EVQ_EW_DESC_SIZE;
133 #else
134         encp->enc_ev_ew_desc_size = 0;
135 #endif
136
137         encp->enc_ev_desc_size = RHEAD_EVQ_DESC_SIZE;
138         encp->enc_rx_desc_size = RHEAD_RXQ_DESC_SIZE;
139         encp->enc_tx_desc_size = RHEAD_TXQ_DESC_SIZE;
140
141         /* No required alignment for WPTR updates */
142         encp->enc_rx_push_align = 1;
143
144         /* Riverhead supports a single Rx prefix size. */
145         encp->enc_rx_prefix_size = ESE_GZ_RX_PKT_PREFIX_LEN;
146
147         /* Alignment for receive packet DMA buffers. */
148         encp->enc_rx_buf_align_start = 1;
149
150         /* Get the RX DMA end padding alignment configuration. */
151         if ((rc = efx_mcdi_get_rxdp_config(enp, &end_padding)) != 0) {
152                 if (rc != EACCES)
153                         goto fail2;
154
155                 /* Assume largest tail padding size supported by hardware. */
156                 end_padding = 128;
157         }
158         encp->enc_rx_buf_align_end = end_padding;
159
160         /* FIXME: It should be extracted from design parameters (Bug 86844) */
161         encp->enc_rx_scatter_max = 7;
162
163         /*
164          * Riverhead stores a single global copy of VPD, not per-PF as on
165          * Huntington.
166          */
167         encp->enc_vpd_is_global = B_TRUE;
168
169         rc = ef10_nic_get_port_mode_bandwidth(enp, &bandwidth);
170         if (rc != 0)
171                 goto fail3;
172         encp->enc_required_pcie_bandwidth_mbps = bandwidth;
173         encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN3;
174
175         return (0);
176
177 fail3:
178         EFSYS_PROBE(fail3);
179 fail2:
180         EFSYS_PROBE(fail2);
181 fail1:
182         EFSYS_PROBE1(fail1, efx_rc_t, rc);
183
184         return (rc);
185 }
186
187         __checkReturn   efx_rc_t
188 rhead_nic_probe(
189         __in            efx_nic_t *enp)
190 {
191         const efx_nic_ops_t *enop = enp->en_enop;
192         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
193         efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
194         efx_rc_t rc;
195
196         EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp));
197
198         /* Read and clear any assertion state */
199         if ((rc = efx_mcdi_read_assertion(enp)) != 0)
200                 goto fail1;
201
202         /* Exit the assertion handler */
203         if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
204                 if (rc != EACCES)
205                         goto fail2;
206
207         if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
208                 goto fail3;
209
210         /* Get remaining controller-specific board config */
211         if ((rc = enop->eno_board_cfg(enp)) != 0)
212                 goto fail4;
213
214         /*
215          * Set default driver config limits (based on board config).
216          *
217          * FIXME: For now allocate a fixed number of VIs which is likely to be
218          * sufficient and small enough to allow multiple functions on the same
219          * port.
220          */
221         edcp->edc_min_vi_count = edcp->edc_max_vi_count =
222             MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit));
223
224         /*
225          * The client driver must configure and enable PIO buffer support,
226          * but there is no PIO support on Riverhead anyway.
227          */
228         edcp->edc_max_piobuf_count = 0;
229         edcp->edc_pio_alloc_size = 0;
230
231 #if EFSYS_OPT_MAC_STATS
232         /* Wipe the MAC statistics */
233         if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
234                 goto fail5;
235 #endif
236
237 #if EFSYS_OPT_LOOPBACK
238         if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
239                 goto fail6;
240 #endif
241
242         return (0);
243
244 #if EFSYS_OPT_LOOPBACK
245 fail6:
246         EFSYS_PROBE(fail6);
247 #endif
248 #if EFSYS_OPT_MAC_STATS
249 fail5:
250         EFSYS_PROBE(fail5);
251 #endif
252 fail4:
253         EFSYS_PROBE(fail4);
254 fail3:
255         EFSYS_PROBE(fail3);
256 fail2:
257         EFSYS_PROBE(fail2);
258 fail1:
259         EFSYS_PROBE1(fail1, efx_rc_t, rc);
260
261         return (rc);
262 }
263
264         __checkReturn   efx_rc_t
265 rhead_nic_set_drv_limits(
266         __inout         efx_nic_t *enp,
267         __in            efx_drv_limits_t *edlp)
268 {
269         const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
270         efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
271         uint32_t min_evq_count, max_evq_count;
272         uint32_t min_rxq_count, max_rxq_count;
273         uint32_t min_txq_count, max_txq_count;
274         efx_rc_t rc;
275
276         if (edlp == NULL) {
277                 rc = EINVAL;
278                 goto fail1;
279         }
280
281         /* Get minimum required and maximum usable VI limits */
282         min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit);
283         min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit);
284         min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit);
285
286         edcp->edc_min_vi_count =
287             MAX(min_evq_count, MAX(min_rxq_count, min_txq_count));
288
289         max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit);
290         max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit);
291         max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit);
292
293         edcp->edc_max_vi_count =
294             MAX(max_evq_count, MAX(max_rxq_count, max_txq_count));
295
296         /* There is no PIO support on Riverhead */
297         edcp->edc_max_piobuf_count = 0;
298         edcp->edc_pio_alloc_size = 0;
299
300         return (0);
301
302 fail1:
303         EFSYS_PROBE1(fail1, efx_rc_t, rc);
304
305         return (rc);
306 }
307
308         __checkReturn   efx_rc_t
309 rhead_nic_reset(
310         __in            efx_nic_t *enp)
311 {
312         efx_rc_t rc;
313
314         /* ef10_nic_reset() is called to recover from BADASSERT failures. */
315         if ((rc = efx_mcdi_read_assertion(enp)) != 0)
316                 goto fail1;
317         if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
318                 goto fail2;
319
320         if ((rc = efx_mcdi_entity_reset(enp)) != 0)
321                 goto fail3;
322
323         /* Clear RX/TX DMA queue errors */
324         enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR);
325
326         return (0);
327
328 fail3:
329         EFSYS_PROBE(fail3);
330 fail2:
331         EFSYS_PROBE(fail2);
332 fail1:
333         EFSYS_PROBE1(fail1, efx_rc_t, rc);
334
335         return (rc);
336 }
337
338         __checkReturn   efx_rc_t
339 rhead_nic_init(
340         __in            efx_nic_t *enp)
341 {
342         const efx_drv_cfg_t *edcp = &(enp->en_drv_cfg);
343         uint32_t min_vi_count, max_vi_count;
344         uint32_t vi_count, vi_base, vi_shift;
345         uint32_t vi_window_size;
346         efx_rc_t rc;
347         boolean_t alloc_vadaptor = B_TRUE;
348
349         EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp));
350         EFSYS_ASSERT3U(edcp->edc_max_piobuf_count, ==, 0);
351
352         /* Enable reporting of some events (e.g. link change) */
353         if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
354                 goto fail1;
355
356         min_vi_count = edcp->edc_min_vi_count;
357         max_vi_count = edcp->edc_max_vi_count;
358
359         /* Ensure that the previously attached driver's VIs are freed */
360         if ((rc = efx_mcdi_free_vis(enp)) != 0)
361                 goto fail2;
362
363         /*
364          * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this
365          * fails then retrying the request for fewer VI resources may succeed.
366          */
367         vi_count = 0;
368         if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count,
369                     &vi_base, &vi_count, &vi_shift)) != 0)
370                 goto fail3;
371
372         EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count);
373
374         if (vi_count < min_vi_count) {
375                 rc = ENOMEM;
376                 goto fail4;
377         }
378
379         enp->en_arch.ef10.ena_vi_base = vi_base;
380         enp->en_arch.ef10.ena_vi_count = vi_count;
381         enp->en_arch.ef10.ena_vi_shift = vi_shift;
382
383         EFSYS_ASSERT3U(enp->en_nic_cfg.enc_vi_window_shift, !=,
384             EFX_VI_WINDOW_SHIFT_INVALID);
385         EFSYS_ASSERT3U(enp->en_nic_cfg.enc_vi_window_shift, <=,
386             EFX_VI_WINDOW_SHIFT_64K);
387         vi_window_size = 1U << enp->en_nic_cfg.enc_vi_window_shift;
388
389         /* Save UC memory mapping details */
390         enp->en_arch.ef10.ena_uc_mem_map_offset = 0;
391         enp->en_arch.ef10.ena_uc_mem_map_size =
392             vi_window_size * enp->en_arch.ef10.ena_vi_count;
393
394         /* No WC memory mapping since PIO is not supported */
395         enp->en_arch.ef10.ena_pio_write_vi_base = 0;
396         enp->en_arch.ef10.ena_wc_mem_map_offset = 0;
397         enp->en_arch.ef10.ena_wc_mem_map_size = 0;
398
399         enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2;
400
401         /*
402          * For SR-IOV use case, vAdaptor is allocated for PF and associated VFs
403          * during NIC initialization when vSwitch is created and vPorts are
404          * allocated. Hence, skip vAdaptor allocation for EVB and update vPort
405          * ID in NIC structure with the one allocated for PF.
406          */
407
408         enp->en_vport_id = EVB_PORT_ID_ASSIGNED;
409 #if EFSYS_OPT_EVB
410         if ((enp->en_vswitchp != NULL) && (enp->en_vswitchp->ev_evcp != NULL)) {
411                 /* For EVB use vPort allocated on vSwitch */
412                 enp->en_vport_id = enp->en_vswitchp->ev_evcp->evc_vport_id;
413                 alloc_vadaptor = B_FALSE;
414         }
415 #endif
416         if (alloc_vadaptor != B_FALSE) {
417                 /* Allocate a vAdaptor attached to our upstream vPort/pPort */
418                 if ((rc = ef10_upstream_port_vadaptor_alloc(enp)) != 0)
419                         goto fail5;
420         }
421
422         return (0);
423
424 fail5:
425         EFSYS_PROBE(fail5);
426
427 fail4:
428         EFSYS_PROBE(fail4);
429
430         (void) efx_mcdi_free_vis(enp);
431
432 fail3:
433         EFSYS_PROBE(fail3);
434 fail2:
435         EFSYS_PROBE(fail2);
436 fail1:
437         EFSYS_PROBE1(fail1, efx_rc_t, rc);
438
439         return (rc);
440 }
441
442         __checkReturn   efx_rc_t
443 rhead_nic_get_vi_pool(
444         __in            efx_nic_t *enp,
445         __out           uint32_t *vi_countp)
446 {
447         /*
448          * Report VIs that the client driver can use.
449          * Do not include VIs used for PIO buffer writes.
450          */
451         *vi_countp = enp->en_arch.ef10.ena_vi_count;
452
453         return (0);
454 }
455
456         __checkReturn   efx_rc_t
457 rhead_nic_get_bar_region(
458         __in            efx_nic_t *enp,
459         __in            efx_nic_region_t region,
460         __out           uint32_t *offsetp,
461         __out           size_t *sizep)
462 {
463         efx_rc_t rc;
464
465         EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp));
466
467         /*
468          * TODO: Specify host memory mapping alignment and granularity
469          * in efx_drv_limits_t so that they can be taken into account
470          * when allocating extra VIs for PIO writes.
471          */
472         switch (region) {
473         case EFX_REGION_VI:
474                 /* UC mapped memory BAR region for VI registers */
475                 *offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset;
476                 *sizep = enp->en_arch.ef10.ena_uc_mem_map_size;
477                 break;
478
479         case EFX_REGION_PIO_WRITE_VI:
480                 /* WC mapped memory BAR region for piobuf writes */
481                 *offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset;
482                 *sizep = enp->en_arch.ef10.ena_wc_mem_map_size;
483                 break;
484
485         default:
486                 rc = EINVAL;
487                 goto fail1;
488         }
489
490         return (0);
491
492 fail1:
493         EFSYS_PROBE1(fail1, efx_rc_t, rc);
494
495         return (rc);
496 }
497
498         __checkReturn   boolean_t
499 rhead_nic_hw_unavailable(
500         __in            efx_nic_t *enp)
501 {
502         efx_dword_t dword;
503
504         if (enp->en_reset_flags & EFX_RESET_HW_UNAVAIL)
505                 return (B_TRUE);
506
507         EFX_BAR_FCW_READD(enp, ER_GZ_MC_SFT_STATUS, &dword);
508         if (EFX_DWORD_FIELD(dword, EFX_DWORD_0) == 0xffffffff)
509                 goto unavail;
510
511         return (B_FALSE);
512
513 unavail:
514         rhead_nic_set_hw_unavailable(enp);
515
516         return (B_TRUE);
517 }
518
519                         void
520 rhead_nic_set_hw_unavailable(
521         __in            efx_nic_t *enp)
522 {
523         EFSYS_PROBE(hw_unavail);
524         enp->en_reset_flags |= EFX_RESET_HW_UNAVAIL;
525 }
526
527                         void
528 rhead_nic_fini(
529         __in            efx_nic_t *enp)
530 {
531         boolean_t do_vadaptor_free = B_TRUE;
532
533 #if EFSYS_OPT_EVB
534         if (enp->en_vswitchp != NULL) {
535                 /*
536                  * For SR-IOV the vAdaptor is freed with the vSwitch,
537                  * so do not free it here.
538                  */
539                 do_vadaptor_free = B_FALSE;
540         }
541 #endif
542         if (do_vadaptor_free != B_FALSE) {
543                 (void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id);
544                 enp->en_vport_id = EVB_PORT_ID_NULL;
545         }
546
547         (void) efx_mcdi_free_vis(enp);
548         enp->en_arch.ef10.ena_vi_count = 0;
549 }
550
551                         void
552 rhead_nic_unprobe(
553         __in            efx_nic_t *enp)
554 {
555         (void) efx_mcdi_drv_attach(enp, B_FALSE);
556 }
557
558 #if EFSYS_OPT_DIAG
559
560         __checkReturn   efx_rc_t
561 rhead_nic_register_test(
562         __in            efx_nic_t *enp)
563 {
564         efx_rc_t rc;
565
566         /* FIXME */
567         _NOTE(ARGUNUSED(enp))
568         _NOTE(CONSTANTCONDITION)
569         if (B_FALSE) {
570                 rc = ENOTSUP;
571                 goto fail1;
572         }
573         /* FIXME */
574
575         return (0);
576
577 fail1:
578         EFSYS_PROBE1(fail1, efx_rc_t, rc);
579
580         return (rc);
581 }
582
583 #endif  /* EFSYS_OPT_DIAG */
584
585         __checkReturn                   efx_rc_t
586 rhead_nic_xilinx_cap_tbl_read_ef100_locator(
587         __in                            efsys_bar_t *esbp,
588         __in                            efsys_dma_addr_t offset,
589         __out                           efx_bar_region_t *ebrp)
590 {
591         efx_oword_t entry;
592         uint32_t rev;
593         uint32_t len;
594         efx_rc_t rc;
595
596         /*
597          * Xilinx Capabilities Table requires 32bit aligned reads.
598          * See SF-119689-TC section 4.2.2 "Discovery Steps".
599          */
600         EFSYS_BAR_READD(esbp, offset +
601                         (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_FORMAT) / 8),
602                         &entry.eo_dword[0], B_FALSE);
603         EFSYS_BAR_READD(esbp, offset +
604                         (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_SIZE) / 8),
605                         &entry.eo_dword[1], B_FALSE);
606
607         rev = EFX_OWORD_FIELD32(entry, ESF_GZ_CFGBAR_ENTRY_REV);
608         len = EFX_OWORD_FIELD32(entry, ESF_GZ_CFGBAR_ENTRY_SIZE);
609
610         if (rev != ESE_GZ_CFGBAR_ENTRY_REV_EF100 ||
611             len < ESE_GZ_CFGBAR_ENTRY_SIZE_EF100) {
612                 rc = EINVAL;
613                 goto fail1;
614         }
615
616         EFSYS_BAR_READD(esbp, offset +
617                         (EFX_LOW_BIT(ESF_GZ_CFGBAR_EF100_BAR) / 8),
618                         &entry.eo_dword[2], B_FALSE);
619
620         ebrp->ebr_index = EFX_OWORD_FIELD32(entry, ESF_GZ_CFGBAR_EF100_BAR);
621         ebrp->ebr_offset = EFX_OWORD_FIELD32(entry,
622                         ESF_GZ_CFGBAR_EF100_FUNC_CTL_WIN_OFF) <<
623                         ESE_GZ_EF100_FUNC_CTL_WIN_OFF_SHIFT;
624         ebrp->ebr_type = EFX_BAR_TYPE_MEM;
625         ebrp->ebr_length = 0;
626
627         return (0);
628
629 fail1:
630         EFSYS_PROBE1(fail1, efx_rc_t, rc);
631
632         return (rc);
633 }
634
635 #endif  /* EFSYS_OPT_RIVERHEAD */