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