xref: /linux/drivers/net/wireless/nxp/nxpwifi/cmdevt.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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