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