]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * | |
3 | * Copyright (c) 2007-2018 Solarflare Communications Inc. | |
4 | * All rights reserved. | |
5 | */ | |
6 | ||
7 | #include "efx.h" | |
8 | #include "efx_impl.h" | |
9 | ||
10 | ||
11 | __checkReturn efx_rc_t | |
12 | efx_family( | |
13 | __in uint16_t venid, | |
14 | __in uint16_t devid, | |
15 | __out efx_family_t *efp, | |
16 | __out unsigned int *membarp) | |
17 | { | |
18 | if (venid == EFX_PCI_VENID_SFC) { | |
19 | switch (devid) { | |
20 | #if EFSYS_OPT_SIENA | |
21 | case EFX_PCI_DEVID_SIENA_F1_UNINIT: | |
22 | /* | |
23 | * Hardware default for PF0 of uninitialised Siena. | |
24 | * manftest must be able to cope with this device id. | |
25 | */ | |
26 | case EFX_PCI_DEVID_BETHPAGE: | |
27 | case EFX_PCI_DEVID_SIENA: | |
28 | *efp = EFX_FAMILY_SIENA; | |
29 | *membarp = EFX_MEM_BAR_SIENA; | |
30 | return (0); | |
31 | #endif /* EFSYS_OPT_SIENA */ | |
32 | ||
33 | #if EFSYS_OPT_HUNTINGTON | |
34 | case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT: | |
35 | /* | |
36 | * Hardware default for PF0 of uninitialised Huntington. | |
37 | * manftest must be able to cope with this device id. | |
38 | */ | |
39 | case EFX_PCI_DEVID_FARMINGDALE: | |
40 | case EFX_PCI_DEVID_GREENPORT: | |
41 | *efp = EFX_FAMILY_HUNTINGTON; | |
42 | *membarp = EFX_MEM_BAR_HUNTINGTON_PF; | |
43 | return (0); | |
44 | ||
45 | case EFX_PCI_DEVID_FARMINGDALE_VF: | |
46 | case EFX_PCI_DEVID_GREENPORT_VF: | |
47 | *efp = EFX_FAMILY_HUNTINGTON; | |
48 | *membarp = EFX_MEM_BAR_HUNTINGTON_VF; | |
49 | return (0); | |
50 | #endif /* EFSYS_OPT_HUNTINGTON */ | |
51 | ||
52 | #if EFSYS_OPT_MEDFORD | |
53 | case EFX_PCI_DEVID_MEDFORD_PF_UNINIT: | |
54 | /* | |
55 | * Hardware default for PF0 of uninitialised Medford. | |
56 | * manftest must be able to cope with this device id. | |
57 | */ | |
58 | case EFX_PCI_DEVID_MEDFORD: | |
59 | *efp = EFX_FAMILY_MEDFORD; | |
60 | *membarp = EFX_MEM_BAR_MEDFORD_PF; | |
61 | return (0); | |
62 | ||
63 | case EFX_PCI_DEVID_MEDFORD_VF: | |
64 | *efp = EFX_FAMILY_MEDFORD; | |
65 | *membarp = EFX_MEM_BAR_MEDFORD_VF; | |
66 | return (0); | |
67 | #endif /* EFSYS_OPT_MEDFORD */ | |
68 | ||
69 | #if EFSYS_OPT_MEDFORD2 | |
70 | case EFX_PCI_DEVID_MEDFORD2_PF_UNINIT: | |
71 | /* | |
72 | * Hardware default for PF0 of uninitialised Medford2. | |
73 | * manftest must be able to cope with this device id. | |
74 | */ | |
75 | case EFX_PCI_DEVID_MEDFORD2: | |
76 | case EFX_PCI_DEVID_MEDFORD2_VF: | |
77 | *efp = EFX_FAMILY_MEDFORD2; | |
78 | *membarp = EFX_MEM_BAR_MEDFORD2; | |
79 | return (0); | |
80 | #endif /* EFSYS_OPT_MEDFORD2 */ | |
81 | ||
82 | case EFX_PCI_DEVID_FALCON: /* Obsolete, not supported */ | |
83 | default: | |
84 | break; | |
85 | } | |
86 | } | |
87 | ||
88 | *efp = EFX_FAMILY_INVALID; | |
89 | return (ENOTSUP); | |
90 | } | |
91 | ||
92 | ||
93 | #if EFSYS_OPT_SIENA | |
94 | ||
95 | static const efx_nic_ops_t __efx_nic_siena_ops = { | |
96 | siena_nic_probe, /* eno_probe */ | |
97 | NULL, /* eno_board_cfg */ | |
98 | NULL, /* eno_set_drv_limits */ | |
99 | siena_nic_reset, /* eno_reset */ | |
100 | siena_nic_init, /* eno_init */ | |
101 | NULL, /* eno_get_vi_pool */ | |
102 | NULL, /* eno_get_bar_region */ | |
9f95a23c TL |
103 | NULL, /* eno_hw_unavailable */ |
104 | NULL, /* eno_set_hw_unavailable */ | |
11fdf7f2 TL |
105 | #if EFSYS_OPT_DIAG |
106 | siena_nic_register_test, /* eno_register_test */ | |
107 | #endif /* EFSYS_OPT_DIAG */ | |
108 | siena_nic_fini, /* eno_fini */ | |
109 | siena_nic_unprobe, /* eno_unprobe */ | |
110 | }; | |
111 | ||
112 | #endif /* EFSYS_OPT_SIENA */ | |
113 | ||
114 | #if EFSYS_OPT_HUNTINGTON | |
115 | ||
116 | static const efx_nic_ops_t __efx_nic_hunt_ops = { | |
117 | ef10_nic_probe, /* eno_probe */ | |
118 | hunt_board_cfg, /* eno_board_cfg */ | |
119 | ef10_nic_set_drv_limits, /* eno_set_drv_limits */ | |
120 | ef10_nic_reset, /* eno_reset */ | |
121 | ef10_nic_init, /* eno_init */ | |
122 | ef10_nic_get_vi_pool, /* eno_get_vi_pool */ | |
123 | ef10_nic_get_bar_region, /* eno_get_bar_region */ | |
9f95a23c TL |
124 | ef10_nic_hw_unavailable, /* eno_hw_unavailable */ |
125 | ef10_nic_set_hw_unavailable, /* eno_set_hw_unavailable */ | |
11fdf7f2 TL |
126 | #if EFSYS_OPT_DIAG |
127 | ef10_nic_register_test, /* eno_register_test */ | |
128 | #endif /* EFSYS_OPT_DIAG */ | |
129 | ef10_nic_fini, /* eno_fini */ | |
130 | ef10_nic_unprobe, /* eno_unprobe */ | |
131 | }; | |
132 | ||
133 | #endif /* EFSYS_OPT_HUNTINGTON */ | |
134 | ||
135 | #if EFSYS_OPT_MEDFORD | |
136 | ||
137 | static const efx_nic_ops_t __efx_nic_medford_ops = { | |
138 | ef10_nic_probe, /* eno_probe */ | |
139 | medford_board_cfg, /* eno_board_cfg */ | |
140 | ef10_nic_set_drv_limits, /* eno_set_drv_limits */ | |
141 | ef10_nic_reset, /* eno_reset */ | |
142 | ef10_nic_init, /* eno_init */ | |
143 | ef10_nic_get_vi_pool, /* eno_get_vi_pool */ | |
144 | ef10_nic_get_bar_region, /* eno_get_bar_region */ | |
9f95a23c TL |
145 | ef10_nic_hw_unavailable, /* eno_hw_unavailable */ |
146 | ef10_nic_set_hw_unavailable, /* eno_set_hw_unavailable */ | |
11fdf7f2 TL |
147 | #if EFSYS_OPT_DIAG |
148 | ef10_nic_register_test, /* eno_register_test */ | |
149 | #endif /* EFSYS_OPT_DIAG */ | |
150 | ef10_nic_fini, /* eno_fini */ | |
151 | ef10_nic_unprobe, /* eno_unprobe */ | |
152 | }; | |
153 | ||
154 | #endif /* EFSYS_OPT_MEDFORD */ | |
155 | ||
156 | #if EFSYS_OPT_MEDFORD2 | |
157 | ||
158 | static const efx_nic_ops_t __efx_nic_medford2_ops = { | |
159 | ef10_nic_probe, /* eno_probe */ | |
160 | medford2_board_cfg, /* eno_board_cfg */ | |
161 | ef10_nic_set_drv_limits, /* eno_set_drv_limits */ | |
162 | ef10_nic_reset, /* eno_reset */ | |
163 | ef10_nic_init, /* eno_init */ | |
164 | ef10_nic_get_vi_pool, /* eno_get_vi_pool */ | |
165 | ef10_nic_get_bar_region, /* eno_get_bar_region */ | |
9f95a23c TL |
166 | ef10_nic_hw_unavailable, /* eno_hw_unavailable */ |
167 | ef10_nic_set_hw_unavailable, /* eno_set_hw_unavailable */ | |
11fdf7f2 TL |
168 | #if EFSYS_OPT_DIAG |
169 | ef10_nic_register_test, /* eno_register_test */ | |
170 | #endif /* EFSYS_OPT_DIAG */ | |
171 | ef10_nic_fini, /* eno_fini */ | |
172 | ef10_nic_unprobe, /* eno_unprobe */ | |
173 | }; | |
174 | ||
175 | #endif /* EFSYS_OPT_MEDFORD2 */ | |
176 | ||
177 | ||
178 | __checkReturn efx_rc_t | |
179 | efx_nic_create( | |
180 | __in efx_family_t family, | |
181 | __in efsys_identifier_t *esip, | |
182 | __in efsys_bar_t *esbp, | |
183 | __in efsys_lock_t *eslp, | |
184 | __deref_out efx_nic_t **enpp) | |
185 | { | |
186 | efx_nic_t *enp; | |
187 | efx_rc_t rc; | |
188 | ||
189 | EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID); | |
190 | EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES); | |
191 | ||
192 | /* Allocate a NIC object */ | |
193 | EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp); | |
194 | ||
195 | if (enp == NULL) { | |
196 | rc = ENOMEM; | |
197 | goto fail1; | |
198 | } | |
199 | ||
200 | enp->en_magic = EFX_NIC_MAGIC; | |
201 | ||
202 | switch (family) { | |
203 | #if EFSYS_OPT_SIENA | |
204 | case EFX_FAMILY_SIENA: | |
205 | enp->en_enop = &__efx_nic_siena_ops; | |
206 | enp->en_features = | |
207 | EFX_FEATURE_IPV6 | | |
208 | EFX_FEATURE_LFSR_HASH_INSERT | | |
209 | EFX_FEATURE_LINK_EVENTS | | |
210 | EFX_FEATURE_PERIODIC_MAC_STATS | | |
211 | EFX_FEATURE_MCDI | | |
212 | EFX_FEATURE_LOOKAHEAD_SPLIT | | |
213 | EFX_FEATURE_MAC_HEADER_FILTERS | | |
214 | EFX_FEATURE_TX_SRC_FILTERS; | |
215 | break; | |
216 | #endif /* EFSYS_OPT_SIENA */ | |
217 | ||
218 | #if EFSYS_OPT_HUNTINGTON | |
219 | case EFX_FAMILY_HUNTINGTON: | |
220 | enp->en_enop = &__efx_nic_hunt_ops; | |
221 | enp->en_features = | |
222 | EFX_FEATURE_IPV6 | | |
223 | EFX_FEATURE_LINK_EVENTS | | |
224 | EFX_FEATURE_PERIODIC_MAC_STATS | | |
225 | EFX_FEATURE_MCDI | | |
226 | EFX_FEATURE_MAC_HEADER_FILTERS | | |
227 | EFX_FEATURE_MCDI_DMA | | |
228 | EFX_FEATURE_PIO_BUFFERS | | |
229 | EFX_FEATURE_FW_ASSISTED_TSO | | |
230 | EFX_FEATURE_FW_ASSISTED_TSO_V2 | | |
9f95a23c TL |
231 | EFX_FEATURE_PACKED_STREAM | |
232 | EFX_FEATURE_TXQ_CKSUM_OP_DESC; | |
11fdf7f2 TL |
233 | break; |
234 | #endif /* EFSYS_OPT_HUNTINGTON */ | |
235 | ||
236 | #if EFSYS_OPT_MEDFORD | |
237 | case EFX_FAMILY_MEDFORD: | |
238 | enp->en_enop = &__efx_nic_medford_ops; | |
239 | /* | |
240 | * FW_ASSISTED_TSO omitted as Medford only supports firmware | |
241 | * assisted TSO version 2, not the v1 scheme used on Huntington. | |
242 | */ | |
243 | enp->en_features = | |
244 | EFX_FEATURE_IPV6 | | |
245 | EFX_FEATURE_LINK_EVENTS | | |
246 | EFX_FEATURE_PERIODIC_MAC_STATS | | |
247 | EFX_FEATURE_MCDI | | |
248 | EFX_FEATURE_MAC_HEADER_FILTERS | | |
249 | EFX_FEATURE_MCDI_DMA | | |
250 | EFX_FEATURE_PIO_BUFFERS | | |
251 | EFX_FEATURE_FW_ASSISTED_TSO_V2 | | |
9f95a23c TL |
252 | EFX_FEATURE_PACKED_STREAM | |
253 | EFX_FEATURE_TXQ_CKSUM_OP_DESC; | |
11fdf7f2 TL |
254 | break; |
255 | #endif /* EFSYS_OPT_MEDFORD */ | |
256 | ||
257 | #if EFSYS_OPT_MEDFORD2 | |
258 | case EFX_FAMILY_MEDFORD2: | |
259 | enp->en_enop = &__efx_nic_medford2_ops; | |
260 | enp->en_features = | |
261 | EFX_FEATURE_IPV6 | | |
262 | EFX_FEATURE_LINK_EVENTS | | |
263 | EFX_FEATURE_PERIODIC_MAC_STATS | | |
264 | EFX_FEATURE_MCDI | | |
265 | EFX_FEATURE_MAC_HEADER_FILTERS | | |
266 | EFX_FEATURE_MCDI_DMA | | |
267 | EFX_FEATURE_PIO_BUFFERS | | |
268 | EFX_FEATURE_FW_ASSISTED_TSO_V2 | | |
9f95a23c TL |
269 | EFX_FEATURE_PACKED_STREAM | |
270 | EFX_FEATURE_TXQ_CKSUM_OP_DESC; | |
11fdf7f2 TL |
271 | break; |
272 | #endif /* EFSYS_OPT_MEDFORD2 */ | |
273 | ||
274 | default: | |
275 | rc = ENOTSUP; | |
276 | goto fail2; | |
277 | } | |
278 | ||
279 | enp->en_family = family; | |
280 | enp->en_esip = esip; | |
281 | enp->en_esbp = esbp; | |
282 | enp->en_eslp = eslp; | |
283 | ||
284 | *enpp = enp; | |
285 | ||
286 | return (0); | |
287 | ||
288 | fail2: | |
289 | EFSYS_PROBE(fail2); | |
290 | ||
291 | enp->en_magic = 0; | |
292 | ||
293 | /* Free the NIC object */ | |
294 | EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); | |
295 | ||
296 | fail1: | |
297 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
298 | ||
299 | return (rc); | |
300 | } | |
301 | ||
302 | __checkReturn efx_rc_t | |
303 | efx_nic_probe( | |
304 | __in efx_nic_t *enp, | |
305 | __in efx_fw_variant_t efv) | |
306 | { | |
307 | const efx_nic_ops_t *enop; | |
308 | efx_rc_t rc; | |
309 | ||
310 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
311 | #if EFSYS_OPT_MCDI | |
312 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); | |
313 | #endif /* EFSYS_OPT_MCDI */ | |
314 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); | |
315 | ||
316 | /* Ensure FW variant codes match with MC_CMD_FW codes */ | |
317 | EFX_STATIC_ASSERT(EFX_FW_VARIANT_FULL_FEATURED == | |
318 | MC_CMD_FW_FULL_FEATURED); | |
319 | EFX_STATIC_ASSERT(EFX_FW_VARIANT_LOW_LATENCY == | |
320 | MC_CMD_FW_LOW_LATENCY); | |
321 | EFX_STATIC_ASSERT(EFX_FW_VARIANT_PACKED_STREAM == | |
322 | MC_CMD_FW_PACKED_STREAM); | |
323 | EFX_STATIC_ASSERT(EFX_FW_VARIANT_HIGH_TX_RATE == | |
324 | MC_CMD_FW_HIGH_TX_RATE); | |
325 | EFX_STATIC_ASSERT(EFX_FW_VARIANT_PACKED_STREAM_HASH_MODE_1 == | |
326 | MC_CMD_FW_PACKED_STREAM_HASH_MODE_1); | |
327 | EFX_STATIC_ASSERT(EFX_FW_VARIANT_RULES_ENGINE == | |
328 | MC_CMD_FW_RULES_ENGINE); | |
329 | EFX_STATIC_ASSERT(EFX_FW_VARIANT_DPDK == | |
330 | MC_CMD_FW_DPDK); | |
331 | EFX_STATIC_ASSERT(EFX_FW_VARIANT_DONT_CARE == | |
332 | (int)MC_CMD_FW_DONT_CARE); | |
333 | ||
334 | enop = enp->en_enop; | |
335 | enp->efv = efv; | |
336 | ||
337 | if ((rc = enop->eno_probe(enp)) != 0) | |
338 | goto fail1; | |
339 | ||
340 | if ((rc = efx_phy_probe(enp)) != 0) | |
341 | goto fail2; | |
342 | ||
343 | enp->en_mod_flags |= EFX_MOD_PROBE; | |
344 | ||
345 | return (0); | |
346 | ||
347 | fail2: | |
348 | EFSYS_PROBE(fail2); | |
349 | ||
350 | enop->eno_unprobe(enp); | |
351 | ||
352 | fail1: | |
353 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
354 | ||
355 | return (rc); | |
356 | } | |
357 | ||
358 | __checkReturn efx_rc_t | |
359 | efx_nic_set_drv_limits( | |
360 | __inout efx_nic_t *enp, | |
361 | __in efx_drv_limits_t *edlp) | |
362 | { | |
363 | const efx_nic_ops_t *enop = enp->en_enop; | |
364 | efx_rc_t rc; | |
365 | ||
366 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
367 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | |
368 | ||
369 | if (enop->eno_set_drv_limits != NULL) { | |
370 | if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0) | |
371 | goto fail1; | |
372 | } | |
373 | ||
374 | return (0); | |
375 | ||
376 | fail1: | |
377 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
378 | ||
379 | return (rc); | |
380 | } | |
381 | ||
382 | __checkReturn efx_rc_t | |
383 | efx_nic_get_bar_region( | |
384 | __in efx_nic_t *enp, | |
385 | __in efx_nic_region_t region, | |
386 | __out uint32_t *offsetp, | |
387 | __out size_t *sizep) | |
388 | { | |
389 | const efx_nic_ops_t *enop = enp->en_enop; | |
390 | efx_rc_t rc; | |
391 | ||
392 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
393 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | |
394 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); | |
395 | ||
396 | if (enop->eno_get_bar_region == NULL) { | |
397 | rc = ENOTSUP; | |
398 | goto fail1; | |
399 | } | |
400 | if ((rc = (enop->eno_get_bar_region)(enp, | |
401 | region, offsetp, sizep)) != 0) { | |
402 | goto fail2; | |
403 | } | |
404 | ||
405 | return (0); | |
406 | ||
407 | fail2: | |
408 | EFSYS_PROBE(fail2); | |
409 | ||
410 | fail1: | |
411 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
412 | ||
413 | return (rc); | |
414 | } | |
415 | ||
416 | ||
417 | __checkReturn efx_rc_t | |
418 | efx_nic_get_vi_pool( | |
419 | __in efx_nic_t *enp, | |
420 | __out uint32_t *evq_countp, | |
421 | __out uint32_t *rxq_countp, | |
422 | __out uint32_t *txq_countp) | |
423 | { | |
424 | const efx_nic_ops_t *enop = enp->en_enop; | |
425 | efx_nic_cfg_t *encp = &enp->en_nic_cfg; | |
426 | efx_rc_t rc; | |
427 | ||
428 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
429 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | |
430 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); | |
431 | ||
432 | if (enop->eno_get_vi_pool != NULL) { | |
433 | uint32_t vi_count = 0; | |
434 | ||
435 | if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0) | |
436 | goto fail1; | |
437 | ||
438 | *evq_countp = vi_count; | |
439 | *rxq_countp = vi_count; | |
440 | *txq_countp = vi_count; | |
441 | } else { | |
442 | /* Use NIC limits as default value */ | |
443 | *evq_countp = encp->enc_evq_limit; | |
444 | *rxq_countp = encp->enc_rxq_limit; | |
445 | *txq_countp = encp->enc_txq_limit; | |
446 | } | |
447 | ||
448 | return (0); | |
449 | ||
450 | fail1: | |
451 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
452 | ||
453 | return (rc); | |
454 | } | |
455 | ||
456 | ||
457 | __checkReturn efx_rc_t | |
458 | efx_nic_init( | |
459 | __in efx_nic_t *enp) | |
460 | { | |
461 | const efx_nic_ops_t *enop = enp->en_enop; | |
462 | efx_rc_t rc; | |
463 | ||
464 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
465 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | |
466 | ||
467 | if (enp->en_mod_flags & EFX_MOD_NIC) { | |
468 | rc = EINVAL; | |
469 | goto fail1; | |
470 | } | |
471 | ||
472 | if ((rc = enop->eno_init(enp)) != 0) | |
473 | goto fail2; | |
474 | ||
475 | enp->en_mod_flags |= EFX_MOD_NIC; | |
476 | ||
477 | return (0); | |
478 | ||
479 | fail2: | |
480 | EFSYS_PROBE(fail2); | |
481 | fail1: | |
482 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
483 | ||
484 | return (rc); | |
485 | } | |
486 | ||
487 | void | |
488 | efx_nic_fini( | |
489 | __in efx_nic_t *enp) | |
490 | { | |
491 | const efx_nic_ops_t *enop = enp->en_enop; | |
492 | ||
493 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
494 | EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); | |
495 | EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC); | |
496 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); | |
497 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); | |
498 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); | |
499 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); | |
500 | ||
501 | enop->eno_fini(enp); | |
502 | ||
503 | enp->en_mod_flags &= ~EFX_MOD_NIC; | |
504 | } | |
505 | ||
506 | void | |
507 | efx_nic_unprobe( | |
508 | __in efx_nic_t *enp) | |
509 | { | |
510 | const efx_nic_ops_t *enop = enp->en_enop; | |
511 | ||
512 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
513 | #if EFSYS_OPT_MCDI | |
514 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); | |
515 | #endif /* EFSYS_OPT_MCDI */ | |
516 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | |
517 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); | |
518 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); | |
519 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); | |
520 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); | |
521 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); | |
522 | ||
523 | efx_phy_unprobe(enp); | |
524 | ||
525 | enop->eno_unprobe(enp); | |
526 | ||
527 | enp->en_mod_flags &= ~EFX_MOD_PROBE; | |
528 | } | |
529 | ||
530 | void | |
531 | efx_nic_destroy( | |
532 | __in efx_nic_t *enp) | |
533 | { | |
534 | efsys_identifier_t *esip = enp->en_esip; | |
535 | ||
536 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
537 | EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); | |
538 | ||
539 | enp->en_family = EFX_FAMILY_INVALID; | |
540 | enp->en_esip = NULL; | |
541 | enp->en_esbp = NULL; | |
542 | enp->en_eslp = NULL; | |
543 | ||
544 | enp->en_enop = NULL; | |
545 | ||
546 | enp->en_magic = 0; | |
547 | ||
548 | /* Free the NIC object */ | |
549 | EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); | |
550 | } | |
551 | ||
552 | __checkReturn efx_rc_t | |
553 | efx_nic_reset( | |
554 | __in efx_nic_t *enp) | |
555 | { | |
556 | const efx_nic_ops_t *enop = enp->en_enop; | |
557 | unsigned int mod_flags; | |
558 | efx_rc_t rc; | |
559 | ||
560 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
561 | EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); | |
562 | /* | |
9f95a23c | 563 | * All modules except the MCDI, PROBE, NVRAM, VPD, MON, TUNNEL |
11fdf7f2 TL |
564 | * (which we do not reset here) must have been shut down or never |
565 | * initialized. | |
566 | * | |
567 | * A rule of thumb here is: If the controller or MC reboots, is *any* | |
568 | * state lost. If it's lost and needs reapplying, then the module | |
569 | * *must* not be initialised during the reset. | |
570 | */ | |
571 | mod_flags = enp->en_mod_flags; | |
572 | mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM | | |
9f95a23c TL |
573 | EFX_MOD_VPD | EFX_MOD_MON); |
574 | #if EFSYS_OPT_TUNNEL | |
575 | mod_flags &= ~EFX_MOD_TUNNEL; | |
576 | #endif /* EFSYS_OPT_TUNNEL */ | |
11fdf7f2 TL |
577 | EFSYS_ASSERT3U(mod_flags, ==, 0); |
578 | if (mod_flags != 0) { | |
579 | rc = EINVAL; | |
580 | goto fail1; | |
581 | } | |
582 | ||
583 | if ((rc = enop->eno_reset(enp)) != 0) | |
584 | goto fail2; | |
585 | ||
586 | return (0); | |
587 | ||
588 | fail2: | |
589 | EFSYS_PROBE(fail2); | |
590 | fail1: | |
591 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
592 | ||
593 | return (rc); | |
594 | } | |
595 | ||
596 | const efx_nic_cfg_t * | |
597 | efx_nic_cfg_get( | |
9f95a23c | 598 | __in const efx_nic_t *enp) |
11fdf7f2 TL |
599 | { |
600 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
9f95a23c | 601 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); |
11fdf7f2 TL |
602 | |
603 | return (&(enp->en_nic_cfg)); | |
604 | } | |
605 | ||
606 | __checkReturn efx_rc_t | |
607 | efx_nic_get_fw_version( | |
608 | __in efx_nic_t *enp, | |
609 | __out efx_nic_fw_info_t *enfip) | |
610 | { | |
611 | uint16_t mc_fw_version[4]; | |
612 | efx_rc_t rc; | |
613 | ||
614 | if (enfip == NULL) { | |
615 | rc = EINVAL; | |
616 | goto fail1; | |
617 | } | |
618 | ||
619 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); | |
620 | EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); | |
621 | ||
622 | /* Ensure RXDP_FW_ID codes match with MC_CMD_GET_CAPABILITIES codes */ | |
623 | EFX_STATIC_ASSERT(EFX_RXDP_FULL_FEATURED_FW_ID == | |
624 | MC_CMD_GET_CAPABILITIES_OUT_RXDP); | |
625 | EFX_STATIC_ASSERT(EFX_RXDP_LOW_LATENCY_FW_ID == | |
626 | MC_CMD_GET_CAPABILITIES_OUT_RXDP_LOW_LATENCY); | |
627 | EFX_STATIC_ASSERT(EFX_RXDP_PACKED_STREAM_FW_ID == | |
628 | MC_CMD_GET_CAPABILITIES_OUT_RXDP_PACKED_STREAM); | |
629 | EFX_STATIC_ASSERT(EFX_RXDP_RULES_ENGINE_FW_ID == | |
630 | MC_CMD_GET_CAPABILITIES_OUT_RXDP_RULES_ENGINE); | |
631 | EFX_STATIC_ASSERT(EFX_RXDP_DPDK_FW_ID == | |
632 | MC_CMD_GET_CAPABILITIES_OUT_RXDP_DPDK); | |
633 | ||
634 | rc = efx_mcdi_version(enp, mc_fw_version, NULL, NULL); | |
635 | if (rc != 0) | |
636 | goto fail2; | |
637 | ||
638 | rc = efx_mcdi_get_capabilities(enp, NULL, | |
639 | &enfip->enfi_rx_dpcpu_fw_id, | |
640 | &enfip->enfi_tx_dpcpu_fw_id, | |
641 | NULL, NULL); | |
642 | if (rc == 0) { | |
643 | enfip->enfi_dpcpu_fw_ids_valid = B_TRUE; | |
644 | } else if (rc == ENOTSUP) { | |
645 | enfip->enfi_dpcpu_fw_ids_valid = B_FALSE; | |
646 | enfip->enfi_rx_dpcpu_fw_id = 0; | |
647 | enfip->enfi_tx_dpcpu_fw_id = 0; | |
648 | } else { | |
649 | goto fail3; | |
650 | } | |
651 | ||
652 | memcpy(enfip->enfi_mc_fw_version, mc_fw_version, | |
653 | sizeof (mc_fw_version)); | |
654 | ||
655 | return (0); | |
656 | ||
657 | fail3: | |
658 | EFSYS_PROBE(fail3); | |
659 | fail2: | |
660 | EFSYS_PROBE(fail2); | |
661 | fail1: | |
662 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
663 | ||
664 | return (rc); | |
665 | } | |
666 | ||
9f95a23c TL |
667 | __checkReturn boolean_t |
668 | efx_nic_hw_unavailable( | |
669 | __in efx_nic_t *enp) | |
670 | { | |
671 | const efx_nic_ops_t *enop = enp->en_enop; | |
672 | ||
673 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
674 | /* NOTE: can be used by MCDI before NIC probe */ | |
675 | ||
676 | if (enop->eno_hw_unavailable != NULL) { | |
677 | if ((enop->eno_hw_unavailable)(enp) != B_FALSE) | |
678 | goto unavail; | |
679 | } | |
680 | ||
681 | return (B_FALSE); | |
682 | ||
683 | unavail: | |
684 | return (B_TRUE); | |
685 | } | |
686 | ||
687 | void | |
688 | efx_nic_set_hw_unavailable( | |
689 | __in efx_nic_t *enp) | |
690 | { | |
691 | const efx_nic_ops_t *enop = enp->en_enop; | |
692 | ||
693 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
694 | ||
695 | if (enop->eno_set_hw_unavailable != NULL) | |
696 | enop->eno_set_hw_unavailable(enp); | |
697 | } | |
698 | ||
699 | ||
11fdf7f2 TL |
700 | #if EFSYS_OPT_DIAG |
701 | ||
702 | __checkReturn efx_rc_t | |
703 | efx_nic_register_test( | |
704 | __in efx_nic_t *enp) | |
705 | { | |
706 | const efx_nic_ops_t *enop = enp->en_enop; | |
707 | efx_rc_t rc; | |
708 | ||
709 | EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); | |
710 | EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); | |
711 | EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); | |
712 | ||
713 | if ((rc = enop->eno_register_test(enp)) != 0) | |
714 | goto fail1; | |
715 | ||
716 | return (0); | |
717 | ||
718 | fail1: | |
719 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
720 | ||
721 | return (rc); | |
722 | } | |
723 | ||
724 | #endif /* EFSYS_OPT_DIAG */ | |
725 | ||
726 | #if EFSYS_OPT_LOOPBACK | |
727 | ||
728 | extern void | |
729 | efx_loopback_mask( | |
730 | __in efx_loopback_kind_t loopback_kind, | |
731 | __out efx_qword_t *maskp) | |
732 | { | |
733 | efx_qword_t mask; | |
734 | ||
735 | EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS); | |
736 | EFSYS_ASSERT(maskp != NULL); | |
737 | ||
738 | /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree */ | |
739 | #define LOOPBACK_CHECK(_mcdi, _efx) \ | |
740 | EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_##_mcdi == EFX_LOOPBACK_##_efx) | |
741 | ||
742 | LOOPBACK_CHECK(NONE, OFF); | |
743 | LOOPBACK_CHECK(DATA, DATA); | |
744 | LOOPBACK_CHECK(GMAC, GMAC); | |
745 | LOOPBACK_CHECK(XGMII, XGMII); | |
746 | LOOPBACK_CHECK(XGXS, XGXS); | |
747 | LOOPBACK_CHECK(XAUI, XAUI); | |
748 | LOOPBACK_CHECK(GMII, GMII); | |
749 | LOOPBACK_CHECK(SGMII, SGMII); | |
750 | LOOPBACK_CHECK(XGBR, XGBR); | |
751 | LOOPBACK_CHECK(XFI, XFI); | |
752 | LOOPBACK_CHECK(XAUI_FAR, XAUI_FAR); | |
753 | LOOPBACK_CHECK(GMII_FAR, GMII_FAR); | |
754 | LOOPBACK_CHECK(SGMII_FAR, SGMII_FAR); | |
755 | LOOPBACK_CHECK(XFI_FAR, XFI_FAR); | |
756 | LOOPBACK_CHECK(GPHY, GPHY); | |
757 | LOOPBACK_CHECK(PHYXS, PHY_XS); | |
758 | LOOPBACK_CHECK(PCS, PCS); | |
759 | LOOPBACK_CHECK(PMAPMD, PMA_PMD); | |
760 | LOOPBACK_CHECK(XPORT, XPORT); | |
761 | LOOPBACK_CHECK(XGMII_WS, XGMII_WS); | |
762 | LOOPBACK_CHECK(XAUI_WS, XAUI_WS); | |
763 | LOOPBACK_CHECK(XAUI_WS_FAR, XAUI_WS_FAR); | |
764 | LOOPBACK_CHECK(XAUI_WS_NEAR, XAUI_WS_NEAR); | |
765 | LOOPBACK_CHECK(GMII_WS, GMII_WS); | |
766 | LOOPBACK_CHECK(XFI_WS, XFI_WS); | |
767 | LOOPBACK_CHECK(XFI_WS_FAR, XFI_WS_FAR); | |
768 | LOOPBACK_CHECK(PHYXS_WS, PHYXS_WS); | |
769 | LOOPBACK_CHECK(PMA_INT, PMA_INT); | |
770 | LOOPBACK_CHECK(SD_NEAR, SD_NEAR); | |
771 | LOOPBACK_CHECK(SD_FAR, SD_FAR); | |
772 | LOOPBACK_CHECK(PMA_INT_WS, PMA_INT_WS); | |
773 | LOOPBACK_CHECK(SD_FEP2_WS, SD_FEP2_WS); | |
774 | LOOPBACK_CHECK(SD_FEP1_5_WS, SD_FEP1_5_WS); | |
775 | LOOPBACK_CHECK(SD_FEP_WS, SD_FEP_WS); | |
776 | LOOPBACK_CHECK(SD_FES_WS, SD_FES_WS); | |
777 | LOOPBACK_CHECK(AOE_INT_NEAR, AOE_INT_NEAR); | |
778 | LOOPBACK_CHECK(DATA_WS, DATA_WS); | |
779 | LOOPBACK_CHECK(FORCE_EXT_LINK, FORCE_EXT_LINK); | |
780 | #undef LOOPBACK_CHECK | |
781 | ||
782 | /* Build bitmask of possible loopback types */ | |
783 | EFX_ZERO_QWORD(mask); | |
784 | ||
785 | if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) || | |
786 | (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { | |
787 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF); | |
788 | } | |
789 | ||
790 | if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) || | |
791 | (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { | |
792 | /* | |
793 | * The "MAC" grouping has historically been used by drivers to | |
794 | * mean loopbacks supported by on-chip hardware. Keep that | |
795 | * meaning here, and include on-chip PHY layer loopbacks. | |
796 | */ | |
797 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA); | |
798 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC); | |
799 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII); | |
800 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS); | |
801 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI); | |
802 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII); | |
803 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII); | |
804 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR); | |
805 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI); | |
806 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR); | |
807 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR); | |
808 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR); | |
809 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR); | |
810 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT); | |
811 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR); | |
812 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR); | |
813 | } | |
814 | ||
815 | if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) || | |
816 | (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { | |
817 | /* | |
818 | * The "PHY" grouping has historically been used by drivers to | |
819 | * mean loopbacks supported by off-chip hardware. Keep that | |
820 | * meaning here. | |
821 | */ | |
822 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY); | |
823 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS); | |
824 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS); | |
825 | EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD); | |
826 | } | |
827 | ||
828 | *maskp = mask; | |
829 | } | |
830 | ||
831 | __checkReturn efx_rc_t | |
832 | efx_mcdi_get_loopback_modes( | |
833 | __in efx_nic_t *enp) | |
834 | { | |
835 | efx_nic_cfg_t *encp = &(enp->en_nic_cfg); | |
836 | efx_mcdi_req_t req; | |
9f95a23c TL |
837 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LOOPBACK_MODES_IN_LEN, |
838 | MC_CMD_GET_LOOPBACK_MODES_OUT_V2_LEN); | |
11fdf7f2 TL |
839 | efx_qword_t mask; |
840 | efx_qword_t modes; | |
841 | efx_rc_t rc; | |
842 | ||
11fdf7f2 TL |
843 | req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES; |
844 | req.emr_in_buf = payload; | |
845 | req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN; | |
846 | req.emr_out_buf = payload; | |
847 | req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_V2_LEN; | |
848 | ||
849 | efx_mcdi_execute(enp, &req); | |
850 | ||
851 | if (req.emr_rc != 0) { | |
852 | rc = req.emr_rc; | |
853 | goto fail1; | |
854 | } | |
855 | ||
856 | if (req.emr_out_length_used < | |
857 | MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + | |
858 | MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) { | |
859 | rc = EMSGSIZE; | |
860 | goto fail2; | |
861 | } | |
862 | ||
863 | /* | |
864 | * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree | |
865 | * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link(). | |
866 | */ | |
867 | efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask); | |
868 | ||
869 | EFX_AND_QWORD(mask, | |
870 | *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED)); | |
871 | ||
872 | modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M); | |
873 | EFX_AND_QWORD(modes, mask); | |
874 | encp->enc_loopback_types[EFX_LINK_100FDX] = modes; | |
875 | ||
876 | modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G); | |
877 | EFX_AND_QWORD(modes, mask); | |
878 | encp->enc_loopback_types[EFX_LINK_1000FDX] = modes; | |
879 | ||
880 | modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G); | |
881 | EFX_AND_QWORD(modes, mask); | |
882 | encp->enc_loopback_types[EFX_LINK_10000FDX] = modes; | |
883 | ||
884 | if (req.emr_out_length_used >= | |
885 | MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST + | |
886 | MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) { | |
887 | /* Response includes 40G loopback modes */ | |
888 | modes = *MCDI_OUT2(req, efx_qword_t, | |
889 | GET_LOOPBACK_MODES_OUT_40G); | |
890 | EFX_AND_QWORD(modes, mask); | |
891 | encp->enc_loopback_types[EFX_LINK_40000FDX] = modes; | |
892 | } | |
893 | ||
894 | if (req.emr_out_length_used >= | |
895 | MC_CMD_GET_LOOPBACK_MODES_OUT_V2_25G_OFST + | |
896 | MC_CMD_GET_LOOPBACK_MODES_OUT_V2_25G_LEN) { | |
897 | /* Response includes 25G loopback modes */ | |
898 | modes = *MCDI_OUT2(req, efx_qword_t, | |
899 | GET_LOOPBACK_MODES_OUT_V2_25G); | |
900 | EFX_AND_QWORD(modes, mask); | |
901 | encp->enc_loopback_types[EFX_LINK_25000FDX] = modes; | |
902 | } | |
903 | ||
904 | if (req.emr_out_length_used >= | |
905 | MC_CMD_GET_LOOPBACK_MODES_OUT_V2_50G_OFST + | |
906 | MC_CMD_GET_LOOPBACK_MODES_OUT_V2_50G_LEN) { | |
907 | /* Response includes 50G loopback modes */ | |
908 | modes = *MCDI_OUT2(req, efx_qword_t, | |
909 | GET_LOOPBACK_MODES_OUT_V2_50G); | |
910 | EFX_AND_QWORD(modes, mask); | |
911 | encp->enc_loopback_types[EFX_LINK_50000FDX] = modes; | |
912 | } | |
913 | ||
914 | if (req.emr_out_length_used >= | |
915 | MC_CMD_GET_LOOPBACK_MODES_OUT_V2_100G_OFST + | |
916 | MC_CMD_GET_LOOPBACK_MODES_OUT_V2_100G_LEN) { | |
917 | /* Response includes 100G loopback modes */ | |
918 | modes = *MCDI_OUT2(req, efx_qword_t, | |
919 | GET_LOOPBACK_MODES_OUT_V2_100G); | |
920 | EFX_AND_QWORD(modes, mask); | |
921 | encp->enc_loopback_types[EFX_LINK_100000FDX] = modes; | |
922 | } | |
923 | ||
924 | EFX_ZERO_QWORD(modes); | |
925 | EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF); | |
926 | EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]); | |
927 | EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]); | |
928 | EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]); | |
929 | EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]); | |
930 | EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_25000FDX]); | |
931 | EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_50000FDX]); | |
932 | EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100000FDX]); | |
933 | encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes; | |
934 | ||
935 | return (0); | |
936 | ||
937 | fail2: | |
938 | EFSYS_PROBE(fail2); | |
939 | fail1: | |
940 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
941 | ||
942 | return (rc); | |
943 | } | |
944 | ||
945 | #endif /* EFSYS_OPT_LOOPBACK */ | |
946 | ||
947 | __checkReturn efx_rc_t | |
948 | efx_nic_calculate_pcie_link_bandwidth( | |
949 | __in uint32_t pcie_link_width, | |
950 | __in uint32_t pcie_link_gen, | |
951 | __out uint32_t *bandwidth_mbpsp) | |
952 | { | |
953 | uint32_t lane_bandwidth; | |
954 | uint32_t total_bandwidth; | |
955 | efx_rc_t rc; | |
956 | ||
957 | if ((pcie_link_width == 0) || (pcie_link_width > 16) || | |
958 | !ISP2(pcie_link_width)) { | |
959 | rc = EINVAL; | |
960 | goto fail1; | |
961 | } | |
962 | ||
963 | switch (pcie_link_gen) { | |
964 | case EFX_PCIE_LINK_SPEED_GEN1: | |
965 | /* 2.5 Gb/s raw bandwidth with 8b/10b encoding */ | |
966 | lane_bandwidth = 2000; | |
967 | break; | |
968 | case EFX_PCIE_LINK_SPEED_GEN2: | |
969 | /* 5.0 Gb/s raw bandwidth with 8b/10b encoding */ | |
970 | lane_bandwidth = 4000; | |
971 | break; | |
972 | case EFX_PCIE_LINK_SPEED_GEN3: | |
973 | /* 8.0 Gb/s raw bandwidth with 128b/130b encoding */ | |
974 | lane_bandwidth = 7877; | |
975 | break; | |
976 | default: | |
977 | rc = EINVAL; | |
978 | goto fail2; | |
979 | } | |
980 | ||
981 | total_bandwidth = lane_bandwidth * pcie_link_width; | |
982 | *bandwidth_mbpsp = total_bandwidth; | |
983 | ||
984 | return (0); | |
985 | ||
986 | fail2: | |
987 | EFSYS_PROBE(fail2); | |
988 | fail1: | |
989 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
990 | ||
991 | return (rc); | |
992 | } | |
993 | ||
994 | #if EFSYS_OPT_FW_SUBVARIANT_AWARE | |
995 | ||
996 | __checkReturn efx_rc_t | |
997 | efx_nic_get_fw_subvariant( | |
998 | __in efx_nic_t *enp, | |
999 | __out efx_nic_fw_subvariant_t *subvariantp) | |
1000 | { | |
1001 | efx_rc_t rc; | |
1002 | uint32_t value; | |
1003 | ||
1004 | rc = efx_mcdi_get_nic_global(enp, | |
1005 | MC_CMD_SET_NIC_GLOBAL_IN_FIRMWARE_SUBVARIANT, &value); | |
1006 | if (rc != 0) | |
1007 | goto fail1; | |
1008 | ||
1009 | /* Mapping is not required since values match MCDI */ | |
1010 | EFX_STATIC_ASSERT(EFX_NIC_FW_SUBVARIANT_DEFAULT == | |
1011 | MC_CMD_SET_NIC_GLOBAL_IN_FW_SUBVARIANT_DEFAULT); | |
1012 | EFX_STATIC_ASSERT(EFX_NIC_FW_SUBVARIANT_NO_TX_CSUM == | |
1013 | MC_CMD_SET_NIC_GLOBAL_IN_FW_SUBVARIANT_NO_TX_CSUM); | |
1014 | ||
1015 | switch (value) { | |
1016 | case MC_CMD_SET_NIC_GLOBAL_IN_FW_SUBVARIANT_DEFAULT: | |
1017 | case MC_CMD_SET_NIC_GLOBAL_IN_FW_SUBVARIANT_NO_TX_CSUM: | |
1018 | *subvariantp = value; | |
1019 | break; | |
1020 | default: | |
1021 | rc = EINVAL; | |
1022 | goto fail2; | |
1023 | } | |
1024 | ||
1025 | return (0); | |
1026 | ||
1027 | fail2: | |
1028 | EFSYS_PROBE(fail2); | |
1029 | ||
1030 | fail1: | |
1031 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
1032 | ||
1033 | return (rc); | |
1034 | } | |
1035 | ||
1036 | __checkReturn efx_rc_t | |
1037 | efx_nic_set_fw_subvariant( | |
1038 | __in efx_nic_t *enp, | |
1039 | __in efx_nic_fw_subvariant_t subvariant) | |
1040 | { | |
1041 | efx_rc_t rc; | |
1042 | ||
1043 | switch (subvariant) { | |
1044 | case EFX_NIC_FW_SUBVARIANT_DEFAULT: | |
1045 | case EFX_NIC_FW_SUBVARIANT_NO_TX_CSUM: | |
1046 | /* Mapping is not required since values match MCDI */ | |
1047 | break; | |
1048 | default: | |
1049 | rc = EINVAL; | |
1050 | goto fail1; | |
1051 | } | |
1052 | ||
1053 | rc = efx_mcdi_set_nic_global(enp, | |
1054 | MC_CMD_SET_NIC_GLOBAL_IN_FIRMWARE_SUBVARIANT, subvariant); | |
1055 | if (rc != 0) | |
1056 | goto fail2; | |
1057 | ||
1058 | return (0); | |
1059 | ||
1060 | fail2: | |
1061 | EFSYS_PROBE(fail2); | |
1062 | ||
1063 | fail1: | |
1064 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
1065 | ||
1066 | return (rc); | |
1067 | } | |
1068 | ||
1069 | #endif /* EFSYS_OPT_FW_SUBVARIANT_AWARE */ | |
1070 | ||
1071 | __checkReturn efx_rc_t | |
1072 | efx_nic_check_pcie_link_speed( | |
1073 | __in efx_nic_t *enp, | |
1074 | __in uint32_t pcie_link_width, | |
1075 | __in uint32_t pcie_link_gen, | |
1076 | __out efx_pcie_link_performance_t *resultp) | |
1077 | { | |
1078 | efx_nic_cfg_t *encp = &(enp->en_nic_cfg); | |
1079 | uint32_t bandwidth; | |
1080 | efx_pcie_link_performance_t result; | |
1081 | efx_rc_t rc; | |
1082 | ||
1083 | if ((encp->enc_required_pcie_bandwidth_mbps == 0) || | |
1084 | (pcie_link_width == 0) || (pcie_link_width == 32) || | |
1085 | (pcie_link_gen == 0)) { | |
1086 | /* | |
1087 | * No usable info on what is required and/or in use. In virtual | |
1088 | * machines, sometimes the PCIe link width is reported as 0 or | |
1089 | * 32, or the speed as 0. | |
1090 | */ | |
1091 | result = EFX_PCIE_LINK_PERFORMANCE_UNKNOWN_BANDWIDTH; | |
1092 | goto out; | |
1093 | } | |
1094 | ||
1095 | /* Calculate the available bandwidth in megabits per second */ | |
1096 | rc = efx_nic_calculate_pcie_link_bandwidth(pcie_link_width, | |
1097 | pcie_link_gen, &bandwidth); | |
1098 | if (rc != 0) | |
1099 | goto fail1; | |
1100 | ||
1101 | if (bandwidth < encp->enc_required_pcie_bandwidth_mbps) { | |
1102 | result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_BANDWIDTH; | |
1103 | } else if (pcie_link_gen < encp->enc_max_pcie_link_gen) { | |
1104 | /* The link provides enough bandwidth but not optimal latency */ | |
1105 | result = EFX_PCIE_LINK_PERFORMANCE_SUBOPTIMAL_LATENCY; | |
1106 | } else { | |
1107 | result = EFX_PCIE_LINK_PERFORMANCE_OPTIMAL; | |
1108 | } | |
1109 | ||
1110 | out: | |
1111 | *resultp = result; | |
1112 | ||
1113 | return (0); | |
1114 | ||
1115 | fail1: | |
1116 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
1117 | ||
1118 | return (rc); | |
1119 | } |