]>
Commit | Line | Data |
---|---|---|
9f95a23c | 1 | /* SPDX-License-Identifier: BSD-3-Clause |
11fdf7f2 | 2 | * |
9f95a23c TL |
3 | * Copyright (c) 2012-2018 Solarflare Communications Inc. |
4 | * All rights reserved. | |
11fdf7f2 TL |
5 | */ |
6 | ||
7 | #include "efx.h" | |
8 | #include "efx_impl.h" | |
9 | #if EFSYS_OPT_MON_MCDI | |
10 | #include "mcdi_mon.h" | |
11 | #endif | |
12 | ||
9f95a23c | 13 | #if EFX_OPTS_EF10() |
11fdf7f2 TL |
14 | |
15 | #include "ef10_tlv_layout.h" | |
16 | ||
17 | __checkReturn efx_rc_t | |
18 | efx_mcdi_get_port_assignment( | |
19 | __in efx_nic_t *enp, | |
20 | __out uint32_t *portp) | |
21 | { | |
22 | efx_mcdi_req_t req; | |
9f95a23c TL |
23 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN, |
24 | MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN); | |
11fdf7f2 TL |
25 | efx_rc_t rc; |
26 | ||
9f95a23c | 27 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 | 28 | |
11fdf7f2 TL |
29 | req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT; |
30 | req.emr_in_buf = payload; | |
31 | req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN; | |
32 | req.emr_out_buf = payload; | |
33 | req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN; | |
34 | ||
35 | efx_mcdi_execute(enp, &req); | |
36 | ||
37 | if (req.emr_rc != 0) { | |
38 | rc = req.emr_rc; | |
39 | goto fail1; | |
40 | } | |
41 | ||
42 | if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) { | |
43 | rc = EMSGSIZE; | |
44 | goto fail2; | |
45 | } | |
46 | ||
47 | *portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT); | |
48 | ||
49 | return (0); | |
50 | ||
51 | fail2: | |
52 | EFSYS_PROBE(fail2); | |
53 | fail1: | |
54 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
55 | ||
56 | return (rc); | |
57 | } | |
58 | ||
59 | __checkReturn efx_rc_t | |
60 | efx_mcdi_get_port_modes( | |
61 | __in efx_nic_t *enp, | |
62 | __out uint32_t *modesp, | |
9f95a23c TL |
63 | __out_opt uint32_t *current_modep, |
64 | __out_opt uint32_t *default_modep) | |
11fdf7f2 TL |
65 | { |
66 | efx_mcdi_req_t req; | |
9f95a23c TL |
67 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PORT_MODES_IN_LEN, |
68 | MC_CMD_GET_PORT_MODES_OUT_LEN); | |
11fdf7f2 TL |
69 | efx_rc_t rc; |
70 | ||
9f95a23c | 71 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 | 72 | |
11fdf7f2 TL |
73 | req.emr_cmd = MC_CMD_GET_PORT_MODES; |
74 | req.emr_in_buf = payload; | |
75 | req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN; | |
76 | req.emr_out_buf = payload; | |
77 | req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN; | |
78 | ||
79 | efx_mcdi_execute(enp, &req); | |
80 | ||
81 | if (req.emr_rc != 0) { | |
82 | rc = req.emr_rc; | |
83 | goto fail1; | |
84 | } | |
85 | ||
86 | /* | |
87 | * Require only Modes and DefaultMode fields, unless the current mode | |
88 | * was requested (CurrentMode field was added for Medford). | |
89 | */ | |
90 | if (req.emr_out_length_used < | |
91 | MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) { | |
92 | rc = EMSGSIZE; | |
93 | goto fail2; | |
94 | } | |
95 | if ((current_modep != NULL) && (req.emr_out_length_used < | |
96 | MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST + 4)) { | |
97 | rc = EMSGSIZE; | |
98 | goto fail3; | |
99 | } | |
100 | ||
101 | *modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES); | |
102 | ||
103 | if (current_modep != NULL) { | |
104 | *current_modep = MCDI_OUT_DWORD(req, | |
105 | GET_PORT_MODES_OUT_CURRENT_MODE); | |
106 | } | |
107 | ||
9f95a23c TL |
108 | if (default_modep != NULL) { |
109 | *default_modep = MCDI_OUT_DWORD(req, | |
110 | GET_PORT_MODES_OUT_DEFAULT_MODE); | |
111 | } | |
112 | ||
11fdf7f2 TL |
113 | return (0); |
114 | ||
115 | fail3: | |
116 | EFSYS_PROBE(fail3); | |
117 | fail2: | |
118 | EFSYS_PROBE(fail2); | |
119 | fail1: | |
120 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
121 | ||
122 | return (rc); | |
123 | } | |
124 | ||
125 | __checkReturn efx_rc_t | |
126 | ef10_nic_get_port_mode_bandwidth( | |
9f95a23c | 127 | __in efx_nic_t *enp, |
11fdf7f2 TL |
128 | __out uint32_t *bandwidth_mbpsp) |
129 | { | |
9f95a23c TL |
130 | uint32_t port_modes; |
131 | uint32_t current_mode; | |
132 | efx_port_t *epp = &(enp->en_port); | |
133 | ||
134 | uint32_t single_lane; | |
135 | uint32_t dual_lane; | |
136 | uint32_t quad_lane; | |
11fdf7f2 TL |
137 | uint32_t bandwidth; |
138 | efx_rc_t rc; | |
139 | ||
9f95a23c TL |
140 | if ((rc = efx_mcdi_get_port_modes(enp, &port_modes, |
141 | ¤t_mode, NULL)) != 0) { | |
142 | /* No port mode info available. */ | |
143 | goto fail1; | |
144 | } | |
145 | ||
146 | if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_25000FDX)) | |
147 | single_lane = 25000; | |
148 | else | |
149 | single_lane = 10000; | |
150 | ||
151 | if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_50000FDX)) | |
152 | dual_lane = 50000; | |
153 | else | |
154 | dual_lane = 20000; | |
155 | ||
156 | if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_100000FDX)) | |
157 | quad_lane = 100000; | |
158 | else | |
159 | quad_lane = 40000; | |
160 | ||
161 | switch (current_mode) { | |
162 | case TLV_PORT_MODE_1x1_NA: /* mode 0 */ | |
163 | bandwidth = single_lane; | |
164 | break; | |
165 | case TLV_PORT_MODE_1x2_NA: /* mode 10 */ | |
166 | case TLV_PORT_MODE_NA_1x2: /* mode 11 */ | |
167 | bandwidth = dual_lane; | |
168 | break; | |
169 | case TLV_PORT_MODE_1x1_1x1: /* mode 2 */ | |
170 | bandwidth = single_lane + single_lane; | |
171 | break; | |
172 | case TLV_PORT_MODE_4x1_NA: /* mode 4 */ | |
173 | case TLV_PORT_MODE_NA_4x1: /* mode 8 */ | |
174 | bandwidth = 4 * single_lane; | |
11fdf7f2 | 175 | break; |
9f95a23c TL |
176 | case TLV_PORT_MODE_2x1_2x1: /* mode 5 */ |
177 | bandwidth = (2 * single_lane) + (2 * single_lane); | |
11fdf7f2 | 178 | break; |
9f95a23c TL |
179 | case TLV_PORT_MODE_1x2_1x2: /* mode 12 */ |
180 | bandwidth = dual_lane + dual_lane; | |
11fdf7f2 | 181 | break; |
9f95a23c TL |
182 | case TLV_PORT_MODE_1x2_2x1: /* mode 17 */ |
183 | case TLV_PORT_MODE_2x1_1x2: /* mode 18 */ | |
184 | bandwidth = dual_lane + (2 * single_lane); | |
11fdf7f2 | 185 | break; |
9f95a23c TL |
186 | /* Legacy Medford-only mode. Do not use (see bug63270) */ |
187 | case TLV_PORT_MODE_10G_10G_10G_10G_Q1_Q2: /* mode 9 */ | |
188 | bandwidth = 4 * single_lane; | |
11fdf7f2 | 189 | break; |
9f95a23c TL |
190 | case TLV_PORT_MODE_1x4_NA: /* mode 1 */ |
191 | case TLV_PORT_MODE_NA_1x4: /* mode 22 */ | |
192 | bandwidth = quad_lane; | |
193 | break; | |
194 | case TLV_PORT_MODE_2x2_NA: /* mode 13 */ | |
195 | case TLV_PORT_MODE_NA_2x2: /* mode 14 */ | |
196 | bandwidth = 2 * dual_lane; | |
197 | break; | |
198 | case TLV_PORT_MODE_1x4_2x1: /* mode 6 */ | |
199 | case TLV_PORT_MODE_2x1_1x4: /* mode 7 */ | |
200 | bandwidth = quad_lane + (2 * single_lane); | |
201 | break; | |
202 | case TLV_PORT_MODE_1x4_1x2: /* mode 15 */ | |
203 | case TLV_PORT_MODE_1x2_1x4: /* mode 16 */ | |
204 | bandwidth = quad_lane + dual_lane; | |
205 | break; | |
206 | case TLV_PORT_MODE_1x4_1x4: /* mode 3 */ | |
207 | bandwidth = quad_lane + quad_lane; | |
11fdf7f2 TL |
208 | break; |
209 | default: | |
210 | rc = EINVAL; | |
9f95a23c | 211 | goto fail2; |
11fdf7f2 TL |
212 | } |
213 | ||
214 | *bandwidth_mbpsp = bandwidth; | |
215 | ||
216 | return (0); | |
217 | ||
9f95a23c TL |
218 | fail2: |
219 | EFSYS_PROBE(fail2); | |
11fdf7f2 TL |
220 | fail1: |
221 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
222 | ||
223 | return (rc); | |
224 | } | |
225 | ||
226 | static __checkReturn efx_rc_t | |
227 | efx_mcdi_vadaptor_alloc( | |
228 | __in efx_nic_t *enp, | |
229 | __in uint32_t port_id) | |
230 | { | |
231 | efx_mcdi_req_t req; | |
9f95a23c TL |
232 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VADAPTOR_ALLOC_IN_LEN, |
233 | MC_CMD_VADAPTOR_ALLOC_OUT_LEN); | |
11fdf7f2 TL |
234 | efx_rc_t rc; |
235 | ||
236 | EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL); | |
237 | ||
11fdf7f2 TL |
238 | req.emr_cmd = MC_CMD_VADAPTOR_ALLOC; |
239 | req.emr_in_buf = payload; | |
240 | req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN; | |
241 | req.emr_out_buf = payload; | |
242 | req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN; | |
243 | ||
244 | MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); | |
245 | MCDI_IN_POPULATE_DWORD_1(req, VADAPTOR_ALLOC_IN_FLAGS, | |
246 | VADAPTOR_ALLOC_IN_FLAG_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED, | |
247 | enp->en_nic_cfg.enc_allow_set_mac_with_installed_filters ? 1 : 0); | |
248 | ||
249 | efx_mcdi_execute(enp, &req); | |
250 | ||
251 | if (req.emr_rc != 0) { | |
252 | rc = req.emr_rc; | |
253 | goto fail1; | |
254 | } | |
255 | ||
256 | return (0); | |
257 | ||
258 | fail1: | |
259 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
260 | ||
261 | return (rc); | |
262 | } | |
263 | ||
264 | static __checkReturn efx_rc_t | |
265 | efx_mcdi_vadaptor_free( | |
266 | __in efx_nic_t *enp, | |
267 | __in uint32_t port_id) | |
268 | { | |
269 | efx_mcdi_req_t req; | |
9f95a23c TL |
270 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VADAPTOR_FREE_IN_LEN, |
271 | MC_CMD_VADAPTOR_FREE_OUT_LEN); | |
11fdf7f2 TL |
272 | efx_rc_t rc; |
273 | ||
11fdf7f2 TL |
274 | req.emr_cmd = MC_CMD_VADAPTOR_FREE; |
275 | req.emr_in_buf = payload; | |
276 | req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN; | |
277 | req.emr_out_buf = payload; | |
278 | req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN; | |
279 | ||
280 | MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); | |
281 | ||
282 | efx_mcdi_execute(enp, &req); | |
283 | ||
284 | if (req.emr_rc != 0) { | |
285 | rc = req.emr_rc; | |
286 | goto fail1; | |
287 | } | |
288 | ||
289 | return (0); | |
290 | ||
291 | fail1: | |
292 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
293 | ||
294 | return (rc); | |
295 | } | |
296 | ||
297 | __checkReturn efx_rc_t | |
298 | efx_mcdi_get_mac_address_pf( | |
299 | __in efx_nic_t *enp, | |
300 | __out_ecount_opt(6) uint8_t mac_addrp[6]) | |
301 | { | |
302 | efx_mcdi_req_t req; | |
9f95a23c TL |
303 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_MAC_ADDRESSES_IN_LEN, |
304 | MC_CMD_GET_MAC_ADDRESSES_OUT_LEN); | |
11fdf7f2 TL |
305 | efx_rc_t rc; |
306 | ||
9f95a23c | 307 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 | 308 | |
11fdf7f2 TL |
309 | req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES; |
310 | req.emr_in_buf = payload; | |
311 | req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN; | |
312 | req.emr_out_buf = payload; | |
313 | req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN; | |
314 | ||
315 | efx_mcdi_execute(enp, &req); | |
316 | ||
317 | if (req.emr_rc != 0) { | |
318 | rc = req.emr_rc; | |
319 | goto fail1; | |
320 | } | |
321 | ||
322 | if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) { | |
323 | rc = EMSGSIZE; | |
324 | goto fail2; | |
325 | } | |
326 | ||
327 | if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) { | |
328 | rc = ENOENT; | |
329 | goto fail3; | |
330 | } | |
331 | ||
332 | if (mac_addrp != NULL) { | |
333 | uint8_t *addrp; | |
334 | ||
335 | addrp = MCDI_OUT2(req, uint8_t, | |
336 | GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE); | |
337 | ||
338 | EFX_MAC_ADDR_COPY(mac_addrp, addrp); | |
339 | } | |
340 | ||
341 | return (0); | |
342 | ||
343 | fail3: | |
344 | EFSYS_PROBE(fail3); | |
345 | fail2: | |
346 | EFSYS_PROBE(fail2); | |
347 | fail1: | |
348 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
349 | ||
350 | return (rc); | |
351 | } | |
352 | ||
353 | __checkReturn efx_rc_t | |
354 | efx_mcdi_get_mac_address_vf( | |
355 | __in efx_nic_t *enp, | |
356 | __out_ecount_opt(6) uint8_t mac_addrp[6]) | |
357 | { | |
358 | efx_mcdi_req_t req; | |
9f95a23c TL |
359 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN, |
360 | MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX); | |
11fdf7f2 TL |
361 | efx_rc_t rc; |
362 | ||
9f95a23c | 363 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 | 364 | |
11fdf7f2 TL |
365 | req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES; |
366 | req.emr_in_buf = payload; | |
367 | req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN; | |
368 | req.emr_out_buf = payload; | |
369 | req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX; | |
370 | ||
371 | MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID, | |
372 | EVB_PORT_ID_ASSIGNED); | |
373 | ||
374 | efx_mcdi_execute(enp, &req); | |
375 | ||
376 | if (req.emr_rc != 0) { | |
377 | rc = req.emr_rc; | |
378 | goto fail1; | |
379 | } | |
380 | ||
381 | if (req.emr_out_length_used < | |
382 | MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) { | |
383 | rc = EMSGSIZE; | |
384 | goto fail2; | |
385 | } | |
386 | ||
387 | if (MCDI_OUT_DWORD(req, | |
388 | VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) { | |
389 | rc = ENOENT; | |
390 | goto fail3; | |
391 | } | |
392 | ||
393 | if (mac_addrp != NULL) { | |
394 | uint8_t *addrp; | |
395 | ||
396 | addrp = MCDI_OUT2(req, uint8_t, | |
397 | VPORT_GET_MAC_ADDRESSES_OUT_MACADDR); | |
398 | ||
399 | EFX_MAC_ADDR_COPY(mac_addrp, addrp); | |
400 | } | |
401 | ||
402 | return (0); | |
403 | ||
404 | fail3: | |
405 | EFSYS_PROBE(fail3); | |
406 | fail2: | |
407 | EFSYS_PROBE(fail2); | |
408 | fail1: | |
409 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
410 | ||
411 | return (rc); | |
412 | } | |
413 | ||
414 | __checkReturn efx_rc_t | |
415 | efx_mcdi_get_clock( | |
416 | __in efx_nic_t *enp, | |
417 | __out uint32_t *sys_freqp, | |
418 | __out uint32_t *dpcpu_freqp) | |
419 | { | |
420 | efx_mcdi_req_t req; | |
9f95a23c TL |
421 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CLOCK_IN_LEN, |
422 | MC_CMD_GET_CLOCK_OUT_LEN); | |
11fdf7f2 TL |
423 | efx_rc_t rc; |
424 | ||
9f95a23c | 425 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 | 426 | |
11fdf7f2 TL |
427 | req.emr_cmd = MC_CMD_GET_CLOCK; |
428 | req.emr_in_buf = payload; | |
429 | req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN; | |
430 | req.emr_out_buf = payload; | |
431 | req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN; | |
432 | ||
433 | efx_mcdi_execute(enp, &req); | |
434 | ||
435 | if (req.emr_rc != 0) { | |
436 | rc = req.emr_rc; | |
437 | goto fail1; | |
438 | } | |
439 | ||
440 | if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) { | |
441 | rc = EMSGSIZE; | |
442 | goto fail2; | |
443 | } | |
444 | ||
445 | *sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ); | |
446 | if (*sys_freqp == 0) { | |
447 | rc = EINVAL; | |
448 | goto fail3; | |
449 | } | |
450 | *dpcpu_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_DPCPU_FREQ); | |
451 | if (*dpcpu_freqp == 0) { | |
452 | rc = EINVAL; | |
453 | goto fail4; | |
454 | } | |
455 | ||
456 | return (0); | |
457 | ||
458 | fail4: | |
459 | EFSYS_PROBE(fail4); | |
460 | fail3: | |
461 | EFSYS_PROBE(fail3); | |
462 | fail2: | |
463 | EFSYS_PROBE(fail2); | |
464 | fail1: | |
465 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
466 | ||
9f95a23c TL |
467 | return (rc); |
468 | } | |
469 | ||
470 | __checkReturn efx_rc_t | |
471 | efx_mcdi_get_rxdp_config( | |
472 | __in efx_nic_t *enp, | |
473 | __out uint32_t *end_paddingp) | |
474 | { | |
475 | efx_mcdi_req_t req; | |
476 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RXDP_CONFIG_IN_LEN, | |
477 | MC_CMD_GET_RXDP_CONFIG_OUT_LEN); | |
478 | uint32_t end_padding; | |
479 | efx_rc_t rc; | |
480 | ||
481 | req.emr_cmd = MC_CMD_GET_RXDP_CONFIG; | |
482 | req.emr_in_buf = payload; | |
483 | req.emr_in_length = MC_CMD_GET_RXDP_CONFIG_IN_LEN; | |
484 | req.emr_out_buf = payload; | |
485 | req.emr_out_length = MC_CMD_GET_RXDP_CONFIG_OUT_LEN; | |
486 | ||
487 | efx_mcdi_execute(enp, &req); | |
488 | if (req.emr_rc != 0) { | |
489 | rc = req.emr_rc; | |
490 | goto fail1; | |
491 | } | |
492 | ||
493 | if (MCDI_OUT_DWORD_FIELD(req, GET_RXDP_CONFIG_OUT_DATA, | |
494 | GET_RXDP_CONFIG_OUT_PAD_HOST_DMA) == 0) { | |
495 | /* RX DMA end padding is disabled */ | |
496 | end_padding = 0; | |
497 | } else { | |
498 | switch (MCDI_OUT_DWORD_FIELD(req, GET_RXDP_CONFIG_OUT_DATA, | |
499 | GET_RXDP_CONFIG_OUT_PAD_HOST_LEN)) { | |
500 | case MC_CMD_SET_RXDP_CONFIG_IN_PAD_HOST_64: | |
501 | end_padding = 64; | |
502 | break; | |
503 | case MC_CMD_SET_RXDP_CONFIG_IN_PAD_HOST_128: | |
504 | end_padding = 128; | |
505 | break; | |
506 | case MC_CMD_SET_RXDP_CONFIG_IN_PAD_HOST_256: | |
507 | end_padding = 256; | |
508 | break; | |
509 | default: | |
510 | rc = ENOTSUP; | |
511 | goto fail2; | |
512 | } | |
513 | } | |
514 | ||
515 | *end_paddingp = end_padding; | |
516 | ||
517 | return (0); | |
518 | ||
519 | fail2: | |
520 | EFSYS_PROBE(fail2); | |
521 | fail1: | |
522 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
523 | ||
11fdf7f2 TL |
524 | return (rc); |
525 | } | |
526 | ||
527 | __checkReturn efx_rc_t | |
528 | efx_mcdi_get_vector_cfg( | |
529 | __in efx_nic_t *enp, | |
530 | __out_opt uint32_t *vec_basep, | |
531 | __out_opt uint32_t *pf_nvecp, | |
532 | __out_opt uint32_t *vf_nvecp) | |
533 | { | |
534 | efx_mcdi_req_t req; | |
9f95a23c TL |
535 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_VECTOR_CFG_IN_LEN, |
536 | MC_CMD_GET_VECTOR_CFG_OUT_LEN); | |
11fdf7f2 TL |
537 | efx_rc_t rc; |
538 | ||
11fdf7f2 TL |
539 | req.emr_cmd = MC_CMD_GET_VECTOR_CFG; |
540 | req.emr_in_buf = payload; | |
541 | req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN; | |
542 | req.emr_out_buf = payload; | |
543 | req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN; | |
544 | ||
545 | efx_mcdi_execute(enp, &req); | |
546 | ||
547 | if (req.emr_rc != 0) { | |
548 | rc = req.emr_rc; | |
549 | goto fail1; | |
550 | } | |
551 | ||
552 | if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) { | |
553 | rc = EMSGSIZE; | |
554 | goto fail2; | |
555 | } | |
556 | ||
557 | if (vec_basep != NULL) | |
558 | *vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE); | |
559 | if (pf_nvecp != NULL) | |
560 | *pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF); | |
561 | if (vf_nvecp != NULL) | |
562 | *vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF); | |
563 | ||
564 | return (0); | |
565 | ||
566 | fail2: | |
567 | EFSYS_PROBE(fail2); | |
568 | fail1: | |
569 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
570 | ||
571 | return (rc); | |
572 | } | |
573 | ||
574 | static __checkReturn efx_rc_t | |
575 | efx_mcdi_alloc_vis( | |
576 | __in efx_nic_t *enp, | |
577 | __in uint32_t min_vi_count, | |
578 | __in uint32_t max_vi_count, | |
579 | __out uint32_t *vi_basep, | |
580 | __out uint32_t *vi_countp, | |
581 | __out uint32_t *vi_shiftp) | |
582 | { | |
583 | efx_mcdi_req_t req; | |
9f95a23c TL |
584 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_ALLOC_VIS_IN_LEN, |
585 | MC_CMD_ALLOC_VIS_EXT_OUT_LEN); | |
11fdf7f2 TL |
586 | efx_rc_t rc; |
587 | ||
588 | if (vi_countp == NULL) { | |
589 | rc = EINVAL; | |
590 | goto fail1; | |
591 | } | |
592 | ||
11fdf7f2 TL |
593 | req.emr_cmd = MC_CMD_ALLOC_VIS; |
594 | req.emr_in_buf = payload; | |
595 | req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN; | |
596 | req.emr_out_buf = payload; | |
597 | req.emr_out_length = MC_CMD_ALLOC_VIS_EXT_OUT_LEN; | |
598 | ||
599 | MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count); | |
600 | MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count); | |
601 | ||
602 | efx_mcdi_execute(enp, &req); | |
603 | ||
604 | if (req.emr_rc != 0) { | |
605 | rc = req.emr_rc; | |
606 | goto fail2; | |
607 | } | |
608 | ||
609 | if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) { | |
610 | rc = EMSGSIZE; | |
611 | goto fail3; | |
612 | } | |
613 | ||
614 | *vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE); | |
615 | *vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT); | |
616 | ||
617 | /* Report VI_SHIFT if available (always zero for Huntington) */ | |
618 | if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN) | |
619 | *vi_shiftp = 0; | |
620 | else | |
621 | *vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT); | |
622 | ||
623 | return (0); | |
624 | ||
625 | fail3: | |
626 | EFSYS_PROBE(fail3); | |
627 | fail2: | |
628 | EFSYS_PROBE(fail2); | |
629 | fail1: | |
630 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
631 | ||
632 | return (rc); | |
633 | } | |
634 | ||
635 | ||
636 | static __checkReturn efx_rc_t | |
637 | efx_mcdi_free_vis( | |
638 | __in efx_nic_t *enp) | |
639 | { | |
640 | efx_mcdi_req_t req; | |
641 | efx_rc_t rc; | |
642 | ||
643 | EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0); | |
644 | EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0); | |
645 | ||
646 | req.emr_cmd = MC_CMD_FREE_VIS; | |
647 | req.emr_in_buf = NULL; | |
648 | req.emr_in_length = 0; | |
649 | req.emr_out_buf = NULL; | |
650 | req.emr_out_length = 0; | |
651 | ||
652 | efx_mcdi_execute_quiet(enp, &req); | |
653 | ||
654 | /* Ignore ELREADY (no allocated VIs, so nothing to free) */ | |
655 | if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) { | |
656 | rc = req.emr_rc; | |
657 | goto fail1; | |
658 | } | |
659 | ||
660 | return (0); | |
661 | ||
662 | fail1: | |
663 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
664 | ||
665 | return (rc); | |
666 | } | |
667 | ||
668 | ||
669 | static __checkReturn efx_rc_t | |
670 | efx_mcdi_alloc_piobuf( | |
671 | __in efx_nic_t *enp, | |
672 | __out efx_piobuf_handle_t *handlep) | |
673 | { | |
674 | efx_mcdi_req_t req; | |
9f95a23c TL |
675 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_ALLOC_PIOBUF_IN_LEN, |
676 | MC_CMD_ALLOC_PIOBUF_OUT_LEN); | |
11fdf7f2 TL |
677 | efx_rc_t rc; |
678 | ||
679 | if (handlep == NULL) { | |
680 | rc = EINVAL; | |
681 | goto fail1; | |
682 | } | |
683 | ||
11fdf7f2 TL |
684 | req.emr_cmd = MC_CMD_ALLOC_PIOBUF; |
685 | req.emr_in_buf = payload; | |
686 | req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN; | |
687 | req.emr_out_buf = payload; | |
688 | req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN; | |
689 | ||
690 | efx_mcdi_execute_quiet(enp, &req); | |
691 | ||
692 | if (req.emr_rc != 0) { | |
693 | rc = req.emr_rc; | |
694 | goto fail2; | |
695 | } | |
696 | ||
697 | if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) { | |
698 | rc = EMSGSIZE; | |
699 | goto fail3; | |
700 | } | |
701 | ||
702 | *handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE); | |
703 | ||
704 | return (0); | |
705 | ||
706 | fail3: | |
707 | EFSYS_PROBE(fail3); | |
708 | fail2: | |
709 | EFSYS_PROBE(fail2); | |
710 | fail1: | |
711 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
712 | ||
713 | return (rc); | |
714 | } | |
715 | ||
716 | static __checkReturn efx_rc_t | |
717 | efx_mcdi_free_piobuf( | |
718 | __in efx_nic_t *enp, | |
719 | __in efx_piobuf_handle_t handle) | |
720 | { | |
721 | efx_mcdi_req_t req; | |
9f95a23c TL |
722 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FREE_PIOBUF_IN_LEN, |
723 | MC_CMD_FREE_PIOBUF_OUT_LEN); | |
11fdf7f2 TL |
724 | efx_rc_t rc; |
725 | ||
11fdf7f2 TL |
726 | req.emr_cmd = MC_CMD_FREE_PIOBUF; |
727 | req.emr_in_buf = payload; | |
728 | req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN; | |
729 | req.emr_out_buf = payload; | |
730 | req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN; | |
731 | ||
732 | MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle); | |
733 | ||
734 | efx_mcdi_execute_quiet(enp, &req); | |
735 | ||
736 | if (req.emr_rc != 0) { | |
737 | rc = req.emr_rc; | |
738 | goto fail1; | |
739 | } | |
740 | ||
741 | return (0); | |
742 | ||
743 | fail1: | |
744 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
745 | ||
746 | return (rc); | |
747 | } | |
748 | ||
749 | static __checkReturn efx_rc_t | |
750 | efx_mcdi_link_piobuf( | |
751 | __in efx_nic_t *enp, | |
752 | __in uint32_t vi_index, | |
753 | __in efx_piobuf_handle_t handle) | |
754 | { | |
755 | efx_mcdi_req_t req; | |
9f95a23c TL |
756 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LINK_PIOBUF_IN_LEN, |
757 | MC_CMD_LINK_PIOBUF_OUT_LEN); | |
11fdf7f2 TL |
758 | efx_rc_t rc; |
759 | ||
11fdf7f2 TL |
760 | req.emr_cmd = MC_CMD_LINK_PIOBUF; |
761 | req.emr_in_buf = payload; | |
762 | req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN; | |
763 | req.emr_out_buf = payload; | |
764 | req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN; | |
765 | ||
766 | MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle); | |
767 | MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); | |
768 | ||
769 | efx_mcdi_execute(enp, &req); | |
770 | ||
771 | if (req.emr_rc != 0) { | |
772 | rc = req.emr_rc; | |
773 | goto fail1; | |
774 | } | |
775 | ||
776 | return (0); | |
777 | ||
778 | fail1: | |
779 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
780 | ||
781 | return (rc); | |
782 | } | |
783 | ||
784 | static __checkReturn efx_rc_t | |
785 | efx_mcdi_unlink_piobuf( | |
786 | __in efx_nic_t *enp, | |
787 | __in uint32_t vi_index) | |
788 | { | |
789 | efx_mcdi_req_t req; | |
9f95a23c TL |
790 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_UNLINK_PIOBUF_IN_LEN, |
791 | MC_CMD_UNLINK_PIOBUF_OUT_LEN); | |
11fdf7f2 TL |
792 | efx_rc_t rc; |
793 | ||
11fdf7f2 TL |
794 | req.emr_cmd = MC_CMD_UNLINK_PIOBUF; |
795 | req.emr_in_buf = payload; | |
796 | req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN; | |
797 | req.emr_out_buf = payload; | |
798 | req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN; | |
799 | ||
800 | MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); | |
801 | ||
802 | efx_mcdi_execute_quiet(enp, &req); | |
803 | ||
804 | if (req.emr_rc != 0) { | |
805 | rc = req.emr_rc; | |
806 | goto fail1; | |
807 | } | |
808 | ||
809 | return (0); | |
810 | ||
811 | fail1: | |
812 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
813 | ||
814 | return (rc); | |
815 | } | |
816 | ||
817 | static void | |
818 | ef10_nic_alloc_piobufs( | |
819 | __in efx_nic_t *enp, | |
820 | __in uint32_t max_piobuf_count) | |
821 | { | |
822 | efx_piobuf_handle_t *handlep; | |
823 | unsigned int i; | |
824 | ||
825 | EFSYS_ASSERT3U(max_piobuf_count, <=, | |
826 | EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle)); | |
827 | ||
828 | enp->en_arch.ef10.ena_piobuf_count = 0; | |
829 | ||
830 | for (i = 0; i < max_piobuf_count; i++) { | |
831 | handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; | |
832 | ||
833 | if (efx_mcdi_alloc_piobuf(enp, handlep) != 0) | |
834 | goto fail1; | |
835 | ||
836 | enp->en_arch.ef10.ena_pio_alloc_map[i] = 0; | |
837 | enp->en_arch.ef10.ena_piobuf_count++; | |
838 | } | |
839 | ||
840 | return; | |
841 | ||
842 | fail1: | |
843 | for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { | |
844 | handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; | |
845 | ||
9f95a23c | 846 | (void) efx_mcdi_free_piobuf(enp, *handlep); |
11fdf7f2 TL |
847 | *handlep = EFX_PIOBUF_HANDLE_INVALID; |
848 | } | |
849 | enp->en_arch.ef10.ena_piobuf_count = 0; | |
850 | } | |
851 | ||
852 | ||
853 | static void | |
854 | ef10_nic_free_piobufs( | |
855 | __in efx_nic_t *enp) | |
856 | { | |
857 | efx_piobuf_handle_t *handlep; | |
858 | unsigned int i; | |
859 | ||
860 | for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { | |
861 | handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; | |
862 | ||
9f95a23c | 863 | (void) efx_mcdi_free_piobuf(enp, *handlep); |
11fdf7f2 TL |
864 | *handlep = EFX_PIOBUF_HANDLE_INVALID; |
865 | } | |
866 | enp->en_arch.ef10.ena_piobuf_count = 0; | |
867 | } | |
868 | ||
869 | /* Sub-allocate a block from a piobuf */ | |
870 | __checkReturn efx_rc_t | |
871 | ef10_nic_pio_alloc( | |
872 | __inout efx_nic_t *enp, | |
873 | __out uint32_t *bufnump, | |
874 | __out efx_piobuf_handle_t *handlep, | |
875 | __out uint32_t *blknump, | |
876 | __out uint32_t *offsetp, | |
877 | __out size_t *sizep) | |
878 | { | |
879 | efx_nic_cfg_t *encp = &enp->en_nic_cfg; | |
880 | efx_drv_cfg_t *edcp = &enp->en_drv_cfg; | |
881 | uint32_t blk_per_buf; | |
882 | uint32_t buf, blk; | |
883 | efx_rc_t rc; | |
884 | ||
9f95a23c | 885 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 TL |
886 | EFSYS_ASSERT(bufnump); |
887 | EFSYS_ASSERT(handlep); | |
888 | EFSYS_ASSERT(blknump); | |
889 | EFSYS_ASSERT(offsetp); | |
890 | EFSYS_ASSERT(sizep); | |
891 | ||
892 | if ((edcp->edc_pio_alloc_size == 0) || | |
893 | (enp->en_arch.ef10.ena_piobuf_count == 0)) { | |
894 | rc = ENOMEM; | |
895 | goto fail1; | |
896 | } | |
897 | blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size; | |
898 | ||
899 | for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) { | |
900 | uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf]; | |
901 | ||
902 | if (~(*map) == 0) | |
903 | continue; | |
904 | ||
905 | EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map))); | |
906 | for (blk = 0; blk < blk_per_buf; blk++) { | |
907 | if ((*map & (1u << blk)) == 0) { | |
908 | *map |= (1u << blk); | |
909 | goto done; | |
910 | } | |
911 | } | |
912 | } | |
913 | rc = ENOMEM; | |
914 | goto fail2; | |
915 | ||
916 | done: | |
917 | *handlep = enp->en_arch.ef10.ena_piobuf_handle[buf]; | |
918 | *bufnump = buf; | |
919 | *blknump = blk; | |
920 | *sizep = edcp->edc_pio_alloc_size; | |
921 | *offsetp = blk * (*sizep); | |
922 | ||
923 | return (0); | |
924 | ||
925 | fail2: | |
926 | EFSYS_PROBE(fail2); | |
927 | fail1: | |
928 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
929 | ||
930 | return (rc); | |
931 | } | |
932 | ||
933 | /* Free a piobuf sub-allocated block */ | |
934 | __checkReturn efx_rc_t | |
935 | ef10_nic_pio_free( | |
936 | __inout efx_nic_t *enp, | |
937 | __in uint32_t bufnum, | |
938 | __in uint32_t blknum) | |
939 | { | |
940 | uint32_t *map; | |
941 | efx_rc_t rc; | |
942 | ||
943 | if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) || | |
944 | (blknum >= (8 * sizeof (*map)))) { | |
945 | rc = EINVAL; | |
946 | goto fail1; | |
947 | } | |
948 | ||
949 | map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum]; | |
950 | if ((*map & (1u << blknum)) == 0) { | |
951 | rc = ENOENT; | |
952 | goto fail2; | |
953 | } | |
954 | *map &= ~(1u << blknum); | |
955 | ||
956 | return (0); | |
957 | ||
958 | fail2: | |
959 | EFSYS_PROBE(fail2); | |
960 | fail1: | |
961 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
962 | ||
963 | return (rc); | |
964 | } | |
965 | ||
966 | __checkReturn efx_rc_t | |
967 | ef10_nic_pio_link( | |
968 | __inout efx_nic_t *enp, | |
969 | __in uint32_t vi_index, | |
970 | __in efx_piobuf_handle_t handle) | |
971 | { | |
972 | return (efx_mcdi_link_piobuf(enp, vi_index, handle)); | |
973 | } | |
974 | ||
975 | __checkReturn efx_rc_t | |
976 | ef10_nic_pio_unlink( | |
977 | __inout efx_nic_t *enp, | |
978 | __in uint32_t vi_index) | |
979 | { | |
980 | return (efx_mcdi_unlink_piobuf(enp, vi_index)); | |
981 | } | |
982 | ||
983 | static __checkReturn efx_rc_t | |
984 | ef10_mcdi_get_pf_count( | |
985 | __in efx_nic_t *enp, | |
986 | __out uint32_t *pf_countp) | |
987 | { | |
988 | efx_mcdi_req_t req; | |
9f95a23c TL |
989 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PF_COUNT_IN_LEN, |
990 | MC_CMD_GET_PF_COUNT_OUT_LEN); | |
11fdf7f2 TL |
991 | efx_rc_t rc; |
992 | ||
11fdf7f2 TL |
993 | req.emr_cmd = MC_CMD_GET_PF_COUNT; |
994 | req.emr_in_buf = payload; | |
995 | req.emr_in_length = MC_CMD_GET_PF_COUNT_IN_LEN; | |
996 | req.emr_out_buf = payload; | |
997 | req.emr_out_length = MC_CMD_GET_PF_COUNT_OUT_LEN; | |
998 | ||
999 | efx_mcdi_execute(enp, &req); | |
1000 | ||
1001 | if (req.emr_rc != 0) { | |
1002 | rc = req.emr_rc; | |
1003 | goto fail1; | |
1004 | } | |
1005 | ||
1006 | if (req.emr_out_length_used < MC_CMD_GET_PF_COUNT_OUT_LEN) { | |
1007 | rc = EMSGSIZE; | |
1008 | goto fail2; | |
1009 | } | |
1010 | ||
1011 | *pf_countp = *MCDI_OUT(req, uint8_t, | |
1012 | MC_CMD_GET_PF_COUNT_OUT_PF_COUNT_OFST); | |
1013 | ||
1014 | EFSYS_ASSERT(*pf_countp != 0); | |
1015 | ||
1016 | return (0); | |
1017 | ||
1018 | fail2: | |
1019 | EFSYS_PROBE(fail2); | |
1020 | fail1: | |
1021 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
1022 | ||
1023 | return (rc); | |
1024 | } | |
1025 | ||
9f95a23c | 1026 | static __checkReturn efx_rc_t |
11fdf7f2 TL |
1027 | ef10_get_datapath_caps( |
1028 | __in efx_nic_t *enp) | |
1029 | { | |
1030 | efx_nic_cfg_t *encp = &(enp->en_nic_cfg); | |
9f95a23c TL |
1031 | efx_mcdi_req_t req; |
1032 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CAPABILITIES_IN_LEN, | |
1033 | MC_CMD_GET_CAPABILITIES_V5_OUT_LEN); | |
11fdf7f2 TL |
1034 | efx_rc_t rc; |
1035 | ||
11fdf7f2 TL |
1036 | if ((rc = ef10_mcdi_get_pf_count(enp, &encp->enc_hw_pf_count)) != 0) |
1037 | goto fail1; | |
1038 | ||
11fdf7f2 | 1039 | |
9f95a23c TL |
1040 | req.emr_cmd = MC_CMD_GET_CAPABILITIES; |
1041 | req.emr_in_buf = payload; | |
1042 | req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; | |
1043 | req.emr_out_buf = payload; | |
1044 | req.emr_out_length = MC_CMD_GET_CAPABILITIES_V5_OUT_LEN; | |
1045 | ||
1046 | efx_mcdi_execute_quiet(enp, &req); | |
1047 | ||
1048 | if (req.emr_rc != 0) { | |
1049 | rc = req.emr_rc; | |
1050 | goto fail2; | |
1051 | } | |
1052 | ||
1053 | if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { | |
1054 | rc = EMSGSIZE; | |
1055 | goto fail3; | |
1056 | } | |
1057 | ||
1058 | #define CAP_FLAGS1(_req, _flag) \ | |
1059 | (MCDI_OUT_DWORD((_req), GET_CAPABILITIES_OUT_FLAGS1) & \ | |
1060 | (1u << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## _flag ## _LBN))) | |
1061 | ||
1062 | #define CAP_FLAGS2(_req, _flag) \ | |
1063 | (((_req).emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) && \ | |
1064 | (MCDI_OUT_DWORD((_req), GET_CAPABILITIES_V2_OUT_FLAGS2) & \ | |
1065 | (1u << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## _flag ## _LBN)))) | |
11fdf7f2 TL |
1066 | |
1067 | /* | |
1068 | * Huntington RXDP firmware inserts a 0 or 14 byte prefix. | |
1069 | * We only support the 14 byte prefix here. | |
1070 | */ | |
9f95a23c | 1071 | if (CAP_FLAGS1(req, RX_PREFIX_LEN_14) == 0) { |
11fdf7f2 | 1072 | rc = ENOTSUP; |
9f95a23c | 1073 | goto fail4; |
11fdf7f2 TL |
1074 | } |
1075 | encp->enc_rx_prefix_size = 14; | |
1076 | ||
9f95a23c TL |
1077 | #if EFSYS_OPT_RX_SCALE |
1078 | /* Check if the firmware supports additional RSS modes */ | |
1079 | if (CAP_FLAGS1(req, ADDITIONAL_RSS_MODES)) | |
1080 | encp->enc_rx_scale_additional_modes_supported = B_TRUE; | |
1081 | else | |
1082 | encp->enc_rx_scale_additional_modes_supported = B_FALSE; | |
1083 | #endif /* EFSYS_OPT_RX_SCALE */ | |
1084 | ||
11fdf7f2 | 1085 | /* Check if the firmware supports TSO */ |
9f95a23c TL |
1086 | if (CAP_FLAGS1(req, TX_TSO)) |
1087 | encp->enc_fw_assisted_tso_enabled = B_TRUE; | |
1088 | else | |
1089 | encp->enc_fw_assisted_tso_enabled = B_FALSE; | |
11fdf7f2 TL |
1090 | |
1091 | /* Check if the firmware supports FATSOv2 */ | |
9f95a23c TL |
1092 | if (CAP_FLAGS2(req, TX_TSO_V2)) { |
1093 | encp->enc_fw_assisted_tso_v2_enabled = B_TRUE; | |
1094 | encp->enc_fw_assisted_tso_v2_n_contexts = MCDI_OUT_WORD(req, | |
1095 | GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS); | |
1096 | } else { | |
1097 | encp->enc_fw_assisted_tso_v2_enabled = B_FALSE; | |
1098 | encp->enc_fw_assisted_tso_v2_n_contexts = 0; | |
1099 | } | |
11fdf7f2 | 1100 | |
9f95a23c TL |
1101 | /* Check if the firmware supports FATSOv2 encap */ |
1102 | if (CAP_FLAGS2(req, TX_TSO_V2_ENCAP)) | |
1103 | encp->enc_fw_assisted_tso_v2_encap_enabled = B_TRUE; | |
1104 | else | |
1105 | encp->enc_fw_assisted_tso_v2_encap_enabled = B_FALSE; | |
11fdf7f2 TL |
1106 | |
1107 | /* Check if the firmware has vadapter/vport/vswitch support */ | |
9f95a23c TL |
1108 | if (CAP_FLAGS1(req, EVB)) |
1109 | encp->enc_datapath_cap_evb = B_TRUE; | |
1110 | else | |
1111 | encp->enc_datapath_cap_evb = B_FALSE; | |
11fdf7f2 TL |
1112 | |
1113 | /* Check if the firmware supports VLAN insertion */ | |
9f95a23c TL |
1114 | if (CAP_FLAGS1(req, TX_VLAN_INSERTION)) |
1115 | encp->enc_hw_tx_insert_vlan_enabled = B_TRUE; | |
1116 | else | |
1117 | encp->enc_hw_tx_insert_vlan_enabled = B_FALSE; | |
11fdf7f2 TL |
1118 | |
1119 | /* Check if the firmware supports RX event batching */ | |
9f95a23c TL |
1120 | if (CAP_FLAGS1(req, RX_BATCHING)) |
1121 | encp->enc_rx_batching_enabled = B_TRUE; | |
1122 | else | |
1123 | encp->enc_rx_batching_enabled = B_FALSE; | |
11fdf7f2 TL |
1124 | |
1125 | /* | |
1126 | * Even if batching isn't reported as supported, we may still get | |
1127 | * batched events (see bug61153). | |
1128 | */ | |
1129 | encp->enc_rx_batch_max = 16; | |
1130 | ||
1131 | /* Check if the firmware supports disabling scatter on RXQs */ | |
9f95a23c TL |
1132 | if (CAP_FLAGS1(req, RX_DISABLE_SCATTER)) |
1133 | encp->enc_rx_disable_scatter_supported = B_TRUE; | |
1134 | else | |
1135 | encp->enc_rx_disable_scatter_supported = B_FALSE; | |
11fdf7f2 TL |
1136 | |
1137 | /* Check if the firmware supports packed stream mode */ | |
9f95a23c TL |
1138 | if (CAP_FLAGS1(req, RX_PACKED_STREAM)) |
1139 | encp->enc_rx_packed_stream_supported = B_TRUE; | |
1140 | else | |
1141 | encp->enc_rx_packed_stream_supported = B_FALSE; | |
11fdf7f2 TL |
1142 | |
1143 | /* | |
1144 | * Check if the firmware supports configurable buffer sizes | |
1145 | * for packed stream mode (otherwise buffer size is 1Mbyte) | |
1146 | */ | |
9f95a23c TL |
1147 | if (CAP_FLAGS1(req, RX_PACKED_STREAM_VAR_BUFFERS)) |
1148 | encp->enc_rx_var_packed_stream_supported = B_TRUE; | |
1149 | else | |
1150 | encp->enc_rx_var_packed_stream_supported = B_FALSE; | |
1151 | ||
1152 | /* Check if the firmware supports equal stride super-buffer mode */ | |
1153 | if (CAP_FLAGS2(req, EQUAL_STRIDE_SUPER_BUFFER)) | |
1154 | encp->enc_rx_es_super_buffer_supported = B_TRUE; | |
1155 | else | |
1156 | encp->enc_rx_es_super_buffer_supported = B_FALSE; | |
1157 | ||
1158 | /* Check if the firmware supports FW subvariant w/o Tx checksumming */ | |
1159 | if (CAP_FLAGS2(req, FW_SUBVARIANT_NO_TX_CSUM)) | |
1160 | encp->enc_fw_subvariant_no_tx_csum_supported = B_TRUE; | |
1161 | else | |
1162 | encp->enc_fw_subvariant_no_tx_csum_supported = B_FALSE; | |
11fdf7f2 TL |
1163 | |
1164 | /* Check if the firmware supports set mac with running filters */ | |
9f95a23c TL |
1165 | if (CAP_FLAGS1(req, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED)) |
1166 | encp->enc_allow_set_mac_with_installed_filters = B_TRUE; | |
1167 | else | |
1168 | encp->enc_allow_set_mac_with_installed_filters = B_FALSE; | |
11fdf7f2 TL |
1169 | |
1170 | /* | |
1171 | * Check if firmware supports the extended MC_CMD_SET_MAC, which allows | |
1172 | * specifying which parameters to configure. | |
1173 | */ | |
9f95a23c TL |
1174 | if (CAP_FLAGS1(req, SET_MAC_ENHANCED)) |
1175 | encp->enc_enhanced_set_mac_supported = B_TRUE; | |
1176 | else | |
1177 | encp->enc_enhanced_set_mac_supported = B_FALSE; | |
11fdf7f2 TL |
1178 | |
1179 | /* | |
1180 | * Check if firmware supports version 2 of MC_CMD_INIT_EVQ, which allows | |
1181 | * us to let the firmware choose the settings to use on an EVQ. | |
1182 | */ | |
9f95a23c TL |
1183 | if (CAP_FLAGS2(req, INIT_EVQ_V2)) |
1184 | encp->enc_init_evq_v2_supported = B_TRUE; | |
1185 | else | |
1186 | encp->enc_init_evq_v2_supported = B_FALSE; | |
1187 | ||
1188 | /* | |
1189 | * Check if the NO_CONT_EV mode for RX events is supported. | |
1190 | */ | |
1191 | if (CAP_FLAGS2(req, INIT_RXQ_NO_CONT_EV)) | |
1192 | encp->enc_no_cont_ev_mode_supported = B_TRUE; | |
1193 | else | |
1194 | encp->enc_no_cont_ev_mode_supported = B_FALSE; | |
1195 | ||
1196 | /* | |
1197 | * Check if buffer size may and must be specified on INIT_RXQ. | |
1198 | * It may be always specified to efx_rx_qcreate(), but will be | |
1199 | * just kept libefx internal if MCDI does not support it. | |
1200 | */ | |
1201 | if (CAP_FLAGS2(req, INIT_RXQ_WITH_BUFFER_SIZE)) | |
1202 | encp->enc_init_rxq_with_buffer_size = B_TRUE; | |
1203 | else | |
1204 | encp->enc_init_rxq_with_buffer_size = B_FALSE; | |
11fdf7f2 TL |
1205 | |
1206 | /* | |
1207 | * Check if firmware-verified NVRAM updates must be used. | |
1208 | * | |
1209 | * The firmware trusted installer requires all NVRAM updates to use | |
1210 | * version 2 of MC_CMD_NVRAM_UPDATE_START (to enable verified update) | |
1211 | * and version 2 of MC_CMD_NVRAM_UPDATE_FINISH (to verify the updated | |
1212 | * partition and report the result). | |
1213 | */ | |
9f95a23c TL |
1214 | if (CAP_FLAGS2(req, NVRAM_UPDATE_REPORT_VERIFY_RESULT)) |
1215 | encp->enc_nvram_update_verify_result_supported = B_TRUE; | |
1216 | else | |
1217 | encp->enc_nvram_update_verify_result_supported = B_FALSE; | |
11fdf7f2 TL |
1218 | |
1219 | /* | |
1220 | * Check if firmware provides packet memory and Rx datapath | |
1221 | * counters. | |
1222 | */ | |
9f95a23c TL |
1223 | if (CAP_FLAGS1(req, PM_AND_RXDP_COUNTERS)) |
1224 | encp->enc_pm_and_rxdp_counters = B_TRUE; | |
1225 | else | |
1226 | encp->enc_pm_and_rxdp_counters = B_FALSE; | |
11fdf7f2 TL |
1227 | |
1228 | /* | |
1229 | * Check if the 40G MAC hardware is capable of reporting | |
1230 | * statistics for Tx size bins. | |
1231 | */ | |
9f95a23c TL |
1232 | if (CAP_FLAGS2(req, MAC_STATS_40G_TX_SIZE_BINS)) |
1233 | encp->enc_mac_stats_40g_tx_size_bins = B_TRUE; | |
1234 | else | |
1235 | encp->enc_mac_stats_40g_tx_size_bins = B_FALSE; | |
1236 | ||
1237 | /* | |
1238 | * Check if firmware supports VXLAN and NVGRE tunnels. | |
1239 | * The capability indicates Geneve protocol support as well. | |
1240 | */ | |
1241 | if (CAP_FLAGS1(req, VXLAN_NVGRE)) { | |
1242 | encp->enc_tunnel_encapsulations_supported = | |
1243 | (1u << EFX_TUNNEL_PROTOCOL_VXLAN) | | |
1244 | (1u << EFX_TUNNEL_PROTOCOL_GENEVE) | | |
1245 | (1u << EFX_TUNNEL_PROTOCOL_NVGRE); | |
1246 | ||
1247 | EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES == | |
1248 | MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM); | |
1249 | encp->enc_tunnel_config_udp_entries_max = | |
1250 | EFX_TUNNEL_MAXNENTRIES; | |
1251 | } else { | |
1252 | encp->enc_tunnel_config_udp_entries_max = 0; | |
1253 | } | |
11fdf7f2 | 1254 | |
9f95a23c TL |
1255 | /* |
1256 | * Check if firmware reports the VI window mode. | |
1257 | * Medford2 has a variable VI window size (8K, 16K or 64K). | |
1258 | * Medford and Huntington have a fixed 8K VI window size. | |
1259 | */ | |
1260 | if (req.emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V3_OUT_LEN) { | |
1261 | uint8_t mode = | |
1262 | MCDI_OUT_BYTE(req, GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE); | |
1263 | ||
1264 | switch (mode) { | |
1265 | case MC_CMD_GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE_8K: | |
1266 | encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_8K; | |
1267 | break; | |
1268 | case MC_CMD_GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE_16K: | |
1269 | encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_16K; | |
1270 | break; | |
1271 | case MC_CMD_GET_CAPABILITIES_V3_OUT_VI_WINDOW_MODE_64K: | |
1272 | encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_64K; | |
1273 | break; | |
1274 | default: | |
1275 | encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_INVALID; | |
1276 | break; | |
1277 | } | |
1278 | } else if ((enp->en_family == EFX_FAMILY_HUNTINGTON) || | |
1279 | (enp->en_family == EFX_FAMILY_MEDFORD)) { | |
1280 | /* Huntington and Medford have fixed 8K window size */ | |
1281 | encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_8K; | |
1282 | } else { | |
1283 | encp->enc_vi_window_shift = EFX_VI_WINDOW_SHIFT_INVALID; | |
1284 | } | |
1285 | ||
1286 | /* Check if firmware supports extended MAC stats. */ | |
1287 | if (req.emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V4_OUT_LEN) { | |
1288 | /* Extended stats buffer supported */ | |
1289 | encp->enc_mac_stats_nstats = MCDI_OUT_WORD(req, | |
1290 | GET_CAPABILITIES_V4_OUT_MAC_STATS_NUM_STATS); | |
1291 | } else { | |
1292 | /* Use Siena-compatible legacy MAC stats */ | |
1293 | encp->enc_mac_stats_nstats = MC_CMD_MAC_NSTATS; | |
1294 | } | |
1295 | ||
1296 | if (encp->enc_mac_stats_nstats >= MC_CMD_MAC_NSTATS_V2) | |
1297 | encp->enc_fec_counters = B_TRUE; | |
1298 | else | |
1299 | encp->enc_fec_counters = B_FALSE; | |
1300 | ||
1301 | /* Check if the firmware provides head-of-line blocking counters */ | |
1302 | if (CAP_FLAGS2(req, RXDP_HLB_IDLE)) | |
1303 | encp->enc_hlb_counters = B_TRUE; | |
1304 | else | |
1305 | encp->enc_hlb_counters = B_FALSE; | |
1306 | ||
1307 | #if EFSYS_OPT_RX_SCALE | |
1308 | if (CAP_FLAGS1(req, RX_RSS_LIMITED)) { | |
1309 | /* Only one exclusive RSS context is available per port. */ | |
1310 | encp->enc_rx_scale_max_exclusive_contexts = 1; | |
1311 | ||
1312 | switch (enp->en_family) { | |
1313 | case EFX_FAMILY_MEDFORD2: | |
1314 | encp->enc_rx_scale_hash_alg_mask = | |
1315 | (1U << EFX_RX_HASHALG_TOEPLITZ); | |
1316 | break; | |
1317 | ||
1318 | case EFX_FAMILY_MEDFORD: | |
1319 | case EFX_FAMILY_HUNTINGTON: | |
1320 | /* | |
1321 | * Packed stream firmware variant maintains a | |
1322 | * non-standard algorithm for hash computation. | |
1323 | * It implies explicit XORing together | |
1324 | * source + destination IP addresses (or last | |
1325 | * four bytes in the case of IPv6) and using the | |
1326 | * resulting value as the input to a Toeplitz hash. | |
1327 | */ | |
1328 | encp->enc_rx_scale_hash_alg_mask = | |
1329 | (1U << EFX_RX_HASHALG_PACKED_STREAM); | |
1330 | break; | |
1331 | ||
1332 | default: | |
1333 | rc = EINVAL; | |
1334 | goto fail5; | |
1335 | } | |
1336 | ||
1337 | /* Port numbers cannot contribute to the hash value */ | |
1338 | encp->enc_rx_scale_l4_hash_supported = B_FALSE; | |
1339 | } else { | |
1340 | /* | |
1341 | * Maximum number of exclusive RSS contexts. | |
1342 | * EF10 hardware supports 64 in total, but 6 are reserved | |
1343 | * for shared contexts. They are a global resource so | |
1344 | * not all may be available. | |
1345 | */ | |
1346 | encp->enc_rx_scale_max_exclusive_contexts = 64 - 6; | |
1347 | ||
1348 | encp->enc_rx_scale_hash_alg_mask = | |
1349 | (1U << EFX_RX_HASHALG_TOEPLITZ); | |
1350 | ||
1351 | /* | |
1352 | * It is possible to use port numbers as | |
1353 | * the input data for hash computation. | |
1354 | */ | |
1355 | encp->enc_rx_scale_l4_hash_supported = B_TRUE; | |
1356 | } | |
1357 | #endif /* EFSYS_OPT_RX_SCALE */ | |
1358 | ||
1359 | /* Check if the firmware supports "FLAG" and "MARK" filter actions */ | |
1360 | if (CAP_FLAGS2(req, FILTER_ACTION_FLAG)) | |
1361 | encp->enc_filter_action_flag_supported = B_TRUE; | |
1362 | else | |
1363 | encp->enc_filter_action_flag_supported = B_FALSE; | |
1364 | ||
1365 | if (CAP_FLAGS2(req, FILTER_ACTION_MARK)) | |
1366 | encp->enc_filter_action_mark_supported = B_TRUE; | |
1367 | else | |
1368 | encp->enc_filter_action_mark_supported = B_FALSE; | |
1369 | ||
1370 | /* Get maximum supported value for "MARK" filter action */ | |
1371 | if (req.emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V5_OUT_LEN) | |
1372 | encp->enc_filter_action_mark_max = MCDI_OUT_DWORD(req, | |
1373 | GET_CAPABILITIES_V5_OUT_FILTER_ACTION_MARK_MAX); | |
1374 | else | |
1375 | encp->enc_filter_action_mark_max = 0; | |
1376 | ||
1377 | #undef CAP_FLAGS1 | |
1378 | #undef CAP_FLAGS2 | |
11fdf7f2 TL |
1379 | |
1380 | return (0); | |
1381 | ||
9f95a23c TL |
1382 | #if EFSYS_OPT_RX_SCALE |
1383 | fail5: | |
1384 | EFSYS_PROBE(fail5); | |
1385 | #endif /* EFSYS_OPT_RX_SCALE */ | |
1386 | fail4: | |
1387 | EFSYS_PROBE(fail4); | |
1388 | fail3: | |
1389 | EFSYS_PROBE(fail3); | |
11fdf7f2 TL |
1390 | fail2: |
1391 | EFSYS_PROBE(fail2); | |
1392 | fail1: | |
1393 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
1394 | ||
1395 | return (rc); | |
1396 | } | |
1397 | ||
1398 | ||
1399 | #define EF10_LEGACY_PF_PRIVILEGE_MASK \ | |
1400 | (MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN | \ | |
1401 | MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK | \ | |
1402 | MC_CMD_PRIVILEGE_MASK_IN_GRP_ONLOAD | \ | |
1403 | MC_CMD_PRIVILEGE_MASK_IN_GRP_PTP | \ | |
1404 | MC_CMD_PRIVILEGE_MASK_IN_GRP_INSECURE_FILTERS | \ | |
1405 | MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING | \ | |
1406 | MC_CMD_PRIVILEGE_MASK_IN_GRP_UNICAST | \ | |
1407 | MC_CMD_PRIVILEGE_MASK_IN_GRP_MULTICAST | \ | |
1408 | MC_CMD_PRIVILEGE_MASK_IN_GRP_BROADCAST | \ | |
1409 | MC_CMD_PRIVILEGE_MASK_IN_GRP_ALL_MULTICAST | \ | |
1410 | MC_CMD_PRIVILEGE_MASK_IN_GRP_PROMISCUOUS) | |
1411 | ||
1412 | #define EF10_LEGACY_VF_PRIVILEGE_MASK 0 | |
1413 | ||
1414 | ||
1415 | __checkReturn efx_rc_t | |
1416 | ef10_get_privilege_mask( | |
1417 | __in efx_nic_t *enp, | |
1418 | __out uint32_t *maskp) | |
1419 | { | |
1420 | efx_nic_cfg_t *encp = &(enp->en_nic_cfg); | |
1421 | uint32_t mask; | |
1422 | efx_rc_t rc; | |
1423 | ||
1424 | if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf, | |
1425 | &mask)) != 0) { | |
1426 | if (rc != ENOTSUP) | |
1427 | goto fail1; | |
1428 | ||
1429 | /* Fallback for old firmware without privilege mask support */ | |
1430 | if (EFX_PCI_FUNCTION_IS_PF(encp)) { | |
1431 | /* Assume PF has admin privilege */ | |
1432 | mask = EF10_LEGACY_PF_PRIVILEGE_MASK; | |
1433 | } else { | |
1434 | /* VF is always unprivileged by default */ | |
1435 | mask = EF10_LEGACY_VF_PRIVILEGE_MASK; | |
1436 | } | |
1437 | } | |
1438 | ||
1439 | *maskp = mask; | |
1440 | ||
1441 | return (0); | |
1442 | ||
1443 | fail1: | |
1444 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
1445 | ||
1446 | return (rc); | |
1447 | } | |
1448 | ||
1449 | ||
9f95a23c TL |
1450 | #define EFX_EXT_PORT_MAX 4 |
1451 | #define EFX_EXT_PORT_NA 0xFF | |
1452 | ||
11fdf7f2 | 1453 | /* |
9f95a23c TL |
1454 | * Table of mapping schemes from port number to external number. |
1455 | * | |
1456 | * Each port number ultimately corresponds to a connector: either as part of | |
1457 | * a cable assembly attached to a module inserted in an SFP+/QSFP+ cage on | |
1458 | * the board, or fixed to the board (e.g. 10GBASE-T magjack on SFN5121T | |
1459 | * "Salina"). In general: | |
1460 | * | |
1461 | * Port number (0-based) | |
1462 | * | | |
1463 | * port mapping (n:1) | |
1464 | * | | |
1465 | * v | |
1466 | * External port number (1-based) | |
1467 | * | | |
1468 | * fixed (1:1) or cable assembly (1:m) | |
1469 | * | | |
1470 | * v | |
1471 | * Connector | |
1472 | * | |
1473 | * The external numbering refers to the cages or magjacks on the board, | |
1474 | * as visibly annotated on the board or back panel. This table describes | |
1475 | * how to determine which external cage/magjack corresponds to the port | |
1476 | * numbers used by the driver. | |
11fdf7f2 | 1477 | * |
9f95a23c TL |
1478 | * The count of consecutive port numbers that map to each external number, |
1479 | * is determined by the chip family and the current port mode. | |
11fdf7f2 TL |
1480 | * |
1481 | * For the Huntington family, the current port mode cannot be discovered, | |
9f95a23c | 1482 | * but a single mapping is used by all modes for a given chip variant, |
11fdf7f2 TL |
1483 | * so the mapping used is instead the last match in the table to the full |
1484 | * set of port modes to which the NIC can be configured. Therefore the | |
9f95a23c | 1485 | * ordering of entries in the mapping table is significant. |
11fdf7f2 | 1486 | */ |
9f95a23c | 1487 | static struct ef10_external_port_map_s { |
11fdf7f2 TL |
1488 | efx_family_t family; |
1489 | uint32_t modes_mask; | |
9f95a23c | 1490 | uint8_t base_port[EFX_EXT_PORT_MAX]; |
11fdf7f2 | 1491 | } __ef10_external_port_mappings[] = { |
9f95a23c TL |
1492 | /* |
1493 | * Modes used by Huntington family controllers where each port | |
1494 | * number maps to a separate cage. | |
1495 | * SFN7x22F (Torino): | |
1496 | * port 0 -> cage 1 | |
1497 | * port 1 -> cage 2 | |
1498 | * SFN7xx4F (Pavia): | |
1499 | * port 0 -> cage 1 | |
1500 | * port 1 -> cage 2 | |
1501 | * port 2 -> cage 3 | |
1502 | * port 3 -> cage 4 | |
1503 | */ | |
11fdf7f2 TL |
1504 | { |
1505 | EFX_FAMILY_HUNTINGTON, | |
9f95a23c TL |
1506 | (1U << TLV_PORT_MODE_10G) | /* mode 0 */ |
1507 | (1U << TLV_PORT_MODE_10G_10G) | /* mode 2 */ | |
1508 | (1U << TLV_PORT_MODE_10G_10G_10G_10G), /* mode 4 */ | |
1509 | { 0, 1, 2, 3 } | |
11fdf7f2 | 1510 | }, |
9f95a23c TL |
1511 | /* |
1512 | * Modes which for Huntington identify a chip variant where 2 | |
1513 | * adjacent port numbers map to each cage. | |
1514 | * SFN7x42Q (Monza): | |
1515 | * port 0 -> cage 1 | |
1516 | * port 1 -> cage 1 | |
1517 | * port 2 -> cage 2 | |
1518 | * port 3 -> cage 2 | |
1519 | */ | |
11fdf7f2 | 1520 | { |
9f95a23c TL |
1521 | EFX_FAMILY_HUNTINGTON, |
1522 | (1U << TLV_PORT_MODE_40G) | /* mode 1 */ | |
1523 | (1U << TLV_PORT_MODE_40G_40G) | /* mode 3 */ | |
1524 | (1U << TLV_PORT_MODE_40G_10G_10G) | /* mode 6 */ | |
1525 | (1U << TLV_PORT_MODE_10G_10G_40G), /* mode 7 */ | |
1526 | { 0, 2, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA } | |
11fdf7f2 | 1527 | }, |
9f95a23c TL |
1528 | /* |
1529 | * Modes that on Medford allocate each port number to a separate | |
1530 | * cage. | |
1531 | * port 0 -> cage 1 | |
1532 | * port 1 -> cage 2 | |
1533 | * port 2 -> cage 3 | |
1534 | * port 3 -> cage 4 | |
1535 | */ | |
11fdf7f2 | 1536 | { |
9f95a23c TL |
1537 | EFX_FAMILY_MEDFORD, |
1538 | (1U << TLV_PORT_MODE_1x1_NA) | /* mode 0 */ | |
1539 | (1U << TLV_PORT_MODE_1x4_NA) | /* mode 1 */ | |
1540 | (1U << TLV_PORT_MODE_1x1_1x1), /* mode 2 */ | |
1541 | { 0, 1, 2, 3 } | |
11fdf7f2 | 1542 | }, |
9f95a23c TL |
1543 | /* |
1544 | * Modes that on Medford allocate 2 adjacent port numbers to each | |
1545 | * cage. | |
1546 | * port 0 -> cage 1 | |
1547 | * port 1 -> cage 1 | |
1548 | * port 2 -> cage 2 | |
1549 | * port 3 -> cage 2 | |
1550 | */ | |
11fdf7f2 TL |
1551 | { |
1552 | EFX_FAMILY_MEDFORD, | |
9f95a23c TL |
1553 | (1U << TLV_PORT_MODE_1x4_1x4) | /* mode 3 */ |
1554 | (1U << TLV_PORT_MODE_2x1_2x1) | /* mode 5 */ | |
1555 | (1U << TLV_PORT_MODE_1x4_2x1) | /* mode 6 */ | |
1556 | (1U << TLV_PORT_MODE_2x1_1x4) | /* mode 7 */ | |
1557 | /* Do not use 10G_10G_10G_10G_Q1_Q2 (see bug63270) */ | |
1558 | (1U << TLV_PORT_MODE_10G_10G_10G_10G_Q1_Q2), /* mode 9 */ | |
1559 | { 0, 2, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA } | |
11fdf7f2 | 1560 | }, |
9f95a23c TL |
1561 | /* |
1562 | * Modes that on Medford allocate 4 adjacent port numbers to | |
1563 | * cage 1. | |
1564 | * port 0 -> cage 1 | |
1565 | * port 1 -> cage 1 | |
1566 | * port 2 -> cage 1 | |
1567 | * port 3 -> cage 1 | |
1568 | */ | |
11fdf7f2 TL |
1569 | { |
1570 | EFX_FAMILY_MEDFORD, | |
9f95a23c TL |
1571 | /* Do not use 10G_10G_10G_10G_Q1 (see bug63270) */ |
1572 | (1U << TLV_PORT_MODE_4x1_NA), /* mode 4 */ | |
1573 | { 0, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA } | |
11fdf7f2 | 1574 | }, |
9f95a23c TL |
1575 | /* |
1576 | * Modes that on Medford allocate 4 adjacent port numbers to | |
1577 | * cage 2. | |
1578 | * port 0 -> cage 2 | |
1579 | * port 1 -> cage 2 | |
1580 | * port 2 -> cage 2 | |
1581 | * port 3 -> cage 2 | |
1582 | */ | |
11fdf7f2 TL |
1583 | { |
1584 | EFX_FAMILY_MEDFORD, | |
9f95a23c TL |
1585 | (1U << TLV_PORT_MODE_NA_4x1), /* mode 8 */ |
1586 | { EFX_EXT_PORT_NA, 0, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA } | |
1587 | }, | |
1588 | /* | |
1589 | * Modes that on Medford2 allocate each port number to a separate | |
1590 | * cage. | |
1591 | * port 0 -> cage 1 | |
1592 | * port 1 -> cage 2 | |
1593 | * port 2 -> cage 3 | |
1594 | * port 3 -> cage 4 | |
1595 | */ | |
1596 | { | |
1597 | EFX_FAMILY_MEDFORD2, | |
1598 | (1U << TLV_PORT_MODE_1x1_NA) | /* mode 0 */ | |
1599 | (1U << TLV_PORT_MODE_1x4_NA) | /* mode 1 */ | |
1600 | (1U << TLV_PORT_MODE_1x1_1x1) | /* mode 2 */ | |
1601 | (1U << TLV_PORT_MODE_1x4_1x4) | /* mode 3 */ | |
1602 | (1U << TLV_PORT_MODE_1x2_NA) | /* mode 10 */ | |
1603 | (1U << TLV_PORT_MODE_1x2_1x2) | /* mode 12 */ | |
1604 | (1U << TLV_PORT_MODE_1x4_1x2) | /* mode 15 */ | |
1605 | (1U << TLV_PORT_MODE_1x2_1x4), /* mode 16 */ | |
1606 | { 0, 1, 2, 3 } | |
1607 | }, | |
1608 | /* | |
1609 | * Modes that on Medford2 allocate 1 port to cage 1 and the rest | |
1610 | * to cage 2. | |
1611 | * port 0 -> cage 1 | |
1612 | * port 1 -> cage 2 | |
1613 | * port 2 -> cage 2 | |
1614 | */ | |
1615 | { | |
1616 | EFX_FAMILY_MEDFORD2, | |
1617 | (1U << TLV_PORT_MODE_1x2_2x1) | /* mode 17 */ | |
1618 | (1U << TLV_PORT_MODE_1x4_2x1), /* mode 6 */ | |
1619 | { 0, 1, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA } | |
1620 | }, | |
1621 | /* | |
1622 | * Modes that on Medford2 allocate 2 adjacent port numbers to cage 1 | |
1623 | * and the rest to cage 2. | |
1624 | * port 0 -> cage 1 | |
1625 | * port 1 -> cage 1 | |
1626 | * port 2 -> cage 2 | |
1627 | * port 3 -> cage 2 | |
1628 | */ | |
1629 | { | |
1630 | EFX_FAMILY_MEDFORD2, | |
1631 | (1U << TLV_PORT_MODE_2x1_2x1) | /* mode 4 */ | |
1632 | (1U << TLV_PORT_MODE_2x1_1x4) | /* mode 7 */ | |
1633 | (1U << TLV_PORT_MODE_2x2_NA) | /* mode 13 */ | |
1634 | (1U << TLV_PORT_MODE_2x1_1x2), /* mode 18 */ | |
1635 | { 0, 2, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA } | |
1636 | }, | |
1637 | /* | |
1638 | * Modes that on Medford2 allocate up to 4 adjacent port numbers | |
1639 | * to cage 1. | |
1640 | * port 0 -> cage 1 | |
1641 | * port 1 -> cage 1 | |
1642 | * port 2 -> cage 1 | |
1643 | * port 3 -> cage 1 | |
1644 | */ | |
1645 | { | |
1646 | EFX_FAMILY_MEDFORD2, | |
1647 | (1U << TLV_PORT_MODE_4x1_NA), /* mode 5 */ | |
1648 | { 0, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA } | |
1649 | }, | |
1650 | /* | |
1651 | * Modes that on Medford2 allocate up to 4 adjacent port numbers | |
1652 | * to cage 2. | |
1653 | * port 0 -> cage 2 | |
1654 | * port 1 -> cage 2 | |
1655 | * port 2 -> cage 2 | |
1656 | * port 3 -> cage 2 | |
1657 | */ | |
1658 | { | |
1659 | EFX_FAMILY_MEDFORD2, | |
1660 | (1U << TLV_PORT_MODE_NA_4x1) | /* mode 8 */ | |
1661 | (1U << TLV_PORT_MODE_NA_1x2) | /* mode 11 */ | |
1662 | (1U << TLV_PORT_MODE_NA_2x2), /* mode 14 */ | |
1663 | { EFX_EXT_PORT_NA, 0, EFX_EXT_PORT_NA, EFX_EXT_PORT_NA } | |
11fdf7f2 TL |
1664 | }, |
1665 | }; | |
1666 | ||
9f95a23c | 1667 | static __checkReturn efx_rc_t |
11fdf7f2 TL |
1668 | ef10_external_port_mapping( |
1669 | __in efx_nic_t *enp, | |
1670 | __in uint32_t port, | |
1671 | __out uint8_t *external_portp) | |
1672 | { | |
1673 | efx_rc_t rc; | |
1674 | int i; | |
1675 | uint32_t port_modes; | |
1676 | uint32_t matches; | |
1677 | uint32_t current; | |
9f95a23c TL |
1678 | struct ef10_external_port_map_s *mapp = NULL; |
1679 | int ext_index = port; /* Default 1-1 mapping */ | |
11fdf7f2 | 1680 | |
9f95a23c TL |
1681 | if ((rc = efx_mcdi_get_port_modes(enp, &port_modes, ¤t, |
1682 | NULL)) != 0) { | |
11fdf7f2 | 1683 | /* |
9f95a23c | 1684 | * No current port mode information (i.e. Huntington) |
11fdf7f2 TL |
1685 | * - infer mapping from available modes |
1686 | */ | |
1687 | if ((rc = efx_mcdi_get_port_modes(enp, | |
9f95a23c | 1688 | &port_modes, NULL, NULL)) != 0) { |
11fdf7f2 TL |
1689 | /* |
1690 | * No port mode information available | |
1691 | * - use default mapping | |
1692 | */ | |
1693 | goto out; | |
1694 | } | |
1695 | } else { | |
1696 | /* Only need to scan the current mode */ | |
1697 | port_modes = 1 << current; | |
1698 | } | |
1699 | ||
1700 | /* | |
9f95a23c | 1701 | * Infer the internal port -> external number mapping from |
11fdf7f2 TL |
1702 | * the possible port modes for this NIC. |
1703 | */ | |
1704 | for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) { | |
9f95a23c TL |
1705 | struct ef10_external_port_map_s *eepmp = |
1706 | &__ef10_external_port_mappings[i]; | |
1707 | if (eepmp->family != enp->en_family) | |
11fdf7f2 | 1708 | continue; |
9f95a23c | 1709 | matches = (eepmp->modes_mask & port_modes); |
11fdf7f2 | 1710 | if (matches != 0) { |
9f95a23c TL |
1711 | /* |
1712 | * Some modes match. For some Huntington boards | |
1713 | * there will be multiple matches. The mapping on the | |
1714 | * last match is used. | |
1715 | */ | |
1716 | mapp = eepmp; | |
11fdf7f2 TL |
1717 | port_modes &= ~matches; |
1718 | } | |
1719 | } | |
1720 | ||
1721 | if (port_modes != 0) { | |
1722 | /* Some advertised modes are not supported */ | |
1723 | rc = ENOTSUP; | |
1724 | goto fail1; | |
1725 | } | |
1726 | ||
1727 | out: | |
9f95a23c TL |
1728 | if (mapp != NULL) { |
1729 | /* | |
1730 | * External ports are assigned a sequence of consecutive | |
1731 | * port numbers, so find the one with the closest base_port. | |
1732 | */ | |
1733 | uint32_t delta = EFX_EXT_PORT_NA; | |
1734 | ||
1735 | for (i = 0; i < EFX_EXT_PORT_MAX; i++) { | |
1736 | uint32_t base = mapp->base_port[i]; | |
1737 | if ((base != EFX_EXT_PORT_NA) && (base <= port)) { | |
1738 | if ((port - base) < delta) { | |
1739 | delta = (port - base); | |
1740 | ext_index = i; | |
1741 | } | |
1742 | } | |
1743 | } | |
1744 | } | |
1745 | *external_portp = (uint8_t)(ext_index + 1); | |
1746 | ||
1747 | return (0); | |
1748 | ||
1749 | fail1: | |
1750 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
1751 | ||
1752 | return (rc); | |
1753 | } | |
1754 | ||
1755 | static __checkReturn efx_rc_t | |
1756 | ef10_nic_board_cfg( | |
1757 | __in efx_nic_t *enp) | |
1758 | { | |
1759 | const efx_nic_ops_t *enop = enp->en_enop; | |
1760 | efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); | |
1761 | efx_nic_cfg_t *encp = &(enp->en_nic_cfg); | |
1762 | ef10_link_state_t els; | |
1763 | efx_port_t *epp = &(enp->en_port); | |
1764 | uint32_t board_type = 0; | |
1765 | uint32_t base, nvec; | |
1766 | uint32_t port; | |
1767 | uint32_t mask; | |
1768 | uint32_t pf; | |
1769 | uint32_t vf; | |
1770 | uint8_t mac_addr[6] = { 0 }; | |
1771 | efx_rc_t rc; | |
1772 | ||
1773 | /* Get the (zero-based) MCDI port number */ | |
1774 | if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0) | |
1775 | goto fail1; | |
1776 | ||
1777 | /* EFX MCDI interface uses one-based port numbers */ | |
1778 | emip->emi_port = port + 1; | |
1779 | ||
1780 | if ((rc = ef10_external_port_mapping(enp, port, | |
1781 | &encp->enc_external_port)) != 0) | |
1782 | goto fail2; | |
1783 | ||
11fdf7f2 | 1784 | /* |
9f95a23c TL |
1785 | * Get PCIe function number from firmware (used for |
1786 | * per-function privilege and dynamic config info). | |
1787 | * - PCIe PF: pf = PF number, vf = 0xffff. | |
1788 | * - PCIe VF: pf = parent PF, vf = VF number. | |
11fdf7f2 | 1789 | */ |
9f95a23c TL |
1790 | if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0) |
1791 | goto fail3; | |
1792 | ||
1793 | encp->enc_pf = pf; | |
1794 | encp->enc_vf = vf; | |
1795 | ||
1796 | /* MAC address for this function */ | |
1797 | if (EFX_PCI_FUNCTION_IS_PF(encp)) { | |
1798 | rc = efx_mcdi_get_mac_address_pf(enp, mac_addr); | |
1799 | #if EFSYS_OPT_ALLOW_UNCONFIGURED_NIC | |
1800 | /* | |
1801 | * Disable static config checking, ONLY for manufacturing test | |
1802 | * and setup at the factory, to allow the static config to be | |
1803 | * installed. | |
1804 | */ | |
1805 | #else /* EFSYS_OPT_ALLOW_UNCONFIGURED_NIC */ | |
1806 | if ((rc == 0) && (mac_addr[0] & 0x02)) { | |
1807 | /* | |
1808 | * If the static config does not include a global MAC | |
1809 | * address pool then the board may return a locally | |
1810 | * administered MAC address (this should only happen on | |
1811 | * incorrectly programmed boards). | |
1812 | */ | |
1813 | rc = EINVAL; | |
1814 | } | |
1815 | #endif /* EFSYS_OPT_ALLOW_UNCONFIGURED_NIC */ | |
1816 | } else { | |
1817 | rc = efx_mcdi_get_mac_address_vf(enp, mac_addr); | |
1818 | } | |
1819 | if (rc != 0) | |
1820 | goto fail4; | |
1821 | ||
1822 | EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr); | |
1823 | ||
1824 | /* Board configuration (legacy) */ | |
1825 | rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL); | |
1826 | if (rc != 0) { | |
1827 | /* Unprivileged functions may not be able to read board cfg */ | |
1828 | if (rc == EACCES) | |
1829 | board_type = 0; | |
1830 | else | |
1831 | goto fail5; | |
1832 | } | |
1833 | ||
1834 | encp->enc_board_type = board_type; | |
1835 | encp->enc_clk_mult = 1; /* not used for EF10 */ | |
1836 | ||
1837 | /* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */ | |
1838 | if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0) | |
1839 | goto fail6; | |
1840 | ||
1841 | /* | |
1842 | * Firmware with support for *_FEC capability bits does not | |
1843 | * report that the corresponding *_FEC_REQUESTED bits are supported. | |
1844 | * Add them here so that drivers understand that they are supported. | |
1845 | */ | |
1846 | if (epp->ep_phy_cap_mask & (1u << EFX_PHY_CAP_BASER_FEC)) | |
1847 | epp->ep_phy_cap_mask |= | |
1848 | (1u << EFX_PHY_CAP_BASER_FEC_REQUESTED); | |
1849 | if (epp->ep_phy_cap_mask & (1u << EFX_PHY_CAP_RS_FEC)) | |
1850 | epp->ep_phy_cap_mask |= | |
1851 | (1u << EFX_PHY_CAP_RS_FEC_REQUESTED); | |
1852 | if (epp->ep_phy_cap_mask & (1u << EFX_PHY_CAP_25G_BASER_FEC)) | |
1853 | epp->ep_phy_cap_mask |= | |
1854 | (1u << EFX_PHY_CAP_25G_BASER_FEC_REQUESTED); | |
1855 | ||
1856 | /* Obtain the default PHY advertised capabilities */ | |
1857 | if ((rc = ef10_phy_get_link(enp, &els)) != 0) | |
1858 | goto fail7; | |
1859 | epp->ep_default_adv_cap_mask = els.epls.epls_adv_cap_mask; | |
1860 | epp->ep_adv_cap_mask = els.epls.epls_adv_cap_mask; | |
1861 | ||
1862 | /* Check capabilities of running datapath firmware */ | |
1863 | if ((rc = ef10_get_datapath_caps(enp)) != 0) | |
1864 | goto fail8; | |
1865 | ||
1866 | /* Alignment for WPTR updates */ | |
1867 | encp->enc_rx_push_align = EF10_RX_WPTR_ALIGN; | |
1868 | ||
1869 | encp->enc_tx_dma_desc_size_max = EFX_MASK32(ESF_DZ_RX_KER_BYTE_CNT); | |
1870 | /* No boundary crossing limits */ | |
1871 | encp->enc_tx_dma_desc_boundary = 0; | |
1872 | ||
1873 | /* | |
1874 | * Maximum number of bytes into the frame the TCP header can start for | |
1875 | * firmware assisted TSO to work. | |
1876 | */ | |
1877 | encp->enc_tx_tso_tcp_header_offset_limit = EF10_TCP_HEADER_OFFSET_LIMIT; | |
1878 | ||
1879 | /* | |
1880 | * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use | |
1881 | * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available | |
1882 | * resources (allocated to this PCIe function), which is zero until | |
1883 | * after we have allocated VIs. | |
1884 | */ | |
1885 | encp->enc_evq_limit = 1024; | |
1886 | encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET; | |
1887 | encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET; | |
1888 | ||
1889 | encp->enc_buftbl_limit = 0xFFFFFFFF; | |
1890 | ||
1891 | /* Get interrupt vector limits */ | |
1892 | if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) { | |
1893 | if (EFX_PCI_FUNCTION_IS_PF(encp)) | |
1894 | goto fail9; | |
1895 | ||
1896 | /* Ignore error (cannot query vector limits from a VF). */ | |
1897 | base = 0; | |
1898 | nvec = 1024; | |
1899 | } | |
1900 | encp->enc_intr_vec_base = base; | |
1901 | encp->enc_intr_limit = nvec; | |
1902 | ||
1903 | /* | |
1904 | * Get the current privilege mask. Note that this may be modified | |
1905 | * dynamically, so this value is informational only. DO NOT use | |
1906 | * the privilege mask to check for sufficient privileges, as that | |
1907 | * can result in time-of-check/time-of-use bugs. | |
1908 | */ | |
1909 | if ((rc = ef10_get_privilege_mask(enp, &mask)) != 0) | |
1910 | goto fail10; | |
1911 | encp->enc_privilege_mask = mask; | |
1912 | ||
1913 | /* Get remaining controller-specific board config */ | |
1914 | if ((rc = enop->eno_board_cfg(enp)) != 0) | |
1915 | if (rc != EACCES) | |
1916 | goto fail11; | |
1917 | ||
11fdf7f2 TL |
1918 | return (0); |
1919 | ||
9f95a23c TL |
1920 | fail11: |
1921 | EFSYS_PROBE(fail11); | |
1922 | fail10: | |
1923 | EFSYS_PROBE(fail10); | |
1924 | fail9: | |
1925 | EFSYS_PROBE(fail9); | |
1926 | fail8: | |
1927 | EFSYS_PROBE(fail8); | |
1928 | fail7: | |
1929 | EFSYS_PROBE(fail7); | |
1930 | fail6: | |
1931 | EFSYS_PROBE(fail6); | |
1932 | fail5: | |
1933 | EFSYS_PROBE(fail5); | |
1934 | fail4: | |
1935 | EFSYS_PROBE(fail4); | |
1936 | fail3: | |
1937 | EFSYS_PROBE(fail3); | |
1938 | fail2: | |
1939 | EFSYS_PROBE(fail2); | |
11fdf7f2 TL |
1940 | fail1: |
1941 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
1942 | ||
1943 | return (rc); | |
1944 | } | |
1945 | ||
11fdf7f2 TL |
1946 | __checkReturn efx_rc_t |
1947 | ef10_nic_probe( | |
1948 | __in efx_nic_t *enp) | |
1949 | { | |
11fdf7f2 TL |
1950 | efx_nic_cfg_t *encp = &(enp->en_nic_cfg); |
1951 | efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); | |
1952 | efx_rc_t rc; | |
1953 | ||
9f95a23c | 1954 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 TL |
1955 | |
1956 | /* Read and clear any assertion state */ | |
1957 | if ((rc = efx_mcdi_read_assertion(enp)) != 0) | |
1958 | goto fail1; | |
1959 | ||
1960 | /* Exit the assertion handler */ | |
1961 | if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) | |
1962 | if (rc != EACCES) | |
1963 | goto fail2; | |
1964 | ||
1965 | if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0) | |
1966 | goto fail3; | |
1967 | ||
9f95a23c TL |
1968 | if ((rc = ef10_nic_board_cfg(enp)) != 0) |
1969 | goto fail4; | |
11fdf7f2 TL |
1970 | |
1971 | /* | |
1972 | * Set default driver config limits (based on board config). | |
1973 | * | |
1974 | * FIXME: For now allocate a fixed number of VIs which is likely to be | |
1975 | * sufficient and small enough to allow multiple functions on the same | |
1976 | * port. | |
1977 | */ | |
1978 | edcp->edc_min_vi_count = edcp->edc_max_vi_count = | |
1979 | MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit)); | |
1980 | ||
1981 | /* The client driver must configure and enable PIO buffer support */ | |
1982 | edcp->edc_max_piobuf_count = 0; | |
1983 | edcp->edc_pio_alloc_size = 0; | |
1984 | ||
1985 | #if EFSYS_OPT_MAC_STATS | |
1986 | /* Wipe the MAC statistics */ | |
1987 | if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0) | |
1988 | goto fail5; | |
1989 | #endif | |
1990 | ||
1991 | #if EFSYS_OPT_LOOPBACK | |
1992 | if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0) | |
1993 | goto fail6; | |
1994 | #endif | |
1995 | ||
1996 | #if EFSYS_OPT_MON_STATS | |
1997 | if ((rc = mcdi_mon_cfg_build(enp)) != 0) { | |
1998 | /* Unprivileged functions do not have access to sensors */ | |
1999 | if (rc != EACCES) | |
2000 | goto fail7; | |
2001 | } | |
2002 | #endif | |
2003 | ||
2004 | encp->enc_features = enp->en_features; | |
2005 | ||
2006 | return (0); | |
2007 | ||
2008 | #if EFSYS_OPT_MON_STATS | |
2009 | fail7: | |
2010 | EFSYS_PROBE(fail7); | |
2011 | #endif | |
2012 | #if EFSYS_OPT_LOOPBACK | |
2013 | fail6: | |
2014 | EFSYS_PROBE(fail6); | |
2015 | #endif | |
2016 | #if EFSYS_OPT_MAC_STATS | |
2017 | fail5: | |
2018 | EFSYS_PROBE(fail5); | |
2019 | #endif | |
2020 | fail4: | |
2021 | EFSYS_PROBE(fail4); | |
2022 | fail3: | |
2023 | EFSYS_PROBE(fail3); | |
2024 | fail2: | |
2025 | EFSYS_PROBE(fail2); | |
2026 | fail1: | |
2027 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
2028 | ||
2029 | return (rc); | |
2030 | } | |
2031 | ||
2032 | __checkReturn efx_rc_t | |
2033 | ef10_nic_set_drv_limits( | |
2034 | __inout efx_nic_t *enp, | |
2035 | __in efx_drv_limits_t *edlp) | |
2036 | { | |
2037 | efx_nic_cfg_t *encp = &(enp->en_nic_cfg); | |
2038 | efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); | |
2039 | uint32_t min_evq_count, max_evq_count; | |
2040 | uint32_t min_rxq_count, max_rxq_count; | |
2041 | uint32_t min_txq_count, max_txq_count; | |
2042 | efx_rc_t rc; | |
2043 | ||
2044 | if (edlp == NULL) { | |
2045 | rc = EINVAL; | |
2046 | goto fail1; | |
2047 | } | |
2048 | ||
2049 | /* Get minimum required and maximum usable VI limits */ | |
2050 | min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit); | |
2051 | min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit); | |
2052 | min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit); | |
2053 | ||
2054 | edcp->edc_min_vi_count = | |
2055 | MAX(min_evq_count, MAX(min_rxq_count, min_txq_count)); | |
2056 | ||
2057 | max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit); | |
2058 | max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit); | |
2059 | max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit); | |
2060 | ||
2061 | edcp->edc_max_vi_count = | |
2062 | MAX(max_evq_count, MAX(max_rxq_count, max_txq_count)); | |
2063 | ||
2064 | /* | |
2065 | * Check limits for sub-allocated piobuf blocks. | |
2066 | * PIO is optional, so don't fail if the limits are incorrect. | |
2067 | */ | |
2068 | if ((encp->enc_piobuf_size == 0) || | |
2069 | (encp->enc_piobuf_limit == 0) || | |
2070 | (edlp->edl_min_pio_alloc_size == 0) || | |
2071 | (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) { | |
2072 | /* Disable PIO */ | |
2073 | edcp->edc_max_piobuf_count = 0; | |
2074 | edcp->edc_pio_alloc_size = 0; | |
2075 | } else { | |
2076 | uint32_t blk_size, blk_count, blks_per_piobuf; | |
2077 | ||
2078 | blk_size = | |
2079 | MAX(edlp->edl_min_pio_alloc_size, | |
2080 | encp->enc_piobuf_min_alloc_size); | |
2081 | ||
2082 | blks_per_piobuf = encp->enc_piobuf_size / blk_size; | |
2083 | EFSYS_ASSERT3U(blks_per_piobuf, <=, 32); | |
2084 | ||
2085 | blk_count = (encp->enc_piobuf_limit * blks_per_piobuf); | |
2086 | ||
2087 | /* A zero max pio alloc count means unlimited */ | |
2088 | if ((edlp->edl_max_pio_alloc_count > 0) && | |
2089 | (edlp->edl_max_pio_alloc_count < blk_count)) { | |
2090 | blk_count = edlp->edl_max_pio_alloc_count; | |
2091 | } | |
2092 | ||
2093 | edcp->edc_pio_alloc_size = blk_size; | |
2094 | edcp->edc_max_piobuf_count = | |
2095 | (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf; | |
2096 | } | |
2097 | ||
2098 | return (0); | |
2099 | ||
2100 | fail1: | |
2101 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
2102 | ||
2103 | return (rc); | |
2104 | } | |
2105 | ||
2106 | ||
2107 | __checkReturn efx_rc_t | |
2108 | ef10_nic_reset( | |
2109 | __in efx_nic_t *enp) | |
2110 | { | |
2111 | efx_mcdi_req_t req; | |
9f95a23c TL |
2112 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_ENTITY_RESET_IN_LEN, |
2113 | MC_CMD_ENTITY_RESET_OUT_LEN); | |
11fdf7f2 TL |
2114 | efx_rc_t rc; |
2115 | ||
2116 | /* ef10_nic_reset() is called to recover from BADASSERT failures. */ | |
2117 | if ((rc = efx_mcdi_read_assertion(enp)) != 0) | |
2118 | goto fail1; | |
2119 | if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) | |
2120 | goto fail2; | |
2121 | ||
11fdf7f2 TL |
2122 | req.emr_cmd = MC_CMD_ENTITY_RESET; |
2123 | req.emr_in_buf = payload; | |
2124 | req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN; | |
2125 | req.emr_out_buf = payload; | |
2126 | req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN; | |
2127 | ||
2128 | MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG, | |
2129 | ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1); | |
2130 | ||
2131 | efx_mcdi_execute(enp, &req); | |
2132 | ||
2133 | if (req.emr_rc != 0) { | |
2134 | rc = req.emr_rc; | |
2135 | goto fail3; | |
2136 | } | |
2137 | ||
2138 | /* Clear RX/TX DMA queue errors */ | |
2139 | enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR); | |
2140 | ||
2141 | return (0); | |
2142 | ||
2143 | fail3: | |
2144 | EFSYS_PROBE(fail3); | |
2145 | fail2: | |
2146 | EFSYS_PROBE(fail2); | |
2147 | fail1: | |
2148 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
2149 | ||
2150 | return (rc); | |
2151 | } | |
2152 | ||
2153 | __checkReturn efx_rc_t | |
2154 | ef10_nic_init( | |
2155 | __in efx_nic_t *enp) | |
2156 | { | |
2157 | efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); | |
2158 | uint32_t min_vi_count, max_vi_count; | |
2159 | uint32_t vi_count, vi_base, vi_shift; | |
2160 | uint32_t i; | |
2161 | uint32_t retry; | |
2162 | uint32_t delay_us; | |
9f95a23c | 2163 | uint32_t vi_window_size; |
11fdf7f2 TL |
2164 | efx_rc_t rc; |
2165 | ||
9f95a23c | 2166 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 TL |
2167 | |
2168 | /* Enable reporting of some events (e.g. link change) */ | |
2169 | if ((rc = efx_mcdi_log_ctrl(enp)) != 0) | |
2170 | goto fail1; | |
2171 | ||
2172 | /* Allocate (optional) on-chip PIO buffers */ | |
2173 | ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count); | |
2174 | ||
2175 | /* | |
2176 | * For best performance, PIO writes should use a write-combined | |
2177 | * (WC) memory mapping. Using a separate WC mapping for the PIO | |
2178 | * aperture of each VI would be a burden to drivers (and not | |
2179 | * possible if the host page size is >4Kbyte). | |
2180 | * | |
2181 | * To avoid this we use a single uncached (UC) mapping for VI | |
2182 | * register access, and a single WC mapping for extra VIs used | |
2183 | * for PIO writes. | |
2184 | * | |
2185 | * Each piobuf must be linked to a VI in the WC mapping, and to | |
2186 | * each VI that is using a sub-allocated block from the piobuf. | |
2187 | */ | |
2188 | min_vi_count = edcp->edc_min_vi_count; | |
2189 | max_vi_count = | |
2190 | edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count; | |
2191 | ||
2192 | /* Ensure that the previously attached driver's VIs are freed */ | |
2193 | if ((rc = efx_mcdi_free_vis(enp)) != 0) | |
2194 | goto fail2; | |
2195 | ||
2196 | /* | |
2197 | * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this | |
2198 | * fails then retrying the request for fewer VI resources may succeed. | |
2199 | */ | |
2200 | vi_count = 0; | |
2201 | if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count, | |
2202 | &vi_base, &vi_count, &vi_shift)) != 0) | |
2203 | goto fail3; | |
2204 | ||
2205 | EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count); | |
2206 | ||
2207 | if (vi_count < min_vi_count) { | |
2208 | rc = ENOMEM; | |
2209 | goto fail4; | |
2210 | } | |
2211 | ||
2212 | enp->en_arch.ef10.ena_vi_base = vi_base; | |
2213 | enp->en_arch.ef10.ena_vi_count = vi_count; | |
2214 | enp->en_arch.ef10.ena_vi_shift = vi_shift; | |
2215 | ||
2216 | if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) { | |
2217 | /* Not enough extra VIs to map piobufs */ | |
2218 | ef10_nic_free_piobufs(enp); | |
2219 | } | |
2220 | ||
2221 | enp->en_arch.ef10.ena_pio_write_vi_base = | |
2222 | vi_count - enp->en_arch.ef10.ena_piobuf_count; | |
2223 | ||
9f95a23c TL |
2224 | EFSYS_ASSERT3U(enp->en_nic_cfg.enc_vi_window_shift, !=, |
2225 | EFX_VI_WINDOW_SHIFT_INVALID); | |
2226 | EFSYS_ASSERT3U(enp->en_nic_cfg.enc_vi_window_shift, <=, | |
2227 | EFX_VI_WINDOW_SHIFT_64K); | |
2228 | vi_window_size = 1U << enp->en_nic_cfg.enc_vi_window_shift; | |
2229 | ||
11fdf7f2 TL |
2230 | /* Save UC memory mapping details */ |
2231 | enp->en_arch.ef10.ena_uc_mem_map_offset = 0; | |
2232 | if (enp->en_arch.ef10.ena_piobuf_count > 0) { | |
2233 | enp->en_arch.ef10.ena_uc_mem_map_size = | |
9f95a23c | 2234 | (vi_window_size * |
11fdf7f2 TL |
2235 | enp->en_arch.ef10.ena_pio_write_vi_base); |
2236 | } else { | |
2237 | enp->en_arch.ef10.ena_uc_mem_map_size = | |
9f95a23c | 2238 | (vi_window_size * |
11fdf7f2 TL |
2239 | enp->en_arch.ef10.ena_vi_count); |
2240 | } | |
2241 | ||
2242 | /* Save WC memory mapping details */ | |
2243 | enp->en_arch.ef10.ena_wc_mem_map_offset = | |
2244 | enp->en_arch.ef10.ena_uc_mem_map_offset + | |
2245 | enp->en_arch.ef10.ena_uc_mem_map_size; | |
2246 | ||
2247 | enp->en_arch.ef10.ena_wc_mem_map_size = | |
9f95a23c | 2248 | (vi_window_size * |
11fdf7f2 TL |
2249 | enp->en_arch.ef10.ena_piobuf_count); |
2250 | ||
2251 | /* Link piobufs to extra VIs in WC mapping */ | |
2252 | if (enp->en_arch.ef10.ena_piobuf_count > 0) { | |
2253 | for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { | |
2254 | rc = efx_mcdi_link_piobuf(enp, | |
2255 | enp->en_arch.ef10.ena_pio_write_vi_base + i, | |
2256 | enp->en_arch.ef10.ena_piobuf_handle[i]); | |
2257 | if (rc != 0) | |
2258 | break; | |
2259 | } | |
2260 | } | |
2261 | ||
2262 | /* | |
2263 | * Allocate a vAdaptor attached to our upstream vPort/pPort. | |
2264 | * | |
2265 | * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF | |
2266 | * driver has yet to bring up the EVB port. See bug 56147. In this case, | |
2267 | * retry the request several times after waiting a while. The wait time | |
2268 | * between retries starts small (10ms) and exponentially increases. | |
2269 | * Total wait time is a little over two seconds. Retry logic in the | |
2270 | * client driver may mean this whole loop is repeated if it continues to | |
2271 | * fail. | |
2272 | */ | |
2273 | retry = 0; | |
2274 | delay_us = 10000; | |
2275 | while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) { | |
2276 | if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) || | |
2277 | (rc != ENOENT)) { | |
2278 | /* | |
2279 | * Do not retry alloc for PF, or for other errors on | |
2280 | * a VF. | |
2281 | */ | |
2282 | goto fail5; | |
2283 | } | |
2284 | ||
2285 | /* VF startup before PF is ready. Retry allocation. */ | |
2286 | if (retry > 5) { | |
2287 | /* Too many attempts */ | |
2288 | rc = EINVAL; | |
2289 | goto fail6; | |
2290 | } | |
2291 | EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry); | |
2292 | EFSYS_SLEEP(delay_us); | |
2293 | retry++; | |
2294 | if (delay_us < 500000) | |
2295 | delay_us <<= 2; | |
2296 | } | |
2297 | ||
2298 | enp->en_vport_id = EVB_PORT_ID_ASSIGNED; | |
2299 | enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2; | |
2300 | ||
2301 | return (0); | |
2302 | ||
2303 | fail6: | |
2304 | EFSYS_PROBE(fail6); | |
2305 | fail5: | |
2306 | EFSYS_PROBE(fail5); | |
2307 | fail4: | |
2308 | EFSYS_PROBE(fail4); | |
2309 | fail3: | |
2310 | EFSYS_PROBE(fail3); | |
2311 | fail2: | |
2312 | EFSYS_PROBE(fail2); | |
2313 | ||
2314 | ef10_nic_free_piobufs(enp); | |
2315 | ||
2316 | fail1: | |
2317 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
2318 | ||
2319 | return (rc); | |
2320 | } | |
2321 | ||
2322 | __checkReturn efx_rc_t | |
2323 | ef10_nic_get_vi_pool( | |
2324 | __in efx_nic_t *enp, | |
2325 | __out uint32_t *vi_countp) | |
2326 | { | |
9f95a23c | 2327 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 TL |
2328 | |
2329 | /* | |
2330 | * Report VIs that the client driver can use. | |
2331 | * Do not include VIs used for PIO buffer writes. | |
2332 | */ | |
2333 | *vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base; | |
2334 | ||
2335 | return (0); | |
2336 | } | |
2337 | ||
2338 | __checkReturn efx_rc_t | |
2339 | ef10_nic_get_bar_region( | |
2340 | __in efx_nic_t *enp, | |
2341 | __in efx_nic_region_t region, | |
2342 | __out uint32_t *offsetp, | |
2343 | __out size_t *sizep) | |
2344 | { | |
2345 | efx_rc_t rc; | |
2346 | ||
9f95a23c | 2347 | EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp)); |
11fdf7f2 TL |
2348 | |
2349 | /* | |
2350 | * TODO: Specify host memory mapping alignment and granularity | |
2351 | * in efx_drv_limits_t so that they can be taken into account | |
2352 | * when allocating extra VIs for PIO writes. | |
2353 | */ | |
2354 | switch (region) { | |
2355 | case EFX_REGION_VI: | |
2356 | /* UC mapped memory BAR region for VI registers */ | |
2357 | *offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset; | |
2358 | *sizep = enp->en_arch.ef10.ena_uc_mem_map_size; | |
2359 | break; | |
2360 | ||
2361 | case EFX_REGION_PIO_WRITE_VI: | |
2362 | /* WC mapped memory BAR region for piobuf writes */ | |
2363 | *offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset; | |
2364 | *sizep = enp->en_arch.ef10.ena_wc_mem_map_size; | |
2365 | break; | |
2366 | ||
2367 | default: | |
2368 | rc = EINVAL; | |
2369 | goto fail1; | |
2370 | } | |
2371 | ||
2372 | return (0); | |
2373 | ||
2374 | fail1: | |
2375 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
2376 | ||
2377 | return (rc); | |
2378 | } | |
2379 | ||
9f95a23c TL |
2380 | __checkReturn boolean_t |
2381 | ef10_nic_hw_unavailable( | |
2382 | __in efx_nic_t *enp) | |
2383 | { | |
2384 | efx_dword_t dword; | |
2385 | ||
2386 | if (enp->en_reset_flags & EFX_RESET_HW_UNAVAIL) | |
2387 | return (B_TRUE); | |
2388 | ||
2389 | EFX_BAR_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, &dword, B_FALSE); | |
2390 | if (EFX_DWORD_FIELD(dword, EFX_DWORD_0) == 0xffffffff) | |
2391 | goto unavail; | |
2392 | ||
2393 | return (B_FALSE); | |
2394 | ||
2395 | unavail: | |
2396 | ef10_nic_set_hw_unavailable(enp); | |
2397 | ||
2398 | return (B_TRUE); | |
2399 | } | |
2400 | ||
2401 | void | |
2402 | ef10_nic_set_hw_unavailable( | |
2403 | __in efx_nic_t *enp) | |
2404 | { | |
2405 | EFSYS_PROBE(hw_unavail); | |
2406 | enp->en_reset_flags |= EFX_RESET_HW_UNAVAIL; | |
2407 | } | |
2408 | ||
2409 | ||
11fdf7f2 TL |
2410 | void |
2411 | ef10_nic_fini( | |
2412 | __in efx_nic_t *enp) | |
2413 | { | |
2414 | uint32_t i; | |
2415 | efx_rc_t rc; | |
2416 | ||
2417 | (void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id); | |
2418 | enp->en_vport_id = 0; | |
2419 | ||
2420 | /* Unlink piobufs from extra VIs in WC mapping */ | |
2421 | if (enp->en_arch.ef10.ena_piobuf_count > 0) { | |
2422 | for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { | |
2423 | rc = efx_mcdi_unlink_piobuf(enp, | |
2424 | enp->en_arch.ef10.ena_pio_write_vi_base + i); | |
2425 | if (rc != 0) | |
2426 | break; | |
2427 | } | |
2428 | } | |
2429 | ||
2430 | ef10_nic_free_piobufs(enp); | |
2431 | ||
2432 | (void) efx_mcdi_free_vis(enp); | |
2433 | enp->en_arch.ef10.ena_vi_count = 0; | |
2434 | } | |
2435 | ||
2436 | void | |
2437 | ef10_nic_unprobe( | |
2438 | __in efx_nic_t *enp) | |
2439 | { | |
2440 | #if EFSYS_OPT_MON_STATS | |
2441 | mcdi_mon_cfg_free(enp); | |
2442 | #endif /* EFSYS_OPT_MON_STATS */ | |
2443 | (void) efx_mcdi_drv_attach(enp, B_FALSE); | |
2444 | } | |
2445 | ||
2446 | #if EFSYS_OPT_DIAG | |
2447 | ||
2448 | __checkReturn efx_rc_t | |
2449 | ef10_nic_register_test( | |
2450 | __in efx_nic_t *enp) | |
2451 | { | |
2452 | efx_rc_t rc; | |
2453 | ||
2454 | /* FIXME */ | |
2455 | _NOTE(ARGUNUSED(enp)) | |
2456 | _NOTE(CONSTANTCONDITION) | |
2457 | if (B_FALSE) { | |
2458 | rc = ENOTSUP; | |
2459 | goto fail1; | |
2460 | } | |
2461 | /* FIXME */ | |
2462 | ||
2463 | return (0); | |
2464 | ||
2465 | fail1: | |
2466 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
2467 | ||
2468 | return (rc); | |
2469 | } | |
2470 | ||
2471 | #endif /* EFSYS_OPT_DIAG */ | |
2472 | ||
9f95a23c TL |
2473 | #if EFSYS_OPT_FW_SUBVARIANT_AWARE |
2474 | ||
2475 | __checkReturn efx_rc_t | |
2476 | efx_mcdi_get_nic_global( | |
2477 | __in efx_nic_t *enp, | |
2478 | __in uint32_t key, | |
2479 | __out uint32_t *valuep) | |
2480 | { | |
2481 | efx_mcdi_req_t req; | |
2482 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_NIC_GLOBAL_IN_LEN, | |
2483 | MC_CMD_GET_NIC_GLOBAL_OUT_LEN); | |
2484 | efx_rc_t rc; | |
2485 | ||
2486 | req.emr_cmd = MC_CMD_GET_NIC_GLOBAL; | |
2487 | req.emr_in_buf = payload; | |
2488 | req.emr_in_length = MC_CMD_GET_NIC_GLOBAL_IN_LEN; | |
2489 | req.emr_out_buf = payload; | |
2490 | req.emr_out_length = MC_CMD_GET_NIC_GLOBAL_OUT_LEN; | |
2491 | ||
2492 | MCDI_IN_SET_DWORD(req, GET_NIC_GLOBAL_IN_KEY, key); | |
2493 | ||
2494 | efx_mcdi_execute(enp, &req); | |
2495 | ||
2496 | if (req.emr_rc != 0) { | |
2497 | rc = req.emr_rc; | |
2498 | goto fail1; | |
2499 | } | |
2500 | ||
2501 | if (req.emr_out_length_used != MC_CMD_GET_NIC_GLOBAL_OUT_LEN) { | |
2502 | rc = EMSGSIZE; | |
2503 | goto fail2; | |
2504 | } | |
2505 | ||
2506 | *valuep = MCDI_OUT_DWORD(req, GET_NIC_GLOBAL_OUT_VALUE); | |
2507 | ||
2508 | return (0); | |
2509 | ||
2510 | fail2: | |
2511 | EFSYS_PROBE(fail2); | |
2512 | fail1: | |
2513 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
2514 | ||
2515 | return (rc); | |
2516 | } | |
2517 | ||
2518 | __checkReturn efx_rc_t | |
2519 | efx_mcdi_set_nic_global( | |
2520 | __in efx_nic_t *enp, | |
2521 | __in uint32_t key, | |
2522 | __in uint32_t value) | |
2523 | { | |
2524 | efx_mcdi_req_t req; | |
2525 | EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_NIC_GLOBAL_IN_LEN, 0); | |
2526 | efx_rc_t rc; | |
2527 | ||
2528 | req.emr_cmd = MC_CMD_SET_NIC_GLOBAL; | |
2529 | req.emr_in_buf = payload; | |
2530 | req.emr_in_length = MC_CMD_SET_NIC_GLOBAL_IN_LEN; | |
2531 | req.emr_out_buf = NULL; | |
2532 | req.emr_out_length = 0; | |
2533 | ||
2534 | MCDI_IN_SET_DWORD(req, SET_NIC_GLOBAL_IN_KEY, key); | |
2535 | MCDI_IN_SET_DWORD(req, SET_NIC_GLOBAL_IN_VALUE, value); | |
2536 | ||
2537 | efx_mcdi_execute(enp, &req); | |
2538 | ||
2539 | if (req.emr_rc != 0) { | |
2540 | rc = req.emr_rc; | |
2541 | goto fail1; | |
2542 | } | |
2543 | ||
2544 | return (0); | |
2545 | ||
2546 | fail1: | |
2547 | EFSYS_PROBE1(fail1, efx_rc_t, rc); | |
2548 | ||
2549 | return (rc); | |
2550 | } | |
2551 | ||
2552 | #endif /* EFSYS_OPT_FW_SUBVARIANT_AWARE */ | |
11fdf7f2 | 2553 | |
9f95a23c | 2554 | #endif /* EFX_OPTS_EF10() */ |