1*73b01e57SJeff Chen // SPDX-License-Identifier: GPL-2.0-only
2*73b01e57SJeff Chen /*
3*73b01e57SJeff Chen * nxpwifi: commands and events
4*73b01e57SJeff Chen *
5*73b01e57SJeff Chen * Copyright 2011-2024 NXP
6*73b01e57SJeff Chen */
7*73b01e57SJeff Chen
8*73b01e57SJeff Chen #include "cfg.h"
9*73b01e57SJeff Chen #include "util.h"
10*73b01e57SJeff Chen #include "fw.h"
11*73b01e57SJeff Chen #include "main.h"
12*73b01e57SJeff Chen #include "cmdevt.h"
13*73b01e57SJeff Chen #include "wmm.h"
14*73b01e57SJeff Chen #include "11n.h"
15*73b01e57SJeff Chen
16*73b01e57SJeff Chen static void nxpwifi_cancel_pending_ioctl(struct nxpwifi_adapter *adapter);
17*73b01e57SJeff Chen
18*73b01e57SJeff Chen /* Initialize command node; set defaults; buffers are supplied by caller. */
19*73b01e57SJeff Chen static void
nxpwifi_init_cmd_node(struct nxpwifi_private * priv,struct cmd_ctrl_node * cmd_node,u32 cmd_no,void * data_buf,bool sync)20*73b01e57SJeff Chen nxpwifi_init_cmd_node(struct nxpwifi_private *priv,
21*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node,
22*73b01e57SJeff Chen u32 cmd_no, void *data_buf, bool sync)
23*73b01e57SJeff Chen {
24*73b01e57SJeff Chen cmd_node->priv = priv;
25*73b01e57SJeff Chen cmd_node->cmd_no = cmd_no;
26*73b01e57SJeff Chen
27*73b01e57SJeff Chen if (sync) {
28*73b01e57SJeff Chen cmd_node->wait_q_enabled = true;
29*73b01e57SJeff Chen cmd_node->cmd_wait_q_woken = false;
30*73b01e57SJeff Chen cmd_node->condition = &cmd_node->cmd_wait_q_woken;
31*73b01e57SJeff Chen }
32*73b01e57SJeff Chen cmd_node->data_buf = data_buf;
33*73b01e57SJeff Chen cmd_node->cmd_skb = cmd_node->skb;
34*73b01e57SJeff Chen cmd_node->cmd_resp = NULL;
35*73b01e57SJeff Chen }
36*73b01e57SJeff Chen
37*73b01e57SJeff Chen /* Get a free command node from cmd_free_q; return NULL if none. */
38*73b01e57SJeff Chen static struct cmd_ctrl_node *
nxpwifi_get_cmd_node(struct nxpwifi_adapter * adapter)39*73b01e57SJeff Chen nxpwifi_get_cmd_node(struct nxpwifi_adapter *adapter)
40*73b01e57SJeff Chen {
41*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node;
42*73b01e57SJeff Chen
43*73b01e57SJeff Chen spin_lock_bh(&adapter->cmd_free_q_lock);
44*73b01e57SJeff Chen if (list_empty(&adapter->cmd_free_q)) {
45*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
46*73b01e57SJeff Chen "GET_CMD_NODE: cmd node not available\n");
47*73b01e57SJeff Chen spin_unlock_bh(&adapter->cmd_free_q_lock);
48*73b01e57SJeff Chen return NULL;
49*73b01e57SJeff Chen }
50*73b01e57SJeff Chen cmd_node = list_first_entry(&adapter->cmd_free_q,
51*73b01e57SJeff Chen struct cmd_ctrl_node, list);
52*73b01e57SJeff Chen list_del(&cmd_node->list);
53*73b01e57SJeff Chen spin_unlock_bh(&adapter->cmd_free_q_lock);
54*73b01e57SJeff Chen
55*73b01e57SJeff Chen return cmd_node;
56*73b01e57SJeff Chen }
57*73b01e57SJeff Chen
58*73b01e57SJeff Chen /* Reset cmd node state; trim cmd skb; complete and clear resp_skb if present. */
59*73b01e57SJeff Chen static void
nxpwifi_clean_cmd_node(struct nxpwifi_adapter * adapter,struct cmd_ctrl_node * cmd_node)60*73b01e57SJeff Chen nxpwifi_clean_cmd_node(struct nxpwifi_adapter *adapter,
61*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node)
62*73b01e57SJeff Chen {
63*73b01e57SJeff Chen cmd_node->cmd_no = 0;
64*73b01e57SJeff Chen cmd_node->cmd_flag = 0;
65*73b01e57SJeff Chen cmd_node->data_buf = NULL;
66*73b01e57SJeff Chen cmd_node->wait_q_enabled = false;
67*73b01e57SJeff Chen
68*73b01e57SJeff Chen if (cmd_node->cmd_skb)
69*73b01e57SJeff Chen skb_trim(cmd_node->cmd_skb, 0);
70*73b01e57SJeff Chen
71*73b01e57SJeff Chen if (cmd_node->resp_skb) {
72*73b01e57SJeff Chen adapter->if_ops.cmdrsp_complete(adapter, cmd_node->resp_skb);
73*73b01e57SJeff Chen cmd_node->resp_skb = NULL;
74*73b01e57SJeff Chen }
75*73b01e57SJeff Chen }
76*73b01e57SJeff Chen
77*73b01e57SJeff Chen /* Optionally complete waiters, clean the node, and add it back to cmd_free_q. */
78*73b01e57SJeff Chen static void
nxpwifi_insert_cmd_to_free_q(struct nxpwifi_adapter * adapter,struct cmd_ctrl_node * cmd_node)79*73b01e57SJeff Chen nxpwifi_insert_cmd_to_free_q(struct nxpwifi_adapter *adapter,
80*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node)
81*73b01e57SJeff Chen {
82*73b01e57SJeff Chen if (!cmd_node)
83*73b01e57SJeff Chen return;
84*73b01e57SJeff Chen
85*73b01e57SJeff Chen if (cmd_node->wait_q_enabled)
86*73b01e57SJeff Chen nxpwifi_complete_cmd(adapter, cmd_node);
87*73b01e57SJeff Chen /* Clean the node */
88*73b01e57SJeff Chen nxpwifi_clean_cmd_node(adapter, cmd_node);
89*73b01e57SJeff Chen
90*73b01e57SJeff Chen /* Insert node into cmd_free_q */
91*73b01e57SJeff Chen spin_lock_bh(&adapter->cmd_free_q_lock);
92*73b01e57SJeff Chen list_add_tail(&cmd_node->list, &adapter->cmd_free_q);
93*73b01e57SJeff Chen spin_unlock_bh(&adapter->cmd_free_q_lock);
94*73b01e57SJeff Chen }
95*73b01e57SJeff Chen
96*73b01e57SJeff Chen /* Reuse a command node. */
nxpwifi_recycle_cmd_node(struct nxpwifi_adapter * adapter,struct cmd_ctrl_node * cmd_node)97*73b01e57SJeff Chen void nxpwifi_recycle_cmd_node(struct nxpwifi_adapter *adapter,
98*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node)
99*73b01e57SJeff Chen {
100*73b01e57SJeff Chen struct host_cmd_ds_command *host_cmd = (void *)cmd_node->cmd_skb->data;
101*73b01e57SJeff Chen
102*73b01e57SJeff Chen nxpwifi_insert_cmd_to_free_q(adapter, cmd_node);
103*73b01e57SJeff Chen
104*73b01e57SJeff Chen atomic_dec(&adapter->cmd_pending);
105*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
106*73b01e57SJeff Chen "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
107*73b01e57SJeff Chen le16_to_cpu(host_cmd->command),
108*73b01e57SJeff Chen atomic_read(&adapter->cmd_pending));
109*73b01e57SJeff Chen }
110*73b01e57SJeff Chen
111*73b01e57SJeff Chen /* Copy host command (userspace-provided) into the driver cmd buffer. */
nxpwifi_cmd_host_cmd(struct nxpwifi_private * priv,struct cmd_ctrl_node * cmd_node)112*73b01e57SJeff Chen static int nxpwifi_cmd_host_cmd(struct nxpwifi_private *priv,
113*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node)
114*73b01e57SJeff Chen {
115*73b01e57SJeff Chen struct host_cmd_ds_command *cmd;
116*73b01e57SJeff Chen struct nxpwifi_ds_misc_cmd *pcmd_ptr;
117*73b01e57SJeff Chen
118*73b01e57SJeff Chen cmd = (struct host_cmd_ds_command *)cmd_node->skb->data;
119*73b01e57SJeff Chen pcmd_ptr = (struct nxpwifi_ds_misc_cmd *)cmd_node->data_buf;
120*73b01e57SJeff Chen
121*73b01e57SJeff Chen /* Copy the HOST command to command buffer */
122*73b01e57SJeff Chen memcpy(cmd, pcmd_ptr->cmd, pcmd_ptr->len);
123*73b01e57SJeff Chen nxpwifi_dbg(priv->adapter, CMD,
124*73b01e57SJeff Chen "cmd: host cmd size = %d\n", pcmd_ptr->len);
125*73b01e57SJeff Chen return 0;
126*73b01e57SJeff Chen }
127*73b01e57SJeff Chen
128*73b01e57SJeff Chen /* Send prepared command to FW: set seq no, adjust skb length, log, start timer. */
nxpwifi_dnld_cmd_to_fw(struct nxpwifi_private * priv,struct cmd_ctrl_node * cmd_node)129*73b01e57SJeff Chen static int nxpwifi_dnld_cmd_to_fw(struct nxpwifi_private *priv,
130*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node)
131*73b01e57SJeff Chen {
132*73b01e57SJeff Chen struct nxpwifi_adapter *adapter = priv->adapter;
133*73b01e57SJeff Chen int ret;
134*73b01e57SJeff Chen struct host_cmd_ds_command *host_cmd;
135*73b01e57SJeff Chen u16 cmd_code;
136*73b01e57SJeff Chen u16 cmd_size;
137*73b01e57SJeff Chen
138*73b01e57SJeff Chen if (!adapter || !cmd_node)
139*73b01e57SJeff Chen return -EINVAL;
140*73b01e57SJeff Chen
141*73b01e57SJeff Chen host_cmd = (struct host_cmd_ds_command *)(cmd_node->cmd_skb->data);
142*73b01e57SJeff Chen
143*73b01e57SJeff Chen /* Sanity test */
144*73b01e57SJeff Chen if (host_cmd->size == 0) {
145*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
146*73b01e57SJeff Chen "DNLD_CMD: host_cmd is null\t"
147*73b01e57SJeff Chen "or cmd size is 0, not sending\n");
148*73b01e57SJeff Chen if (cmd_node->wait_q_enabled)
149*73b01e57SJeff Chen adapter->cmd_wait_q.status = -1;
150*73b01e57SJeff Chen nxpwifi_recycle_cmd_node(adapter, cmd_node);
151*73b01e57SJeff Chen return -EINVAL;
152*73b01e57SJeff Chen }
153*73b01e57SJeff Chen
154*73b01e57SJeff Chen cmd_code = le16_to_cpu(host_cmd->command);
155*73b01e57SJeff Chen cmd_node->cmd_no = cmd_code;
156*73b01e57SJeff Chen cmd_size = le16_to_cpu(host_cmd->size);
157*73b01e57SJeff Chen
158*73b01e57SJeff Chen if (adapter->hw_status == NXPWIFI_HW_STATUS_RESET &&
159*73b01e57SJeff Chen cmd_code != HOST_CMD_FUNC_SHUTDOWN &&
160*73b01e57SJeff Chen cmd_code != HOST_CMD_FUNC_INIT) {
161*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
162*73b01e57SJeff Chen "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
163*73b01e57SJeff Chen cmd_code);
164*73b01e57SJeff Chen nxpwifi_recycle_cmd_node(adapter, cmd_node);
165*73b01e57SJeff Chen nxpwifi_queue_work(adapter, &adapter->main_work);
166*73b01e57SJeff Chen return -EPERM;
167*73b01e57SJeff Chen }
168*73b01e57SJeff Chen
169*73b01e57SJeff Chen /* Set command sequence number */
170*73b01e57SJeff Chen adapter->seq_num++;
171*73b01e57SJeff Chen host_cmd->seq_num = cpu_to_le16(HOST_SET_SEQ_NO_BSS_INFO
172*73b01e57SJeff Chen (adapter->seq_num,
173*73b01e57SJeff Chen cmd_node->priv->bss_num,
174*73b01e57SJeff Chen cmd_node->priv->bss_type));
175*73b01e57SJeff Chen
176*73b01e57SJeff Chen spin_lock_bh(&adapter->nxpwifi_cmd_lock);
177*73b01e57SJeff Chen adapter->curr_cmd = cmd_node;
178*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
179*73b01e57SJeff Chen
180*73b01e57SJeff Chen /* Adjust skb length */
181*73b01e57SJeff Chen if (cmd_node->cmd_skb->len > cmd_size)
182*73b01e57SJeff Chen /*
183*73b01e57SJeff Chen * cmd_size is less than sizeof(struct host_cmd_ds_command).
184*73b01e57SJeff Chen * Trim off the unused portion.
185*73b01e57SJeff Chen */
186*73b01e57SJeff Chen skb_trim(cmd_node->cmd_skb, cmd_size);
187*73b01e57SJeff Chen else if (cmd_node->cmd_skb->len < cmd_size)
188*73b01e57SJeff Chen /*
189*73b01e57SJeff Chen * cmd_size is larger than sizeof(struct host_cmd_ds_command)
190*73b01e57SJeff Chen * because we have appended custom element TLV. Increase skb length
191*73b01e57SJeff Chen * accordingly.
192*73b01e57SJeff Chen */
193*73b01e57SJeff Chen skb_put(cmd_node->cmd_skb, cmd_size - cmd_node->cmd_skb->len);
194*73b01e57SJeff Chen
195*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
196*73b01e57SJeff Chen "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n",
197*73b01e57SJeff Chen cmd_code,
198*73b01e57SJeff Chen get_unaligned_le16((u8 *)host_cmd + S_DS_GEN),
199*73b01e57SJeff Chen cmd_size, le16_to_cpu(host_cmd->seq_num));
200*73b01e57SJeff Chen nxpwifi_dbg_dump(adapter, CMD_D, "cmd buffer:", host_cmd, cmd_size);
201*73b01e57SJeff Chen
202*73b01e57SJeff Chen skb_push(cmd_node->cmd_skb, adapter->intf_hdr_len);
203*73b01e57SJeff Chen ret = adapter->if_ops.host_to_card(adapter, NXPWIFI_TYPE_CMD,
204*73b01e57SJeff Chen cmd_node->cmd_skb, NULL);
205*73b01e57SJeff Chen skb_pull(cmd_node->cmd_skb, adapter->intf_hdr_len);
206*73b01e57SJeff Chen
207*73b01e57SJeff Chen if (ret) {
208*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
209*73b01e57SJeff Chen "DNLD_CMD: host to card failed\n");
210*73b01e57SJeff Chen if (cmd_node->wait_q_enabled)
211*73b01e57SJeff Chen adapter->cmd_wait_q.status = -1;
212*73b01e57SJeff Chen nxpwifi_recycle_cmd_node(adapter, adapter->curr_cmd);
213*73b01e57SJeff Chen
214*73b01e57SJeff Chen spin_lock_bh(&adapter->nxpwifi_cmd_lock);
215*73b01e57SJeff Chen adapter->curr_cmd = NULL;
216*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
217*73b01e57SJeff Chen
218*73b01e57SJeff Chen adapter->dbg.num_cmd_host_to_card_failure++;
219*73b01e57SJeff Chen return ret;
220*73b01e57SJeff Chen }
221*73b01e57SJeff Chen
222*73b01e57SJeff Chen /* Save the last command id and action to debug log */
223*73b01e57SJeff Chen adapter->dbg.last_cmd_index =
224*73b01e57SJeff Chen (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
225*73b01e57SJeff Chen adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code;
226*73b01e57SJeff Chen adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] =
227*73b01e57SJeff Chen get_unaligned_le16((u8 *)host_cmd + S_DS_GEN);
228*73b01e57SJeff Chen
229*73b01e57SJeff Chen /*
230*73b01e57SJeff Chen * Setup the timer after transmit command, except that specific
231*73b01e57SJeff Chen * command might not have command response.
232*73b01e57SJeff Chen */
233*73b01e57SJeff Chen if (cmd_code != HOST_CMD_FW_DUMP_EVENT)
234*73b01e57SJeff Chen mod_timer(&adapter->cmd_timer,
235*73b01e57SJeff Chen jiffies + msecs_to_jiffies(NXPWIFI_TIMER_10S));
236*73b01e57SJeff Chen
237*73b01e57SJeff Chen /* Clear BSS_NO_BITS from HOST */
238*73b01e57SJeff Chen cmd_code &= HOST_CMD_ID_MASK;
239*73b01e57SJeff Chen
240*73b01e57SJeff Chen return 0;
241*73b01e57SJeff Chen }
242*73b01e57SJeff Chen
243*73b01e57SJeff Chen /* Send sleep-confirm command to FW; set seq no; resp may be skipped when resp_ctrl=0. */
nxpwifi_dnld_sleep_confirm_cmd(struct nxpwifi_adapter * adapter)244*73b01e57SJeff Chen static int nxpwifi_dnld_sleep_confirm_cmd(struct nxpwifi_adapter *adapter)
245*73b01e57SJeff Chen {
246*73b01e57SJeff Chen int ret;
247*73b01e57SJeff Chen struct nxpwifi_private *priv;
248*73b01e57SJeff Chen struct nxpwifi_opt_sleep_confirm *sleep_cfm_buf =
249*73b01e57SJeff Chen (struct nxpwifi_opt_sleep_confirm *)
250*73b01e57SJeff Chen adapter->sleep_cfm->data;
251*73b01e57SJeff Chen
252*73b01e57SJeff Chen priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY);
253*73b01e57SJeff Chen
254*73b01e57SJeff Chen adapter->seq_num++;
255*73b01e57SJeff Chen sleep_cfm_buf->seq_num =
256*73b01e57SJeff Chen cpu_to_le16(HOST_SET_SEQ_NO_BSS_INFO
257*73b01e57SJeff Chen (adapter->seq_num, priv->bss_num,
258*73b01e57SJeff Chen priv->bss_type));
259*73b01e57SJeff Chen
260*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
261*73b01e57SJeff Chen "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n",
262*73b01e57SJeff Chen le16_to_cpu(sleep_cfm_buf->command),
263*73b01e57SJeff Chen le16_to_cpu(sleep_cfm_buf->action),
264*73b01e57SJeff Chen le16_to_cpu(sleep_cfm_buf->size),
265*73b01e57SJeff Chen le16_to_cpu(sleep_cfm_buf->seq_num));
266*73b01e57SJeff Chen nxpwifi_dbg_dump(adapter, CMD_D, "SLEEP_CFM buffer: ", sleep_cfm_buf,
267*73b01e57SJeff Chen le16_to_cpu(sleep_cfm_buf->size));
268*73b01e57SJeff Chen
269*73b01e57SJeff Chen skb_push(adapter->sleep_cfm, adapter->intf_hdr_len);
270*73b01e57SJeff Chen ret = adapter->if_ops.host_to_card(adapter, NXPWIFI_TYPE_CMD,
271*73b01e57SJeff Chen adapter->sleep_cfm, NULL);
272*73b01e57SJeff Chen skb_pull(adapter->sleep_cfm, adapter->intf_hdr_len);
273*73b01e57SJeff Chen
274*73b01e57SJeff Chen if (ret) {
275*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR, "SLEEP_CFM: failed\n");
276*73b01e57SJeff Chen adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
277*73b01e57SJeff Chen return ret;
278*73b01e57SJeff Chen }
279*73b01e57SJeff Chen
280*73b01e57SJeff Chen if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl))
281*73b01e57SJeff Chen /* Response is not needed for sleep confirm command */
282*73b01e57SJeff Chen adapter->ps_state = PS_STATE_SLEEP;
283*73b01e57SJeff Chen else
284*73b01e57SJeff Chen adapter->ps_state = PS_STATE_SLEEP_CFM;
285*73b01e57SJeff Chen
286*73b01e57SJeff Chen if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl) &&
287*73b01e57SJeff Chen (test_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags) &&
288*73b01e57SJeff Chen !adapter->sleep_period.period)) {
289*73b01e57SJeff Chen adapter->pm_wakeup_card_req = true;
290*73b01e57SJeff Chen nxpwifi_hs_activated_event(nxpwifi_get_priv
291*73b01e57SJeff Chen (adapter, NXPWIFI_BSS_ROLE_ANY), true);
292*73b01e57SJeff Chen }
293*73b01e57SJeff Chen
294*73b01e57SJeff Chen return ret;
295*73b01e57SJeff Chen }
296*73b01e57SJeff Chen
297*73b01e57SJeff Chen /* Allocate cmd pool and link all nodes to cmd_free_q (used/returned by cmds). */
nxpwifi_alloc_cmd_buffer(struct nxpwifi_adapter * adapter)298*73b01e57SJeff Chen int nxpwifi_alloc_cmd_buffer(struct nxpwifi_adapter *adapter)
299*73b01e57SJeff Chen {
300*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_array;
301*73b01e57SJeff Chen u32 i;
302*73b01e57SJeff Chen
303*73b01e57SJeff Chen /* Allocate and initialize struct cmd_ctrl_node */
304*73b01e57SJeff Chen cmd_array = kzalloc_objs(struct cmd_ctrl_node,
305*73b01e57SJeff Chen NXPWIFI_NUM_OF_CMD_BUFFER, GFP_KERNEL);
306*73b01e57SJeff Chen if (!cmd_array)
307*73b01e57SJeff Chen return -ENOMEM;
308*73b01e57SJeff Chen
309*73b01e57SJeff Chen adapter->cmd_pool = cmd_array;
310*73b01e57SJeff Chen
311*73b01e57SJeff Chen /* Allocate and initialize command buffers */
312*73b01e57SJeff Chen for (i = 0; i < NXPWIFI_NUM_OF_CMD_BUFFER; i++) {
313*73b01e57SJeff Chen cmd_array[i].skb = dev_alloc_skb(NXPWIFI_SIZE_OF_CMD_BUFFER);
314*73b01e57SJeff Chen if (!cmd_array[i].skb)
315*73b01e57SJeff Chen return -ENOMEM;
316*73b01e57SJeff Chen }
317*73b01e57SJeff Chen
318*73b01e57SJeff Chen for (i = 0; i < NXPWIFI_NUM_OF_CMD_BUFFER; i++)
319*73b01e57SJeff Chen nxpwifi_insert_cmd_to_free_q(adapter, &cmd_array[i]);
320*73b01e57SJeff Chen
321*73b01e57SJeff Chen return 0;
322*73b01e57SJeff Chen }
323*73b01e57SJeff Chen
324*73b01e57SJeff Chen /* Free cmd pool; release any remaining resp skbs. */
nxpwifi_free_cmd_buffer(struct nxpwifi_adapter * adapter)325*73b01e57SJeff Chen void nxpwifi_free_cmd_buffer(struct nxpwifi_adapter *adapter)
326*73b01e57SJeff Chen {
327*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_array;
328*73b01e57SJeff Chen u32 i;
329*73b01e57SJeff Chen
330*73b01e57SJeff Chen /* Need to check if cmd pool is allocated or not */
331*73b01e57SJeff Chen if (!adapter->cmd_pool) {
332*73b01e57SJeff Chen nxpwifi_dbg(adapter, FATAL,
333*73b01e57SJeff Chen "info: FREE_CMD_BUF: cmd_pool is null\n");
334*73b01e57SJeff Chen return;
335*73b01e57SJeff Chen }
336*73b01e57SJeff Chen
337*73b01e57SJeff Chen cmd_array = adapter->cmd_pool;
338*73b01e57SJeff Chen
339*73b01e57SJeff Chen /* Release shared memory buffers */
340*73b01e57SJeff Chen for (i = 0; i < NXPWIFI_NUM_OF_CMD_BUFFER; i++) {
341*73b01e57SJeff Chen if (cmd_array[i].skb) {
342*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
343*73b01e57SJeff Chen "cmd: free cmd buffer %d\n", i);
344*73b01e57SJeff Chen dev_kfree_skb_any(cmd_array[i].skb);
345*73b01e57SJeff Chen }
346*73b01e57SJeff Chen if (!cmd_array[i].resp_skb)
347*73b01e57SJeff Chen continue;
348*73b01e57SJeff Chen
349*73b01e57SJeff Chen dev_kfree_skb_any(cmd_array[i].resp_skb);
350*73b01e57SJeff Chen }
351*73b01e57SJeff Chen /* Release struct cmd_ctrl_node */
352*73b01e57SJeff Chen if (adapter->cmd_pool) {
353*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
354*73b01e57SJeff Chen "cmd: free cmd pool\n");
355*73b01e57SJeff Chen kfree(adapter->cmd_pool);
356*73b01e57SJeff Chen adapter->cmd_pool = NULL;
357*73b01e57SJeff Chen }
358*73b01e57SJeff Chen }
359*73b01e57SJeff Chen
360*73b01e57SJeff Chen /*
361*73b01e57SJeff Chen * Handle FW event: select per-BSS priv, fill rxinfo, dispatch to STA/UAP handler, complete.
362*73b01e57SJeff Chen */
nxpwifi_process_event(struct nxpwifi_adapter * adapter)363*73b01e57SJeff Chen int nxpwifi_process_event(struct nxpwifi_adapter *adapter)
364*73b01e57SJeff Chen {
365*73b01e57SJeff Chen int ret, i;
366*73b01e57SJeff Chen struct nxpwifi_private *priv =
367*73b01e57SJeff Chen nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY);
368*73b01e57SJeff Chen struct sk_buff *skb = adapter->event_skb;
369*73b01e57SJeff Chen u32 eventcause;
370*73b01e57SJeff Chen struct nxpwifi_rxinfo *rx_info;
371*73b01e57SJeff Chen
372*73b01e57SJeff Chen if ((adapter->event_cause & EVENT_ID_MASK) == EVENT_RADAR_DETECTED) {
373*73b01e57SJeff Chen for (i = 0; i < adapter->priv_num; i++) {
374*73b01e57SJeff Chen priv = adapter->priv[i];
375*73b01e57SJeff Chen if (nxpwifi_is_11h_active(priv)) {
376*73b01e57SJeff Chen adapter->event_cause |=
377*73b01e57SJeff Chen ((priv->bss_num & 0xff) << 16) |
378*73b01e57SJeff Chen ((priv->bss_type & 0xff) << 24);
379*73b01e57SJeff Chen break;
380*73b01e57SJeff Chen }
381*73b01e57SJeff Chen }
382*73b01e57SJeff Chen }
383*73b01e57SJeff Chen
384*73b01e57SJeff Chen eventcause = adapter->event_cause;
385*73b01e57SJeff Chen
386*73b01e57SJeff Chen /* Save the last event to debug log */
387*73b01e57SJeff Chen adapter->dbg.last_event_index =
388*73b01e57SJeff Chen (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
389*73b01e57SJeff Chen adapter->dbg.last_event[adapter->dbg.last_event_index] =
390*73b01e57SJeff Chen (u16)eventcause;
391*73b01e57SJeff Chen
392*73b01e57SJeff Chen /* Get BSS number and corresponding priv */
393*73b01e57SJeff Chen priv = nxpwifi_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause),
394*73b01e57SJeff Chen EVENT_GET_BSS_TYPE(eventcause));
395*73b01e57SJeff Chen if (!priv)
396*73b01e57SJeff Chen priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY);
397*73b01e57SJeff Chen
398*73b01e57SJeff Chen /* Clear BSS_NO_BITS from event */
399*73b01e57SJeff Chen eventcause &= EVENT_ID_MASK;
400*73b01e57SJeff Chen adapter->event_cause = eventcause;
401*73b01e57SJeff Chen
402*73b01e57SJeff Chen if (skb) {
403*73b01e57SJeff Chen rx_info = NXPWIFI_SKB_RXCB(skb);
404*73b01e57SJeff Chen memset(rx_info, 0, sizeof(*rx_info));
405*73b01e57SJeff Chen rx_info->bss_num = priv->bss_num;
406*73b01e57SJeff Chen rx_info->bss_type = priv->bss_type;
407*73b01e57SJeff Chen nxpwifi_dbg_dump(adapter, EVT_D, "Event Buf:",
408*73b01e57SJeff Chen skb->data, skb->len);
409*73b01e57SJeff Chen }
410*73b01e57SJeff Chen
411*73b01e57SJeff Chen nxpwifi_dbg(adapter, EVENT, "EVENT: cause: %#x\n", eventcause);
412*73b01e57SJeff Chen
413*73b01e57SJeff Chen if (priv->bss_role == NXPWIFI_BSS_ROLE_UAP)
414*73b01e57SJeff Chen ret = nxpwifi_process_uap_event(priv);
415*73b01e57SJeff Chen else
416*73b01e57SJeff Chen ret = nxpwifi_process_sta_event(priv);
417*73b01e57SJeff Chen
418*73b01e57SJeff Chen adapter->event_cause = 0;
419*73b01e57SJeff Chen adapter->event_skb = NULL;
420*73b01e57SJeff Chen adapter->if_ops.event_complete(adapter, skb);
421*73b01e57SJeff Chen
422*73b01e57SJeff Chen return ret;
423*73b01e57SJeff Chen }
424*73b01e57SJeff Chen
425*73b01e57SJeff Chen /*
426*73b01e57SJeff Chen * Prepare and queue a command: sanity checks, get node, init, fill, and enqueue/dispatch.
427*73b01e57SJeff Chen */
nxpwifi_send_cmd(struct nxpwifi_private * priv,u16 cmd_no,u16 cmd_action,u32 cmd_oid,void * data_buf,bool sync)428*73b01e57SJeff Chen int nxpwifi_send_cmd(struct nxpwifi_private *priv, u16 cmd_no,
429*73b01e57SJeff Chen u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync)
430*73b01e57SJeff Chen {
431*73b01e57SJeff Chen int ret;
432*73b01e57SJeff Chen struct nxpwifi_adapter *adapter = priv->adapter;
433*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node;
434*73b01e57SJeff Chen
435*73b01e57SJeff Chen if (!adapter) {
436*73b01e57SJeff Chen pr_err("PREP_CMD: adapter is NULL\n");
437*73b01e57SJeff Chen return -EINVAL;
438*73b01e57SJeff Chen }
439*73b01e57SJeff Chen
440*73b01e57SJeff Chen if (test_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags)) {
441*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
442*73b01e57SJeff Chen "PREP_CMD: device in suspended state\n");
443*73b01e57SJeff Chen return -EPERM;
444*73b01e57SJeff Chen }
445*73b01e57SJeff Chen
446*73b01e57SJeff Chen if (test_bit(NXPWIFI_IS_HS_ENABLING, &adapter->work_flags) &&
447*73b01e57SJeff Chen cmd_no != HOST_CMD_802_11_HS_CFG_ENH) {
448*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
449*73b01e57SJeff Chen "PREP_CMD: host entering sleep state\n");
450*73b01e57SJeff Chen return -EPERM;
451*73b01e57SJeff Chen }
452*73b01e57SJeff Chen
453*73b01e57SJeff Chen if (test_bit(NXPWIFI_SURPRISE_REMOVED, &adapter->work_flags)) {
454*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
455*73b01e57SJeff Chen "PREP_CMD: card is removed\n");
456*73b01e57SJeff Chen return -EPERM;
457*73b01e57SJeff Chen }
458*73b01e57SJeff Chen
459*73b01e57SJeff Chen if (test_bit(NXPWIFI_IS_CMD_TIMEDOUT, &adapter->work_flags)) {
460*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
461*73b01e57SJeff Chen "PREP_CMD: FW is in bad state\n");
462*73b01e57SJeff Chen return -EPERM;
463*73b01e57SJeff Chen }
464*73b01e57SJeff Chen
465*73b01e57SJeff Chen if (adapter->hw_status == NXPWIFI_HW_STATUS_RESET) {
466*73b01e57SJeff Chen if (cmd_no != HOST_CMD_FUNC_INIT) {
467*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
468*73b01e57SJeff Chen "PREP_CMD: FW in reset state\n");
469*73b01e57SJeff Chen return -EPERM;
470*73b01e57SJeff Chen }
471*73b01e57SJeff Chen }
472*73b01e57SJeff Chen
473*73b01e57SJeff Chen if (priv->adapter->hs_activated_manually &&
474*73b01e57SJeff Chen cmd_no != HOST_CMD_802_11_HS_CFG_ENH) {
475*73b01e57SJeff Chen nxpwifi_cancel_hs(priv, NXPWIFI_ASYNC_CMD);
476*73b01e57SJeff Chen priv->adapter->hs_activated_manually = false;
477*73b01e57SJeff Chen }
478*73b01e57SJeff Chen
479*73b01e57SJeff Chen /* Get a new command node */
480*73b01e57SJeff Chen cmd_node = nxpwifi_get_cmd_node(adapter);
481*73b01e57SJeff Chen
482*73b01e57SJeff Chen if (!cmd_node) {
483*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
484*73b01e57SJeff Chen "PREP_CMD: no free cmd node\n");
485*73b01e57SJeff Chen return -ENOMEM;
486*73b01e57SJeff Chen }
487*73b01e57SJeff Chen
488*73b01e57SJeff Chen /* Initialize the command node */
489*73b01e57SJeff Chen nxpwifi_init_cmd_node(priv, cmd_node, cmd_no, data_buf, sync);
490*73b01e57SJeff Chen
491*73b01e57SJeff Chen if (!cmd_node->cmd_skb) {
492*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
493*73b01e57SJeff Chen "PREP_CMD: no free cmd buf\n");
494*73b01e57SJeff Chen return -ENOMEM;
495*73b01e57SJeff Chen }
496*73b01e57SJeff Chen
497*73b01e57SJeff Chen skb_put_zero(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command));
498*73b01e57SJeff Chen
499*73b01e57SJeff Chen /* Prepare command */
500*73b01e57SJeff Chen if (cmd_no) {
501*73b01e57SJeff Chen switch (cmd_no) {
502*73b01e57SJeff Chen case HOST_CMD_UAP_SYS_CONFIG:
503*73b01e57SJeff Chen case HOST_CMD_UAP_BSS_START:
504*73b01e57SJeff Chen case HOST_CMD_UAP_BSS_STOP:
505*73b01e57SJeff Chen case HOST_CMD_UAP_STA_DEAUTH:
506*73b01e57SJeff Chen case HOST_CMD_APCMD_SYS_RESET:
507*73b01e57SJeff Chen case HOST_CMD_APCMD_STA_LIST:
508*73b01e57SJeff Chen case HOST_CMD_CHAN_REPORT_REQUEST:
509*73b01e57SJeff Chen case HOST_CMD_ADD_NEW_STATION:
510*73b01e57SJeff Chen ret = nxpwifi_uap_prepare_cmd(priv, cmd_node,
511*73b01e57SJeff Chen cmd_action, cmd_oid);
512*73b01e57SJeff Chen break;
513*73b01e57SJeff Chen default:
514*73b01e57SJeff Chen ret = nxpwifi_sta_prepare_cmd(priv, cmd_node,
515*73b01e57SJeff Chen cmd_action, cmd_oid);
516*73b01e57SJeff Chen break;
517*73b01e57SJeff Chen }
518*73b01e57SJeff Chen } else {
519*73b01e57SJeff Chen ret = nxpwifi_cmd_host_cmd(priv, cmd_node);
520*73b01e57SJeff Chen cmd_node->cmd_flag |= CMD_F_HOSTCMD;
521*73b01e57SJeff Chen }
522*73b01e57SJeff Chen
523*73b01e57SJeff Chen /* Return error, since the command preparation failed */
524*73b01e57SJeff Chen if (ret) {
525*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
526*73b01e57SJeff Chen "PREP_CMD: cmd %#x preparation failed\n",
527*73b01e57SJeff Chen cmd_no);
528*73b01e57SJeff Chen nxpwifi_insert_cmd_to_free_q(adapter, cmd_node);
529*73b01e57SJeff Chen return ret;
530*73b01e57SJeff Chen }
531*73b01e57SJeff Chen
532*73b01e57SJeff Chen /* Send command */
533*73b01e57SJeff Chen if (cmd_no == HOST_CMD_802_11_SCAN ||
534*73b01e57SJeff Chen cmd_no == HOST_CMD_802_11_SCAN_EXT) {
535*73b01e57SJeff Chen nxpwifi_queue_scan_cmd(priv, cmd_node);
536*73b01e57SJeff Chen } else {
537*73b01e57SJeff Chen nxpwifi_insert_cmd_to_pending_q(adapter, cmd_node);
538*73b01e57SJeff Chen nxpwifi_queue_work(adapter, &adapter->main_work);
539*73b01e57SJeff Chen if (cmd_node->wait_q_enabled)
540*73b01e57SJeff Chen ret = nxpwifi_wait_queue_complete(adapter, cmd_node);
541*73b01e57SJeff Chen }
542*73b01e57SJeff Chen
543*73b01e57SJeff Chen return ret;
544*73b01e57SJeff Chen }
545*73b01e57SJeff Chen
546*73b01e57SJeff Chen /* Queue command to cmd_pending_q; EXIT_PS and HS_ACTIVATE go to the head. */
547*73b01e57SJeff Chen void
nxpwifi_insert_cmd_to_pending_q(struct nxpwifi_adapter * adapter,struct cmd_ctrl_node * cmd_node)548*73b01e57SJeff Chen nxpwifi_insert_cmd_to_pending_q(struct nxpwifi_adapter *adapter,
549*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node)
550*73b01e57SJeff Chen {
551*73b01e57SJeff Chen struct host_cmd_ds_command *host_cmd = NULL;
552*73b01e57SJeff Chen u16 command;
553*73b01e57SJeff Chen bool add_tail = true;
554*73b01e57SJeff Chen
555*73b01e57SJeff Chen host_cmd = (struct host_cmd_ds_command *)(cmd_node->cmd_skb->data);
556*73b01e57SJeff Chen if (!host_cmd) {
557*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR, "QUEUE_CMD: host_cmd is NULL\n");
558*73b01e57SJeff Chen return;
559*73b01e57SJeff Chen }
560*73b01e57SJeff Chen
561*73b01e57SJeff Chen command = le16_to_cpu(host_cmd->command);
562*73b01e57SJeff Chen
563*73b01e57SJeff Chen /* Exit_PS command needs to be queued in the header always. */
564*73b01e57SJeff Chen if (command == HOST_CMD_802_11_PS_MODE_ENH) {
565*73b01e57SJeff Chen struct host_cmd_ds_802_11_ps_mode_enh *pm =
566*73b01e57SJeff Chen &host_cmd->params.psmode_enh;
567*73b01e57SJeff Chen if ((le16_to_cpu(pm->action) == DIS_PS) ||
568*73b01e57SJeff Chen (le16_to_cpu(pm->action) == DIS_AUTO_PS)) {
569*73b01e57SJeff Chen if (adapter->ps_state != PS_STATE_AWAKE)
570*73b01e57SJeff Chen add_tail = false;
571*73b01e57SJeff Chen }
572*73b01e57SJeff Chen }
573*73b01e57SJeff Chen
574*73b01e57SJeff Chen /* Same with exit host sleep cmd, luckily that can't happen at the same time as EXIT_PS */
575*73b01e57SJeff Chen if (command == HOST_CMD_802_11_HS_CFG_ENH) {
576*73b01e57SJeff Chen struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg =
577*73b01e57SJeff Chen &host_cmd->params.opt_hs_cfg;
578*73b01e57SJeff Chen
579*73b01e57SJeff Chen if (le16_to_cpu(hs_cfg->action) == HS_ACTIVATE)
580*73b01e57SJeff Chen add_tail = false;
581*73b01e57SJeff Chen }
582*73b01e57SJeff Chen
583*73b01e57SJeff Chen spin_lock_bh(&adapter->cmd_pending_q_lock);
584*73b01e57SJeff Chen if (add_tail)
585*73b01e57SJeff Chen list_add_tail(&cmd_node->list, &adapter->cmd_pending_q);
586*73b01e57SJeff Chen else
587*73b01e57SJeff Chen list_add(&cmd_node->list, &adapter->cmd_pending_q);
588*73b01e57SJeff Chen spin_unlock_bh(&adapter->cmd_pending_q_lock);
589*73b01e57SJeff Chen
590*73b01e57SJeff Chen atomic_inc(&adapter->cmd_pending);
591*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
592*73b01e57SJeff Chen "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n",
593*73b01e57SJeff Chen command, atomic_read(&adapter->cmd_pending));
594*73b01e57SJeff Chen }
595*73b01e57SJeff Chen
596*73b01e57SJeff Chen /* Dequeue next cmd and download to FW; if HS active (except HS_CFG), deactivate it. */
nxpwifi_exec_next_cmd(struct nxpwifi_adapter * adapter)597*73b01e57SJeff Chen int nxpwifi_exec_next_cmd(struct nxpwifi_adapter *adapter)
598*73b01e57SJeff Chen {
599*73b01e57SJeff Chen struct nxpwifi_private *priv;
600*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node;
601*73b01e57SJeff Chen int ret = 0;
602*73b01e57SJeff Chen struct host_cmd_ds_command *host_cmd;
603*73b01e57SJeff Chen
604*73b01e57SJeff Chen /* Check if already in processing */
605*73b01e57SJeff Chen if (adapter->curr_cmd) {
606*73b01e57SJeff Chen nxpwifi_dbg(adapter, FATAL,
607*73b01e57SJeff Chen "EXEC_NEXT_CMD: cmd in processing\n");
608*73b01e57SJeff Chen return -EBUSY;
609*73b01e57SJeff Chen }
610*73b01e57SJeff Chen
611*73b01e57SJeff Chen spin_lock_bh(&adapter->nxpwifi_cmd_lock);
612*73b01e57SJeff Chen /* Check if any command is pending */
613*73b01e57SJeff Chen spin_lock_bh(&adapter->cmd_pending_q_lock);
614*73b01e57SJeff Chen if (list_empty(&adapter->cmd_pending_q)) {
615*73b01e57SJeff Chen spin_unlock_bh(&adapter->cmd_pending_q_lock);
616*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
617*73b01e57SJeff Chen return -ENODATA;
618*73b01e57SJeff Chen }
619*73b01e57SJeff Chen cmd_node = list_first_entry(&adapter->cmd_pending_q,
620*73b01e57SJeff Chen struct cmd_ctrl_node, list);
621*73b01e57SJeff Chen
622*73b01e57SJeff Chen host_cmd = (struct host_cmd_ds_command *)(cmd_node->cmd_skb->data);
623*73b01e57SJeff Chen priv = cmd_node->priv;
624*73b01e57SJeff Chen
625*73b01e57SJeff Chen if (adapter->ps_state != PS_STATE_AWAKE) {
626*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
627*73b01e57SJeff Chen "%s: cannot send cmd in sleep state,\t"
628*73b01e57SJeff Chen "this should not happen\n", __func__);
629*73b01e57SJeff Chen spin_unlock_bh(&adapter->cmd_pending_q_lock);
630*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
631*73b01e57SJeff Chen return ret;
632*73b01e57SJeff Chen }
633*73b01e57SJeff Chen
634*73b01e57SJeff Chen list_del(&cmd_node->list);
635*73b01e57SJeff Chen spin_unlock_bh(&adapter->cmd_pending_q_lock);
636*73b01e57SJeff Chen
637*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
638*73b01e57SJeff Chen ret = nxpwifi_dnld_cmd_to_fw(priv, cmd_node);
639*73b01e57SJeff Chen priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY);
640*73b01e57SJeff Chen /*
641*73b01e57SJeff Chen * Any command sent to the firmware when host is in sleep
642*73b01e57SJeff Chen * mode should de-configure host sleep. We should skip the
643*73b01e57SJeff Chen * host sleep configuration command itself though
644*73b01e57SJeff Chen */
645*73b01e57SJeff Chen if (priv && host_cmd->command !=
646*73b01e57SJeff Chen cpu_to_le16(HOST_CMD_802_11_HS_CFG_ENH)) {
647*73b01e57SJeff Chen if (adapter->hs_activated) {
648*73b01e57SJeff Chen clear_bit(NXPWIFI_IS_HS_CONFIGURED,
649*73b01e57SJeff Chen &adapter->work_flags);
650*73b01e57SJeff Chen nxpwifi_hs_activated_event(priv, false);
651*73b01e57SJeff Chen }
652*73b01e57SJeff Chen }
653*73b01e57SJeff Chen
654*73b01e57SJeff Chen return ret;
655*73b01e57SJeff Chen }
656*73b01e57SJeff Chen
657*73b01e57SJeff Chen static void
nxpwifi_process_cmdresp_error(struct nxpwifi_private * priv,struct host_cmd_ds_command * resp)658*73b01e57SJeff Chen nxpwifi_process_cmdresp_error(struct nxpwifi_private *priv,
659*73b01e57SJeff Chen struct host_cmd_ds_command *resp)
660*73b01e57SJeff Chen {
661*73b01e57SJeff Chen struct nxpwifi_adapter *adapter = priv->adapter;
662*73b01e57SJeff Chen struct host_cmd_ds_802_11_ps_mode_enh *pm;
663*73b01e57SJeff Chen
664*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
665*73b01e57SJeff Chen "CMD_RESP: cmd %#x error, result=%#x\n",
666*73b01e57SJeff Chen resp->command, resp->result);
667*73b01e57SJeff Chen
668*73b01e57SJeff Chen if (adapter->curr_cmd->wait_q_enabled)
669*73b01e57SJeff Chen adapter->cmd_wait_q.status = -1;
670*73b01e57SJeff Chen
671*73b01e57SJeff Chen switch (le16_to_cpu(resp->command)) {
672*73b01e57SJeff Chen case HOST_CMD_802_11_PS_MODE_ENH:
673*73b01e57SJeff Chen pm = &resp->params.psmode_enh;
674*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
675*73b01e57SJeff Chen "PS_MODE_ENH cmd failed: result=0x%x action=0x%X\n",
676*73b01e57SJeff Chen resp->result, le16_to_cpu(pm->action));
677*73b01e57SJeff Chen break;
678*73b01e57SJeff Chen case HOST_CMD_802_11_SCAN:
679*73b01e57SJeff Chen case HOST_CMD_802_11_SCAN_EXT:
680*73b01e57SJeff Chen nxpwifi_cancel_scan(adapter);
681*73b01e57SJeff Chen break;
682*73b01e57SJeff Chen
683*73b01e57SJeff Chen case HOST_CMD_MAC_CONTROL:
684*73b01e57SJeff Chen break;
685*73b01e57SJeff Chen
686*73b01e57SJeff Chen case HOST_CMD_SDIO_SP_RX_AGGR_CFG:
687*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
688*73b01e57SJeff Chen "SDIO RX single-port aggregation Not support\n");
689*73b01e57SJeff Chen break;
690*73b01e57SJeff Chen
691*73b01e57SJeff Chen default:
692*73b01e57SJeff Chen break;
693*73b01e57SJeff Chen }
694*73b01e57SJeff Chen /* Handling errors here */
695*73b01e57SJeff Chen nxpwifi_recycle_cmd_node(adapter, adapter->curr_cmd);
696*73b01e57SJeff Chen
697*73b01e57SJeff Chen spin_lock_bh(&adapter->nxpwifi_cmd_lock);
698*73b01e57SJeff Chen adapter->curr_cmd = NULL;
699*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
700*73b01e57SJeff Chen }
701*73b01e57SJeff Chen
702*73b01e57SJeff Chen /* Handle command response: validate, cancel timer, dispatch, set status, recycle node. */
nxpwifi_process_cmdresp(struct nxpwifi_adapter * adapter)703*73b01e57SJeff Chen int nxpwifi_process_cmdresp(struct nxpwifi_adapter *adapter)
704*73b01e57SJeff Chen {
705*73b01e57SJeff Chen struct host_cmd_ds_command *resp;
706*73b01e57SJeff Chen struct nxpwifi_private *priv =
707*73b01e57SJeff Chen nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY);
708*73b01e57SJeff Chen int ret = 0;
709*73b01e57SJeff Chen u16 orig_cmdresp_no;
710*73b01e57SJeff Chen u16 cmdresp_no;
711*73b01e57SJeff Chen u16 cmdresp_result;
712*73b01e57SJeff Chen
713*73b01e57SJeff Chen if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
714*73b01e57SJeff Chen resp = (struct host_cmd_ds_command *)adapter->upld_buf;
715*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
716*73b01e57SJeff Chen "CMD_RESP: NULL curr_cmd, %#x\n",
717*73b01e57SJeff Chen le16_to_cpu(resp->command));
718*73b01e57SJeff Chen return -EINVAL;
719*73b01e57SJeff Chen }
720*73b01e57SJeff Chen
721*73b01e57SJeff Chen resp = (struct host_cmd_ds_command *)adapter->curr_cmd->resp_skb->data;
722*73b01e57SJeff Chen orig_cmdresp_no = le16_to_cpu(resp->command);
723*73b01e57SJeff Chen cmdresp_no = (orig_cmdresp_no & HOST_CMD_ID_MASK);
724*73b01e57SJeff Chen
725*73b01e57SJeff Chen if (adapter->curr_cmd->cmd_no != cmdresp_no) {
726*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
727*73b01e57SJeff Chen "cmdresp error: cmd=0x%x cmd_resp=0x%x\n",
728*73b01e57SJeff Chen adapter->curr_cmd->cmd_no, cmdresp_no);
729*73b01e57SJeff Chen return -EINVAL;
730*73b01e57SJeff Chen }
731*73b01e57SJeff Chen /* Now we got response from FW, cancel the command timer */
732*73b01e57SJeff Chen timer_delete_sync(&adapter->cmd_timer);
733*73b01e57SJeff Chen clear_bit(NXPWIFI_IS_CMD_TIMEDOUT, &adapter->work_flags);
734*73b01e57SJeff Chen
735*73b01e57SJeff Chen if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
736*73b01e57SJeff Chen /* Copy original response back to response buffer */
737*73b01e57SJeff Chen struct nxpwifi_ds_misc_cmd *hostcmd;
738*73b01e57SJeff Chen u16 size = le16_to_cpu(resp->size);
739*73b01e57SJeff Chen
740*73b01e57SJeff Chen nxpwifi_dbg(adapter, INFO,
741*73b01e57SJeff Chen "info: host cmd resp size = %d\n", size);
742*73b01e57SJeff Chen size = min_t(u16, size, NXPWIFI_SIZE_OF_CMD_BUFFER);
743*73b01e57SJeff Chen if (adapter->curr_cmd->data_buf) {
744*73b01e57SJeff Chen hostcmd = adapter->curr_cmd->data_buf;
745*73b01e57SJeff Chen hostcmd->len = size;
746*73b01e57SJeff Chen memcpy(hostcmd->cmd, resp, size);
747*73b01e57SJeff Chen }
748*73b01e57SJeff Chen }
749*73b01e57SJeff Chen
750*73b01e57SJeff Chen /* Get BSS number and corresponding priv */
751*73b01e57SJeff Chen priv = nxpwifi_get_priv_by_id
752*73b01e57SJeff Chen (adapter, HOST_GET_BSS_NO(le16_to_cpu(resp->seq_num)),
753*73b01e57SJeff Chen HOST_GET_BSS_TYPE(le16_to_cpu(resp->seq_num)));
754*73b01e57SJeff Chen if (!priv)
755*73b01e57SJeff Chen priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY);
756*73b01e57SJeff Chen /* Clear RET_BIT from HOST */
757*73b01e57SJeff Chen resp->command = cpu_to_le16(orig_cmdresp_no & HOST_CMD_ID_MASK);
758*73b01e57SJeff Chen
759*73b01e57SJeff Chen cmdresp_no = le16_to_cpu(resp->command);
760*73b01e57SJeff Chen cmdresp_result = le16_to_cpu(resp->result);
761*73b01e57SJeff Chen
762*73b01e57SJeff Chen /* Save the last command response to debug log */
763*73b01e57SJeff Chen adapter->dbg.last_cmd_resp_index =
764*73b01e57SJeff Chen (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
765*73b01e57SJeff Chen adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] =
766*73b01e57SJeff Chen orig_cmdresp_no;
767*73b01e57SJeff Chen
768*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
769*73b01e57SJeff Chen "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
770*73b01e57SJeff Chen orig_cmdresp_no, cmdresp_result,
771*73b01e57SJeff Chen le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
772*73b01e57SJeff Chen nxpwifi_dbg_dump(adapter, CMD_D, "CMD_RESP buffer:", resp,
773*73b01e57SJeff Chen le16_to_cpu(resp->size));
774*73b01e57SJeff Chen
775*73b01e57SJeff Chen if (!(orig_cmdresp_no & HOST_RET_BIT)) {
776*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR, "CMD_RESP: invalid cmd resp\n");
777*73b01e57SJeff Chen if (adapter->curr_cmd->wait_q_enabled)
778*73b01e57SJeff Chen adapter->cmd_wait_q.status = -1;
779*73b01e57SJeff Chen
780*73b01e57SJeff Chen nxpwifi_recycle_cmd_node(adapter, adapter->curr_cmd);
781*73b01e57SJeff Chen spin_lock_bh(&adapter->nxpwifi_cmd_lock);
782*73b01e57SJeff Chen adapter->curr_cmd = NULL;
783*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
784*73b01e57SJeff Chen return -EINVAL;
785*73b01e57SJeff Chen }
786*73b01e57SJeff Chen
787*73b01e57SJeff Chen if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
788*73b01e57SJeff Chen adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
789*73b01e57SJeff Chen if (cmdresp_result == HOST_RESULT_OK &&
790*73b01e57SJeff Chen cmdresp_no == HOST_CMD_802_11_HS_CFG_ENH)
791*73b01e57SJeff Chen ret = nxpwifi_ret_802_11_hs_cfg(priv, resp);
792*73b01e57SJeff Chen } else {
793*73b01e57SJeff Chen if (resp->result != HOST_RESULT_OK) {
794*73b01e57SJeff Chen nxpwifi_process_cmdresp_error(priv, resp);
795*73b01e57SJeff Chen return -EFAULT;
796*73b01e57SJeff Chen }
797*73b01e57SJeff Chen if (adapter->curr_cmd->cmd_resp) {
798*73b01e57SJeff Chen void *data_buf = adapter->curr_cmd->data_buf;
799*73b01e57SJeff Chen
800*73b01e57SJeff Chen ret = adapter->curr_cmd->cmd_resp(priv, resp,
801*73b01e57SJeff Chen cmdresp_no,
802*73b01e57SJeff Chen data_buf);
803*73b01e57SJeff Chen }
804*73b01e57SJeff Chen }
805*73b01e57SJeff Chen
806*73b01e57SJeff Chen if (adapter->curr_cmd) {
807*73b01e57SJeff Chen if (adapter->curr_cmd->wait_q_enabled)
808*73b01e57SJeff Chen adapter->cmd_wait_q.status = ret;
809*73b01e57SJeff Chen
810*73b01e57SJeff Chen nxpwifi_recycle_cmd_node(adapter, adapter->curr_cmd);
811*73b01e57SJeff Chen
812*73b01e57SJeff Chen spin_lock_bh(&adapter->nxpwifi_cmd_lock);
813*73b01e57SJeff Chen adapter->curr_cmd = NULL;
814*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
815*73b01e57SJeff Chen }
816*73b01e57SJeff Chen
817*73b01e57SJeff Chen return ret;
818*73b01e57SJeff Chen }
819*73b01e57SJeff Chen
nxpwifi_process_assoc_resp(struct nxpwifi_adapter * adapter)820*73b01e57SJeff Chen void nxpwifi_process_assoc_resp(struct nxpwifi_adapter *adapter)
821*73b01e57SJeff Chen {
822*73b01e57SJeff Chen struct cfg80211_rx_assoc_resp_data assoc_resp = {
823*73b01e57SJeff Chen .uapsd_queues = -1,
824*73b01e57SJeff Chen };
825*73b01e57SJeff Chen struct nxpwifi_private *priv =
826*73b01e57SJeff Chen nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA);
827*73b01e57SJeff Chen
828*73b01e57SJeff Chen if (priv->assoc_rsp_size) {
829*73b01e57SJeff Chen assoc_resp.links[0].bss = priv->req_bss;
830*73b01e57SJeff Chen assoc_resp.buf = priv->assoc_rsp_buf;
831*73b01e57SJeff Chen assoc_resp.len = priv->assoc_rsp_size;
832*73b01e57SJeff Chen cfg80211_rx_assoc_resp(priv->netdev,
833*73b01e57SJeff Chen &assoc_resp);
834*73b01e57SJeff Chen priv->assoc_rsp_size = 0;
835*73b01e57SJeff Chen }
836*73b01e57SJeff Chen }
837*73b01e57SJeff Chen
838*73b01e57SJeff Chen /*
839*73b01e57SJeff Chen * Command timeout handler: mark timed out, cancel pending IOCTL, dump/reset device if provided.
840*73b01e57SJeff Chen */
841*73b01e57SJeff Chen void
nxpwifi_cmd_timeout_func(struct timer_list * t)842*73b01e57SJeff Chen nxpwifi_cmd_timeout_func(struct timer_list *t)
843*73b01e57SJeff Chen {
844*73b01e57SJeff Chen struct nxpwifi_adapter *adapter = timer_container_of(adapter, t, cmd_timer);
845*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node;
846*73b01e57SJeff Chen
847*73b01e57SJeff Chen set_bit(NXPWIFI_IS_CMD_TIMEDOUT, &adapter->work_flags);
848*73b01e57SJeff Chen if (!adapter->curr_cmd) {
849*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
850*73b01e57SJeff Chen "cmd: empty curr_cmd\n");
851*73b01e57SJeff Chen return;
852*73b01e57SJeff Chen }
853*73b01e57SJeff Chen cmd_node = adapter->curr_cmd;
854*73b01e57SJeff Chen if (cmd_node) {
855*73b01e57SJeff Chen adapter->dbg.timeout_cmd_id =
856*73b01e57SJeff Chen adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index];
857*73b01e57SJeff Chen adapter->dbg.timeout_cmd_act =
858*73b01e57SJeff Chen adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index];
859*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
860*73b01e57SJeff Chen "%s: Timeout cmd id = %#x, act = %#x\n", __func__,
861*73b01e57SJeff Chen adapter->dbg.timeout_cmd_id,
862*73b01e57SJeff Chen adapter->dbg.timeout_cmd_act);
863*73b01e57SJeff Chen
864*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
865*73b01e57SJeff Chen "num_data_h2c_failure = %d\n",
866*73b01e57SJeff Chen adapter->dbg.num_tx_host_to_card_failure);
867*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
868*73b01e57SJeff Chen "num_cmd_h2c_failure = %d\n",
869*73b01e57SJeff Chen adapter->dbg.num_cmd_host_to_card_failure);
870*73b01e57SJeff Chen
871*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
872*73b01e57SJeff Chen "is_cmd_timedout = %d\n",
873*73b01e57SJeff Chen test_bit(NXPWIFI_IS_CMD_TIMEDOUT,
874*73b01e57SJeff Chen &adapter->work_flags));
875*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
876*73b01e57SJeff Chen "num_tx_timeout = %d\n",
877*73b01e57SJeff Chen adapter->dbg.num_tx_timeout);
878*73b01e57SJeff Chen
879*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
880*73b01e57SJeff Chen "last_cmd_index = %d\n",
881*73b01e57SJeff Chen adapter->dbg.last_cmd_index);
882*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
883*73b01e57SJeff Chen "last_cmd_id: %*ph\n",
884*73b01e57SJeff Chen (int)sizeof(adapter->dbg.last_cmd_id),
885*73b01e57SJeff Chen adapter->dbg.last_cmd_id);
886*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
887*73b01e57SJeff Chen "last_cmd_act: %*ph\n",
888*73b01e57SJeff Chen (int)sizeof(adapter->dbg.last_cmd_act),
889*73b01e57SJeff Chen adapter->dbg.last_cmd_act);
890*73b01e57SJeff Chen
891*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
892*73b01e57SJeff Chen "last_cmd_resp_index = %d\n",
893*73b01e57SJeff Chen adapter->dbg.last_cmd_resp_index);
894*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
895*73b01e57SJeff Chen "last_cmd_resp_id: %*ph\n",
896*73b01e57SJeff Chen (int)sizeof(adapter->dbg.last_cmd_resp_id),
897*73b01e57SJeff Chen adapter->dbg.last_cmd_resp_id);
898*73b01e57SJeff Chen
899*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
900*73b01e57SJeff Chen "last_event_index = %d\n",
901*73b01e57SJeff Chen adapter->dbg.last_event_index);
902*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
903*73b01e57SJeff Chen "last_event: %*ph\n",
904*73b01e57SJeff Chen (int)sizeof(adapter->dbg.last_event),
905*73b01e57SJeff Chen adapter->dbg.last_event);
906*73b01e57SJeff Chen
907*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
908*73b01e57SJeff Chen "data_sent=%d cmd_sent=%d\n",
909*73b01e57SJeff Chen adapter->data_sent, adapter->cmd_sent);
910*73b01e57SJeff Chen
911*73b01e57SJeff Chen nxpwifi_dbg(adapter, MSG,
912*73b01e57SJeff Chen "ps_mode=%d ps_state=%d\n",
913*73b01e57SJeff Chen adapter->ps_mode, adapter->ps_state);
914*73b01e57SJeff Chen
915*73b01e57SJeff Chen if (cmd_node->wait_q_enabled) {
916*73b01e57SJeff Chen adapter->cmd_wait_q.status = -ETIMEDOUT;
917*73b01e57SJeff Chen nxpwifi_cancel_pending_ioctl(adapter);
918*73b01e57SJeff Chen }
919*73b01e57SJeff Chen }
920*73b01e57SJeff Chen
921*73b01e57SJeff Chen if (adapter->if_ops.device_dump)
922*73b01e57SJeff Chen adapter->if_ops.device_dump(adapter);
923*73b01e57SJeff Chen
924*73b01e57SJeff Chen if (adapter->if_ops.card_reset)
925*73b01e57SJeff Chen adapter->if_ops.card_reset(adapter);
926*73b01e57SJeff Chen }
927*73b01e57SJeff Chen
928*73b01e57SJeff Chen void
nxpwifi_cancel_pending_scan_cmd(struct nxpwifi_adapter * adapter)929*73b01e57SJeff Chen nxpwifi_cancel_pending_scan_cmd(struct nxpwifi_adapter *adapter)
930*73b01e57SJeff Chen {
931*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
932*73b01e57SJeff Chen
933*73b01e57SJeff Chen /* Cancel all pending scan command */
934*73b01e57SJeff Chen spin_lock_bh(&adapter->scan_pending_q_lock);
935*73b01e57SJeff Chen list_for_each_entry_safe(cmd_node, tmp_node,
936*73b01e57SJeff Chen &adapter->scan_pending_q, list) {
937*73b01e57SJeff Chen list_del(&cmd_node->list);
938*73b01e57SJeff Chen cmd_node->wait_q_enabled = false;
939*73b01e57SJeff Chen nxpwifi_insert_cmd_to_free_q(adapter, cmd_node);
940*73b01e57SJeff Chen }
941*73b01e57SJeff Chen spin_unlock_bh(&adapter->scan_pending_q_lock);
942*73b01e57SJeff Chen }
943*73b01e57SJeff Chen
944*73b01e57SJeff Chen /*
945*73b01e57SJeff Chen * Cancel current cmd (if waiting), all pending cmds, and pending scan cmds; complete with error.
946*73b01e57SJeff Chen */
947*73b01e57SJeff Chen void
nxpwifi_cancel_all_pending_cmd(struct nxpwifi_adapter * adapter)948*73b01e57SJeff Chen nxpwifi_cancel_all_pending_cmd(struct nxpwifi_adapter *adapter)
949*73b01e57SJeff Chen {
950*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
951*73b01e57SJeff Chen
952*73b01e57SJeff Chen spin_lock_bh(&adapter->nxpwifi_cmd_lock);
953*73b01e57SJeff Chen /* Cancel current cmd */
954*73b01e57SJeff Chen if (adapter->curr_cmd && adapter->curr_cmd->wait_q_enabled) {
955*73b01e57SJeff Chen adapter->cmd_wait_q.status = -1;
956*73b01e57SJeff Chen nxpwifi_complete_cmd(adapter, adapter->curr_cmd);
957*73b01e57SJeff Chen adapter->curr_cmd->wait_q_enabled = false;
958*73b01e57SJeff Chen /* no recycle probably wait for response */
959*73b01e57SJeff Chen }
960*73b01e57SJeff Chen /* Cancel all pending command */
961*73b01e57SJeff Chen spin_lock_bh(&adapter->cmd_pending_q_lock);
962*73b01e57SJeff Chen list_for_each_entry_safe(cmd_node, tmp_node,
963*73b01e57SJeff Chen &adapter->cmd_pending_q, list) {
964*73b01e57SJeff Chen list_del(&cmd_node->list);
965*73b01e57SJeff Chen
966*73b01e57SJeff Chen if (cmd_node->wait_q_enabled)
967*73b01e57SJeff Chen adapter->cmd_wait_q.status = -1;
968*73b01e57SJeff Chen nxpwifi_recycle_cmd_node(adapter, cmd_node);
969*73b01e57SJeff Chen }
970*73b01e57SJeff Chen spin_unlock_bh(&adapter->cmd_pending_q_lock);
971*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
972*73b01e57SJeff Chen
973*73b01e57SJeff Chen nxpwifi_cancel_scan(adapter);
974*73b01e57SJeff Chen }
975*73b01e57SJeff Chen
976*73b01e57SJeff Chen /* Cancel current/pending commands for the pending IOCTL; also cancel scan cmds. */
977*73b01e57SJeff Chen static void
nxpwifi_cancel_pending_ioctl(struct nxpwifi_adapter * adapter)978*73b01e57SJeff Chen nxpwifi_cancel_pending_ioctl(struct nxpwifi_adapter *adapter)
979*73b01e57SJeff Chen {
980*73b01e57SJeff Chen struct cmd_ctrl_node *cmd_node = NULL;
981*73b01e57SJeff Chen
982*73b01e57SJeff Chen if (adapter->curr_cmd &&
983*73b01e57SJeff Chen adapter->curr_cmd->wait_q_enabled) {
984*73b01e57SJeff Chen spin_lock_bh(&adapter->nxpwifi_cmd_lock);
985*73b01e57SJeff Chen cmd_node = adapter->curr_cmd;
986*73b01e57SJeff Chen /*
987*73b01e57SJeff Chen * Be careful when setting curr_cmd = NULL:
988*73b01e57SJeff Chen * nxpwifi_process_cmdresp expects a non-NULL pointer.
989*73b01e57SJeff Chen * This is safe here because only cmd_timeout calls this path
990*73b01e57SJeff Chen * and no response is expected at that point.
991*73b01e57SJeff Chen */
992*73b01e57SJeff Chen adapter->curr_cmd = NULL;
993*73b01e57SJeff Chen spin_unlock_bh(&adapter->nxpwifi_cmd_lock);
994*73b01e57SJeff Chen
995*73b01e57SJeff Chen nxpwifi_recycle_cmd_node(adapter, cmd_node);
996*73b01e57SJeff Chen }
997*73b01e57SJeff Chen
998*73b01e57SJeff Chen nxpwifi_cancel_scan(adapter);
999*73b01e57SJeff Chen }
1000*73b01e57SJeff Chen
1001*73b01e57SJeff Chen /* If no cmd/event/tx is pending, send sleep-confirm to FW; otherwise defer. */
1002*73b01e57SJeff Chen void
nxpwifi_check_ps_cond(struct nxpwifi_adapter * adapter)1003*73b01e57SJeff Chen nxpwifi_check_ps_cond(struct nxpwifi_adapter *adapter)
1004*73b01e57SJeff Chen {
1005*73b01e57SJeff Chen if (!adapter->cmd_sent && !atomic_read(&adapter->tx_hw_pending) &&
1006*73b01e57SJeff Chen !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter))
1007*73b01e57SJeff Chen nxpwifi_dnld_sleep_confirm_cmd(adapter);
1008*73b01e57SJeff Chen else
1009*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
1010*73b01e57SJeff Chen "cmd: Delay Sleep Confirm (%s%s%s%s)\n",
1011*73b01e57SJeff Chen (adapter->cmd_sent) ? "D" : "",
1012*73b01e57SJeff Chen atomic_read(&adapter->tx_hw_pending) ? "T" : "",
1013*73b01e57SJeff Chen (adapter->curr_cmd) ? "C" : "",
1014*73b01e57SJeff Chen (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
1015*73b01e57SJeff Chen }
1016*73b01e57SJeff Chen
1017*73b01e57SJeff Chen /* Generate HS activated/deactivated event for userspace; update flags and wake waiters. */
1018*73b01e57SJeff Chen void
nxpwifi_hs_activated_event(struct nxpwifi_private * priv,u8 activated)1019*73b01e57SJeff Chen nxpwifi_hs_activated_event(struct nxpwifi_private *priv, u8 activated)
1020*73b01e57SJeff Chen {
1021*73b01e57SJeff Chen if (activated) {
1022*73b01e57SJeff Chen if (test_bit(NXPWIFI_IS_HS_CONFIGURED,
1023*73b01e57SJeff Chen &priv->adapter->work_flags)) {
1024*73b01e57SJeff Chen priv->adapter->hs_activated = true;
1025*73b01e57SJeff Chen nxpwifi_update_rxreor_flags(priv->adapter,
1026*73b01e57SJeff Chen RXREOR_FORCE_NO_DROP);
1027*73b01e57SJeff Chen nxpwifi_dbg(priv->adapter, EVENT,
1028*73b01e57SJeff Chen "event: hs_activated\n");
1029*73b01e57SJeff Chen priv->adapter->hs_activate_wait_q_woken = true;
1030*73b01e57SJeff Chen wake_up_interruptible(&priv->adapter->hs_activate_wait_q);
1031*73b01e57SJeff Chen } else {
1032*73b01e57SJeff Chen nxpwifi_dbg(priv->adapter, EVENT,
1033*73b01e57SJeff Chen "event: HS not configured\n");
1034*73b01e57SJeff Chen }
1035*73b01e57SJeff Chen } else {
1036*73b01e57SJeff Chen nxpwifi_dbg(priv->adapter, EVENT,
1037*73b01e57SJeff Chen "event: hs_deactivated\n");
1038*73b01e57SJeff Chen priv->adapter->hs_activated = false;
1039*73b01e57SJeff Chen }
1040*73b01e57SJeff Chen }
1041*73b01e57SJeff Chen
1042*73b01e57SJeff Chen /* Handle HS_CFG response: update HS configured/activated flags and emit HS events. */
nxpwifi_ret_802_11_hs_cfg(struct nxpwifi_private * priv,struct host_cmd_ds_command * resp)1043*73b01e57SJeff Chen int nxpwifi_ret_802_11_hs_cfg(struct nxpwifi_private *priv,
1044*73b01e57SJeff Chen struct host_cmd_ds_command *resp)
1045*73b01e57SJeff Chen {
1046*73b01e57SJeff Chen struct nxpwifi_adapter *adapter = priv->adapter;
1047*73b01e57SJeff Chen struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg =
1048*73b01e57SJeff Chen &resp->params.opt_hs_cfg;
1049*73b01e57SJeff Chen u32 conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
1050*73b01e57SJeff Chen
1051*73b01e57SJeff Chen if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) {
1052*73b01e57SJeff Chen nxpwifi_hs_activated_event(priv, true);
1053*73b01e57SJeff Chen goto done;
1054*73b01e57SJeff Chen } else {
1055*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
1056*73b01e57SJeff Chen "cmd: CMD_RESP: HS_CFG cmd reply\t"
1057*73b01e57SJeff Chen " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n",
1058*73b01e57SJeff Chen resp->result, conditions,
1059*73b01e57SJeff Chen phs_cfg->params.hs_config.gpio,
1060*73b01e57SJeff Chen phs_cfg->params.hs_config.gap);
1061*73b01e57SJeff Chen }
1062*73b01e57SJeff Chen if (conditions != HS_CFG_CANCEL) {
1063*73b01e57SJeff Chen set_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags);
1064*73b01e57SJeff Chen } else {
1065*73b01e57SJeff Chen clear_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags);
1066*73b01e57SJeff Chen if (adapter->hs_activated)
1067*73b01e57SJeff Chen nxpwifi_hs_activated_event(priv, false);
1068*73b01e57SJeff Chen }
1069*73b01e57SJeff Chen
1070*73b01e57SJeff Chen done:
1071*73b01e57SJeff Chen return 0;
1072*73b01e57SJeff Chen }
1073*73b01e57SJeff Chen
1074*73b01e57SJeff Chen /* On power-up interrupt, wake device and cancel HS if armed; clear flags and notify. */
1075*73b01e57SJeff Chen void
nxpwifi_process_hs_config(struct nxpwifi_adapter * adapter)1076*73b01e57SJeff Chen nxpwifi_process_hs_config(struct nxpwifi_adapter *adapter)
1077*73b01e57SJeff Chen {
1078*73b01e57SJeff Chen nxpwifi_dbg(adapter, INFO,
1079*73b01e57SJeff Chen "info: %s: auto cancelling host sleep\t"
1080*73b01e57SJeff Chen "since there is interrupt from the firmware\n",
1081*73b01e57SJeff Chen __func__);
1082*73b01e57SJeff Chen
1083*73b01e57SJeff Chen adapter->if_ops.wakeup(adapter);
1084*73b01e57SJeff Chen
1085*73b01e57SJeff Chen if (adapter->hs_activated_manually) {
1086*73b01e57SJeff Chen nxpwifi_cancel_hs(nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_ANY),
1087*73b01e57SJeff Chen NXPWIFI_ASYNC_CMD);
1088*73b01e57SJeff Chen adapter->hs_activated_manually = false;
1089*73b01e57SJeff Chen }
1090*73b01e57SJeff Chen
1091*73b01e57SJeff Chen adapter->hs_activated = false;
1092*73b01e57SJeff Chen clear_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags);
1093*73b01e57SJeff Chen clear_bit(NXPWIFI_IS_SUSPENDED, &adapter->work_flags);
1094*73b01e57SJeff Chen nxpwifi_hs_activated_event(nxpwifi_get_priv(adapter,
1095*73b01e57SJeff Chen NXPWIFI_BSS_ROLE_ANY),
1096*73b01e57SJeff Chen false);
1097*73b01e57SJeff Chen }
1098*73b01e57SJeff Chen EXPORT_SYMBOL_GPL(nxpwifi_process_hs_config);
1099*73b01e57SJeff Chen
1100*73b01e57SJeff Chen /* Handle sleep-confirm response; set ps_state and hs activation accordingly. */
1101*73b01e57SJeff Chen void
nxpwifi_process_sleep_confirm_resp(struct nxpwifi_adapter * adapter,u8 * pbuf,u32 upld_len)1102*73b01e57SJeff Chen nxpwifi_process_sleep_confirm_resp(struct nxpwifi_adapter *adapter,
1103*73b01e57SJeff Chen u8 *pbuf, u32 upld_len)
1104*73b01e57SJeff Chen {
1105*73b01e57SJeff Chen struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *)pbuf;
1106*73b01e57SJeff Chen u16 result = le16_to_cpu(cmd->result);
1107*73b01e57SJeff Chen u16 command = le16_to_cpu(cmd->command);
1108*73b01e57SJeff Chen u16 seq_num = le16_to_cpu(cmd->seq_num);
1109*73b01e57SJeff Chen
1110*73b01e57SJeff Chen if (!upld_len) {
1111*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
1112*73b01e57SJeff Chen "%s: cmd size is 0\n", __func__);
1113*73b01e57SJeff Chen return;
1114*73b01e57SJeff Chen }
1115*73b01e57SJeff Chen
1116*73b01e57SJeff Chen nxpwifi_dbg(adapter, CMD,
1117*73b01e57SJeff Chen "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
1118*73b01e57SJeff Chen command, result, le16_to_cpu(cmd->size), seq_num);
1119*73b01e57SJeff Chen
1120*73b01e57SJeff Chen /* Update sequence number */
1121*73b01e57SJeff Chen seq_num = HOST_GET_SEQ_NO(seq_num);
1122*73b01e57SJeff Chen /* Clear RET_BIT from HOST */
1123*73b01e57SJeff Chen command &= HOST_CMD_ID_MASK;
1124*73b01e57SJeff Chen
1125*73b01e57SJeff Chen if (command != HOST_CMD_802_11_PS_MODE_ENH) {
1126*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
1127*73b01e57SJeff Chen "%s: rcvd unexpected resp for cmd %#x, result = %x\n",
1128*73b01e57SJeff Chen __func__, command, result);
1129*73b01e57SJeff Chen return;
1130*73b01e57SJeff Chen }
1131*73b01e57SJeff Chen
1132*73b01e57SJeff Chen if (result) {
1133*73b01e57SJeff Chen nxpwifi_dbg(adapter, ERROR,
1134*73b01e57SJeff Chen "%s: sleep confirm cmd failed\n",
1135*73b01e57SJeff Chen __func__);
1136*73b01e57SJeff Chen adapter->pm_wakeup_card_req = false;
1137*73b01e57SJeff Chen adapter->ps_state = PS_STATE_AWAKE;
1138*73b01e57SJeff Chen return;
1139*73b01e57SJeff Chen }
1140*73b01e57SJeff Chen adapter->pm_wakeup_card_req = true;
1141*73b01e57SJeff Chen if (test_bit(NXPWIFI_IS_HS_CONFIGURED, &adapter->work_flags))
1142*73b01e57SJeff Chen nxpwifi_hs_activated_event(nxpwifi_get_priv
1143*73b01e57SJeff Chen (adapter, NXPWIFI_BSS_ROLE_ANY),
1144*73b01e57SJeff Chen true);
1145*73b01e57SJeff Chen adapter->ps_state = PS_STATE_SLEEP;
1146*73b01e57SJeff Chen cmd->command = cpu_to_le16(command);
1147*73b01e57SJeff Chen cmd->seq_num = cpu_to_le16(seq_num);
1148*73b01e57SJeff Chen }
1149*73b01e57SJeff Chen EXPORT_SYMBOL_GPL(nxpwifi_process_sleep_confirm_resp);
1150*73b01e57SJeff Chen
nxpwifi_mgmt_frame_reg(struct nxpwifi_private * priv,u32 mask)1151*73b01e57SJeff Chen int nxpwifi_mgmt_frame_reg(struct nxpwifi_private *priv, u32 mask)
1152*73b01e57SJeff Chen {
1153*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_MGMT_FRAME_REG, HOST_ACT_GEN_SET,
1154*73b01e57SJeff Chen 0, &mask, false);
1155*73b01e57SJeff Chen }
1156*73b01e57SJeff Chen
nxpwifi_set_uap_sys_cfg(struct nxpwifi_private * priv,struct nxpwifi_uap_bss_param * cfg)1157*73b01e57SJeff Chen int nxpwifi_set_uap_sys_cfg(struct nxpwifi_private *priv,
1158*73b01e57SJeff Chen struct nxpwifi_uap_bss_param *cfg)
1159*73b01e57SJeff Chen {
1160*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_UAP_SYS_CONFIG, HOST_ACT_GEN_SET,
1161*73b01e57SJeff Chen UAP_BSS_PARAMS_I, cfg, false);
1162*73b01e57SJeff Chen }
1163*73b01e57SJeff Chen
nxpwifi_set_rts(struct nxpwifi_private * priv,u32 rts_thr)1164*73b01e57SJeff Chen int nxpwifi_set_rts(struct nxpwifi_private *priv, u32 rts_thr)
1165*73b01e57SJeff Chen {
1166*73b01e57SJeff Chen if (rts_thr < NXPWIFI_RTS_THRESHOLD_MIN || rts_thr > NXPWIFI_RTS_THRESHOLD_MAX)
1167*73b01e57SJeff Chen rts_thr = NXPWIFI_RTS_THRESHOLD_MAX;
1168*73b01e57SJeff Chen
1169*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB,
1170*73b01e57SJeff Chen HOST_ACT_GEN_SET, RTS_THRESH_I, &rts_thr, true);
1171*73b01e57SJeff Chen }
1172*73b01e57SJeff Chen
nxpwifi_set_frag(struct nxpwifi_private * priv,u32 frag_thr)1173*73b01e57SJeff Chen int nxpwifi_set_frag(struct nxpwifi_private *priv, u32 frag_thr)
1174*73b01e57SJeff Chen {
1175*73b01e57SJeff Chen if (frag_thr < NXPWIFI_FRAG_THRESHOLD_MIN ||
1176*73b01e57SJeff Chen frag_thr > NXPWIFI_FRAG_THRESHOLD_MAX)
1177*73b01e57SJeff Chen frag_thr = NXPWIFI_FRAG_THRESHOLD_MAX;
1178*73b01e57SJeff Chen
1179*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB,
1180*73b01e57SJeff Chen HOST_ACT_GEN_SET, FRAG_THRESH_I, &frag_thr,
1181*73b01e57SJeff Chen true);
1182*73b01e57SJeff Chen }
1183*73b01e57SJeff Chen
nxpwifi_set_bss_mode(struct nxpwifi_private * priv)1184*73b01e57SJeff Chen int nxpwifi_set_bss_mode(struct nxpwifi_private *priv)
1185*73b01e57SJeff Chen {
1186*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_SET_BSS_MODE, HOST_ACT_GEN_SET,
1187*73b01e57SJeff Chen 0, NULL, true);
1188*73b01e57SJeff Chen }
1189*73b01e57SJeff Chen
nxpwifi_config_monitor_mode(struct nxpwifi_private * priv,struct nxpwifi_802_11_net_monitor * cfg)1190*73b01e57SJeff Chen int nxpwifi_config_monitor_mode(struct nxpwifi_private *priv,
1191*73b01e57SJeff Chen struct nxpwifi_802_11_net_monitor *cfg)
1192*73b01e57SJeff Chen {
1193*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_802_11_NET_MONITOR,
1194*73b01e57SJeff Chen HOST_ACT_GEN_SET, 0, cfg, true);
1195*73b01e57SJeff Chen }
1196*73b01e57SJeff Chen
nxpwifi_get_tx_pwr(struct nxpwifi_private * priv)1197*73b01e57SJeff Chen int nxpwifi_get_tx_pwr(struct nxpwifi_private *priv)
1198*73b01e57SJeff Chen {
1199*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_RF_TX_PWR, HOST_ACT_GEN_GET, 0,
1200*73b01e57SJeff Chen NULL, true);
1201*73b01e57SJeff Chen }
1202*73b01e57SJeff Chen
nxpwifi_apply_regdomain(struct nxpwifi_private * priv)1203*73b01e57SJeff Chen int nxpwifi_apply_regdomain(struct nxpwifi_private *priv)
1204*73b01e57SJeff Chen {
1205*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_802_11D_DOMAIN_INFO, HOST_ACT_GEN_SET,
1206*73b01e57SJeff Chen 0, NULL, false);
1207*73b01e57SJeff Chen }
1208*73b01e57SJeff Chen
nxpwifi_get_rssi_info(struct nxpwifi_private * priv)1209*73b01e57SJeff Chen int nxpwifi_get_rssi_info(struct nxpwifi_private *priv)
1210*73b01e57SJeff Chen {
1211*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_RSSI_INFO, HOST_ACT_GEN_GET, 0,
1212*73b01e57SJeff Chen NULL, true);
1213*73b01e57SJeff Chen }
1214*73b01e57SJeff Chen
nxpwifi_get_802_11_snmp_mib(struct nxpwifi_private * priv,u16 oid,void * value)1215*73b01e57SJeff Chen int nxpwifi_get_802_11_snmp_mib(struct nxpwifi_private *priv, u16 oid, void *value)
1216*73b01e57SJeff Chen {
1217*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB, HOST_ACT_GEN_GET,
1218*73b01e57SJeff Chen oid, value, true);
1219*73b01e57SJeff Chen }
1220*73b01e57SJeff Chen
nxpwifi_set_rf_antenna(struct nxpwifi_private * priv,void * antcfg)1221*73b01e57SJeff Chen int nxpwifi_set_rf_antenna(struct nxpwifi_private *priv, void *antcfg)
1222*73b01e57SJeff Chen {
1223*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_RF_ANTENNA, HOST_ACT_GEN_SET, 0, antcfg,
1224*73b01e57SJeff Chen true);
1225*73b01e57SJeff Chen }
1226*73b01e57SJeff Chen
nxpwifi_get_rf_antenna(struct nxpwifi_private * priv,u32 * tx_ant,u32 * rx_ant)1227*73b01e57SJeff Chen int nxpwifi_get_rf_antenna(struct nxpwifi_private *priv, u32 *tx_ant, u32 *rx_ant)
1228*73b01e57SJeff Chen {
1229*73b01e57SJeff Chen int ret;
1230*73b01e57SJeff Chen
1231*73b01e57SJeff Chen ret = nxpwifi_send_cmd(priv, HOST_CMD_RF_ANTENNA, HOST_ACT_GEN_GET, 0, NULL, true);
1232*73b01e57SJeff Chen
1233*73b01e57SJeff Chen if (!ret) {
1234*73b01e57SJeff Chen *tx_ant = priv->tx_ant;
1235*73b01e57SJeff Chen *rx_ant = priv->rx_ant;
1236*73b01e57SJeff Chen }
1237*73b01e57SJeff Chen
1238*73b01e57SJeff Chen return ret;
1239*73b01e57SJeff Chen }
1240*73b01e57SJeff Chen
nxpwifi_ap_stop_bss(struct nxpwifi_private * priv)1241*73b01e57SJeff Chen int nxpwifi_ap_stop_bss(struct nxpwifi_private *priv)
1242*73b01e57SJeff Chen {
1243*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_UAP_BSS_STOP, HOST_ACT_GEN_SET,
1244*73b01e57SJeff Chen 0, NULL, true);
1245*73b01e57SJeff Chen }
1246*73b01e57SJeff Chen
nxpwifi_ap_sys_reset(struct nxpwifi_private * priv)1247*73b01e57SJeff Chen int nxpwifi_ap_sys_reset(struct nxpwifi_private *priv)
1248*73b01e57SJeff Chen {
1249*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET,
1250*73b01e57SJeff Chen HOST_ACT_GEN_SET, 0, NULL, true);
1251*73b01e57SJeff Chen }
1252*73b01e57SJeff Chen
nxpwifi_ap_get_sta_list(struct nxpwifi_private * priv)1253*73b01e57SJeff Chen int nxpwifi_ap_get_sta_list(struct nxpwifi_private *priv)
1254*73b01e57SJeff Chen {
1255*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_APCMD_STA_LIST, HOST_ACT_GEN_GET,
1256*73b01e57SJeff Chen 0, NULL, true);
1257*73b01e57SJeff Chen }
1258*73b01e57SJeff Chen
nxpwifi_set_tx_rate(struct nxpwifi_private * priv,void * bitmap_rates)1259*73b01e57SJeff Chen int nxpwifi_set_tx_rate(struct nxpwifi_private *priv, void *bitmap_rates)
1260*73b01e57SJeff Chen {
1261*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_TX_RATE_CFG, HOST_ACT_GEN_SET, 0,
1262*73b01e57SJeff Chen bitmap_rates, true);
1263*73b01e57SJeff Chen }
1264*73b01e57SJeff Chen
nxpwifi_802_11_subscribe_event(struct nxpwifi_private * priv,struct nxpwifi_ds_misc_subsc_evt * subsc_evt)1265*73b01e57SJeff Chen int nxpwifi_802_11_subscribe_event(struct nxpwifi_private *priv,
1266*73b01e57SJeff Chen struct nxpwifi_ds_misc_subsc_evt *subsc_evt)
1267*73b01e57SJeff Chen {
1268*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_802_11_SUBSCRIBE_EVENT, 0, 0, subsc_evt,
1269*73b01e57SJeff Chen true);
1270*73b01e57SJeff Chen }
1271*73b01e57SJeff Chen
nxpwifi_uap_sta_deauth(struct nxpwifi_private * priv,u8 * mac)1272*73b01e57SJeff Chen int nxpwifi_uap_sta_deauth(struct nxpwifi_private *priv, u8 *mac)
1273*73b01e57SJeff Chen {
1274*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_UAP_STA_DEAUTH, HOST_ACT_GEN_SET, 0, mac, true);
1275*73b01e57SJeff Chen }
1276*73b01e57SJeff Chen
nxpwifi_bg_scan_config(struct nxpwifi_private * priv,void * bg_scan_cfg)1277*73b01e57SJeff Chen int nxpwifi_bg_scan_config(struct nxpwifi_private *priv, void *bg_scan_cfg)
1278*73b01e57SJeff Chen {
1279*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_802_11_BG_SCAN_CONFIG, HOST_ACT_GEN_SET,
1280*73b01e57SJeff Chen 0, bg_scan_cfg, true);
1281*73b01e57SJeff Chen }
1282*73b01e57SJeff Chen
nxpwifi_mef_cfg(struct nxpwifi_private * priv,void * mef_cfg)1283*73b01e57SJeff Chen int nxpwifi_mef_cfg(struct nxpwifi_private *priv, void *mef_cfg)
1284*73b01e57SJeff Chen {
1285*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_MEF_CFG, HOST_ACT_GEN_SET, 0, mef_cfg,
1286*73b01e57SJeff Chen true);
1287*73b01e57SJeff Chen }
1288*73b01e57SJeff Chen
nxpwifi_coalesce_cfg(struct nxpwifi_private * priv,void * coalesce_cfg)1289*73b01e57SJeff Chen int nxpwifi_coalesce_cfg(struct nxpwifi_private *priv, void *coalesce_cfg)
1290*73b01e57SJeff Chen {
1291*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_COALESCE_CFG, HOST_ACT_GEN_SET, 0,
1292*73b01e57SJeff Chen coalesce_cfg, true);
1293*73b01e57SJeff Chen }
1294*73b01e57SJeff Chen
nxpwifi_add_new_station(struct nxpwifi_private * priv,void * add_sta)1295*73b01e57SJeff Chen int nxpwifi_add_new_station(struct nxpwifi_private *priv, void *add_sta)
1296*73b01e57SJeff Chen {
1297*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_ADD_NEW_STATION, HOST_ACT_ADD_STA, 0,
1298*73b01e57SJeff Chen add_sta, true);
1299*73b01e57SJeff Chen }
1300*73b01e57SJeff Chen
nxpwifi_hostcmd(struct nxpwifi_private * priv,struct nxpwifi_ds_misc_cmd * hostcmd)1301*73b01e57SJeff Chen int nxpwifi_hostcmd(struct nxpwifi_private *priv, struct nxpwifi_ds_misc_cmd *hostcmd)
1302*73b01e57SJeff Chen {
1303*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, 0, 0, 0, hostcmd, true);
1304*73b01e57SJeff Chen }
1305*73b01e57SJeff Chen
nxpwifi_chan_report_request(struct nxpwifi_private * priv,void * radar_params)1306*73b01e57SJeff Chen int nxpwifi_chan_report_request(struct nxpwifi_private *priv, void *radar_params)
1307*73b01e57SJeff Chen {
1308*73b01e57SJeff Chen return nxpwifi_send_cmd(priv, HOST_CMD_CHAN_REPORT_REQUEST, HOST_ACT_GEN_SET, 0,
1309*73b01e57SJeff Chen radar_params, true);
1310*73b01e57SJeff Chen }
1311