2 ******************************************************************************
6 * Handles queueing (push to IPC, ack/cfm from IPC) of commands issued to
9 * Copyright (C) ESWIN 2015-2020
11 ******************************************************************************
14 #include <linux/list.h>
16 #include "ecrnx_cmds.h"
17 #include "ecrnx_defs.h"
18 #include "ecrnx_strs.h"
19 #define CREATE_TRACE_POINTS
20 #include "ecrnx_events.h"
25 static void cmd_dump(const struct ecrnx_cmd *cmd)
27 #ifndef CONFIG_ECRNX_FHOST
28 ECRNX_PRINT("tkn[%d] flags:%04x result:%3d cmd:%4d-%-24s - reqcfm(%4d-%-s)\n",
29 cmd->tkn, cmd->flags, cmd->result, cmd->id, ECRNX_ID2STR(cmd->id),
30 cmd->reqid, cmd->reqid != (lmac_msg_id_t)-1 ? ECRNX_ID2STR(cmd->reqid) : "none");
37 static void cmd_complete(struct ecrnx_cmd_mgr *cmd_mgr, struct ecrnx_cmd *cmd)
39 lockdep_assert_held(&cmd_mgr->lock);
44 cmd->flags |= ECRNX_CMD_FLAG_DONE;
45 if (cmd->flags & ECRNX_CMD_FLAG_NONBLOCK) {
48 if (ECRNX_CMD_WAIT_COMPLETE(cmd->flags)) {
50 complete(&cmd->complete);
58 static int cmd_mgr_queue(struct ecrnx_cmd_mgr *cmd_mgr, struct ecrnx_cmd *cmd)
60 struct ecrnx_hw *ecrnx_hw = container_of(cmd_mgr, struct ecrnx_hw, cmd_mgr);
61 bool defer_push = false;
63 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
64 trace_msg_send(cmd->id);
66 spin_lock_bh(&cmd_mgr->lock);
68 if (cmd_mgr->state == ECRNX_CMD_MGR_STATE_CRASHED) {
69 ECRNX_PRINT(KERN_CRIT"cmd queue crashed\n");
71 spin_unlock_bh(&cmd_mgr->lock);
75 #ifndef CONFIG_ECRNX_FHOST
76 if (!list_empty(&cmd_mgr->cmds)) {
77 struct ecrnx_cmd *last;
79 if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) {
80 ECRNX_ERR(KERN_CRIT"Too many cmds (%d) already queued\n",
81 cmd_mgr->max_queue_sz);
82 cmd->result = -ENOMEM;
83 spin_unlock_bh(&cmd_mgr->lock);
86 last = list_entry(cmd_mgr->cmds.prev, struct ecrnx_cmd, list);
87 if (last->flags & (ECRNX_CMD_FLAG_WAIT_ACK | ECRNX_CMD_FLAG_WAIT_PUSH)) {
88 #if 0 // queue even NONBLOCK command.
89 if (cmd->flags & ECRNX_CMD_FLAG_NONBLOCK) {
90 printk(KERN_CRIT"cmd queue busy\n");
92 spin_unlock_bh(&cmd_mgr->lock);
96 cmd->flags |= ECRNX_CMD_FLAG_WAIT_PUSH;
102 cmd->flags |= ECRNX_CMD_FLAG_WAIT_ACK;
103 if (cmd->flags & ECRNX_CMD_FLAG_REQ_CFM)
104 cmd->flags |= ECRNX_CMD_FLAG_WAIT_CFM;
106 cmd->tkn = cmd_mgr->next_tkn++;
107 cmd->result = -EINTR;
109 if (!(cmd->flags & ECRNX_CMD_FLAG_NONBLOCK))
110 init_completion(&cmd->complete);
112 list_add_tail(&cmd->list, &cmd_mgr->cmds);
114 spin_unlock_bh(&cmd_mgr->lock);
117 ecrnx_ipc_msg_push(ecrnx_hw, cmd, ECRNX_CMD_A2EMSG_LEN(cmd->a2e_msg));
121 if (!(cmd->flags & ECRNX_CMD_FLAG_NONBLOCK)) {
122 #ifdef CONFIG_ECRNX_FHOST
123 if (wait_for_completion_killable(&cmd->complete)) {
124 if (cmd->flags & ECRNX_CMD_FLAG_WAIT_ACK)
125 up(&ecrnx_hw->term.fw_cmd);
126 cmd->result = -EINTR;
127 spin_lock_bh(&cmd_mgr->lock);
128 cmd_complete(cmd_mgr, cmd);
129 spin_unlock_bh(&cmd_mgr->lock);
130 /* TODO: kill the cmd at fw level */
132 if (cmd->flags & ECRNX_CMD_FLAG_WAIT_ACK)
133 up(&ecrnx_hw->term.fw_cmd);
136 unsigned long tout = msecs_to_jiffies(ECRNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
137 if (!wait_for_completion_killable_timeout(&cmd->complete, tout)) {
138 ECRNX_PRINT("cmd timed-out queue_sz:%d\n",cmd_mgr->queue_sz);
140 spin_lock_bh(&cmd_mgr->lock);
141 //cmd_mgr->state = ECRNX_CMD_MGR_STATE_CRASHED;
142 if (!(cmd->flags & ECRNX_CMD_FLAG_DONE)) {
143 cmd->result = -ETIMEDOUT;
144 cmd_complete(cmd_mgr, cmd);
146 spin_unlock_bh(&cmd_mgr->lock);
159 static int cmd_mgr_llind(struct ecrnx_cmd_mgr *cmd_mgr, struct ecrnx_cmd *cmd)
161 struct ecrnx_cmd *cur, *acked = NULL, *next = NULL;
163 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
165 spin_lock(&cmd_mgr->lock);
166 list_for_each_entry(cur, &cmd_mgr->cmds, list) {
168 if (cur->tkn == cmd->tkn) {
169 if (WARN_ON_ONCE(cur != cmd)) {
176 if (cur->flags & ECRNX_CMD_FLAG_WAIT_PUSH) {
182 ECRNX_PRINT(KERN_CRIT "Error: acked cmd not found\n");
184 cmd->flags &= ~ECRNX_CMD_FLAG_WAIT_ACK;
185 if (ECRNX_CMD_WAIT_COMPLETE(cmd->flags))
186 cmd_complete(cmd_mgr, cmd);
189 struct ecrnx_hw *ecrnx_hw = container_of(cmd_mgr, struct ecrnx_hw, cmd_mgr);
190 next->flags &= ~ECRNX_CMD_FLAG_WAIT_PUSH;
191 ecrnx_ipc_msg_push(ecrnx_hw, next, ECRNX_CMD_A2EMSG_LEN(next->a2e_msg));
192 kfree(next->a2e_msg);
194 spin_unlock(&cmd_mgr->lock);
201 static int cmd_mgr_run_callback(struct ecrnx_hw *ecrnx_hw, struct ecrnx_cmd *cmd,
202 struct ecrnx_cmd_e2amsg *msg, msg_cb_fct cb)
209 spin_lock(&ecrnx_hw->cb_lock);
210 res = cb(ecrnx_hw, cmd, msg);
211 spin_unlock(&ecrnx_hw->cb_lock);
220 static int cmd_mgr_msgind(struct ecrnx_cmd_mgr *cmd_mgr, struct ecrnx_cmd_e2amsg *msg,
223 struct ecrnx_hw *ecrnx_hw = container_of(cmd_mgr, struct ecrnx_hw, cmd_mgr);
224 struct ecrnx_cmd *cmd;
227 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
228 trace_msg_recv(msg->id);
230 spin_lock(&cmd_mgr->lock);
231 list_for_each_entry(cmd, &cmd_mgr->cmds, list) {
232 if (cmd->reqid == msg->id &&
233 (cmd->flags & ECRNX_CMD_FLAG_WAIT_CFM)) {
235 if (!cmd_mgr_run_callback(ecrnx_hw, cmd, msg, cb)) {
237 cmd->flags &= ~ECRNX_CMD_FLAG_WAIT_CFM;
239 if (WARN((msg->param_len > ECRNX_CMD_E2AMSG_LEN_MAX),
240 "Unexpect E2A msg len %d > %d\n", msg->param_len,
241 ECRNX_CMD_E2AMSG_LEN_MAX)) {
242 msg->param_len = ECRNX_CMD_E2AMSG_LEN_MAX;
245 if (cmd->e2a_msg && msg->param_len)
246 memcpy(cmd->e2a_msg, &msg->param, msg->param_len);
248 if (ECRNX_CMD_WAIT_COMPLETE(cmd->flags))
249 cmd_complete(cmd_mgr, cmd);
255 spin_unlock(&cmd_mgr->lock);
258 cmd_mgr_run_callback(ecrnx_hw, NULL, msg, cb);
260 ECRNX_DBG("%s exit!! \n", __func__);
267 static void cmd_mgr_print(struct ecrnx_cmd_mgr *cmd_mgr)
269 struct ecrnx_cmd *cur;
271 spin_lock_bh(&cmd_mgr->lock);
272 ECRNX_PRINT("q_sz/max: %2d / %2d - next tkn: %d\n",
273 cmd_mgr->queue_sz, cmd_mgr->max_queue_sz,
275 list_for_each_entry(cur, &cmd_mgr->cmds, list) {
278 spin_unlock_bh(&cmd_mgr->lock);
284 static void cmd_mgr_drain(struct ecrnx_cmd_mgr *cmd_mgr)
286 struct ecrnx_cmd *cur, *nxt;
288 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
290 spin_lock_bh(&cmd_mgr->lock);
291 list_for_each_entry_safe(cur, nxt, &cmd_mgr->cmds, list) {
292 list_del(&cur->list);
294 if (!(cur->flags & ECRNX_CMD_FLAG_NONBLOCK))
295 complete(&cur->complete);
297 spin_unlock_bh(&cmd_mgr->lock);
303 void ecrnx_cmd_mgr_init(struct ecrnx_cmd_mgr *cmd_mgr)
305 ECRNX_DBG(ECRNX_FN_ENTRY_STR);
307 INIT_LIST_HEAD(&cmd_mgr->cmds);
308 spin_lock_init(&cmd_mgr->lock);
309 cmd_mgr->max_queue_sz = ECRNX_CMD_MAX_QUEUED;
310 cmd_mgr->queue = &cmd_mgr_queue;
311 cmd_mgr->print = &cmd_mgr_print;
312 cmd_mgr->drain = &cmd_mgr_drain;
313 cmd_mgr->llind = &cmd_mgr_llind;
314 cmd_mgr->msgind = &cmd_mgr_msgind;
320 void ecrnx_cmd_mgr_deinit(struct ecrnx_cmd_mgr *cmd_mgr)
322 cmd_mgr->print(cmd_mgr);
323 cmd_mgr->drain(cmd_mgr);
324 memset(cmd_mgr, 0, sizeof(*cmd_mgr));