1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (C) 2025 Intel Corporation */
3
4 #include "ixd.h"
5 #include "ixd_ctlq.h"
6 #include "ixd_virtchnl.h"
7
8 #define IXD_CTLQ_RX_TASK_DELAY_JIFFIES msecs_to_jiffies(300)
9
10 /**
11 * ixd_ctlq_clean_sq - Clean the send control queue after sending the message
12 * @adapter: The adapter that sent the messages
13 * @force: Clean regardless of send status
14 *
15 * Free the libie send resources after sending the message and handling
16 * the response.
17 */
ixd_ctlq_clean_sq(struct ixd_adapter * adapter,bool force)18 void ixd_ctlq_clean_sq(struct ixd_adapter *adapter, bool force)
19 {
20 libie_ctlq_xn_send_clean(adapter->asq, kfree, force);
21 }
22
23 /**
24 * ixd_ctlq_init_sparams - Initialize control queue send parameters
25 * @adapter: The adapter with initialized mailbox
26 * @sparams: Parameters to initialize
27 * @msg_buf: DMA-mappable pointer to the message being sent
28 * @msg_size: Message size
29 */
ixd_ctlq_init_sparams(struct ixd_adapter * adapter,struct libie_ctlq_xn_send_params * sparams,void * msg_buf,size_t msg_size)30 static void ixd_ctlq_init_sparams(struct ixd_adapter *adapter,
31 struct libie_ctlq_xn_send_params *sparams,
32 void *msg_buf, size_t msg_size)
33 {
34 *sparams = (struct libie_ctlq_xn_send_params) {
35 .rel_tx_buf = kfree,
36 .xnm = adapter->xnm,
37 .ctlq = adapter->asq,
38 .timeout_ms = IXD_CTLQ_TIMEOUT,
39 .send_buf = (struct kvec) {
40 .iov_base = msg_buf,
41 .iov_len = msg_size,
42 },
43 };
44 }
45
46 /**
47 * ixd_ctlq_do_req - Perform a standard virtchnl request
48 * @adapter: The adapter with initialized mailbox
49 * @req: virtchnl request description
50 *
51 * Return: %0 if a message was sent and received a response
52 * that was successfully handled by the custom callback,
53 * negative error otherwise.
54 */
ixd_ctlq_do_req(struct ixd_adapter * adapter,const struct ixd_ctlq_req * req)55 int ixd_ctlq_do_req(struct ixd_adapter *adapter, const struct ixd_ctlq_req *req)
56 {
57 u8 onstack_send_buff[LIBIE_CP_TX_COPYBREAK] __aligned_largest = {};
58 struct libie_ctlq_xn_send_params send_params = {};
59 struct kvec *recv_mem;
60 void *send_buff;
61 int err;
62
63 send_buff = libie_cp_can_send_onstack(req->send_size) ?
64 &onstack_send_buff : kzalloc(req->send_size, GFP_KERNEL);
65 if (!send_buff)
66 return -ENOMEM;
67
68 ixd_ctlq_init_sparams(adapter, &send_params, send_buff,
69 req->send_size);
70
71 send_params.chnl_opcode = req->opcode;
72
73 if (req->send_buff_init)
74 req->send_buff_init(adapter, send_buff, req->ctx);
75
76 ixd_ctlq_clean_sq(adapter, false);
77 err = libie_ctlq_xn_send(&send_params);
78 if (err)
79 return err;
80
81 recv_mem = &send_params.recv_mem;
82 if (req->recv_process)
83 err = req->recv_process(adapter, recv_mem->iov_base,
84 recv_mem->iov_len, req->ctx);
85
86 libie_ctlq_release_rx_buf(recv_mem);
87
88 return err;
89 }
90
91 /**
92 * ixd_ctlq_handle_msg - Default control queue message handler
93 * @ctx: Control plane communication context
94 * @msg: Message received
95 */
ixd_ctlq_handle_msg(struct libie_ctlq_ctx * ctx,struct libie_ctlq_msg * msg)96 static void ixd_ctlq_handle_msg(struct libie_ctlq_ctx *ctx,
97 struct libie_ctlq_msg *msg)
98 {
99 struct ixd_adapter *adapter = pci_get_drvdata(ctx->mmio_info.pdev);
100
101 if (ixd_vc_can_handle_msg(msg))
102 ixd_vc_recv_event_msg(adapter, msg);
103 else
104 dev_dbg_ratelimited(ixd_to_dev(adapter),
105 "Received an unsupported opcode 0x%x from the CP\n",
106 msg->chnl_opcode);
107
108 libie_ctlq_release_rx_buf(&msg->recv_mem);
109 }
110
111 /**
112 * ixd_ctlq_recv_mb_msg - Receive a potential message over mailbox periodically
113 * @adapter: The adapter with initialized mailbox
114 */
ixd_ctlq_recv_mb_msg(struct ixd_adapter * adapter)115 static void ixd_ctlq_recv_mb_msg(struct ixd_adapter *adapter)
116 {
117 struct libie_ctlq_xn_recv_params xn_params = {
118 .xnm = adapter->xnm,
119 .ctlq = adapter->arq,
120 .ctlq_msg_handler = ixd_ctlq_handle_msg,
121 .budget = LIBIE_CTLQ_MAX_XN_ENTRIES,
122 };
123
124 libie_ctlq_xn_recv(&xn_params);
125 }
126
127 /**
128 * ixd_ctlq_rx_task - Periodically check for mailbox responses and events
129 * @work: work handle
130 */
ixd_ctlq_rx_task(struct work_struct * work)131 void ixd_ctlq_rx_task(struct work_struct *work)
132 {
133 struct ixd_adapter *adapter;
134
135 adapter = container_of(work, struct ixd_adapter, mbx_task.work);
136
137 queue_delayed_work(system_dfl_wq, &adapter->mbx_task,
138 IXD_CTLQ_RX_TASK_DELAY_JIFFIES);
139
140 ixd_ctlq_recv_mb_msg(adapter);
141 }
142