1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /**************************************************************************** |
3 | * Driver for Solarflare network controllers and boards |
4 | * Copyright 2008-2013 Solarflare Communications Inc. |
5 | */ |
6 | |
7 | #include <linux/delay.h> |
8 | #include <linux/moduleparam.h> |
9 | #include <linux/atomic.h> |
10 | #include "net_driver.h" |
11 | #include "nic.h" |
12 | #include "io.h" |
13 | #include "mcdi_pcol.h" |
14 | |
15 | /************************************************************************** |
16 | * |
17 | * Management-Controller-to-Driver Interface |
18 | * |
19 | ************************************************************************** |
20 | */ |
21 | |
22 | #define MCDI_RPC_TIMEOUT (10 * HZ) |
23 | |
24 | /* A reboot/assertion causes the MCDI status word to be set after the |
25 | * command word is set or a REBOOT event is sent. If we notice a reboot |
26 | * via these mechanisms then wait 250ms for the status word to be set. |
27 | */ |
28 | #define MCDI_STATUS_DELAY_US 100 |
29 | #define MCDI_STATUS_DELAY_COUNT 2500 |
30 | #define MCDI_STATUS_SLEEP_MS \ |
31 | (MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000) |
32 | |
33 | #define SEQ_MASK \ |
34 | EFX_MASK32(EFX_WIDTH(MCDI_HEADER_SEQ)) |
35 | |
36 | struct efx_mcdi_async_param { |
37 | struct list_head list; |
38 | unsigned int cmd; |
39 | size_t inlen; |
40 | size_t outlen; |
41 | bool quiet; |
42 | efx_mcdi_async_completer *complete; |
43 | unsigned long cookie; |
44 | /* followed by request/response buffer */ |
45 | }; |
46 | |
47 | static void efx_mcdi_timeout_async(struct timer_list *t); |
48 | static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, |
49 | bool *was_attached_out); |
50 | static bool efx_mcdi_poll_once(struct efx_nic *efx); |
51 | static void efx_mcdi_abandon(struct efx_nic *efx); |
52 | |
53 | #ifdef CONFIG_SFC_MCDI_LOGGING |
54 | static bool mcdi_logging_default; |
55 | module_param(mcdi_logging_default, bool, 0644); |
56 | MODULE_PARM_DESC(mcdi_logging_default, |
57 | "Enable MCDI logging on newly-probed functions" ); |
58 | #endif |
59 | |
60 | int efx_mcdi_init(struct efx_nic *efx) |
61 | { |
62 | struct efx_mcdi_iface *mcdi; |
63 | bool already_attached; |
64 | int rc = -ENOMEM; |
65 | |
66 | efx->mcdi = kzalloc(size: sizeof(*efx->mcdi), GFP_KERNEL); |
67 | if (!efx->mcdi) |
68 | goto fail; |
69 | |
70 | mcdi = efx_mcdi(efx); |
71 | mcdi->efx = efx; |
72 | #ifdef CONFIG_SFC_MCDI_LOGGING |
73 | /* consuming code assumes buffer is page-sized */ |
74 | mcdi->logging_buffer = (char *)__get_free_page(GFP_KERNEL); |
75 | if (!mcdi->logging_buffer) |
76 | goto fail1; |
77 | mcdi->logging_enabled = mcdi_logging_default; |
78 | #endif |
79 | init_waitqueue_head(&mcdi->wq); |
80 | init_waitqueue_head(&mcdi->proxy_rx_wq); |
81 | spin_lock_init(&mcdi->iface_lock); |
82 | mcdi->state = MCDI_STATE_QUIESCENT; |
83 | mcdi->mode = MCDI_MODE_POLL; |
84 | spin_lock_init(&mcdi->async_lock); |
85 | INIT_LIST_HEAD(list: &mcdi->async_list); |
86 | timer_setup(&mcdi->async_timer, efx_mcdi_timeout_async, 0); |
87 | |
88 | (void) efx_mcdi_poll_reboot(efx); |
89 | mcdi->new_epoch = true; |
90 | |
91 | /* Recover from a failed assertion before probing */ |
92 | rc = efx_mcdi_handle_assertion(efx); |
93 | if (rc) |
94 | goto fail2; |
95 | |
96 | /* Let the MC (and BMC, if this is a LOM) know that the driver |
97 | * is loaded. We should do this before we reset the NIC. |
98 | */ |
99 | rc = efx_mcdi_drv_attach(efx, driver_operating: true, was_attached_out: &already_attached); |
100 | if (rc) { |
101 | pci_err(efx->pci_dev, "Unable to register driver with MCPU\n" ); |
102 | goto fail2; |
103 | } |
104 | if (already_attached) |
105 | /* Not a fatal error */ |
106 | pci_err(efx->pci_dev, "Host already registered with MCPU\n" ); |
107 | |
108 | if (efx->mcdi->fn_flags & |
109 | (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY)) |
110 | efx->primary = efx; |
111 | |
112 | return 0; |
113 | fail2: |
114 | #ifdef CONFIG_SFC_MCDI_LOGGING |
115 | free_page((unsigned long)mcdi->logging_buffer); |
116 | fail1: |
117 | #endif |
118 | kfree(objp: efx->mcdi); |
119 | efx->mcdi = NULL; |
120 | fail: |
121 | return rc; |
122 | } |
123 | |
124 | void efx_mcdi_detach(struct efx_nic *efx) |
125 | { |
126 | if (!efx->mcdi) |
127 | return; |
128 | |
129 | BUG_ON(efx->mcdi->iface.state != MCDI_STATE_QUIESCENT); |
130 | |
131 | /* Relinquish the device (back to the BMC, if this is a LOM) */ |
132 | efx_mcdi_drv_attach(efx, driver_operating: false, NULL); |
133 | } |
134 | |
135 | void efx_mcdi_fini(struct efx_nic *efx) |
136 | { |
137 | if (!efx->mcdi) |
138 | return; |
139 | |
140 | #ifdef CONFIG_SFC_MCDI_LOGGING |
141 | free_page((unsigned long)efx->mcdi->iface.logging_buffer); |
142 | #endif |
143 | |
144 | kfree(objp: efx->mcdi); |
145 | } |
146 | |
147 | static void efx_mcdi_send_request(struct efx_nic *efx, unsigned cmd, |
148 | const efx_dword_t *inbuf, size_t inlen) |
149 | { |
150 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
151 | #ifdef CONFIG_SFC_MCDI_LOGGING |
152 | char *buf = mcdi->logging_buffer; /* page-sized */ |
153 | #endif |
154 | efx_dword_t hdr[2]; |
155 | size_t hdr_len; |
156 | u32 xflags, seqno; |
157 | |
158 | BUG_ON(mcdi->state == MCDI_STATE_QUIESCENT); |
159 | |
160 | /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */ |
161 | spin_lock_bh(lock: &mcdi->iface_lock); |
162 | ++mcdi->seqno; |
163 | seqno = mcdi->seqno & SEQ_MASK; |
164 | spin_unlock_bh(lock: &mcdi->iface_lock); |
165 | |
166 | xflags = 0; |
167 | if (mcdi->mode == MCDI_MODE_EVENTS) |
168 | xflags |= MCDI_HEADER_XFLAGS_EVREQ; |
169 | |
170 | if (efx->type->mcdi_max_ver == 1) { |
171 | /* MCDI v1 */ |
172 | EFX_POPULATE_DWORD_7(hdr[0], |
173 | MCDI_HEADER_RESPONSE, 0, |
174 | MCDI_HEADER_RESYNC, 1, |
175 | MCDI_HEADER_CODE, cmd, |
176 | MCDI_HEADER_DATALEN, inlen, |
177 | MCDI_HEADER_SEQ, seqno, |
178 | MCDI_HEADER_XFLAGS, xflags, |
179 | MCDI_HEADER_NOT_EPOCH, !mcdi->new_epoch); |
180 | hdr_len = 4; |
181 | } else { |
182 | /* MCDI v2 */ |
183 | BUG_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V2); |
184 | EFX_POPULATE_DWORD_7(hdr[0], |
185 | MCDI_HEADER_RESPONSE, 0, |
186 | MCDI_HEADER_RESYNC, 1, |
187 | MCDI_HEADER_CODE, MC_CMD_V2_EXTN, |
188 | MCDI_HEADER_DATALEN, 0, |
189 | MCDI_HEADER_SEQ, seqno, |
190 | MCDI_HEADER_XFLAGS, xflags, |
191 | MCDI_HEADER_NOT_EPOCH, !mcdi->new_epoch); |
192 | EFX_POPULATE_DWORD_2(hdr[1], |
193 | MC_CMD_V2_EXTN_IN_EXTENDED_CMD, cmd, |
194 | MC_CMD_V2_EXTN_IN_ACTUAL_LEN, inlen); |
195 | hdr_len = 8; |
196 | } |
197 | |
198 | #ifdef CONFIG_SFC_MCDI_LOGGING |
199 | if (mcdi->logging_enabled && !WARN_ON_ONCE(!buf)) { |
200 | int bytes = 0; |
201 | int i; |
202 | /* Lengths should always be a whole number of dwords, so scream |
203 | * if they're not. |
204 | */ |
205 | WARN_ON_ONCE(hdr_len % 4); |
206 | WARN_ON_ONCE(inlen % 4); |
207 | |
208 | /* We own the logging buffer, as only one MCDI can be in |
209 | * progress on a NIC at any one time. So no need for locking. |
210 | */ |
211 | for (i = 0; i < hdr_len / 4 && bytes < PAGE_SIZE; i++) |
212 | bytes += scnprintf(buf: buf + bytes, PAGE_SIZE - bytes, |
213 | fmt: " %08x" , |
214 | le32_to_cpu(hdr[i].u32[0])); |
215 | |
216 | for (i = 0; i < inlen / 4 && bytes < PAGE_SIZE; i++) |
217 | bytes += scnprintf(buf: buf + bytes, PAGE_SIZE - bytes, |
218 | fmt: " %08x" , |
219 | le32_to_cpu(inbuf[i].u32[0])); |
220 | |
221 | netif_info(efx, hw, efx->net_dev, "MCDI RPC REQ:%s\n" , buf); |
222 | } |
223 | #endif |
224 | |
225 | efx->type->mcdi_request(efx, hdr, hdr_len, inbuf, inlen); |
226 | |
227 | mcdi->new_epoch = false; |
228 | } |
229 | |
230 | static int efx_mcdi_errno(unsigned int mcdi_err) |
231 | { |
232 | switch (mcdi_err) { |
233 | case 0: |
234 | return 0; |
235 | #define TRANSLATE_ERROR(name) \ |
236 | case MC_CMD_ERR_ ## name: \ |
237 | return -name; |
238 | TRANSLATE_ERROR(EPERM); |
239 | TRANSLATE_ERROR(ENOENT); |
240 | TRANSLATE_ERROR(EINTR); |
241 | TRANSLATE_ERROR(EAGAIN); |
242 | TRANSLATE_ERROR(EACCES); |
243 | TRANSLATE_ERROR(EBUSY); |
244 | TRANSLATE_ERROR(EINVAL); |
245 | TRANSLATE_ERROR(EDEADLK); |
246 | TRANSLATE_ERROR(ENOSYS); |
247 | TRANSLATE_ERROR(ETIME); |
248 | TRANSLATE_ERROR(EALREADY); |
249 | TRANSLATE_ERROR(ENOSPC); |
250 | #undef TRANSLATE_ERROR |
251 | case MC_CMD_ERR_ENOTSUP: |
252 | return -EOPNOTSUPP; |
253 | case MC_CMD_ERR_ALLOC_FAIL: |
254 | return -ENOBUFS; |
255 | case MC_CMD_ERR_MAC_EXIST: |
256 | return -EADDRINUSE; |
257 | default: |
258 | return -EPROTO; |
259 | } |
260 | } |
261 | |
262 | static void (struct efx_nic *efx) |
263 | { |
264 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
265 | unsigned int respseq, respcmd, error; |
266 | #ifdef CONFIG_SFC_MCDI_LOGGING |
267 | char *buf = mcdi->logging_buffer; /* page-sized */ |
268 | #endif |
269 | efx_dword_t hdr; |
270 | |
271 | efx->type->mcdi_read_response(efx, &hdr, 0, 4); |
272 | respseq = EFX_DWORD_FIELD(hdr, MCDI_HEADER_SEQ); |
273 | respcmd = EFX_DWORD_FIELD(hdr, MCDI_HEADER_CODE); |
274 | error = EFX_DWORD_FIELD(hdr, MCDI_HEADER_ERROR); |
275 | |
276 | if (respcmd != MC_CMD_V2_EXTN) { |
277 | mcdi->resp_hdr_len = 4; |
278 | mcdi->resp_data_len = EFX_DWORD_FIELD(hdr, MCDI_HEADER_DATALEN); |
279 | } else { |
280 | efx->type->mcdi_read_response(efx, &hdr, 4, 4); |
281 | mcdi->resp_hdr_len = 8; |
282 | mcdi->resp_data_len = |
283 | EFX_DWORD_FIELD(hdr, MC_CMD_V2_EXTN_IN_ACTUAL_LEN); |
284 | } |
285 | |
286 | #ifdef CONFIG_SFC_MCDI_LOGGING |
287 | if (mcdi->logging_enabled && !WARN_ON_ONCE(!buf)) { |
288 | size_t hdr_len, data_len; |
289 | int bytes = 0; |
290 | int i; |
291 | |
292 | WARN_ON_ONCE(mcdi->resp_hdr_len % 4); |
293 | hdr_len = mcdi->resp_hdr_len / 4; |
294 | /* MCDI_DECLARE_BUF ensures that underlying buffer is padded |
295 | * to dword size, and the MCDI buffer is always dword size |
296 | */ |
297 | data_len = DIV_ROUND_UP(mcdi->resp_data_len, 4); |
298 | |
299 | /* We own the logging buffer, as only one MCDI can be in |
300 | * progress on a NIC at any one time. So no need for locking. |
301 | */ |
302 | for (i = 0; i < hdr_len && bytes < PAGE_SIZE; i++) { |
303 | efx->type->mcdi_read_response(efx, &hdr, (i * 4), 4); |
304 | bytes += scnprintf(buf: buf + bytes, PAGE_SIZE - bytes, |
305 | fmt: " %08x" , le32_to_cpu(hdr.u32[0])); |
306 | } |
307 | |
308 | for (i = 0; i < data_len && bytes < PAGE_SIZE; i++) { |
309 | efx->type->mcdi_read_response(efx, &hdr, |
310 | mcdi->resp_hdr_len + (i * 4), 4); |
311 | bytes += scnprintf(buf: buf + bytes, PAGE_SIZE - bytes, |
312 | fmt: " %08x" , le32_to_cpu(hdr.u32[0])); |
313 | } |
314 | |
315 | netif_info(efx, hw, efx->net_dev, "MCDI RPC RESP:%s\n" , buf); |
316 | } |
317 | #endif |
318 | |
319 | mcdi->resprc_raw = 0; |
320 | if (error && mcdi->resp_data_len == 0) { |
321 | netif_err(efx, hw, efx->net_dev, "MC rebooted\n" ); |
322 | mcdi->resprc = -EIO; |
323 | } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) { |
324 | netif_err(efx, hw, efx->net_dev, |
325 | "MC response mismatch tx seq 0x%x rx seq 0x%x\n" , |
326 | respseq, mcdi->seqno); |
327 | mcdi->resprc = -EIO; |
328 | } else if (error) { |
329 | efx->type->mcdi_read_response(efx, &hdr, mcdi->resp_hdr_len, 4); |
330 | mcdi->resprc_raw = EFX_DWORD_FIELD(hdr, EFX_DWORD_0); |
331 | mcdi->resprc = efx_mcdi_errno(mcdi_err: mcdi->resprc_raw); |
332 | } else { |
333 | mcdi->resprc = 0; |
334 | } |
335 | } |
336 | |
337 | static bool efx_mcdi_poll_once(struct efx_nic *efx) |
338 | { |
339 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
340 | |
341 | rmb(); |
342 | if (!efx->type->mcdi_poll_response(efx)) |
343 | return false; |
344 | |
345 | spin_lock_bh(lock: &mcdi->iface_lock); |
346 | efx_mcdi_read_response_header(efx); |
347 | spin_unlock_bh(lock: &mcdi->iface_lock); |
348 | |
349 | return true; |
350 | } |
351 | |
352 | static int efx_mcdi_poll(struct efx_nic *efx) |
353 | { |
354 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
355 | unsigned long time, finish; |
356 | unsigned int spins; |
357 | int rc; |
358 | |
359 | /* Check for a reboot atomically with respect to efx_mcdi_copyout() */ |
360 | rc = efx_mcdi_poll_reboot(efx); |
361 | if (rc) { |
362 | spin_lock_bh(lock: &mcdi->iface_lock); |
363 | mcdi->resprc = rc; |
364 | mcdi->resp_hdr_len = 0; |
365 | mcdi->resp_data_len = 0; |
366 | spin_unlock_bh(lock: &mcdi->iface_lock); |
367 | return 0; |
368 | } |
369 | |
370 | /* Poll for completion. Poll quickly (once a us) for the 1st jiffy, |
371 | * because generally mcdi responses are fast. After that, back off |
372 | * and poll once a jiffy (approximately) |
373 | */ |
374 | spins = USER_TICK_USEC; |
375 | finish = jiffies + MCDI_RPC_TIMEOUT; |
376 | |
377 | while (1) { |
378 | if (spins != 0) { |
379 | --spins; |
380 | udelay(1); |
381 | } else { |
382 | schedule_timeout_uninterruptible(timeout: 1); |
383 | } |
384 | |
385 | time = jiffies; |
386 | |
387 | if (efx_mcdi_poll_once(efx)) |
388 | break; |
389 | |
390 | if (time_after(time, finish)) |
391 | return -ETIMEDOUT; |
392 | } |
393 | |
394 | /* Return rc=0 like wait_event_timeout() */ |
395 | return 0; |
396 | } |
397 | |
398 | /* Test and clear MC-rebooted flag for this port/function; reset |
399 | * software state as necessary. |
400 | */ |
401 | int efx_mcdi_poll_reboot(struct efx_nic *efx) |
402 | { |
403 | if (!efx->mcdi) |
404 | return 0; |
405 | |
406 | return efx->type->mcdi_poll_reboot(efx); |
407 | } |
408 | |
409 | static bool efx_mcdi_acquire_async(struct efx_mcdi_iface *mcdi) |
410 | { |
411 | return cmpxchg(&mcdi->state, |
412 | MCDI_STATE_QUIESCENT, MCDI_STATE_RUNNING_ASYNC) == |
413 | MCDI_STATE_QUIESCENT; |
414 | } |
415 | |
416 | static void efx_mcdi_acquire_sync(struct efx_mcdi_iface *mcdi) |
417 | { |
418 | /* Wait until the interface becomes QUIESCENT and we win the race |
419 | * to mark it RUNNING_SYNC. |
420 | */ |
421 | wait_event(mcdi->wq, |
422 | cmpxchg(&mcdi->state, |
423 | MCDI_STATE_QUIESCENT, MCDI_STATE_RUNNING_SYNC) == |
424 | MCDI_STATE_QUIESCENT); |
425 | } |
426 | |
427 | static int efx_mcdi_await_completion(struct efx_nic *efx) |
428 | { |
429 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
430 | |
431 | if (wait_event_timeout(mcdi->wq, mcdi->state == MCDI_STATE_COMPLETED, |
432 | MCDI_RPC_TIMEOUT) == 0) |
433 | return -ETIMEDOUT; |
434 | |
435 | /* Check if efx_mcdi_set_mode() switched us back to polled completions. |
436 | * In which case, poll for completions directly. If efx_mcdi_ev_cpl() |
437 | * completed the request first, then we'll just end up completing the |
438 | * request again, which is safe. |
439 | * |
440 | * We need an smp_rmb() to synchronise with efx_mcdi_mode_poll(), which |
441 | * wait_event_timeout() implicitly provides. |
442 | */ |
443 | if (mcdi->mode == MCDI_MODE_POLL) |
444 | return efx_mcdi_poll(efx); |
445 | |
446 | return 0; |
447 | } |
448 | |
449 | /* If the interface is RUNNING_SYNC, switch to COMPLETED and wake the |
450 | * requester. Return whether this was done. Does not take any locks. |
451 | */ |
452 | static bool efx_mcdi_complete_sync(struct efx_mcdi_iface *mcdi) |
453 | { |
454 | if (cmpxchg(&mcdi->state, |
455 | MCDI_STATE_RUNNING_SYNC, MCDI_STATE_COMPLETED) == |
456 | MCDI_STATE_RUNNING_SYNC) { |
457 | wake_up(&mcdi->wq); |
458 | return true; |
459 | } |
460 | |
461 | return false; |
462 | } |
463 | |
464 | static void efx_mcdi_release(struct efx_mcdi_iface *mcdi) |
465 | { |
466 | if (mcdi->mode == MCDI_MODE_EVENTS) { |
467 | struct efx_mcdi_async_param *async; |
468 | struct efx_nic *efx = mcdi->efx; |
469 | |
470 | /* Process the asynchronous request queue */ |
471 | spin_lock_bh(lock: &mcdi->async_lock); |
472 | async = list_first_entry_or_null( |
473 | &mcdi->async_list, struct efx_mcdi_async_param, list); |
474 | if (async) { |
475 | mcdi->state = MCDI_STATE_RUNNING_ASYNC; |
476 | efx_mcdi_send_request(efx, cmd: async->cmd, |
477 | inbuf: (const efx_dword_t *)(async + 1), |
478 | inlen: async->inlen); |
479 | mod_timer(timer: &mcdi->async_timer, |
480 | expires: jiffies + MCDI_RPC_TIMEOUT); |
481 | } |
482 | spin_unlock_bh(lock: &mcdi->async_lock); |
483 | |
484 | if (async) |
485 | return; |
486 | } |
487 | |
488 | mcdi->state = MCDI_STATE_QUIESCENT; |
489 | wake_up(&mcdi->wq); |
490 | } |
491 | |
492 | /* If the interface is RUNNING_ASYNC, switch to COMPLETED, call the |
493 | * asynchronous completion function, and release the interface. |
494 | * Return whether this was done. Must be called in bh-disabled |
495 | * context. Will take iface_lock and async_lock. |
496 | */ |
497 | static bool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout) |
498 | { |
499 | struct efx_nic *efx = mcdi->efx; |
500 | struct efx_mcdi_async_param *async; |
501 | size_t hdr_len, data_len, err_len; |
502 | efx_dword_t *outbuf; |
503 | MCDI_DECLARE_BUF_ERR(errbuf); |
504 | int rc; |
505 | |
506 | if (cmpxchg(&mcdi->state, |
507 | MCDI_STATE_RUNNING_ASYNC, MCDI_STATE_COMPLETED) != |
508 | MCDI_STATE_RUNNING_ASYNC) |
509 | return false; |
510 | |
511 | spin_lock(lock: &mcdi->iface_lock); |
512 | if (timeout) { |
513 | /* Ensure that if the completion event arrives later, |
514 | * the seqno check in efx_mcdi_ev_cpl() will fail |
515 | */ |
516 | ++mcdi->seqno; |
517 | ++mcdi->credits; |
518 | rc = -ETIMEDOUT; |
519 | hdr_len = 0; |
520 | data_len = 0; |
521 | } else { |
522 | rc = mcdi->resprc; |
523 | hdr_len = mcdi->resp_hdr_len; |
524 | data_len = mcdi->resp_data_len; |
525 | } |
526 | spin_unlock(lock: &mcdi->iface_lock); |
527 | |
528 | /* Stop the timer. In case the timer function is running, we |
529 | * must wait for it to return so that there is no possibility |
530 | * of it aborting the next request. |
531 | */ |
532 | if (!timeout) |
533 | del_timer_sync(timer: &mcdi->async_timer); |
534 | |
535 | spin_lock(lock: &mcdi->async_lock); |
536 | async = list_first_entry(&mcdi->async_list, |
537 | struct efx_mcdi_async_param, list); |
538 | list_del(entry: &async->list); |
539 | spin_unlock(lock: &mcdi->async_lock); |
540 | |
541 | outbuf = (efx_dword_t *)(async + 1); |
542 | efx->type->mcdi_read_response(efx, outbuf, hdr_len, |
543 | min(async->outlen, data_len)); |
544 | if (!timeout && rc && !async->quiet) { |
545 | err_len = min(sizeof(errbuf), data_len); |
546 | efx->type->mcdi_read_response(efx, errbuf, hdr_len, |
547 | sizeof(errbuf)); |
548 | efx_mcdi_display_error(efx, cmd: async->cmd, inlen: async->inlen, outbuf: errbuf, |
549 | outlen: err_len, rc); |
550 | } |
551 | |
552 | if (async->complete) |
553 | async->complete(efx, async->cookie, rc, outbuf, |
554 | min(async->outlen, data_len)); |
555 | kfree(objp: async); |
556 | |
557 | efx_mcdi_release(mcdi); |
558 | |
559 | return true; |
560 | } |
561 | |
562 | static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno, |
563 | unsigned int datalen, unsigned int mcdi_err) |
564 | { |
565 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
566 | bool wake = false; |
567 | |
568 | spin_lock(lock: &mcdi->iface_lock); |
569 | |
570 | if ((seqno ^ mcdi->seqno) & SEQ_MASK) { |
571 | if (mcdi->credits) |
572 | /* The request has been cancelled */ |
573 | --mcdi->credits; |
574 | else |
575 | netif_err(efx, hw, efx->net_dev, |
576 | "MC response mismatch tx seq 0x%x rx " |
577 | "seq 0x%x\n" , seqno, mcdi->seqno); |
578 | } else { |
579 | if (efx->type->mcdi_max_ver >= 2) { |
580 | /* MCDI v2 responses don't fit in an event */ |
581 | efx_mcdi_read_response_header(efx); |
582 | } else { |
583 | mcdi->resprc = efx_mcdi_errno(mcdi_err); |
584 | mcdi->resp_hdr_len = 4; |
585 | mcdi->resp_data_len = datalen; |
586 | } |
587 | |
588 | wake = true; |
589 | } |
590 | |
591 | spin_unlock(lock: &mcdi->iface_lock); |
592 | |
593 | if (wake) { |
594 | if (!efx_mcdi_complete_async(mcdi, timeout: false)) |
595 | (void) efx_mcdi_complete_sync(mcdi); |
596 | |
597 | /* If the interface isn't RUNNING_ASYNC or |
598 | * RUNNING_SYNC then we've received a duplicate |
599 | * completion after we've already transitioned back to |
600 | * QUIESCENT. [A subsequent invocation would increment |
601 | * seqno, so would have failed the seqno check]. |
602 | */ |
603 | } |
604 | } |
605 | |
606 | static void efx_mcdi_timeout_async(struct timer_list *t) |
607 | { |
608 | struct efx_mcdi_iface *mcdi = from_timer(mcdi, t, async_timer); |
609 | |
610 | efx_mcdi_complete_async(mcdi, timeout: true); |
611 | } |
612 | |
613 | static int |
614 | efx_mcdi_check_supported(struct efx_nic *efx, unsigned int cmd, size_t inlen) |
615 | { |
616 | if (efx->type->mcdi_max_ver < 0 || |
617 | (efx->type->mcdi_max_ver < 2 && |
618 | cmd > MC_CMD_CMD_SPACE_ESCAPE_7)) |
619 | return -EINVAL; |
620 | |
621 | if (inlen > MCDI_CTL_SDU_LEN_MAX_V2 || |
622 | (efx->type->mcdi_max_ver < 2 && |
623 | inlen > MCDI_CTL_SDU_LEN_MAX_V1)) |
624 | return -EMSGSIZE; |
625 | |
626 | return 0; |
627 | } |
628 | |
629 | static bool efx_mcdi_get_proxy_handle(struct efx_nic *efx, |
630 | size_t hdr_len, size_t data_len, |
631 | u32 *proxy_handle) |
632 | { |
633 | MCDI_DECLARE_BUF_ERR(testbuf); |
634 | const size_t buflen = sizeof(testbuf); |
635 | |
636 | if (!proxy_handle || data_len < buflen) |
637 | return false; |
638 | |
639 | efx->type->mcdi_read_response(efx, testbuf, hdr_len, buflen); |
640 | if (MCDI_DWORD(testbuf, ERR_CODE) == MC_CMD_ERR_PROXY_PENDING) { |
641 | *proxy_handle = MCDI_DWORD(testbuf, ERR_PROXY_PENDING_HANDLE); |
642 | return true; |
643 | } |
644 | |
645 | return false; |
646 | } |
647 | |
648 | static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned int cmd, |
649 | size_t inlen, |
650 | efx_dword_t *outbuf, size_t outlen, |
651 | size_t *outlen_actual, bool quiet, |
652 | u32 *proxy_handle, int *raw_rc) |
653 | { |
654 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
655 | MCDI_DECLARE_BUF_ERR(errbuf); |
656 | int rc; |
657 | |
658 | if (mcdi->mode == MCDI_MODE_POLL) |
659 | rc = efx_mcdi_poll(efx); |
660 | else |
661 | rc = efx_mcdi_await_completion(efx); |
662 | |
663 | if (rc != 0) { |
664 | netif_err(efx, hw, efx->net_dev, |
665 | "MC command 0x%x inlen %d mode %d timed out\n" , |
666 | cmd, (int)inlen, mcdi->mode); |
667 | |
668 | if (mcdi->mode == MCDI_MODE_EVENTS && efx_mcdi_poll_once(efx)) { |
669 | netif_err(efx, hw, efx->net_dev, |
670 | "MCDI request was completed without an event\n" ); |
671 | rc = 0; |
672 | } |
673 | |
674 | efx_mcdi_abandon(efx); |
675 | |
676 | /* Close the race with efx_mcdi_ev_cpl() executing just too late |
677 | * and completing a request we've just cancelled, by ensuring |
678 | * that the seqno check therein fails. |
679 | */ |
680 | spin_lock_bh(lock: &mcdi->iface_lock); |
681 | ++mcdi->seqno; |
682 | ++mcdi->credits; |
683 | spin_unlock_bh(lock: &mcdi->iface_lock); |
684 | } |
685 | |
686 | if (proxy_handle) |
687 | *proxy_handle = 0; |
688 | |
689 | if (rc != 0) { |
690 | if (outlen_actual) |
691 | *outlen_actual = 0; |
692 | } else { |
693 | size_t hdr_len, data_len, err_len; |
694 | |
695 | /* At the very least we need a memory barrier here to ensure |
696 | * we pick up changes from efx_mcdi_ev_cpl(). Protect against |
697 | * a spurious efx_mcdi_ev_cpl() running concurrently by |
698 | * acquiring the iface_lock. */ |
699 | spin_lock_bh(lock: &mcdi->iface_lock); |
700 | rc = mcdi->resprc; |
701 | if (raw_rc) |
702 | *raw_rc = mcdi->resprc_raw; |
703 | hdr_len = mcdi->resp_hdr_len; |
704 | data_len = mcdi->resp_data_len; |
705 | err_len = min(sizeof(errbuf), data_len); |
706 | spin_unlock_bh(lock: &mcdi->iface_lock); |
707 | |
708 | BUG_ON(rc > 0); |
709 | |
710 | efx->type->mcdi_read_response(efx, outbuf, hdr_len, |
711 | min(outlen, data_len)); |
712 | if (outlen_actual) |
713 | *outlen_actual = data_len; |
714 | |
715 | efx->type->mcdi_read_response(efx, errbuf, hdr_len, err_len); |
716 | |
717 | if (cmd == MC_CMD_REBOOT && rc == -EIO) { |
718 | /* Don't reset if MC_CMD_REBOOT returns EIO */ |
719 | } else if (rc == -EIO || rc == -EINTR) { |
720 | netif_err(efx, hw, efx->net_dev, "MC reboot detected\n" ); |
721 | netif_dbg(efx, hw, efx->net_dev, "MC rebooted during command %d rc %d\n" , |
722 | cmd, -rc); |
723 | if (efx->type->mcdi_reboot_detected) |
724 | efx->type->mcdi_reboot_detected(efx); |
725 | efx_schedule_reset(efx, type: RESET_TYPE_MC_FAILURE); |
726 | } else if (proxy_handle && (rc == -EPROTO) && |
727 | efx_mcdi_get_proxy_handle(efx, hdr_len, data_len, |
728 | proxy_handle)) { |
729 | mcdi->proxy_rx_status = 0; |
730 | mcdi->proxy_rx_handle = 0; |
731 | mcdi->state = MCDI_STATE_PROXY_WAIT; |
732 | } else if (rc && !quiet) { |
733 | efx_mcdi_display_error(efx, cmd, inlen, outbuf: errbuf, outlen: err_len, |
734 | rc); |
735 | } |
736 | |
737 | if (rc == -EIO || rc == -EINTR) { |
738 | msleep(MCDI_STATUS_SLEEP_MS); |
739 | efx_mcdi_poll_reboot(efx); |
740 | mcdi->new_epoch = true; |
741 | } |
742 | } |
743 | |
744 | if (!proxy_handle || !*proxy_handle) |
745 | efx_mcdi_release(mcdi); |
746 | return rc; |
747 | } |
748 | |
749 | static void efx_mcdi_proxy_abort(struct efx_mcdi_iface *mcdi) |
750 | { |
751 | if (mcdi->state == MCDI_STATE_PROXY_WAIT) { |
752 | /* Interrupt the proxy wait. */ |
753 | mcdi->proxy_rx_status = -EINTR; |
754 | wake_up(&mcdi->proxy_rx_wq); |
755 | } |
756 | } |
757 | |
758 | static void efx_mcdi_ev_proxy_response(struct efx_nic *efx, |
759 | u32 handle, int status) |
760 | { |
761 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
762 | |
763 | WARN_ON(mcdi->state != MCDI_STATE_PROXY_WAIT); |
764 | |
765 | mcdi->proxy_rx_status = efx_mcdi_errno(mcdi_err: status); |
766 | /* Ensure the status is written before we update the handle, since the |
767 | * latter is used to check if we've finished. |
768 | */ |
769 | wmb(); |
770 | mcdi->proxy_rx_handle = handle; |
771 | wake_up(&mcdi->proxy_rx_wq); |
772 | } |
773 | |
774 | static int efx_mcdi_proxy_wait(struct efx_nic *efx, u32 handle, bool quiet) |
775 | { |
776 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
777 | int rc; |
778 | |
779 | /* Wait for a proxy event, or timeout. */ |
780 | rc = wait_event_timeout(mcdi->proxy_rx_wq, |
781 | mcdi->proxy_rx_handle != 0 || |
782 | mcdi->proxy_rx_status == -EINTR, |
783 | MCDI_RPC_TIMEOUT); |
784 | |
785 | if (rc <= 0) { |
786 | netif_dbg(efx, hw, efx->net_dev, |
787 | "MCDI proxy timeout %d\n" , handle); |
788 | return -ETIMEDOUT; |
789 | } else if (mcdi->proxy_rx_handle != handle) { |
790 | netif_warn(efx, hw, efx->net_dev, |
791 | "MCDI proxy unexpected handle %d (expected %d)\n" , |
792 | mcdi->proxy_rx_handle, handle); |
793 | return -EINVAL; |
794 | } |
795 | |
796 | return mcdi->proxy_rx_status; |
797 | } |
798 | |
799 | static int _efx_mcdi_rpc(struct efx_nic *efx, unsigned int cmd, |
800 | const efx_dword_t *inbuf, size_t inlen, |
801 | efx_dword_t *outbuf, size_t outlen, |
802 | size_t *outlen_actual, bool quiet, int *raw_rc) |
803 | { |
804 | u32 proxy_handle = 0; /* Zero is an invalid proxy handle. */ |
805 | int rc; |
806 | |
807 | if (inbuf && inlen && (inbuf == outbuf)) { |
808 | /* The input buffer can't be aliased with the output. */ |
809 | WARN_ON(1); |
810 | return -EINVAL; |
811 | } |
812 | |
813 | rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen); |
814 | if (rc) |
815 | return rc; |
816 | |
817 | rc = _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen, |
818 | outlen_actual, quiet, proxy_handle: &proxy_handle, raw_rc); |
819 | |
820 | if (proxy_handle) { |
821 | /* Handle proxy authorisation. This allows approval of MCDI |
822 | * operations to be delegated to the admin function, allowing |
823 | * fine control over (eg) multicast subscriptions. |
824 | */ |
825 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
826 | |
827 | netif_dbg(efx, hw, efx->net_dev, |
828 | "MCDI waiting for proxy auth %d\n" , |
829 | proxy_handle); |
830 | rc = efx_mcdi_proxy_wait(efx, handle: proxy_handle, quiet); |
831 | |
832 | if (rc == 0) { |
833 | netif_dbg(efx, hw, efx->net_dev, |
834 | "MCDI proxy retry %d\n" , proxy_handle); |
835 | |
836 | /* We now retry the original request. */ |
837 | mcdi->state = MCDI_STATE_RUNNING_SYNC; |
838 | efx_mcdi_send_request(efx, cmd, inbuf, inlen); |
839 | |
840 | rc = _efx_mcdi_rpc_finish(efx, cmd, inlen, |
841 | outbuf, outlen, outlen_actual, |
842 | quiet, NULL, raw_rc); |
843 | } else { |
844 | netif_cond_dbg(efx, hw, efx->net_dev, rc == -EPERM, err, |
845 | "MC command 0x%x failed after proxy auth rc=%d\n" , |
846 | cmd, rc); |
847 | |
848 | if (rc == -EINTR || rc == -EIO) |
849 | efx_schedule_reset(efx, type: RESET_TYPE_MC_FAILURE); |
850 | efx_mcdi_release(mcdi); |
851 | } |
852 | } |
853 | |
854 | return rc; |
855 | } |
856 | |
857 | static int _efx_mcdi_rpc_evb_retry(struct efx_nic *efx, unsigned cmd, |
858 | const efx_dword_t *inbuf, size_t inlen, |
859 | efx_dword_t *outbuf, size_t outlen, |
860 | size_t *outlen_actual, bool quiet) |
861 | { |
862 | int raw_rc = 0; |
863 | int rc; |
864 | |
865 | rc = _efx_mcdi_rpc(efx, cmd, inbuf, inlen, |
866 | outbuf, outlen, outlen_actual, quiet: true, raw_rc: &raw_rc); |
867 | |
868 | if ((rc == -EPROTO) && (raw_rc == MC_CMD_ERR_NO_EVB_PORT) && |
869 | efx->type->is_vf) { |
870 | /* If the EVB port isn't available within a VF this may |
871 | * mean the PF is still bringing the switch up. We should |
872 | * retry our request shortly. |
873 | */ |
874 | unsigned long abort_time = jiffies + MCDI_RPC_TIMEOUT; |
875 | unsigned int delay_us = 10000; |
876 | |
877 | netif_dbg(efx, hw, efx->net_dev, |
878 | "%s: NO_EVB_PORT; will retry request\n" , |
879 | __func__); |
880 | |
881 | do { |
882 | usleep_range(min: delay_us, max: delay_us + 10000); |
883 | rc = _efx_mcdi_rpc(efx, cmd, inbuf, inlen, |
884 | outbuf, outlen, outlen_actual, |
885 | quiet: true, raw_rc: &raw_rc); |
886 | if (delay_us < 100000) |
887 | delay_us <<= 1; |
888 | } while ((rc == -EPROTO) && |
889 | (raw_rc == MC_CMD_ERR_NO_EVB_PORT) && |
890 | time_before(jiffies, abort_time)); |
891 | } |
892 | |
893 | if (rc && !quiet && !(cmd == MC_CMD_REBOOT && rc == -EIO)) |
894 | efx_mcdi_display_error(efx, cmd, inlen, |
895 | outbuf, outlen, rc); |
896 | |
897 | return rc; |
898 | } |
899 | |
900 | /** |
901 | * efx_mcdi_rpc - Issue an MCDI command and wait for completion |
902 | * @efx: NIC through which to issue the command |
903 | * @cmd: Command type number |
904 | * @inbuf: Command parameters |
905 | * @inlen: Length of command parameters, in bytes. Must be a multiple |
906 | * of 4 and no greater than %MCDI_CTL_SDU_LEN_MAX_V1. |
907 | * @outbuf: Response buffer. May be %NULL if @outlen is 0. |
908 | * @outlen: Length of response buffer, in bytes. If the actual |
909 | * response is longer than @outlen & ~3, it will be truncated |
910 | * to that length. |
911 | * @outlen_actual: Pointer through which to return the actual response |
912 | * length. May be %NULL if this is not needed. |
913 | * |
914 | * This function may sleep and therefore must be called in an appropriate |
915 | * context. |
916 | * |
917 | * Return: A negative error code, or zero if successful. The error |
918 | * code may come from the MCDI response or may indicate a failure |
919 | * to communicate with the MC. In the former case, the response |
920 | * will still be copied to @outbuf and *@outlen_actual will be |
921 | * set accordingly. In the latter case, *@outlen_actual will be |
922 | * set to zero. |
923 | */ |
924 | int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, |
925 | const efx_dword_t *inbuf, size_t inlen, |
926 | efx_dword_t *outbuf, size_t outlen, |
927 | size_t *outlen_actual) |
928 | { |
929 | return _efx_mcdi_rpc_evb_retry(efx, cmd, inbuf, inlen, outbuf, outlen, |
930 | outlen_actual, quiet: false); |
931 | } |
932 | |
933 | /* Normally, on receiving an error code in the MCDI response, |
934 | * efx_mcdi_rpc will log an error message containing (among other |
935 | * things) the raw error code, by means of efx_mcdi_display_error. |
936 | * This _quiet version suppresses that; if the caller wishes to log |
937 | * the error conditionally on the return code, it should call this |
938 | * function and is then responsible for calling efx_mcdi_display_error |
939 | * as needed. |
940 | */ |
941 | int efx_mcdi_rpc_quiet(struct efx_nic *efx, unsigned cmd, |
942 | const efx_dword_t *inbuf, size_t inlen, |
943 | efx_dword_t *outbuf, size_t outlen, |
944 | size_t *outlen_actual) |
945 | { |
946 | return _efx_mcdi_rpc_evb_retry(efx, cmd, inbuf, inlen, outbuf, outlen, |
947 | outlen_actual, quiet: true); |
948 | } |
949 | |
950 | int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd, |
951 | const efx_dword_t *inbuf, size_t inlen) |
952 | { |
953 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
954 | int rc; |
955 | |
956 | rc = efx_mcdi_check_supported(efx, cmd, inlen); |
957 | if (rc) |
958 | return rc; |
959 | |
960 | if (efx->mc_bist_for_other_fn) |
961 | return -ENETDOWN; |
962 | |
963 | if (mcdi->mode == MCDI_MODE_FAIL) |
964 | return -ENETDOWN; |
965 | |
966 | efx_mcdi_acquire_sync(mcdi); |
967 | efx_mcdi_send_request(efx, cmd, inbuf, inlen); |
968 | return 0; |
969 | } |
970 | |
971 | static int _efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd, |
972 | const efx_dword_t *inbuf, size_t inlen, |
973 | size_t outlen, |
974 | efx_mcdi_async_completer *complete, |
975 | unsigned long cookie, bool quiet) |
976 | { |
977 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
978 | struct efx_mcdi_async_param *async; |
979 | int rc; |
980 | |
981 | rc = efx_mcdi_check_supported(efx, cmd, inlen); |
982 | if (rc) |
983 | return rc; |
984 | |
985 | if (efx->mc_bist_for_other_fn) |
986 | return -ENETDOWN; |
987 | |
988 | async = kmalloc(size: sizeof(*async) + ALIGN(max(inlen, outlen), 4), |
989 | GFP_ATOMIC); |
990 | if (!async) |
991 | return -ENOMEM; |
992 | |
993 | async->cmd = cmd; |
994 | async->inlen = inlen; |
995 | async->outlen = outlen; |
996 | async->quiet = quiet; |
997 | async->complete = complete; |
998 | async->cookie = cookie; |
999 | memcpy(async + 1, inbuf, inlen); |
1000 | |
1001 | spin_lock_bh(lock: &mcdi->async_lock); |
1002 | |
1003 | if (mcdi->mode == MCDI_MODE_EVENTS) { |
1004 | list_add_tail(new: &async->list, head: &mcdi->async_list); |
1005 | |
1006 | /* If this is at the front of the queue, try to start it |
1007 | * immediately |
1008 | */ |
1009 | if (mcdi->async_list.next == &async->list && |
1010 | efx_mcdi_acquire_async(mcdi)) { |
1011 | efx_mcdi_send_request(efx, cmd, inbuf, inlen); |
1012 | mod_timer(timer: &mcdi->async_timer, |
1013 | expires: jiffies + MCDI_RPC_TIMEOUT); |
1014 | } |
1015 | } else { |
1016 | kfree(objp: async); |
1017 | rc = -ENETDOWN; |
1018 | } |
1019 | |
1020 | spin_unlock_bh(lock: &mcdi->async_lock); |
1021 | |
1022 | return rc; |
1023 | } |
1024 | |
1025 | /** |
1026 | * efx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously |
1027 | * @efx: NIC through which to issue the command |
1028 | * @cmd: Command type number |
1029 | * @inbuf: Command parameters |
1030 | * @inlen: Length of command parameters, in bytes |
1031 | * @outlen: Length to allocate for response buffer, in bytes |
1032 | * @complete: Function to be called on completion or cancellation. |
1033 | * @cookie: Arbitrary value to be passed to @complete. |
1034 | * |
1035 | * This function does not sleep and therefore may be called in atomic |
1036 | * context. It will fail if event queues are disabled or if MCDI |
1037 | * event completions have been disabled due to an error. |
1038 | * |
1039 | * If it succeeds, the @complete function will be called exactly once |
1040 | * in atomic context, when one of the following occurs: |
1041 | * (a) the completion event is received (in NAPI context) |
1042 | * (b) event queues are disabled (in the process that disables them) |
1043 | * (c) the request times-out (in timer context) |
1044 | */ |
1045 | int |
1046 | efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd, |
1047 | const efx_dword_t *inbuf, size_t inlen, size_t outlen, |
1048 | efx_mcdi_async_completer *complete, unsigned long cookie) |
1049 | { |
1050 | return _efx_mcdi_rpc_async(efx, cmd, inbuf, inlen, outlen, complete, |
1051 | cookie, quiet: false); |
1052 | } |
1053 | |
1054 | int efx_mcdi_rpc_async_quiet(struct efx_nic *efx, unsigned int cmd, |
1055 | const efx_dword_t *inbuf, size_t inlen, |
1056 | size_t outlen, efx_mcdi_async_completer *complete, |
1057 | unsigned long cookie) |
1058 | { |
1059 | return _efx_mcdi_rpc_async(efx, cmd, inbuf, inlen, outlen, complete, |
1060 | cookie, quiet: true); |
1061 | } |
1062 | |
1063 | int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, |
1064 | efx_dword_t *outbuf, size_t outlen, |
1065 | size_t *outlen_actual) |
1066 | { |
1067 | return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen, |
1068 | outlen_actual, quiet: false, NULL, NULL); |
1069 | } |
1070 | |
1071 | int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, size_t inlen, |
1072 | efx_dword_t *outbuf, size_t outlen, |
1073 | size_t *outlen_actual) |
1074 | { |
1075 | return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen, |
1076 | outlen_actual, quiet: true, NULL, NULL); |
1077 | } |
1078 | |
1079 | void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd, |
1080 | size_t inlen, efx_dword_t *outbuf, |
1081 | size_t outlen, int rc) |
1082 | { |
1083 | int code = 0, err_arg = 0; |
1084 | |
1085 | if (outlen >= MC_CMD_ERR_CODE_OFST + 4) |
1086 | code = MCDI_DWORD(outbuf, ERR_CODE); |
1087 | if (outlen >= MC_CMD_ERR_ARG_OFST + 4) |
1088 | err_arg = MCDI_DWORD(outbuf, ERR_ARG); |
1089 | netif_cond_dbg(efx, hw, efx->net_dev, rc == -EPERM, err, |
1090 | "MC command 0x%x inlen %zu failed rc=%d (raw=%d) arg=%d\n" , |
1091 | cmd, inlen, rc, code, err_arg); |
1092 | } |
1093 | |
1094 | /* Switch to polled MCDI completions. This can be called in various |
1095 | * error conditions with various locks held, so it must be lockless. |
1096 | * Caller is responsible for flushing asynchronous requests later. |
1097 | */ |
1098 | void efx_mcdi_mode_poll(struct efx_nic *efx) |
1099 | { |
1100 | struct efx_mcdi_iface *mcdi; |
1101 | |
1102 | if (!efx->mcdi) |
1103 | return; |
1104 | |
1105 | mcdi = efx_mcdi(efx); |
1106 | /* If already in polling mode, nothing to do. |
1107 | * If in fail-fast state, don't switch to polled completion. |
1108 | * FLR recovery will do that later. |
1109 | */ |
1110 | if (mcdi->mode == MCDI_MODE_POLL || mcdi->mode == MCDI_MODE_FAIL) |
1111 | return; |
1112 | |
1113 | /* We can switch from event completion to polled completion, because |
1114 | * mcdi requests are always completed in shared memory. We do this by |
1115 | * switching the mode to POLL'd then completing the request. |
1116 | * efx_mcdi_await_completion() will then call efx_mcdi_poll(). |
1117 | * |
1118 | * We need an smp_wmb() to synchronise with efx_mcdi_await_completion(), |
1119 | * which efx_mcdi_complete_sync() provides for us. |
1120 | */ |
1121 | mcdi->mode = MCDI_MODE_POLL; |
1122 | |
1123 | efx_mcdi_complete_sync(mcdi); |
1124 | } |
1125 | |
1126 | /* Flush any running or queued asynchronous requests, after event processing |
1127 | * is stopped |
1128 | */ |
1129 | void efx_mcdi_flush_async(struct efx_nic *efx) |
1130 | { |
1131 | struct efx_mcdi_async_param *async, *next; |
1132 | struct efx_mcdi_iface *mcdi; |
1133 | |
1134 | if (!efx->mcdi) |
1135 | return; |
1136 | |
1137 | mcdi = efx_mcdi(efx); |
1138 | |
1139 | /* We must be in poll or fail mode so no more requests can be queued */ |
1140 | BUG_ON(mcdi->mode == MCDI_MODE_EVENTS); |
1141 | |
1142 | del_timer_sync(timer: &mcdi->async_timer); |
1143 | |
1144 | /* If a request is still running, make sure we give the MC |
1145 | * time to complete it so that the response won't overwrite our |
1146 | * next request. |
1147 | */ |
1148 | if (mcdi->state == MCDI_STATE_RUNNING_ASYNC) { |
1149 | efx_mcdi_poll(efx); |
1150 | mcdi->state = MCDI_STATE_QUIESCENT; |
1151 | } |
1152 | |
1153 | /* Nothing else will access the async list now, so it is safe |
1154 | * to walk it without holding async_lock. If we hold it while |
1155 | * calling a completer then lockdep may warn that we have |
1156 | * acquired locks in the wrong order. |
1157 | */ |
1158 | list_for_each_entry_safe(async, next, &mcdi->async_list, list) { |
1159 | if (async->complete) |
1160 | async->complete(efx, async->cookie, -ENETDOWN, NULL, 0); |
1161 | list_del(entry: &async->list); |
1162 | kfree(objp: async); |
1163 | } |
1164 | } |
1165 | |
1166 | void efx_mcdi_mode_event(struct efx_nic *efx) |
1167 | { |
1168 | struct efx_mcdi_iface *mcdi; |
1169 | |
1170 | if (!efx->mcdi) |
1171 | return; |
1172 | |
1173 | mcdi = efx_mcdi(efx); |
1174 | /* If already in event completion mode, nothing to do. |
1175 | * If in fail-fast state, don't switch to event completion. FLR |
1176 | * recovery will do that later. |
1177 | */ |
1178 | if (mcdi->mode == MCDI_MODE_EVENTS || mcdi->mode == MCDI_MODE_FAIL) |
1179 | return; |
1180 | |
1181 | /* We can't switch from polled to event completion in the middle of a |
1182 | * request, because the completion method is specified in the request. |
1183 | * So acquire the interface to serialise the requestors. We don't need |
1184 | * to acquire the iface_lock to change the mode here, but we do need a |
1185 | * write memory barrier ensure that efx_mcdi_rpc() sees it, which |
1186 | * efx_mcdi_acquire() provides. |
1187 | */ |
1188 | efx_mcdi_acquire_sync(mcdi); |
1189 | mcdi->mode = MCDI_MODE_EVENTS; |
1190 | efx_mcdi_release(mcdi); |
1191 | } |
1192 | |
1193 | static void efx_mcdi_ev_death(struct efx_nic *efx, int rc) |
1194 | { |
1195 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
1196 | |
1197 | /* If there is an outstanding MCDI request, it has been terminated |
1198 | * either by a BADASSERT or REBOOT event. If the mcdi interface is |
1199 | * in polled mode, then do nothing because the MC reboot handler will |
1200 | * set the header correctly. However, if the mcdi interface is waiting |
1201 | * for a CMDDONE event it won't receive it [and since all MCDI events |
1202 | * are sent to the same queue, we can't be racing with |
1203 | * efx_mcdi_ev_cpl()] |
1204 | * |
1205 | * If there is an outstanding asynchronous request, we can't |
1206 | * complete it now (efx_mcdi_complete() would deadlock). The |
1207 | * reset process will take care of this. |
1208 | * |
1209 | * There's a race here with efx_mcdi_send_request(), because |
1210 | * we might receive a REBOOT event *before* the request has |
1211 | * been copied out. In polled mode (during startup) this is |
1212 | * irrelevant, because efx_mcdi_complete_sync() is ignored. In |
1213 | * event mode, this condition is just an edge-case of |
1214 | * receiving a REBOOT event after posting the MCDI |
1215 | * request. Did the mc reboot before or after the copyout? The |
1216 | * best we can do always is just return failure. |
1217 | * |
1218 | * If there is an outstanding proxy response expected it is not going |
1219 | * to arrive. We should thus abort it. |
1220 | */ |
1221 | spin_lock(lock: &mcdi->iface_lock); |
1222 | efx_mcdi_proxy_abort(mcdi); |
1223 | |
1224 | if (efx_mcdi_complete_sync(mcdi)) { |
1225 | if (mcdi->mode == MCDI_MODE_EVENTS) { |
1226 | mcdi->resprc = rc; |
1227 | mcdi->resp_hdr_len = 0; |
1228 | mcdi->resp_data_len = 0; |
1229 | ++mcdi->credits; |
1230 | } |
1231 | } else { |
1232 | int count; |
1233 | |
1234 | /* Consume the status word since efx_mcdi_rpc_finish() won't */ |
1235 | for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) { |
1236 | rc = efx_mcdi_poll_reboot(efx); |
1237 | if (rc) |
1238 | break; |
1239 | udelay(MCDI_STATUS_DELAY_US); |
1240 | } |
1241 | |
1242 | /* On EF10, a CODE_MC_REBOOT event can be received without the |
1243 | * reboot detection in efx_mcdi_poll_reboot() being triggered. |
1244 | * If zero was returned from the final call to |
1245 | * efx_mcdi_poll_reboot(), the MC reboot wasn't noticed but the |
1246 | * MC has definitely rebooted so prepare for the reset. |
1247 | */ |
1248 | if (!rc && efx->type->mcdi_reboot_detected) |
1249 | efx->type->mcdi_reboot_detected(efx); |
1250 | |
1251 | mcdi->new_epoch = true; |
1252 | |
1253 | /* Nobody was waiting for an MCDI request, so trigger a reset */ |
1254 | efx_schedule_reset(efx, type: RESET_TYPE_MC_FAILURE); |
1255 | } |
1256 | |
1257 | spin_unlock(lock: &mcdi->iface_lock); |
1258 | } |
1259 | |
1260 | /* The MC is going down in to BIST mode. set the BIST flag to block |
1261 | * new MCDI, cancel any outstanding MCDI and schedule a BIST-type reset |
1262 | * (which doesn't actually execute a reset, it waits for the controlling |
1263 | * function to reset it). |
1264 | */ |
1265 | static void efx_mcdi_ev_bist(struct efx_nic *efx) |
1266 | { |
1267 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
1268 | |
1269 | spin_lock(lock: &mcdi->iface_lock); |
1270 | efx->mc_bist_for_other_fn = true; |
1271 | efx_mcdi_proxy_abort(mcdi); |
1272 | |
1273 | if (efx_mcdi_complete_sync(mcdi)) { |
1274 | if (mcdi->mode == MCDI_MODE_EVENTS) { |
1275 | mcdi->resprc = -EIO; |
1276 | mcdi->resp_hdr_len = 0; |
1277 | mcdi->resp_data_len = 0; |
1278 | ++mcdi->credits; |
1279 | } |
1280 | } |
1281 | mcdi->new_epoch = true; |
1282 | efx_schedule_reset(efx, type: RESET_TYPE_MC_BIST); |
1283 | spin_unlock(lock: &mcdi->iface_lock); |
1284 | } |
1285 | |
1286 | /* MCDI timeouts seen, so make all MCDI calls fail-fast and issue an FLR to try |
1287 | * to recover. |
1288 | */ |
1289 | static void efx_mcdi_abandon(struct efx_nic *efx) |
1290 | { |
1291 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
1292 | |
1293 | if (xchg(&mcdi->mode, MCDI_MODE_FAIL) == MCDI_MODE_FAIL) |
1294 | return; /* it had already been done */ |
1295 | netif_dbg(efx, hw, efx->net_dev, "MCDI is timing out; trying to recover\n" ); |
1296 | efx_schedule_reset(efx, type: RESET_TYPE_MCDI_TIMEOUT); |
1297 | } |
1298 | |
1299 | static void efx_handle_drain_event(struct efx_nic *efx) |
1300 | { |
1301 | if (atomic_dec_and_test(v: &efx->active_queues)) |
1302 | wake_up(&efx->flush_wq); |
1303 | |
1304 | WARN_ON(atomic_read(&efx->active_queues) < 0); |
1305 | } |
1306 | |
1307 | /* Called from efx_farch_ev_process and efx_ef10_ev_process for MCDI events */ |
1308 | void efx_mcdi_process_event(struct efx_channel *channel, |
1309 | efx_qword_t *event) |
1310 | { |
1311 | struct efx_nic *efx = channel->efx; |
1312 | int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE); |
1313 | u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA); |
1314 | |
1315 | switch (code) { |
1316 | case MCDI_EVENT_CODE_BADSSERT: |
1317 | netif_err(efx, hw, efx->net_dev, |
1318 | "MC watchdog or assertion failure at 0x%x\n" , data); |
1319 | efx_mcdi_ev_death(efx, rc: -EINTR); |
1320 | break; |
1321 | |
1322 | case MCDI_EVENT_CODE_PMNOTICE: |
1323 | netif_info(efx, wol, efx->net_dev, "MCDI PM event.\n" ); |
1324 | break; |
1325 | |
1326 | case MCDI_EVENT_CODE_CMDDONE: |
1327 | efx_mcdi_ev_cpl(efx, |
1328 | MCDI_EVENT_FIELD(*event, CMDDONE_SEQ), |
1329 | MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN), |
1330 | MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO)); |
1331 | break; |
1332 | |
1333 | case MCDI_EVENT_CODE_LINKCHANGE: |
1334 | efx_mcdi_process_link_change(efx, ev: event); |
1335 | break; |
1336 | case MCDI_EVENT_CODE_SENSOREVT: |
1337 | efx_sensor_event(efx, ev: event); |
1338 | break; |
1339 | case MCDI_EVENT_CODE_SCHEDERR: |
1340 | netif_dbg(efx, hw, efx->net_dev, |
1341 | "MC Scheduler alert (0x%x)\n" , data); |
1342 | break; |
1343 | case MCDI_EVENT_CODE_REBOOT: |
1344 | case MCDI_EVENT_CODE_MC_REBOOT: |
1345 | netif_info(efx, hw, efx->net_dev, "MC Reboot\n" ); |
1346 | efx_mcdi_ev_death(efx, rc: -EIO); |
1347 | break; |
1348 | case MCDI_EVENT_CODE_MC_BIST: |
1349 | netif_info(efx, hw, efx->net_dev, "MC entered BIST mode\n" ); |
1350 | efx_mcdi_ev_bist(efx); |
1351 | break; |
1352 | case MCDI_EVENT_CODE_MAC_STATS_DMA: |
1353 | /* MAC stats are gather lazily. We can ignore this. */ |
1354 | break; |
1355 | case MCDI_EVENT_CODE_PTP_FAULT: |
1356 | case MCDI_EVENT_CODE_PTP_PPS: |
1357 | efx_ptp_event(efx, ev: event); |
1358 | break; |
1359 | case MCDI_EVENT_CODE_PTP_TIME: |
1360 | efx_time_sync_event(channel, ev: event); |
1361 | break; |
1362 | case MCDI_EVENT_CODE_TX_FLUSH: |
1363 | case MCDI_EVENT_CODE_RX_FLUSH: |
1364 | /* Two flush events will be sent: one to the same event |
1365 | * queue as completions, and one to event queue 0. |
1366 | * In the latter case the {RX,TX}_FLUSH_TO_DRIVER |
1367 | * flag will be set, and we should ignore the event |
1368 | * because we want to wait for all completions. |
1369 | */ |
1370 | BUILD_BUG_ON(MCDI_EVENT_TX_FLUSH_TO_DRIVER_LBN != |
1371 | MCDI_EVENT_RX_FLUSH_TO_DRIVER_LBN); |
1372 | if (!MCDI_EVENT_FIELD(*event, TX_FLUSH_TO_DRIVER)) |
1373 | efx_handle_drain_event(efx); |
1374 | break; |
1375 | case MCDI_EVENT_CODE_TX_ERR: |
1376 | case MCDI_EVENT_CODE_RX_ERR: |
1377 | netif_err(efx, hw, efx->net_dev, |
1378 | "%s DMA error (event: " EFX_QWORD_FMT")\n" , |
1379 | code == MCDI_EVENT_CODE_TX_ERR ? "TX" : "RX" , |
1380 | EFX_QWORD_VAL(*event)); |
1381 | efx_schedule_reset(efx, type: RESET_TYPE_DMA_ERROR); |
1382 | break; |
1383 | case MCDI_EVENT_CODE_PROXY_RESPONSE: |
1384 | efx_mcdi_ev_proxy_response(efx, |
1385 | MCDI_EVENT_FIELD(*event, PROXY_RESPONSE_HANDLE), |
1386 | MCDI_EVENT_FIELD(*event, PROXY_RESPONSE_RC)); |
1387 | break; |
1388 | default: |
1389 | netif_err(efx, hw, efx->net_dev, |
1390 | "Unknown MCDI event " EFX_QWORD_FMT "\n" , |
1391 | EFX_QWORD_VAL(*event)); |
1392 | } |
1393 | } |
1394 | |
1395 | /************************************************************************** |
1396 | * |
1397 | * Specific request functions |
1398 | * |
1399 | ************************************************************************** |
1400 | */ |
1401 | |
1402 | void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len) |
1403 | { |
1404 | MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_OUT_LEN); |
1405 | size_t outlength; |
1406 | const __le16 *ver_words; |
1407 | size_t offset; |
1408 | int rc; |
1409 | |
1410 | BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0); |
1411 | rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, inlen: 0, |
1412 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlength); |
1413 | if (rc) |
1414 | goto fail; |
1415 | if (outlength < MC_CMD_GET_VERSION_OUT_LEN) { |
1416 | rc = -EIO; |
1417 | goto fail; |
1418 | } |
1419 | |
1420 | ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION); |
1421 | offset = scnprintf(buf, size: len, fmt: "%u.%u.%u.%u" , |
1422 | le16_to_cpu(ver_words[0]), |
1423 | le16_to_cpu(ver_words[1]), |
1424 | le16_to_cpu(ver_words[2]), |
1425 | le16_to_cpu(ver_words[3])); |
1426 | |
1427 | if (efx->type->print_additional_fwver) |
1428 | offset += efx->type->print_additional_fwver(efx, buf + offset, |
1429 | len - offset); |
1430 | |
1431 | /* It's theoretically possible for the string to exceed 31 |
1432 | * characters, though in practice the first three version |
1433 | * components are short enough that this doesn't happen. |
1434 | */ |
1435 | if (WARN_ON(offset >= len)) |
1436 | buf[0] = 0; |
1437 | |
1438 | return; |
1439 | |
1440 | fail: |
1441 | pci_err(efx->pci_dev, "%s: failed rc=%d\n" , __func__, rc); |
1442 | buf[0] = 0; |
1443 | } |
1444 | |
1445 | static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, |
1446 | bool *was_attached) |
1447 | { |
1448 | MCDI_DECLARE_BUF(inbuf, MC_CMD_DRV_ATTACH_IN_LEN); |
1449 | MCDI_DECLARE_BUF(outbuf, MC_CMD_DRV_ATTACH_EXT_OUT_LEN); |
1450 | size_t outlen; |
1451 | int rc; |
1452 | |
1453 | MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE, |
1454 | driver_operating ? 1 : 0); |
1455 | MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1); |
1456 | MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_LOW_LATENCY); |
1457 | |
1458 | rc = efx_mcdi_rpc_quiet(efx, MC_CMD_DRV_ATTACH, inbuf, inlen: sizeof(inbuf), |
1459 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
1460 | /* If we're not the primary PF, trying to ATTACH with a FIRMWARE_ID |
1461 | * specified will fail with EPERM, and we have to tell the MC we don't |
1462 | * care what firmware we get. |
1463 | */ |
1464 | if (rc == -EPERM) { |
1465 | pci_dbg(efx->pci_dev, |
1466 | "%s with fw-variant setting failed EPERM, trying without it\n" , |
1467 | __func__); |
1468 | MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, |
1469 | MC_CMD_FW_DONT_CARE); |
1470 | rc = efx_mcdi_rpc_quiet(efx, MC_CMD_DRV_ATTACH, inbuf, |
1471 | inlen: sizeof(inbuf), outbuf, outlen: sizeof(outbuf), |
1472 | outlen_actual: &outlen); |
1473 | } |
1474 | if (rc) { |
1475 | efx_mcdi_display_error(efx, MC_CMD_DRV_ATTACH, inlen: sizeof(inbuf), |
1476 | outbuf, outlen, rc); |
1477 | goto fail; |
1478 | } |
1479 | if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) { |
1480 | rc = -EIO; |
1481 | goto fail; |
1482 | } |
1483 | |
1484 | if (driver_operating) { |
1485 | if (outlen >= MC_CMD_DRV_ATTACH_EXT_OUT_LEN) { |
1486 | efx->mcdi->fn_flags = |
1487 | MCDI_DWORD(outbuf, |
1488 | DRV_ATTACH_EXT_OUT_FUNC_FLAGS); |
1489 | } else { |
1490 | /* Synthesise flags for Siena */ |
1491 | efx->mcdi->fn_flags = |
1492 | 1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL | |
1493 | 1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED | |
1494 | (efx_port_num(efx) == 0) << |
1495 | MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY; |
1496 | } |
1497 | } |
1498 | |
1499 | /* We currently assume we have control of the external link |
1500 | * and are completely trusted by firmware. Abort probing |
1501 | * if that's not true for this function. |
1502 | */ |
1503 | |
1504 | if (was_attached != NULL) |
1505 | *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE); |
1506 | return 0; |
1507 | |
1508 | fail: |
1509 | pci_err(efx->pci_dev, "%s: failed rc=%d\n" , __func__, rc); |
1510 | return rc; |
1511 | } |
1512 | |
1513 | int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, |
1514 | u16 *fw_subtype_list, u32 *capabilities) |
1515 | { |
1516 | MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_BOARD_CFG_OUT_LENMAX); |
1517 | size_t outlen, i; |
1518 | int port_num = efx_port_num(efx); |
1519 | int rc; |
1520 | |
1521 | BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0); |
1522 | /* we need __aligned(2) for ether_addr_copy */ |
1523 | BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST & 1); |
1524 | BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST & 1); |
1525 | |
1526 | rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, inlen: 0, |
1527 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
1528 | if (rc) |
1529 | goto fail; |
1530 | |
1531 | if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { |
1532 | rc = -EIO; |
1533 | goto fail; |
1534 | } |
1535 | |
1536 | if (mac_address) |
1537 | ether_addr_copy(dst: mac_address, |
1538 | src: port_num ? |
1539 | MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) : |
1540 | MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0)); |
1541 | if (fw_subtype_list) { |
1542 | for (i = 0; |
1543 | i < MCDI_VAR_ARRAY_LEN(outlen, |
1544 | GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST); |
1545 | i++) |
1546 | fw_subtype_list[i] = MCDI_ARRAY_WORD( |
1547 | outbuf, GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST, i); |
1548 | for (; i < MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_MAXNUM; i++) |
1549 | fw_subtype_list[i] = 0; |
1550 | } |
1551 | if (capabilities) { |
1552 | if (port_num) |
1553 | *capabilities = MCDI_DWORD(outbuf, |
1554 | GET_BOARD_CFG_OUT_CAPABILITIES_PORT1); |
1555 | else |
1556 | *capabilities = MCDI_DWORD(outbuf, |
1557 | GET_BOARD_CFG_OUT_CAPABILITIES_PORT0); |
1558 | } |
1559 | |
1560 | return 0; |
1561 | |
1562 | fail: |
1563 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d len=%d\n" , |
1564 | __func__, rc, (int)outlen); |
1565 | |
1566 | return rc; |
1567 | } |
1568 | |
1569 | int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq) |
1570 | { |
1571 | MCDI_DECLARE_BUF(inbuf, MC_CMD_LOG_CTRL_IN_LEN); |
1572 | u32 dest = 0; |
1573 | int rc; |
1574 | |
1575 | if (uart) |
1576 | dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART; |
1577 | if (evq) |
1578 | dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ; |
1579 | |
1580 | MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest); |
1581 | MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq); |
1582 | |
1583 | BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0); |
1584 | |
1585 | rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, inlen: sizeof(inbuf), |
1586 | NULL, outlen: 0, NULL); |
1587 | return rc; |
1588 | } |
1589 | |
1590 | int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out) |
1591 | { |
1592 | MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TYPES_OUT_LEN); |
1593 | size_t outlen; |
1594 | int rc; |
1595 | |
1596 | BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0); |
1597 | |
1598 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, inlen: 0, |
1599 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
1600 | if (rc) |
1601 | goto fail; |
1602 | if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) { |
1603 | rc = -EIO; |
1604 | goto fail; |
1605 | } |
1606 | |
1607 | *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES); |
1608 | return 0; |
1609 | |
1610 | fail: |
1611 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n" , |
1612 | __func__, rc); |
1613 | return rc; |
1614 | } |
1615 | |
1616 | /* This function finds types using the new NVRAM_PARTITIONS mcdi. */ |
1617 | static int efx_new_mcdi_nvram_types(struct efx_nic *efx, u32 *number, |
1618 | u32 *nvram_types) |
1619 | { |
1620 | efx_dword_t *outbuf = kzalloc(MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX_MCDI2, |
1621 | GFP_KERNEL); |
1622 | size_t outlen; |
1623 | int rc; |
1624 | |
1625 | if (!outbuf) |
1626 | return -ENOMEM; |
1627 | |
1628 | BUILD_BUG_ON(MC_CMD_NVRAM_PARTITIONS_IN_LEN != 0); |
1629 | |
1630 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_PARTITIONS, NULL, inlen: 0, |
1631 | outbuf, MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX_MCDI2, outlen_actual: &outlen); |
1632 | if (rc) |
1633 | goto fail; |
1634 | |
1635 | *number = MCDI_DWORD(outbuf, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS); |
1636 | |
1637 | memcpy(nvram_types, MCDI_PTR(outbuf, NVRAM_PARTITIONS_OUT_TYPE_ID), |
1638 | *number * sizeof(u32)); |
1639 | |
1640 | fail: |
1641 | kfree(objp: outbuf); |
1642 | return rc; |
1643 | } |
1644 | |
1645 | int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, |
1646 | size_t *size_out, size_t *erase_size_out, |
1647 | bool *protected_out) |
1648 | { |
1649 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_INFO_IN_LEN); |
1650 | MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_OUT_LEN); |
1651 | size_t outlen; |
1652 | int rc; |
1653 | |
1654 | MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type); |
1655 | |
1656 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, inlen: sizeof(inbuf), |
1657 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
1658 | if (rc) |
1659 | goto fail; |
1660 | if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) { |
1661 | rc = -EIO; |
1662 | goto fail; |
1663 | } |
1664 | |
1665 | *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE); |
1666 | *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE); |
1667 | *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) & |
1668 | (1 << MC_CMD_NVRAM_INFO_OUT_PROTECTED_LBN)); |
1669 | return 0; |
1670 | |
1671 | fail: |
1672 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n" , __func__, rc); |
1673 | return rc; |
1674 | } |
1675 | |
1676 | static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type) |
1677 | { |
1678 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_TEST_IN_LEN); |
1679 | MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TEST_OUT_LEN); |
1680 | int rc; |
1681 | |
1682 | MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type); |
1683 | |
1684 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, inlen: sizeof(inbuf), |
1685 | outbuf, outlen: sizeof(outbuf), NULL); |
1686 | if (rc) |
1687 | return rc; |
1688 | |
1689 | switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) { |
1690 | case MC_CMD_NVRAM_TEST_PASS: |
1691 | case MC_CMD_NVRAM_TEST_NOTSUPP: |
1692 | return 0; |
1693 | default: |
1694 | return -EIO; |
1695 | } |
1696 | } |
1697 | |
1698 | /* This function tests nvram partitions using the new mcdi partition lookup scheme */ |
1699 | int efx_new_mcdi_nvram_test_all(struct efx_nic *efx) |
1700 | { |
1701 | u32 *nvram_types = kzalloc(MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX_MCDI2, |
1702 | GFP_KERNEL); |
1703 | unsigned int number; |
1704 | int rc, i; |
1705 | |
1706 | if (!nvram_types) |
1707 | return -ENOMEM; |
1708 | |
1709 | rc = efx_new_mcdi_nvram_types(efx, number: &number, nvram_types); |
1710 | if (rc) |
1711 | goto fail; |
1712 | |
1713 | /* Require at least one check */ |
1714 | rc = -EAGAIN; |
1715 | |
1716 | for (i = 0; i < number; i++) { |
1717 | if (nvram_types[i] == NVRAM_PARTITION_TYPE_PARTITION_MAP || |
1718 | nvram_types[i] == NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG) |
1719 | continue; |
1720 | |
1721 | rc = efx_mcdi_nvram_test(efx, type: nvram_types[i]); |
1722 | if (rc) |
1723 | goto fail; |
1724 | } |
1725 | |
1726 | fail: |
1727 | kfree(objp: nvram_types); |
1728 | return rc; |
1729 | } |
1730 | |
1731 | int efx_mcdi_nvram_test_all(struct efx_nic *efx) |
1732 | { |
1733 | u32 nvram_types; |
1734 | unsigned int type; |
1735 | int rc; |
1736 | |
1737 | rc = efx_mcdi_nvram_types(efx, nvram_types_out: &nvram_types); |
1738 | if (rc) |
1739 | goto fail1; |
1740 | |
1741 | type = 0; |
1742 | while (nvram_types != 0) { |
1743 | if (nvram_types & 1) { |
1744 | rc = efx_mcdi_nvram_test(efx, type); |
1745 | if (rc) |
1746 | goto fail2; |
1747 | } |
1748 | type++; |
1749 | nvram_types >>= 1; |
1750 | } |
1751 | |
1752 | return 0; |
1753 | |
1754 | fail2: |
1755 | netif_err(efx, hw, efx->net_dev, "%s: failed type=%u\n" , |
1756 | __func__, type); |
1757 | fail1: |
1758 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n" , __func__, rc); |
1759 | return rc; |
1760 | } |
1761 | |
1762 | /* Returns 1 if an assertion was read, 0 if no assertion had fired, |
1763 | * negative on error. |
1764 | */ |
1765 | static int efx_mcdi_read_assertion(struct efx_nic *efx) |
1766 | { |
1767 | MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN); |
1768 | MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN); |
1769 | unsigned int flags, index; |
1770 | const char *reason; |
1771 | size_t outlen; |
1772 | int retry; |
1773 | int rc; |
1774 | |
1775 | /* Attempt to read any stored assertion state before we reboot |
1776 | * the mcfw out of the assertion handler. Retry twice, once |
1777 | * because a boot-time assertion might cause this command to fail |
1778 | * with EINTR. And once again because GET_ASSERTS can race with |
1779 | * MC_CMD_REBOOT running on the other port. */ |
1780 | retry = 2; |
1781 | do { |
1782 | MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1); |
1783 | rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_ASSERTS, |
1784 | inbuf, MC_CMD_GET_ASSERTS_IN_LEN, |
1785 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
1786 | if (rc == -EPERM) |
1787 | return 0; |
1788 | } while ((rc == -EINTR || rc == -EIO) && retry-- > 0); |
1789 | |
1790 | if (rc) { |
1791 | efx_mcdi_display_error(efx, MC_CMD_GET_ASSERTS, |
1792 | MC_CMD_GET_ASSERTS_IN_LEN, outbuf, |
1793 | outlen, rc); |
1794 | return rc; |
1795 | } |
1796 | if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN) |
1797 | return -EIO; |
1798 | |
1799 | /* Print out any recorded assertion state */ |
1800 | flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS); |
1801 | if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) |
1802 | return 0; |
1803 | |
1804 | reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) |
1805 | ? "system-level assertion" |
1806 | : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) |
1807 | ? "thread-level assertion" |
1808 | : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) |
1809 | ? "watchdog reset" |
1810 | : "unknown assertion" ; |
1811 | netif_err(efx, hw, efx->net_dev, |
1812 | "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n" , reason, |
1813 | MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS), |
1814 | MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS)); |
1815 | |
1816 | /* Print out the registers */ |
1817 | for (index = 0; |
1818 | index < MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM; |
1819 | index++) |
1820 | netif_err(efx, hw, efx->net_dev, "R%.2d (?): 0x%.8x\n" , |
1821 | 1 + index, |
1822 | MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS, |
1823 | index)); |
1824 | |
1825 | return 1; |
1826 | } |
1827 | |
1828 | static int efx_mcdi_exit_assertion(struct efx_nic *efx) |
1829 | { |
1830 | MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN); |
1831 | int rc; |
1832 | |
1833 | /* If the MC is running debug firmware, it might now be |
1834 | * waiting for a debugger to attach, but we just want it to |
1835 | * reboot. We set a flag that makes the command a no-op if it |
1836 | * has already done so. |
1837 | * The MCDI will thus return either 0 or -EIO. |
1838 | */ |
1839 | BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); |
1840 | MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, |
1841 | MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION); |
1842 | rc = efx_mcdi_rpc_quiet(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN, |
1843 | NULL, outlen: 0, NULL); |
1844 | if (rc == -EIO) |
1845 | rc = 0; |
1846 | if (rc) |
1847 | efx_mcdi_display_error(efx, MC_CMD_REBOOT, MC_CMD_REBOOT_IN_LEN, |
1848 | NULL, outlen: 0, rc); |
1849 | return rc; |
1850 | } |
1851 | |
1852 | int efx_mcdi_handle_assertion(struct efx_nic *efx) |
1853 | { |
1854 | int rc; |
1855 | |
1856 | rc = efx_mcdi_read_assertion(efx); |
1857 | if (rc <= 0) |
1858 | return rc; |
1859 | |
1860 | return efx_mcdi_exit_assertion(efx); |
1861 | } |
1862 | |
1863 | int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) |
1864 | { |
1865 | MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_ID_LED_IN_LEN); |
1866 | |
1867 | BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF); |
1868 | BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON); |
1869 | BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT); |
1870 | |
1871 | BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0); |
1872 | |
1873 | MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode); |
1874 | |
1875 | return efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, inlen: sizeof(inbuf), NULL, outlen: 0, NULL); |
1876 | } |
1877 | |
1878 | static int efx_mcdi_reset_func(struct efx_nic *efx) |
1879 | { |
1880 | MCDI_DECLARE_BUF(inbuf, MC_CMD_ENTITY_RESET_IN_LEN); |
1881 | int rc; |
1882 | |
1883 | BUILD_BUG_ON(MC_CMD_ENTITY_RESET_OUT_LEN != 0); |
1884 | MCDI_POPULATE_DWORD_1(inbuf, ENTITY_RESET_IN_FLAG, |
1885 | ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1); |
1886 | rc = efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, inbuf, inlen: sizeof(inbuf), |
1887 | NULL, outlen: 0, NULL); |
1888 | return rc; |
1889 | } |
1890 | |
1891 | static int efx_mcdi_reset_mc(struct efx_nic *efx) |
1892 | { |
1893 | MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN); |
1894 | int rc; |
1895 | |
1896 | BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); |
1897 | MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0); |
1898 | rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, inlen: sizeof(inbuf), |
1899 | NULL, outlen: 0, NULL); |
1900 | /* White is black, and up is down */ |
1901 | if (rc == -EIO) |
1902 | return 0; |
1903 | if (rc == 0) |
1904 | rc = -EIO; |
1905 | return rc; |
1906 | } |
1907 | |
1908 | enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason) |
1909 | { |
1910 | return RESET_TYPE_RECOVER_OR_ALL; |
1911 | } |
1912 | |
1913 | int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method) |
1914 | { |
1915 | int rc; |
1916 | |
1917 | /* If MCDI is down, we can't handle_assertion */ |
1918 | if (method == RESET_TYPE_MCDI_TIMEOUT) { |
1919 | rc = pci_reset_function(dev: efx->pci_dev); |
1920 | if (rc) |
1921 | return rc; |
1922 | /* Re-enable polled MCDI completion */ |
1923 | if (efx->mcdi) { |
1924 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
1925 | mcdi->mode = MCDI_MODE_POLL; |
1926 | } |
1927 | return 0; |
1928 | } |
1929 | |
1930 | /* Recover from a failed assertion pre-reset */ |
1931 | rc = efx_mcdi_handle_assertion(efx); |
1932 | if (rc) |
1933 | return rc; |
1934 | |
1935 | if (method == RESET_TYPE_DATAPATH) |
1936 | return 0; |
1937 | else if (method == RESET_TYPE_WORLD) |
1938 | return efx_mcdi_reset_mc(efx); |
1939 | else |
1940 | return efx_mcdi_reset_func(efx); |
1941 | } |
1942 | |
1943 | static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, |
1944 | const u8 *mac, int *id_out) |
1945 | { |
1946 | MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_SET_IN_LEN); |
1947 | MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_SET_OUT_LEN); |
1948 | size_t outlen; |
1949 | int rc; |
1950 | |
1951 | MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type); |
1952 | MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE, |
1953 | MC_CMD_FILTER_MODE_SIMPLE); |
1954 | ether_addr_copy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), src: mac); |
1955 | |
1956 | rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, inlen: sizeof(inbuf), |
1957 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
1958 | if (rc) |
1959 | goto fail; |
1960 | |
1961 | if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) { |
1962 | rc = -EIO; |
1963 | goto fail; |
1964 | } |
1965 | |
1966 | *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID); |
1967 | |
1968 | return 0; |
1969 | |
1970 | fail: |
1971 | *id_out = -1; |
1972 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n" , __func__, rc); |
1973 | return rc; |
1974 | |
1975 | } |
1976 | |
1977 | |
1978 | int |
1979 | efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out) |
1980 | { |
1981 | return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out); |
1982 | } |
1983 | |
1984 | |
1985 | int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out) |
1986 | { |
1987 | MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_GET_OUT_LEN); |
1988 | size_t outlen; |
1989 | int rc; |
1990 | |
1991 | rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, inlen: 0, |
1992 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
1993 | if (rc) |
1994 | goto fail; |
1995 | |
1996 | if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) { |
1997 | rc = -EIO; |
1998 | goto fail; |
1999 | } |
2000 | |
2001 | *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID); |
2002 | |
2003 | return 0; |
2004 | |
2005 | fail: |
2006 | *id_out = -1; |
2007 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n" , __func__, rc); |
2008 | return rc; |
2009 | } |
2010 | |
2011 | |
2012 | int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id) |
2013 | { |
2014 | MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_REMOVE_IN_LEN); |
2015 | int rc; |
2016 | |
2017 | MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id); |
2018 | |
2019 | rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, inlen: sizeof(inbuf), |
2020 | NULL, outlen: 0, NULL); |
2021 | return rc; |
2022 | } |
2023 | |
2024 | int efx_mcdi_flush_rxqs(struct efx_nic *efx) |
2025 | { |
2026 | struct efx_channel *channel; |
2027 | struct efx_rx_queue *rx_queue; |
2028 | MCDI_DECLARE_BUF(inbuf, |
2029 | MC_CMD_FLUSH_RX_QUEUES_IN_LEN(EFX_MAX_CHANNELS)); |
2030 | int rc, count; |
2031 | |
2032 | BUILD_BUG_ON(EFX_MAX_CHANNELS > |
2033 | MC_CMD_FLUSH_RX_QUEUES_IN_QID_OFST_MAXNUM); |
2034 | |
2035 | count = 0; |
2036 | efx_for_each_channel(channel, efx) { |
2037 | efx_for_each_channel_rx_queue(rx_queue, channel) { |
2038 | if (rx_queue->flush_pending) { |
2039 | rx_queue->flush_pending = false; |
2040 | atomic_dec(v: &efx->rxq_flush_pending); |
2041 | MCDI_SET_ARRAY_DWORD( |
2042 | inbuf, FLUSH_RX_QUEUES_IN_QID_OFST, |
2043 | count, efx_rx_queue_index(rx_queue)); |
2044 | count++; |
2045 | } |
2046 | } |
2047 | } |
2048 | |
2049 | rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, inbuf, |
2050 | MC_CMD_FLUSH_RX_QUEUES_IN_LEN(count), NULL, outlen: 0, NULL); |
2051 | WARN_ON(rc < 0); |
2052 | |
2053 | return rc; |
2054 | } |
2055 | |
2056 | int efx_mcdi_wol_filter_reset(struct efx_nic *efx) |
2057 | { |
2058 | int rc; |
2059 | |
2060 | rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, inlen: 0, NULL, outlen: 0, NULL); |
2061 | return rc; |
2062 | } |
2063 | |
2064 | int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled, |
2065 | unsigned int *flags) |
2066 | { |
2067 | MCDI_DECLARE_BUF(inbuf, MC_CMD_WORKAROUND_IN_LEN); |
2068 | MCDI_DECLARE_BUF(outbuf, MC_CMD_WORKAROUND_EXT_OUT_LEN); |
2069 | size_t outlen; |
2070 | int rc; |
2071 | |
2072 | BUILD_BUG_ON(MC_CMD_WORKAROUND_OUT_LEN != 0); |
2073 | MCDI_SET_DWORD(inbuf, WORKAROUND_IN_TYPE, type); |
2074 | MCDI_SET_DWORD(inbuf, WORKAROUND_IN_ENABLED, enabled); |
2075 | rc = efx_mcdi_rpc(efx, MC_CMD_WORKAROUND, inbuf, inlen: sizeof(inbuf), |
2076 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
2077 | if (rc) |
2078 | return rc; |
2079 | |
2080 | if (!flags) |
2081 | return 0; |
2082 | |
2083 | if (outlen >= MC_CMD_WORKAROUND_EXT_OUT_LEN) |
2084 | *flags = MCDI_DWORD(outbuf, WORKAROUND_EXT_OUT_FLAGS); |
2085 | else |
2086 | *flags = 0; |
2087 | |
2088 | return 0; |
2089 | } |
2090 | |
2091 | int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out, |
2092 | unsigned int *enabled_out) |
2093 | { |
2094 | MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_WORKAROUNDS_OUT_LEN); |
2095 | size_t outlen; |
2096 | int rc; |
2097 | |
2098 | rc = efx_mcdi_rpc(efx, MC_CMD_GET_WORKAROUNDS, NULL, inlen: 0, |
2099 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
2100 | if (rc) |
2101 | goto fail; |
2102 | |
2103 | if (outlen < MC_CMD_GET_WORKAROUNDS_OUT_LEN) { |
2104 | rc = -EIO; |
2105 | goto fail; |
2106 | } |
2107 | |
2108 | if (impl_out) |
2109 | *impl_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_IMPLEMENTED); |
2110 | |
2111 | if (enabled_out) |
2112 | *enabled_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_ENABLED); |
2113 | |
2114 | return 0; |
2115 | |
2116 | fail: |
2117 | /* Older firmware lacks GET_WORKAROUNDS and this isn't especially |
2118 | * terrifying. The call site will have to deal with it though. |
2119 | */ |
2120 | netif_cond_dbg(efx, hw, efx->net_dev, rc == -ENOSYS, err, |
2121 | "%s: failed rc=%d\n" , __func__, rc); |
2122 | return rc; |
2123 | } |
2124 | |
2125 | /* Failure to read a privilege mask is never fatal, because we can always |
2126 | * carry on as though we didn't have the privilege we were interested in. |
2127 | * So use efx_mcdi_rpc_quiet(). |
2128 | */ |
2129 | int efx_mcdi_get_privilege_mask(struct efx_nic *efx, u32 *mask) |
2130 | { |
2131 | MCDI_DECLARE_BUF(fi_outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN); |
2132 | MCDI_DECLARE_BUF(pm_inbuf, MC_CMD_PRIVILEGE_MASK_IN_LEN); |
2133 | MCDI_DECLARE_BUF(pm_outbuf, MC_CMD_PRIVILEGE_MASK_OUT_LEN); |
2134 | size_t outlen; |
2135 | u16 pf, vf; |
2136 | int rc; |
2137 | |
2138 | if (!efx || !mask) |
2139 | return -EINVAL; |
2140 | |
2141 | /* Get our function number */ |
2142 | rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_FUNCTION_INFO, NULL, inlen: 0, |
2143 | outbuf: fi_outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN, |
2144 | outlen_actual: &outlen); |
2145 | if (rc != 0) |
2146 | return rc; |
2147 | if (outlen < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) |
2148 | return -EIO; |
2149 | |
2150 | pf = MCDI_DWORD(fi_outbuf, GET_FUNCTION_INFO_OUT_PF); |
2151 | vf = MCDI_DWORD(fi_outbuf, GET_FUNCTION_INFO_OUT_VF); |
2152 | |
2153 | MCDI_POPULATE_DWORD_2(pm_inbuf, PRIVILEGE_MASK_IN_FUNCTION, |
2154 | PRIVILEGE_MASK_IN_FUNCTION_PF, pf, |
2155 | PRIVILEGE_MASK_IN_FUNCTION_VF, vf); |
2156 | |
2157 | rc = efx_mcdi_rpc_quiet(efx, MC_CMD_PRIVILEGE_MASK, |
2158 | inbuf: pm_inbuf, inlen: sizeof(pm_inbuf), |
2159 | outbuf: pm_outbuf, outlen: sizeof(pm_outbuf), outlen_actual: &outlen); |
2160 | |
2161 | if (rc != 0) |
2162 | return rc; |
2163 | if (outlen < MC_CMD_PRIVILEGE_MASK_OUT_LEN) |
2164 | return -EIO; |
2165 | |
2166 | *mask = MCDI_DWORD(pm_outbuf, PRIVILEGE_MASK_OUT_OLD_MASK); |
2167 | |
2168 | return 0; |
2169 | } |
2170 | |
2171 | int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type, |
2172 | u32 *subtype, u16 version[4], char *desc, |
2173 | size_t descsize) |
2174 | { |
2175 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN); |
2176 | efx_dword_t *outbuf; |
2177 | size_t outlen; |
2178 | u32 flags; |
2179 | int rc; |
2180 | |
2181 | outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL); |
2182 | if (!outbuf) |
2183 | return -ENOMEM; |
2184 | |
2185 | MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type); |
2186 | |
2187 | rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf, |
2188 | inlen: sizeof(inbuf), outbuf, |
2189 | MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, |
2190 | outlen_actual: &outlen); |
2191 | if (rc) |
2192 | goto out_free; |
2193 | if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) { |
2194 | rc = -EIO; |
2195 | goto out_free; |
2196 | } |
2197 | |
2198 | flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS); |
2199 | |
2200 | if (desc && descsize > 0) { |
2201 | if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) { |
2202 | if (descsize <= |
2203 | MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) { |
2204 | rc = -E2BIG; |
2205 | goto out_free; |
2206 | } |
2207 | |
2208 | strscpy(p: desc, |
2209 | MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION), |
2210 | MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)); |
2211 | } else { |
2212 | desc[0] = '\0'; |
2213 | } |
2214 | } |
2215 | |
2216 | if (subtype) { |
2217 | if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN)) |
2218 | *subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE); |
2219 | else |
2220 | *subtype = 0; |
2221 | } |
2222 | |
2223 | if (version) { |
2224 | if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) { |
2225 | version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W); |
2226 | version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X); |
2227 | version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y); |
2228 | version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z); |
2229 | } else { |
2230 | version[0] = 0; |
2231 | version[1] = 0; |
2232 | version[2] = 0; |
2233 | version[3] = 0; |
2234 | } |
2235 | } |
2236 | |
2237 | out_free: |
2238 | kfree(objp: outbuf); |
2239 | return rc; |
2240 | } |
2241 | |
2242 | #ifdef CONFIG_SFC_MTD |
2243 | |
2244 | #define EFX_MCDI_NVRAM_LEN_MAX 128 |
2245 | |
2246 | static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type) |
2247 | { |
2248 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN); |
2249 | int rc; |
2250 | |
2251 | MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type); |
2252 | MCDI_POPULATE_DWORD_1(inbuf, NVRAM_UPDATE_START_V2_IN_FLAGS, |
2253 | NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, |
2254 | 1); |
2255 | |
2256 | BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0); |
2257 | |
2258 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, inlen: sizeof(inbuf), |
2259 | NULL, outlen: 0, NULL); |
2260 | |
2261 | return rc; |
2262 | } |
2263 | |
2264 | static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, |
2265 | loff_t offset, u8 *buffer, size_t length) |
2266 | { |
2267 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_V2_LEN); |
2268 | MCDI_DECLARE_BUF(outbuf, |
2269 | MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX)); |
2270 | size_t outlen; |
2271 | int rc; |
2272 | |
2273 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type); |
2274 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset); |
2275 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length); |
2276 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_V2_MODE, |
2277 | MC_CMD_NVRAM_READ_IN_V2_DEFAULT); |
2278 | |
2279 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, inlen: sizeof(inbuf), |
2280 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
2281 | if (rc) |
2282 | return rc; |
2283 | |
2284 | memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length); |
2285 | return 0; |
2286 | } |
2287 | |
2288 | static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, |
2289 | loff_t offset, const u8 *buffer, size_t length) |
2290 | { |
2291 | MCDI_DECLARE_BUF(inbuf, |
2292 | MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX)); |
2293 | int rc; |
2294 | |
2295 | MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type); |
2296 | MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset); |
2297 | MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length); |
2298 | memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length); |
2299 | |
2300 | BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0); |
2301 | |
2302 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, |
2303 | ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4), |
2304 | NULL, outlen: 0, NULL); |
2305 | return rc; |
2306 | } |
2307 | |
2308 | static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, |
2309 | loff_t offset, size_t length) |
2310 | { |
2311 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN); |
2312 | int rc; |
2313 | |
2314 | MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type); |
2315 | MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset); |
2316 | MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length); |
2317 | |
2318 | BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0); |
2319 | |
2320 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, inlen: sizeof(inbuf), |
2321 | NULL, outlen: 0, NULL); |
2322 | return rc; |
2323 | } |
2324 | |
2325 | static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type) |
2326 | { |
2327 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN); |
2328 | MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN); |
2329 | size_t outlen; |
2330 | int rc, rc2; |
2331 | |
2332 | MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type); |
2333 | /* Always set this flag. Old firmware ignores it */ |
2334 | MCDI_POPULATE_DWORD_1(inbuf, NVRAM_UPDATE_FINISH_V2_IN_FLAGS, |
2335 | NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, |
2336 | 1); |
2337 | |
2338 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, inlen: sizeof(inbuf), |
2339 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
2340 | if (!rc && outlen >= MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) { |
2341 | rc2 = MCDI_DWORD(outbuf, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE); |
2342 | if (rc2 != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) |
2343 | netif_err(efx, drv, efx->net_dev, |
2344 | "NVRAM update failed verification with code 0x%x\n" , |
2345 | rc2); |
2346 | switch (rc2) { |
2347 | case MC_CMD_NVRAM_VERIFY_RC_SUCCESS: |
2348 | break; |
2349 | case MC_CMD_NVRAM_VERIFY_RC_CMS_CHECK_FAILED: |
2350 | case MC_CMD_NVRAM_VERIFY_RC_MESSAGE_DIGEST_CHECK_FAILED: |
2351 | case MC_CMD_NVRAM_VERIFY_RC_SIGNATURE_CHECK_FAILED: |
2352 | case MC_CMD_NVRAM_VERIFY_RC_TRUSTED_APPROVERS_CHECK_FAILED: |
2353 | case MC_CMD_NVRAM_VERIFY_RC_SIGNATURE_CHAIN_CHECK_FAILED: |
2354 | rc = -EIO; |
2355 | break; |
2356 | case MC_CMD_NVRAM_VERIFY_RC_INVALID_CMS_FORMAT: |
2357 | case MC_CMD_NVRAM_VERIFY_RC_BAD_MESSAGE_DIGEST: |
2358 | rc = -EINVAL; |
2359 | break; |
2360 | case MC_CMD_NVRAM_VERIFY_RC_NO_VALID_SIGNATURES: |
2361 | case MC_CMD_NVRAM_VERIFY_RC_NO_TRUSTED_APPROVERS: |
2362 | case MC_CMD_NVRAM_VERIFY_RC_NO_SIGNATURE_MATCH: |
2363 | rc = -EPERM; |
2364 | break; |
2365 | default: |
2366 | netif_err(efx, drv, efx->net_dev, |
2367 | "Unknown response to NVRAM_UPDATE_FINISH\n" ); |
2368 | rc = -EIO; |
2369 | } |
2370 | } |
2371 | |
2372 | return rc; |
2373 | } |
2374 | |
2375 | int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start, |
2376 | size_t len, size_t *retlen, u8 *buffer) |
2377 | { |
2378 | struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd); |
2379 | struct efx_nic *efx = mtd->priv; |
2380 | loff_t offset = start; |
2381 | loff_t end = min_t(loff_t, start + len, mtd->size); |
2382 | size_t chunk; |
2383 | int rc = 0; |
2384 | |
2385 | while (offset < end) { |
2386 | chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX); |
2387 | rc = efx_mcdi_nvram_read(efx, type: part->nvram_type, offset, |
2388 | buffer, length: chunk); |
2389 | if (rc) |
2390 | goto out; |
2391 | offset += chunk; |
2392 | buffer += chunk; |
2393 | } |
2394 | out: |
2395 | *retlen = offset - start; |
2396 | return rc; |
2397 | } |
2398 | |
2399 | int efx_mcdi_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) |
2400 | { |
2401 | struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd); |
2402 | struct efx_nic *efx = mtd->priv; |
2403 | loff_t offset = start & ~((loff_t)(mtd->erasesize - 1)); |
2404 | loff_t end = min_t(loff_t, start + len, mtd->size); |
2405 | size_t chunk = part->common.mtd.erasesize; |
2406 | int rc = 0; |
2407 | |
2408 | if (!part->updating) { |
2409 | rc = efx_mcdi_nvram_update_start(efx, type: part->nvram_type); |
2410 | if (rc) |
2411 | goto out; |
2412 | part->updating = true; |
2413 | } |
2414 | |
2415 | /* The MCDI interface can in fact do multiple erase blocks at once; |
2416 | * but erasing may be slow, so we make multiple calls here to avoid |
2417 | * tripping the MCDI RPC timeout. */ |
2418 | while (offset < end) { |
2419 | rc = efx_mcdi_nvram_erase(efx, type: part->nvram_type, offset, |
2420 | length: chunk); |
2421 | if (rc) |
2422 | goto out; |
2423 | offset += chunk; |
2424 | } |
2425 | out: |
2426 | return rc; |
2427 | } |
2428 | |
2429 | int efx_mcdi_mtd_write(struct mtd_info *mtd, loff_t start, |
2430 | size_t len, size_t *retlen, const u8 *buffer) |
2431 | { |
2432 | struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd); |
2433 | struct efx_nic *efx = mtd->priv; |
2434 | loff_t offset = start; |
2435 | loff_t end = min_t(loff_t, start + len, mtd->size); |
2436 | size_t chunk; |
2437 | int rc = 0; |
2438 | |
2439 | if (!part->updating) { |
2440 | rc = efx_mcdi_nvram_update_start(efx, type: part->nvram_type); |
2441 | if (rc) |
2442 | goto out; |
2443 | part->updating = true; |
2444 | } |
2445 | |
2446 | while (offset < end) { |
2447 | chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX); |
2448 | rc = efx_mcdi_nvram_write(efx, type: part->nvram_type, offset, |
2449 | buffer, length: chunk); |
2450 | if (rc) |
2451 | goto out; |
2452 | offset += chunk; |
2453 | buffer += chunk; |
2454 | } |
2455 | out: |
2456 | *retlen = offset - start; |
2457 | return rc; |
2458 | } |
2459 | |
2460 | int efx_mcdi_mtd_sync(struct mtd_info *mtd) |
2461 | { |
2462 | struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd); |
2463 | struct efx_nic *efx = mtd->priv; |
2464 | int rc = 0; |
2465 | |
2466 | if (part->updating) { |
2467 | part->updating = false; |
2468 | rc = efx_mcdi_nvram_update_finish(efx, type: part->nvram_type); |
2469 | } |
2470 | |
2471 | return rc; |
2472 | } |
2473 | |
2474 | void efx_mcdi_mtd_rename(struct efx_mtd_partition *part) |
2475 | { |
2476 | struct efx_mcdi_mtd_partition *mcdi_part = |
2477 | container_of(part, struct efx_mcdi_mtd_partition, common); |
2478 | struct efx_nic *efx = part->mtd.priv; |
2479 | |
2480 | snprintf(buf: part->name, size: sizeof(part->name), fmt: "%s %s:%02x" , |
2481 | efx->name, part->type_name, mcdi_part->fw_subtype); |
2482 | } |
2483 | |
2484 | #endif /* CONFIG_SFC_MTD */ |
2485 | |