1 // SPDX-License-Identifier: GPL-2.0
3 * Management-Controller-to-Driver Interface
5 * Copyright 2008-2013 Solarflare Communications Inc.
6 * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
8 #include <linux/delay.h>
9 #include <linux/slab.h>
11 #include <linux/spinlock.h>
12 #include <linux/netdevice.h>
13 #include <linux/etherdevice.h>
14 #include <linux/ethtool.h>
15 #include <linux/if_vlan.h>
16 #include <linux/timer.h>
17 #include <linux/list.h>
18 #include <linux/pci.h>
19 #include <linux/device.h>
20 #include <linux/rwsem.h>
21 #include <linux/vmalloc.h>
22 #include <net/netevent.h>
23 #include <linux/log2.h>
24 #include <linux/net_tstamp.h>
25 #include <linux/wait.h>
30 static void cdx_mcdi_cancel_cmd(struct cdx_mcdi
*cdx
, struct cdx_mcdi_cmd
*cmd
);
31 static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi
*cdx
);
32 static int cdx_mcdi_rpc_async_internal(struct cdx_mcdi
*cdx
,
33 struct cdx_mcdi_cmd
*cmd
,
34 unsigned int *handle
);
35 static void cdx_mcdi_start_or_queue(struct cdx_mcdi_iface
*mcdi
,
37 static void cdx_mcdi_cmd_start_or_queue(struct cdx_mcdi_iface
*mcdi
,
38 struct cdx_mcdi_cmd
*cmd
);
39 static bool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface
*mcdi
,
40 struct cdx_mcdi_cmd
*cmd
,
41 struct cdx_dword
*outbuf
,
43 struct list_head
*cleanup_list
);
44 static void cdx_mcdi_timeout_cmd(struct cdx_mcdi_iface
*mcdi
,
45 struct cdx_mcdi_cmd
*cmd
,
46 struct list_head
*cleanup_list
);
47 static void cdx_mcdi_cmd_work(struct work_struct
*context
);
48 static void cdx_mcdi_mode_fail(struct cdx_mcdi
*cdx
, struct list_head
*cleanup_list
);
49 static void _cdx_mcdi_display_error(struct cdx_mcdi
*cdx
, unsigned int cmd
,
50 size_t inlen
, int raw
, int arg
, int err_no
);
52 static bool cdx_cmd_cancelled(struct cdx_mcdi_cmd
*cmd
)
54 return cmd
->state
== MCDI_STATE_RUNNING_CANCELLED
;
57 static void cdx_mcdi_cmd_release(struct kref
*ref
)
59 kfree(container_of(ref
, struct cdx_mcdi_cmd
, ref
));
62 static unsigned int cdx_mcdi_cmd_handle(struct cdx_mcdi_cmd
*cmd
)
67 static void _cdx_mcdi_remove_cmd(struct cdx_mcdi_iface
*mcdi
,
68 struct cdx_mcdi_cmd
*cmd
,
69 struct list_head
*cleanup_list
)
71 /* if cancelled, the completers have already been called */
72 if (cdx_cmd_cancelled(cmd
))
76 list_add_tail(&cmd
->cleanup_list
, cleanup_list
);
77 ++mcdi
->outstanding_cleanups
;
82 static void cdx_mcdi_remove_cmd(struct cdx_mcdi_iface
*mcdi
,
83 struct cdx_mcdi_cmd
*cmd
,
84 struct list_head
*cleanup_list
)
87 _cdx_mcdi_remove_cmd(mcdi
, cmd
, cleanup_list
);
88 cmd
->state
= MCDI_STATE_FINISHED
;
89 kref_put(&cmd
->ref
, cdx_mcdi_cmd_release
);
90 if (list_empty(&mcdi
->cmd_list
))
91 wake_up(&mcdi
->cmd_complete_wq
);
94 static unsigned long cdx_mcdi_rpc_timeout(struct cdx_mcdi
*cdx
, unsigned int cmd
)
96 if (!cdx
->mcdi_ops
->mcdi_rpc_timeout
)
97 return MCDI_RPC_TIMEOUT
;
99 return cdx
->mcdi_ops
->mcdi_rpc_timeout(cdx
, cmd
);
102 int cdx_mcdi_init(struct cdx_mcdi
*cdx
)
104 struct cdx_mcdi_iface
*mcdi
;
107 cdx
->mcdi
= kzalloc(sizeof(*cdx
->mcdi
), GFP_KERNEL
);
111 mcdi
= cdx_mcdi_if(cdx
);
114 mcdi
->workqueue
= alloc_ordered_workqueue("mcdi_wq", 0);
115 if (!mcdi
->workqueue
)
117 mutex_init(&mcdi
->iface_lock
);
118 mcdi
->mode
= MCDI_MODE_EVENTS
;
119 INIT_LIST_HEAD(&mcdi
->cmd_list
);
120 init_waitqueue_head(&mcdi
->cmd_complete_wq
);
122 mcdi
->new_epoch
= true;
132 void cdx_mcdi_finish(struct cdx_mcdi
*cdx
)
134 struct cdx_mcdi_iface
*mcdi
;
136 mcdi
= cdx_mcdi_if(cdx
);
140 cdx_mcdi_wait_for_cleanup(cdx
);
142 destroy_workqueue(mcdi
->workqueue
);
147 static bool cdx_mcdi_flushed(struct cdx_mcdi_iface
*mcdi
, bool ignore_cleanups
)
151 mutex_lock(&mcdi
->iface_lock
);
152 flushed
= list_empty(&mcdi
->cmd_list
) &&
153 (ignore_cleanups
|| !mcdi
->outstanding_cleanups
);
154 mutex_unlock(&mcdi
->iface_lock
);
158 /* Wait for outstanding MCDI commands to complete. */
159 static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi
*cdx
)
161 struct cdx_mcdi_iface
*mcdi
= cdx_mcdi_if(cdx
);
166 wait_event(mcdi
->cmd_complete_wq
,
167 cdx_mcdi_flushed(mcdi
, false));
170 int cdx_mcdi_wait_for_quiescence(struct cdx_mcdi
*cdx
,
171 unsigned int timeout_jiffies
)
173 struct cdx_mcdi_iface
*mcdi
= cdx_mcdi_if(cdx
);
174 DEFINE_WAIT_FUNC(wait
, woken_wake_function
);
180 flush_workqueue(mcdi
->workqueue
);
182 add_wait_queue(&mcdi
->cmd_complete_wq
, &wait
);
184 while (!cdx_mcdi_flushed(mcdi
, true)) {
185 rc
= wait_woken(&wait
, TASK_IDLE
, timeout_jiffies
);
191 remove_wait_queue(&mcdi
->cmd_complete_wq
, &wait
);
201 static u8
cdx_mcdi_payload_csum(const struct cdx_dword
*hdr
, size_t hdr_len
,
202 const struct cdx_dword
*sdu
, size_t sdu_len
)
208 for (i
= 0; i
< hdr_len
; i
++)
212 for (i
= 0; i
< sdu_len
; i
++)
218 static void cdx_mcdi_send_request(struct cdx_mcdi
*cdx
,
219 struct cdx_mcdi_cmd
*cmd
)
221 struct cdx_mcdi_iface
*mcdi
= cdx_mcdi_if(cdx
);
222 const struct cdx_dword
*inbuf
= cmd
->inbuf
;
223 size_t inlen
= cmd
->inlen
;
224 struct cdx_dword hdr
[2];
232 mcdi
->prev_seq
= cmd
->seq
;
233 mcdi
->seq_held_by
[cmd
->seq
] = cmd
;
234 mcdi
->db_held_by
= cmd
;
235 cmd
->started
= jiffies
;
237 not_epoch
= !mcdi
->new_epoch
;
241 WARN_ON(inlen
> MCDI_CTL_SDU_LEN_MAX_V2
);
242 CDX_POPULATE_DWORD_7(hdr
[0],
243 MCDI_HEADER_RESPONSE
, 0,
244 MCDI_HEADER_RESYNC
, 1,
245 MCDI_HEADER_CODE
, MC_CMD_V2_EXTN
,
246 MCDI_HEADER_DATALEN
, 0,
247 MCDI_HEADER_SEQ
, cmd
->seq
,
248 MCDI_HEADER_XFLAGS
, xflags
,
249 MCDI_HEADER_NOT_EPOCH
, not_epoch
);
250 CDX_POPULATE_DWORD_3(hdr
[1],
251 MC_CMD_V2_EXTN_IN_EXTENDED_CMD
, cmd
->cmd
,
252 MC_CMD_V2_EXTN_IN_ACTUAL_LEN
, inlen
,
253 MC_CMD_V2_EXTN_IN_MESSAGE_TYPE
,
254 MC_CMD_V2_EXTN_IN_MCDI_MESSAGE_TYPE_PLATFORM
);
257 hdr
[0].cdx_u32
|= (__force __le32
)(cdx_mcdi_payload_csum(hdr
, hdr_len
, inbuf
, inlen
) <<
258 MCDI_HEADER_XFLAGS_LBN
);
260 print_hex_dump_debug("MCDI REQ HEADER: ", DUMP_PREFIX_NONE
, 32, 4, hdr
, hdr_len
, false);
261 print_hex_dump_debug("MCDI REQ PAYLOAD: ", DUMP_PREFIX_NONE
, 32, 4, inbuf
, inlen
, false);
263 cdx
->mcdi_ops
->mcdi_request(cdx
, hdr
, hdr_len
, inbuf
, inlen
);
265 mcdi
->new_epoch
= false;
268 static int cdx_mcdi_errno(struct cdx_mcdi
*cdx
, unsigned int mcdi_err
)
272 case MC_CMD_ERR_QUEUE_FULL
:
274 case MC_CMD_ERR_EPERM
:
276 case MC_CMD_ERR_ENOENT
:
278 case MC_CMD_ERR_EINTR
:
280 case MC_CMD_ERR_EAGAIN
:
282 case MC_CMD_ERR_EACCES
:
284 case MC_CMD_ERR_EBUSY
:
286 case MC_CMD_ERR_EINVAL
:
288 case MC_CMD_ERR_ERANGE
:
290 case MC_CMD_ERR_EDEADLK
:
292 case MC_CMD_ERR_ENOSYS
:
294 case MC_CMD_ERR_ETIME
:
296 case MC_CMD_ERR_EALREADY
:
298 case MC_CMD_ERR_ENOSPC
:
300 case MC_CMD_ERR_ENOMEM
:
302 case MC_CMD_ERR_ENOTSUP
:
304 case MC_CMD_ERR_ALLOC_FAIL
:
306 case MC_CMD_ERR_MAC_EXIST
:
308 case MC_CMD_ERR_NO_EVB_PORT
:
315 static void cdx_mcdi_process_cleanup_list(struct cdx_mcdi
*cdx
,
316 struct list_head
*cleanup_list
)
318 struct cdx_mcdi_iface
*mcdi
= cdx_mcdi_if(cdx
);
319 unsigned int cleanups
= 0;
324 while (!list_empty(cleanup_list
)) {
325 struct cdx_mcdi_cmd
*cmd
=
326 list_first_entry(cleanup_list
,
327 struct cdx_mcdi_cmd
, cleanup_list
);
328 cmd
->completer(cdx
, cmd
->cookie
, cmd
->rc
,
329 cmd
->outbuf
, cmd
->outlen
);
330 list_del(&cmd
->cleanup_list
);
331 kref_put(&cmd
->ref
, cdx_mcdi_cmd_release
);
338 mutex_lock(&mcdi
->iface_lock
);
339 CDX_WARN_ON_PARANOID(cleanups
> mcdi
->outstanding_cleanups
);
340 all_done
= (mcdi
->outstanding_cleanups
-= cleanups
) == 0;
341 mutex_unlock(&mcdi
->iface_lock
);
343 wake_up(&mcdi
->cmd_complete_wq
);
347 static void _cdx_mcdi_cancel_cmd(struct cdx_mcdi_iface
*mcdi
,
349 struct list_head
*cleanup_list
)
351 struct cdx_mcdi_cmd
*cmd
;
353 list_for_each_entry(cmd
, &mcdi
->cmd_list
, list
)
354 if (cdx_mcdi_cmd_handle(cmd
) == handle
) {
355 switch (cmd
->state
) {
356 case MCDI_STATE_QUEUED
:
357 case MCDI_STATE_RETRY
:
358 pr_debug("command %#x inlen %zu cancelled in queue\n",
359 cmd
->cmd
, cmd
->inlen
);
360 /* if not yet running, properly cancel it */
362 cdx_mcdi_remove_cmd(mcdi
, cmd
, cleanup_list
);
364 case MCDI_STATE_RUNNING
:
365 case MCDI_STATE_RUNNING_CANCELLED
:
366 case MCDI_STATE_FINISHED
:
375 static void cdx_mcdi_cancel_cmd(struct cdx_mcdi
*cdx
, struct cdx_mcdi_cmd
*cmd
)
377 struct cdx_mcdi_iface
*mcdi
= cdx_mcdi_if(cdx
);
378 LIST_HEAD(cleanup_list
);
383 mutex_lock(&mcdi
->iface_lock
);
384 cdx_mcdi_timeout_cmd(mcdi
, cmd
, &cleanup_list
);
385 mutex_unlock(&mcdi
->iface_lock
);
386 cdx_mcdi_process_cleanup_list(cdx
, &cleanup_list
);
389 struct cdx_mcdi_blocking_data
{
392 wait_queue_head_t wq
;
394 struct cdx_dword
*outbuf
;
396 size_t outlen_actual
;
399 static void cdx_mcdi_blocking_data_release(struct kref
*ref
)
401 kfree(container_of(ref
, struct cdx_mcdi_blocking_data
, ref
));
404 static void cdx_mcdi_rpc_completer(struct cdx_mcdi
*cdx
, unsigned long cookie
,
405 int rc
, struct cdx_dword
*outbuf
,
406 size_t outlen_actual
)
408 struct cdx_mcdi_blocking_data
*wait_data
=
409 (struct cdx_mcdi_blocking_data
*)cookie
;
412 memcpy(wait_data
->outbuf
, outbuf
,
413 min(outlen_actual
, wait_data
->outlen
));
414 wait_data
->outlen_actual
= outlen_actual
;
417 wait_data
->done
= true;
418 wake_up(&wait_data
->wq
);
419 kref_put(&wait_data
->ref
, cdx_mcdi_blocking_data_release
);
422 static int cdx_mcdi_rpc_sync(struct cdx_mcdi
*cdx
, unsigned int cmd
,
423 const struct cdx_dword
*inbuf
, size_t inlen
,
424 struct cdx_dword
*outbuf
, size_t outlen
,
425 size_t *outlen_actual
, bool quiet
)
427 struct cdx_mcdi_blocking_data
*wait_data
;
428 struct cdx_mcdi_cmd
*cmd_item
;
435 wait_data
= kmalloc(sizeof(*wait_data
), GFP_KERNEL
);
439 cmd_item
= kmalloc(sizeof(*cmd_item
), GFP_KERNEL
);
445 kref_init(&wait_data
->ref
);
446 wait_data
->done
= false;
447 init_waitqueue_head(&wait_data
->wq
);
448 wait_data
->outbuf
= outbuf
;
449 wait_data
->outlen
= outlen
;
451 kref_init(&cmd_item
->ref
);
452 cmd_item
->quiet
= quiet
;
453 cmd_item
->cookie
= (unsigned long)wait_data
;
454 cmd_item
->completer
= &cdx_mcdi_rpc_completer
;
456 cmd_item
->inlen
= inlen
;
457 cmd_item
->inbuf
= inbuf
;
459 /* Claim an extra reference for the completer to put. */
460 kref_get(&wait_data
->ref
);
461 rc
= cdx_mcdi_rpc_async_internal(cdx
, cmd_item
, &handle
);
463 kref_put(&wait_data
->ref
, cdx_mcdi_blocking_data_release
);
467 if (!wait_event_timeout(wait_data
->wq
, wait_data
->done
,
468 cdx_mcdi_rpc_timeout(cdx
, cmd
)) &&
470 pr_err("MC command 0x%x inlen %zu timed out (sync)\n",
473 cdx_mcdi_cancel_cmd(cdx
, cmd_item
);
475 wait_data
->rc
= -ETIMEDOUT
;
476 wait_data
->outlen_actual
= 0;
480 *outlen_actual
= wait_data
->outlen_actual
;
484 kref_put(&wait_data
->ref
, cdx_mcdi_blocking_data_release
);
489 static bool cdx_mcdi_get_seq(struct cdx_mcdi_iface
*mcdi
, unsigned char *seq
)
491 *seq
= mcdi
->prev_seq
;
493 *seq
= (*seq
+ 1) % ARRAY_SIZE(mcdi
->seq_held_by
);
494 } while (mcdi
->seq_held_by
[*seq
] && *seq
!= mcdi
->prev_seq
);
495 return !mcdi
->seq_held_by
[*seq
];
498 static int cdx_mcdi_rpc_async_internal(struct cdx_mcdi
*cdx
,
499 struct cdx_mcdi_cmd
*cmd
,
500 unsigned int *handle
)
502 struct cdx_mcdi_iface
*mcdi
= cdx_mcdi_if(cdx
);
503 LIST_HEAD(cleanup_list
);
506 kref_put(&cmd
->ref
, cdx_mcdi_cmd_release
);
510 if (mcdi
->mode
== MCDI_MODE_FAIL
) {
511 kref_put(&cmd
->ref
, cdx_mcdi_cmd_release
);
516 INIT_WORK(&cmd
->work
, cdx_mcdi_cmd_work
);
517 INIT_LIST_HEAD(&cmd
->list
);
518 INIT_LIST_HEAD(&cmd
->cleanup_list
);
523 queue_work(mcdi
->workqueue
, &cmd
->work
);
527 static void cdx_mcdi_cmd_start_or_queue(struct cdx_mcdi_iface
*mcdi
,
528 struct cdx_mcdi_cmd
*cmd
)
530 struct cdx_mcdi
*cdx
= mcdi
->cdx
;
533 if (!mcdi
->db_held_by
&&
534 cdx_mcdi_get_seq(mcdi
, &seq
)) {
536 cmd
->reboot_seen
= false;
537 cdx_mcdi_send_request(cdx
, cmd
);
538 cmd
->state
= MCDI_STATE_RUNNING
;
540 cmd
->state
= MCDI_STATE_QUEUED
;
544 /* try to advance other commands */
545 static void cdx_mcdi_start_or_queue(struct cdx_mcdi_iface
*mcdi
,
548 struct cdx_mcdi_cmd
*cmd
, *tmp
;
550 list_for_each_entry_safe(cmd
, tmp
, &mcdi
->cmd_list
, list
)
551 if (cmd
->state
== MCDI_STATE_QUEUED
||
552 (cmd
->state
== MCDI_STATE_RETRY
&& allow_retry
))
553 cdx_mcdi_cmd_start_or_queue(mcdi
, cmd
);
556 void cdx_mcdi_process_cmd(struct cdx_mcdi
*cdx
, struct cdx_dword
*outbuf
, int len
)
558 struct cdx_mcdi_iface
*mcdi
;
559 struct cdx_mcdi_cmd
*cmd
;
560 LIST_HEAD(cleanup_list
);
561 unsigned int respseq
;
563 if (!len
|| !outbuf
) {
564 pr_err("Got empty MC response\n");
568 mcdi
= cdx_mcdi_if(cdx
);
572 respseq
= CDX_DWORD_FIELD(outbuf
[0], MCDI_HEADER_SEQ
);
574 mutex_lock(&mcdi
->iface_lock
);
575 cmd
= mcdi
->seq_held_by
[respseq
];
578 if (cmd
->state
== MCDI_STATE_FINISHED
) {
579 mutex_unlock(&mcdi
->iface_lock
);
580 kref_put(&cmd
->ref
, cdx_mcdi_cmd_release
);
584 cdx_mcdi_complete_cmd(mcdi
, cmd
, outbuf
, len
, &cleanup_list
);
586 pr_err("MC response unexpected for seq : %0X\n", respseq
);
589 mutex_unlock(&mcdi
->iface_lock
);
591 cdx_mcdi_process_cleanup_list(mcdi
->cdx
, &cleanup_list
);
594 static void cdx_mcdi_cmd_work(struct work_struct
*context
)
596 struct cdx_mcdi_cmd
*cmd
=
597 container_of(context
, struct cdx_mcdi_cmd
, work
);
598 struct cdx_mcdi_iface
*mcdi
= cmd
->mcdi
;
600 mutex_lock(&mcdi
->iface_lock
);
602 cmd
->handle
= mcdi
->prev_handle
++;
603 list_add_tail(&cmd
->list
, &mcdi
->cmd_list
);
604 cdx_mcdi_cmd_start_or_queue(mcdi
, cmd
);
606 mutex_unlock(&mcdi
->iface_lock
);
610 * Returns true if the MCDI module is finished with the command.
611 * (examples of false would be if the command was proxied, or it was
612 * rejected by the MC due to lack of resources and requeued).
614 static bool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface
*mcdi
,
615 struct cdx_mcdi_cmd
*cmd
,
616 struct cdx_dword
*outbuf
,
618 struct list_head
*cleanup_list
)
620 size_t resp_hdr_len
, resp_data_len
;
621 struct cdx_mcdi
*cdx
= mcdi
->cdx
;
622 unsigned int respcmd
, error
;
623 bool completed
= false;
626 /* ensure the command can't go away before this function returns */
629 respcmd
= CDX_DWORD_FIELD(outbuf
[0], MCDI_HEADER_CODE
);
630 error
= CDX_DWORD_FIELD(outbuf
[0], MCDI_HEADER_ERROR
);
632 if (respcmd
!= MC_CMD_V2_EXTN
) {
634 resp_data_len
= CDX_DWORD_FIELD(outbuf
[0], MCDI_HEADER_DATALEN
);
640 CDX_DWORD_FIELD(outbuf
[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN
);
643 if ((resp_hdr_len
+ resp_data_len
) > len
) {
644 pr_warn("Incomplete MCDI response received %d. Expected %zu\n",
645 len
, (resp_hdr_len
+ resp_data_len
));
649 print_hex_dump_debug("MCDI RESP HEADER: ", DUMP_PREFIX_NONE
, 32, 4,
650 outbuf
, resp_hdr_len
, false);
651 print_hex_dump_debug("MCDI RESP PAYLOAD: ", DUMP_PREFIX_NONE
, 32, 4,
652 outbuf
+ (resp_hdr_len
/ 4), resp_data_len
, false);
654 if (error
&& resp_data_len
== 0) {
655 /* MC rebooted during command */
658 if (WARN_ON_ONCE(error
&& resp_data_len
< 4))
661 rc
= CDX_DWORD_FIELD(outbuf
[resp_hdr_len
/ 4], CDX_DWORD
);
665 if (resp_data_len
>= MC_CMD_ERR_ARG_OFST
+ 4) {
666 int offset
= (resp_hdr_len
+ MC_CMD_ERR_ARG_OFST
) / 4;
668 err_arg
= CDX_DWORD_VAL(outbuf
[offset
]);
671 _cdx_mcdi_display_error(cdx
, cmd
->cmd
,
672 cmd
->inlen
, rc
, err_arg
,
673 cdx_mcdi_errno(cdx
, rc
));
675 rc
= cdx_mcdi_errno(cdx
, rc
);
682 if (mcdi
->db_held_by
== cmd
)
683 mcdi
->db_held_by
= NULL
;
685 if (cdx_cmd_cancelled(cmd
)) {
686 list_del(&cmd
->list
);
687 kref_put(&cmd
->ref
, cdx_mcdi_cmd_release
);
689 } else if (rc
== MC_CMD_ERR_QUEUE_FULL
) {
690 cmd
->state
= MCDI_STATE_RETRY
;
693 cmd
->outbuf
= outbuf
+ DIV_ROUND_UP(resp_hdr_len
, 4);
694 cmd
->outlen
= resp_data_len
;
695 cdx_mcdi_remove_cmd(mcdi
, cmd
, cleanup_list
);
699 /* free sequence number and buffer */
700 mcdi
->seq_held_by
[cmd
->seq
] = NULL
;
702 cdx_mcdi_start_or_queue(mcdi
, rc
!= MC_CMD_ERR_QUEUE_FULL
);
704 /* wake up anyone waiting for flush */
705 wake_up(&mcdi
->cmd_complete_wq
);
707 kref_put(&cmd
->ref
, cdx_mcdi_cmd_release
);
712 static void cdx_mcdi_timeout_cmd(struct cdx_mcdi_iface
*mcdi
,
713 struct cdx_mcdi_cmd
*cmd
,
714 struct list_head
*cleanup_list
)
716 struct cdx_mcdi
*cdx
= mcdi
->cdx
;
718 pr_err("MC command 0x%x inlen %zu state %d timed out after %u ms\n",
719 cmd
->cmd
, cmd
->inlen
, cmd
->state
,
720 jiffies_to_msecs(jiffies
- cmd
->started
));
722 cmd
->rc
= -ETIMEDOUT
;
723 cdx_mcdi_remove_cmd(mcdi
, cmd
, cleanup_list
);
725 cdx_mcdi_mode_fail(cdx
, cleanup_list
);
729 * cdx_mcdi_rpc - Issue an MCDI command and wait for completion
730 * @cdx: NIC through which to issue the command
731 * @cmd: Command type number
732 * @inbuf: Command parameters
733 * @inlen: Length of command parameters, in bytes. Must be a multiple
734 * of 4 and no greater than %MCDI_CTL_SDU_LEN_MAX_V1.
735 * @outbuf: Response buffer. May be %NULL if @outlen is 0.
736 * @outlen: Length of response buffer, in bytes. If the actual
737 * response is longer than @outlen & ~3, it will be truncated
739 * @outlen_actual: Pointer through which to return the actual response
740 * length. May be %NULL if this is not needed.
742 * This function may sleep and therefore must be called in process
745 * Return: A negative error code, or zero if successful. The error
746 * code may come from the MCDI response or may indicate a failure
747 * to communicate with the MC. In the former case, the response
748 * will still be copied to @outbuf and *@outlen_actual will be
749 * set accordingly. In the latter case, *@outlen_actual will be
752 int cdx_mcdi_rpc(struct cdx_mcdi
*cdx
, unsigned int cmd
,
753 const struct cdx_dword
*inbuf
, size_t inlen
,
754 struct cdx_dword
*outbuf
, size_t outlen
,
755 size_t *outlen_actual
)
757 return cdx_mcdi_rpc_sync(cdx
, cmd
, inbuf
, inlen
, outbuf
, outlen
,
758 outlen_actual
, false);
762 * cdx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously
763 * @cdx: NIC through which to issue the command
764 * @cmd: Command type number
765 * @inbuf: Command parameters
766 * @inlen: Length of command parameters, in bytes
767 * @complete: Function to be called on completion or cancellation.
768 * @cookie: Arbitrary value to be passed to @complete.
770 * This function does not sleep and therefore may be called in atomic
771 * context. It will fail if event queues are disabled or if MCDI
772 * event completions have been disabled due to an error.
774 * If it succeeds, the @complete function will be called exactly once
775 * in process context, when one of the following occurs:
776 * (a) the completion event is received (in process context)
777 * (b) event queues are disabled (in the process that disables them)
780 cdx_mcdi_rpc_async(struct cdx_mcdi
*cdx
, unsigned int cmd
,
781 const struct cdx_dword
*inbuf
, size_t inlen
,
782 cdx_mcdi_async_completer
*complete
, unsigned long cookie
)
784 struct cdx_mcdi_cmd
*cmd_item
=
785 kmalloc(sizeof(struct cdx_mcdi_cmd
) + inlen
, GFP_ATOMIC
);
790 kref_init(&cmd_item
->ref
);
791 cmd_item
->quiet
= true;
792 cmd_item
->cookie
= cookie
;
793 cmd_item
->completer
= complete
;
795 cmd_item
->inlen
= inlen
;
796 /* inbuf is probably not valid after return, so take a copy */
797 cmd_item
->inbuf
= (struct cdx_dword
*)(cmd_item
+ 1);
798 memcpy(cmd_item
+ 1, inbuf
, inlen
);
800 return cdx_mcdi_rpc_async_internal(cdx
, cmd_item
, NULL
);
803 static void _cdx_mcdi_display_error(struct cdx_mcdi
*cdx
, unsigned int cmd
,
804 size_t inlen
, int raw
, int arg
, int err_no
)
806 pr_err("MC command 0x%x inlen %d failed err_no=%d (raw=%d) arg=%d\n",
807 cmd
, (int)inlen
, err_no
, raw
, arg
);
811 * Set MCDI mode to fail to prevent any new commands, then cancel any
812 * outstanding commands.
813 * Caller must hold the mcdi iface_lock.
815 static void cdx_mcdi_mode_fail(struct cdx_mcdi
*cdx
, struct list_head
*cleanup_list
)
817 struct cdx_mcdi_iface
*mcdi
= cdx_mcdi_if(cdx
);
822 mcdi
->mode
= MCDI_MODE_FAIL
;
824 while (!list_empty(&mcdi
->cmd_list
)) {
825 struct cdx_mcdi_cmd
*cmd
;
827 cmd
= list_first_entry(&mcdi
->cmd_list
, struct cdx_mcdi_cmd
,
829 _cdx_mcdi_cancel_cmd(mcdi
, cdx_mcdi_cmd_handle(cmd
), cleanup_list
);