1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/moduleparam.h>
19#include <linux/etherdevice.h>
20#include <linux/if_arp.h>
21
22#include "wil6210.h"
23#include "txrx.h"
24#include "wmi.h"
25#include "trace.h"
26
27static uint max_assoc_sta = WIL6210_MAX_CID;
28module_param(max_assoc_sta, uint, 0644);
29MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
30
31int agg_wsize;
32module_param(agg_wsize, int, 0644);
33MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
34 " 0 - use default; < 0 - don't auto-establish");
35
36u8 led_id = WIL_LED_INVALID_ID;
37module_param(led_id, byte, 0444);
38MODULE_PARM_DESC(led_id,
39 " 60G device led enablement. Set the led ID (0-2) to enable");
40
41#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
42#define WIL_WMI_CALL_GENERAL_TO_MS 100
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90const struct fw_map sparrow_fw_mapping[] = {
91
92 {0x000000, 0x040000, 0x8c0000, "fw_code", true},
93
94 {0x800000, 0x808000, 0x900000, "fw_data", true},
95
96 {0x840000, 0x860000, 0x908000, "fw_peri", true},
97
98 {0x880000, 0x88a000, 0x880000, "rgf", true},
99
100 {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
101
102 {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
103
104 {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext", true},
105
106 {0x8c0000, 0x949000, 0x8c0000, "upper", true},
107
108
109
110
111 {0x000000, 0x020000, 0x920000, "uc_code", false},
112
113 {0x800000, 0x804000, 0x940000, "uc_data", false},
114};
115
116
117
118
119
120const struct fw_map sparrow_d0_mac_rgf_ext = {
121 0x88c000, 0x88c500, 0x88c000, "mac_rgf_ext", true
122};
123
124
125
126
127
128
129
130
131
132
133
134
135const struct fw_map talyn_fw_mapping[] = {
136
137 {0x000000, 0x100000, 0x900000, "fw_code", true},
138
139 {0x800000, 0x820000, 0xa00000, "fw_data", true},
140
141 {0x840000, 0x858000, 0xa20000, "fw_peri", true},
142
143 {0x880000, 0x88a000, 0x880000, "rgf", true},
144
145 {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
146
147 {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
148
149 {0x88c000, 0x88c540, 0x88c000, "mac_rgf_ext", true},
150
151 {0x88d000, 0x88e000, 0x88d000, "ext_user_rgf", true},
152
153 {0x8a0000, 0x8a1000, 0x8a0000, "otp", true},
154
155 {0x8b0000, 0x8c0000, 0x8b0000, "dma_ext_rgf", true},
156
157 {0x900000, 0xa80000, 0x900000, "upper", true},
158
159
160
161
162 {0x000000, 0x040000, 0xa38000, "uc_code", false},
163
164 {0x800000, 0x808000, 0xa78000, "uc_data", false},
165};
166
167struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
168
169struct blink_on_off_time led_blink_time[] = {
170 {WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
171 {WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
172 {WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS},
173};
174
175u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
176
177
178
179
180
181
182static u32 wmi_addr_remap(u32 x)
183{
184 uint i;
185
186 for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
187 if (fw_mapping[i].fw &&
188 ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)))
189 return x + fw_mapping[i].host - fw_mapping[i].from;
190 }
191
192 return 0;
193}
194
195
196
197
198
199
200
201struct fw_map *wil_find_fw_mapping(const char *section)
202{
203 int i;
204
205 for (i = 0; i < ARRAY_SIZE(fw_mapping); i++)
206 if (fw_mapping[i].name &&
207 !strcmp(section, fw_mapping[i].name))
208 return &fw_mapping[i];
209
210 return NULL;
211}
212
213
214
215
216
217
218
219
220
221
222
223
224void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size)
225{
226 u32 off;
227 u32 ptr = le32_to_cpu(ptr_);
228
229 if (ptr % 4)
230 return NULL;
231
232 ptr = wmi_addr_remap(ptr);
233 if (ptr < WIL6210_FW_HOST_OFF)
234 return NULL;
235
236 off = HOSTADDR(ptr);
237 if (off > wil->bar_size - 4)
238 return NULL;
239 if (size && ((off + size > wil->bar_size) || (off + size < off)))
240 return NULL;
241
242 return wil->csr + off;
243}
244
245void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
246{
247 return wmi_buffer_block(wil, ptr_, 0);
248}
249
250
251
252
253void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
254{
255 u32 off;
256
257 if (ptr % 4)
258 return NULL;
259
260 if (ptr < WIL6210_FW_HOST_OFF)
261 return NULL;
262
263 off = HOSTADDR(ptr);
264 if (off > wil->bar_size - 4)
265 return NULL;
266
267 return wil->csr + off;
268}
269
270int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
271 struct wil6210_mbox_hdr *hdr)
272{
273 void __iomem *src = wmi_buffer(wil, ptr);
274
275 if (!src)
276 return -EINVAL;
277
278 wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
279
280 return 0;
281}
282
283static const char *cmdid2name(u16 cmdid)
284{
285 switch (cmdid) {
286 case WMI_NOTIFY_REQ_CMDID:
287 return "WMI_NOTIFY_REQ_CMD";
288 case WMI_START_SCAN_CMDID:
289 return "WMI_START_SCAN_CMD";
290 case WMI_CONNECT_CMDID:
291 return "WMI_CONNECT_CMD";
292 case WMI_DISCONNECT_CMDID:
293 return "WMI_DISCONNECT_CMD";
294 case WMI_SW_TX_REQ_CMDID:
295 return "WMI_SW_TX_REQ_CMD";
296 case WMI_GET_RF_SECTOR_PARAMS_CMDID:
297 return "WMI_GET_RF_SECTOR_PARAMS_CMD";
298 case WMI_SET_RF_SECTOR_PARAMS_CMDID:
299 return "WMI_SET_RF_SECTOR_PARAMS_CMD";
300 case WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID:
301 return "WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD";
302 case WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID:
303 return "WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD";
304 case WMI_BRP_SET_ANT_LIMIT_CMDID:
305 return "WMI_BRP_SET_ANT_LIMIT_CMD";
306 case WMI_TOF_SESSION_START_CMDID:
307 return "WMI_TOF_SESSION_START_CMD";
308 case WMI_AOA_MEAS_CMDID:
309 return "WMI_AOA_MEAS_CMD";
310 case WMI_PMC_CMDID:
311 return "WMI_PMC_CMD";
312 case WMI_TOF_GET_TX_RX_OFFSET_CMDID:
313 return "WMI_TOF_GET_TX_RX_OFFSET_CMD";
314 case WMI_TOF_SET_TX_RX_OFFSET_CMDID:
315 return "WMI_TOF_SET_TX_RX_OFFSET_CMD";
316 case WMI_VRING_CFG_CMDID:
317 return "WMI_VRING_CFG_CMD";
318 case WMI_BCAST_VRING_CFG_CMDID:
319 return "WMI_BCAST_VRING_CFG_CMD";
320 case WMI_TRAFFIC_SUSPEND_CMDID:
321 return "WMI_TRAFFIC_SUSPEND_CMD";
322 case WMI_TRAFFIC_RESUME_CMDID:
323 return "WMI_TRAFFIC_RESUME_CMD";
324 case WMI_ECHO_CMDID:
325 return "WMI_ECHO_CMD";
326 case WMI_SET_MAC_ADDRESS_CMDID:
327 return "WMI_SET_MAC_ADDRESS_CMD";
328 case WMI_LED_CFG_CMDID:
329 return "WMI_LED_CFG_CMD";
330 case WMI_PCP_START_CMDID:
331 return "WMI_PCP_START_CMD";
332 case WMI_PCP_STOP_CMDID:
333 return "WMI_PCP_STOP_CMD";
334 case WMI_SET_SSID_CMDID:
335 return "WMI_SET_SSID_CMD";
336 case WMI_GET_SSID_CMDID:
337 return "WMI_GET_SSID_CMD";
338 case WMI_SET_PCP_CHANNEL_CMDID:
339 return "WMI_SET_PCP_CHANNEL_CMD";
340 case WMI_GET_PCP_CHANNEL_CMDID:
341 return "WMI_GET_PCP_CHANNEL_CMD";
342 case WMI_P2P_CFG_CMDID:
343 return "WMI_P2P_CFG_CMD";
344 case WMI_START_LISTEN_CMDID:
345 return "WMI_START_LISTEN_CMD";
346 case WMI_START_SEARCH_CMDID:
347 return "WMI_START_SEARCH_CMD";
348 case WMI_DISCOVERY_STOP_CMDID:
349 return "WMI_DISCOVERY_STOP_CMD";
350 case WMI_DELETE_CIPHER_KEY_CMDID:
351 return "WMI_DELETE_CIPHER_KEY_CMD";
352 case WMI_ADD_CIPHER_KEY_CMDID:
353 return "WMI_ADD_CIPHER_KEY_CMD";
354 case WMI_SET_APPIE_CMDID:
355 return "WMI_SET_APPIE_CMD";
356 case WMI_CFG_RX_CHAIN_CMDID:
357 return "WMI_CFG_RX_CHAIN_CMD";
358 case WMI_TEMP_SENSE_CMDID:
359 return "WMI_TEMP_SENSE_CMD";
360 case WMI_DEL_STA_CMDID:
361 return "WMI_DEL_STA_CMD";
362 case WMI_DISCONNECT_STA_CMDID:
363 return "WMI_DISCONNECT_STA_CMD";
364 case WMI_VRING_BA_EN_CMDID:
365 return "WMI_VRING_BA_EN_CMD";
366 case WMI_VRING_BA_DIS_CMDID:
367 return "WMI_VRING_BA_DIS_CMD";
368 case WMI_RCP_DELBA_CMDID:
369 return "WMI_RCP_DELBA_CMD";
370 case WMI_RCP_ADDBA_RESP_CMDID:
371 return "WMI_RCP_ADDBA_RESP_CMD";
372 case WMI_PS_DEV_PROFILE_CFG_CMDID:
373 return "WMI_PS_DEV_PROFILE_CFG_CMD";
374 case WMI_SET_MGMT_RETRY_LIMIT_CMDID:
375 return "WMI_SET_MGMT_RETRY_LIMIT_CMD";
376 case WMI_GET_MGMT_RETRY_LIMIT_CMDID:
377 return "WMI_GET_MGMT_RETRY_LIMIT_CMD";
378 case WMI_ABORT_SCAN_CMDID:
379 return "WMI_ABORT_SCAN_CMD";
380 case WMI_NEW_STA_CMDID:
381 return "WMI_NEW_STA_CMD";
382 case WMI_SET_THERMAL_THROTTLING_CFG_CMDID:
383 return "WMI_SET_THERMAL_THROTTLING_CFG_CMD";
384 case WMI_GET_THERMAL_THROTTLING_CFG_CMDID:
385 return "WMI_GET_THERMAL_THROTTLING_CFG_CMD";
386 case WMI_LINK_MAINTAIN_CFG_WRITE_CMDID:
387 return "WMI_LINK_MAINTAIN_CFG_WRITE_CMD";
388 case WMI_LO_POWER_CALIB_FROM_OTP_CMDID:
389 return "WMI_LO_POWER_CALIB_FROM_OTP_CMD";
390 case WMI_START_SCHED_SCAN_CMDID:
391 return "WMI_START_SCHED_SCAN_CMD";
392 case WMI_STOP_SCHED_SCAN_CMDID:
393 return "WMI_STOP_SCHED_SCAN_CMD";
394 default:
395 return "Untracked CMD";
396 }
397}
398
399static const char *eventid2name(u16 eventid)
400{
401 switch (eventid) {
402 case WMI_NOTIFY_REQ_DONE_EVENTID:
403 return "WMI_NOTIFY_REQ_DONE_EVENT";
404 case WMI_DISCONNECT_EVENTID:
405 return "WMI_DISCONNECT_EVENT";
406 case WMI_SW_TX_COMPLETE_EVENTID:
407 return "WMI_SW_TX_COMPLETE_EVENT";
408 case WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID:
409 return "WMI_GET_RF_SECTOR_PARAMS_DONE_EVENT";
410 case WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID:
411 return "WMI_SET_RF_SECTOR_PARAMS_DONE_EVENT";
412 case WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
413 return "WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
414 case WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID:
415 return "WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT";
416 case WMI_BRP_SET_ANT_LIMIT_EVENTID:
417 return "WMI_BRP_SET_ANT_LIMIT_EVENT";
418 case WMI_FW_READY_EVENTID:
419 return "WMI_FW_READY_EVENT";
420 case WMI_TRAFFIC_RESUME_EVENTID:
421 return "WMI_TRAFFIC_RESUME_EVENT";
422 case WMI_TOF_GET_TX_RX_OFFSET_EVENTID:
423 return "WMI_TOF_GET_TX_RX_OFFSET_EVENT";
424 case WMI_TOF_SET_TX_RX_OFFSET_EVENTID:
425 return "WMI_TOF_SET_TX_RX_OFFSET_EVENT";
426 case WMI_VRING_CFG_DONE_EVENTID:
427 return "WMI_VRING_CFG_DONE_EVENT";
428 case WMI_READY_EVENTID:
429 return "WMI_READY_EVENT";
430 case WMI_RX_MGMT_PACKET_EVENTID:
431 return "WMI_RX_MGMT_PACKET_EVENT";
432 case WMI_TX_MGMT_PACKET_EVENTID:
433 return "WMI_TX_MGMT_PACKET_EVENT";
434 case WMI_SCAN_COMPLETE_EVENTID:
435 return "WMI_SCAN_COMPLETE_EVENT";
436 case WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID:
437 return "WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENT";
438 case WMI_CONNECT_EVENTID:
439 return "WMI_CONNECT_EVENT";
440 case WMI_EAPOL_RX_EVENTID:
441 return "WMI_EAPOL_RX_EVENT";
442 case WMI_BA_STATUS_EVENTID:
443 return "WMI_BA_STATUS_EVENT";
444 case WMI_RCP_ADDBA_REQ_EVENTID:
445 return "WMI_RCP_ADDBA_REQ_EVENT";
446 case WMI_DELBA_EVENTID:
447 return "WMI_DELBA_EVENT";
448 case WMI_VRING_EN_EVENTID:
449 return "WMI_VRING_EN_EVENT";
450 case WMI_DATA_PORT_OPEN_EVENTID:
451 return "WMI_DATA_PORT_OPEN_EVENT";
452 case WMI_AOA_MEAS_EVENTID:
453 return "WMI_AOA_MEAS_EVENT";
454 case WMI_TOF_SESSION_END_EVENTID:
455 return "WMI_TOF_SESSION_END_EVENT";
456 case WMI_TOF_GET_CAPABILITIES_EVENTID:
457 return "WMI_TOF_GET_CAPABILITIES_EVENT";
458 case WMI_TOF_SET_LCR_EVENTID:
459 return "WMI_TOF_SET_LCR_EVENT";
460 case WMI_TOF_SET_LCI_EVENTID:
461 return "WMI_TOF_SET_LCI_EVENT";
462 case WMI_TOF_FTM_PER_DEST_RES_EVENTID:
463 return "WMI_TOF_FTM_PER_DEST_RES_EVENT";
464 case WMI_TOF_CHANNEL_INFO_EVENTID:
465 return "WMI_TOF_CHANNEL_INFO_EVENT";
466 case WMI_TRAFFIC_SUSPEND_EVENTID:
467 return "WMI_TRAFFIC_SUSPEND_EVENT";
468 case WMI_ECHO_RSP_EVENTID:
469 return "WMI_ECHO_RSP_EVENT";
470 case WMI_LED_CFG_DONE_EVENTID:
471 return "WMI_LED_CFG_DONE_EVENT";
472 case WMI_PCP_STARTED_EVENTID:
473 return "WMI_PCP_STARTED_EVENT";
474 case WMI_PCP_STOPPED_EVENTID:
475 return "WMI_PCP_STOPPED_EVENT";
476 case WMI_GET_SSID_EVENTID:
477 return "WMI_GET_SSID_EVENT";
478 case WMI_GET_PCP_CHANNEL_EVENTID:
479 return "WMI_GET_PCP_CHANNEL_EVENT";
480 case WMI_P2P_CFG_DONE_EVENTID:
481 return "WMI_P2P_CFG_DONE_EVENT";
482 case WMI_LISTEN_STARTED_EVENTID:
483 return "WMI_LISTEN_STARTED_EVENT";
484 case WMI_SEARCH_STARTED_EVENTID:
485 return "WMI_SEARCH_STARTED_EVENT";
486 case WMI_DISCOVERY_STOPPED_EVENTID:
487 return "WMI_DISCOVERY_STOPPED_EVENT";
488 case WMI_CFG_RX_CHAIN_DONE_EVENTID:
489 return "WMI_CFG_RX_CHAIN_DONE_EVENT";
490 case WMI_TEMP_SENSE_DONE_EVENTID:
491 return "WMI_TEMP_SENSE_DONE_EVENT";
492 case WMI_RCP_ADDBA_RESP_SENT_EVENTID:
493 return "WMI_RCP_ADDBA_RESP_SENT_EVENT";
494 case WMI_PS_DEV_PROFILE_CFG_EVENTID:
495 return "WMI_PS_DEV_PROFILE_CFG_EVENT";
496 case WMI_SET_MGMT_RETRY_LIMIT_EVENTID:
497 return "WMI_SET_MGMT_RETRY_LIMIT_EVENT";
498 case WMI_GET_MGMT_RETRY_LIMIT_EVENTID:
499 return "WMI_GET_MGMT_RETRY_LIMIT_EVENT";
500 case WMI_SET_THERMAL_THROTTLING_CFG_EVENTID:
501 return "WMI_SET_THERMAL_THROTTLING_CFG_EVENT";
502 case WMI_GET_THERMAL_THROTTLING_CFG_EVENTID:
503 return "WMI_GET_THERMAL_THROTTLING_CFG_EVENT";
504 case WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID:
505 return "WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENT";
506 case WMI_LO_POWER_CALIB_FROM_OTP_EVENTID:
507 return "WMI_LO_POWER_CALIB_FROM_OTP_EVENT";
508 case WMI_START_SCHED_SCAN_EVENTID:
509 return "WMI_START_SCHED_SCAN_EVENT";
510 case WMI_STOP_SCHED_SCAN_EVENTID:
511 return "WMI_STOP_SCHED_SCAN_EVENT";
512 case WMI_SCHED_SCAN_RESULT_EVENTID:
513 return "WMI_SCHED_SCAN_RESULT_EVENT";
514 default:
515 return "Untracked EVENT";
516 }
517}
518
519static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
520{
521 struct {
522 struct wil6210_mbox_hdr hdr;
523 struct wmi_cmd_hdr wmi;
524 } __packed cmd = {
525 .hdr = {
526 .type = WIL_MBOX_HDR_TYPE_WMI,
527 .flags = 0,
528 .len = cpu_to_le16(sizeof(cmd.wmi) + len),
529 },
530 .wmi = {
531 .mid = 0,
532 .command_id = cpu_to_le16(cmdid),
533 },
534 };
535 struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
536 struct wil6210_mbox_ring_desc d_head;
537 u32 next_head;
538 void __iomem *dst;
539 void __iomem *head = wmi_addr(wil, r->head);
540 uint retry;
541 int rc = 0;
542
543 if (len > r->entry_size - sizeof(cmd)) {
544 wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
545 (int)(sizeof(cmd) + len), r->entry_size);
546 return -ERANGE;
547 }
548
549 might_sleep();
550
551 if (!test_bit(wil_status_fwready, wil->status)) {
552 wil_err(wil, "WMI: cannot send command while FW not ready\n");
553 return -EAGAIN;
554 }
555
556
557 if ((test_bit(wil_status_suspending, wil->status) ||
558 test_bit(wil_status_suspended, wil->status) ||
559 test_bit(wil_status_resuming, wil->status)) &&
560 ((cmdid != WMI_TRAFFIC_SUSPEND_CMDID) &&
561 (cmdid != WMI_TRAFFIC_RESUME_CMDID))) {
562 wil_err(wil, "WMI: reject send_command during suspend\n");
563 return -EINVAL;
564 }
565
566 if (!head) {
567 wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
568 return -EINVAL;
569 }
570
571 wil_halp_vote(wil);
572
573
574 for (retry = 5; retry > 0; retry--) {
575 wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
576 if (d_head.sync == 0)
577 break;
578 msleep(20);
579 }
580 if (d_head.sync != 0) {
581 wil_err(wil, "WMI head busy\n");
582 rc = -EBUSY;
583 goto out;
584 }
585
586 next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
587 wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
588
589 for (retry = 5; retry > 0; retry--) {
590 if (!test_bit(wil_status_fwready, wil->status)) {
591 wil_err(wil, "WMI: cannot send command while FW not ready\n");
592 rc = -EAGAIN;
593 goto out;
594 }
595 r->tail = wil_r(wil, RGF_MBOX +
596 offsetof(struct wil6210_mbox_ctl, tx.tail));
597 if (next_head != r->tail)
598 break;
599 msleep(20);
600 }
601 if (next_head == r->tail) {
602 wil_err(wil, "WMI ring full\n");
603 rc = -EBUSY;
604 goto out;
605 }
606 dst = wmi_buffer(wil, d_head.addr);
607 if (!dst) {
608 wil_err(wil, "invalid WMI buffer: 0x%08x\n",
609 le32_to_cpu(d_head.addr));
610 rc = -EAGAIN;
611 goto out;
612 }
613 cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
614
615 wil_dbg_wmi(wil, "sending %s (0x%04x) [%d]\n",
616 cmdid2name(cmdid), cmdid, len);
617 wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
618 sizeof(cmd), true);
619 wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
620 len, true);
621 wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
622 wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
623
624 wil_w(wil, r->head + offsetof(struct wil6210_mbox_ring_desc, sync), 1);
625
626 wil_w(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, tx.head),
627 r->head = next_head);
628
629 trace_wil6210_wmi_cmd(&cmd.wmi, buf, len);
630
631
632 wil_w(wil, RGF_USER_USER_ICR + offsetof(struct RGF_ICR, ICS),
633 SW_INT_MBOX);
634
635out:
636 wil_halp_unvote(wil);
637 return rc;
638}
639
640int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
641{
642 int rc;
643
644 mutex_lock(&wil->wmi_mutex);
645 rc = __wmi_send(wil, cmdid, buf, len);
646 mutex_unlock(&wil->wmi_mutex);
647
648 return rc;
649}
650
651
652static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
653{
654 struct wireless_dev *wdev = wil->wdev;
655 struct wmi_ready_event *evt = d;
656
657 wil->n_mids = evt->numof_additional_mids;
658
659 wil_info(wil, "FW ver. %s(SW %d); MAC %pM; %d MID's\n",
660 wil->fw_version, le32_to_cpu(evt->sw_version),
661 evt->mac, wil->n_mids);
662
663 strlcpy(wdev->wiphy->fw_version, wil->fw_version,
664 sizeof(wdev->wiphy->fw_version));
665
666 if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) {
667 wil_dbg_wmi(wil, "rfc calibration result %d\n",
668 evt->rfc_read_calib_result);
669 wil->fw_calib_result = evt->rfc_read_calib_result;
670 }
671 wil_set_recovery_state(wil, fw_recovery_idle);
672 set_bit(wil_status_fwready, wil->status);
673
674 complete(&wil->wmi_ready);
675}
676
677static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
678{
679 struct wmi_rx_mgmt_packet_event *data = d;
680 struct wiphy *wiphy = wil_to_wiphy(wil);
681 struct ieee80211_mgmt *rx_mgmt_frame =
682 (struct ieee80211_mgmt *)data->payload;
683 int flen = len - offsetof(struct wmi_rx_mgmt_packet_event, payload);
684 int ch_no;
685 u32 freq;
686 struct ieee80211_channel *channel;
687 s32 signal;
688 __le16 fc;
689 u32 d_len;
690 u16 d_status;
691
692 if (flen < 0) {
693 wil_err(wil, "MGMT Rx: short event, len %d\n", len);
694 return;
695 }
696
697 d_len = le32_to_cpu(data->info.len);
698 if (d_len != flen) {
699 wil_err(wil,
700 "MGMT Rx: length mismatch, d_len %d should be %d\n",
701 d_len, flen);
702 return;
703 }
704
705 ch_no = data->info.channel + 1;
706 freq = ieee80211_channel_to_frequency(ch_no, NL80211_BAND_60GHZ);
707 channel = ieee80211_get_channel(wiphy, freq);
708 if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
709 signal = 100 * data->info.rssi;
710 else
711 signal = data->info.sqi;
712 d_status = le16_to_cpu(data->info.status);
713 fc = rx_mgmt_frame->frame_control;
714
715 wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d RSSI %d SQI %d%%\n",
716 data->info.channel, data->info.mcs, data->info.rssi,
717 data->info.sqi);
718 wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
719 le16_to_cpu(fc));
720 wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
721 data->info.qid, data->info.mid, data->info.cid);
722 wil_hex_dump_wmi("MGMT Rx ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame,
723 d_len, true);
724
725 if (!channel) {
726 wil_err(wil, "Frame on unsupported channel\n");
727 return;
728 }
729
730 if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
731 struct cfg80211_bss *bss;
732 u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
733 u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
734 u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
735 const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
736 size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
737 u.beacon.variable);
738 wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
739 wil_dbg_wmi(wil, "TSF : 0x%016llx\n", tsf);
740 wil_dbg_wmi(wil, "Beacon interval : %d\n", bi);
741 wil_hex_dump_wmi("IE ", DUMP_PREFIX_OFFSET, 16, 1, ie_buf,
742 ie_len, true);
743
744 wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
745
746 bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
747 d_len, signal, GFP_KERNEL);
748 if (bss) {
749 wil_dbg_wmi(wil, "Added BSS %pM\n",
750 rx_mgmt_frame->bssid);
751 cfg80211_put_bss(wiphy, bss);
752 } else {
753 wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
754 }
755 } else {
756 mutex_lock(&wil->p2p_wdev_mutex);
757 cfg80211_rx_mgmt(wil->radio_wdev, freq, signal,
758 (void *)rx_mgmt_frame, d_len, 0);
759 mutex_unlock(&wil->p2p_wdev_mutex);
760 }
761}
762
763static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
764{
765 struct wmi_tx_mgmt_packet_event *data = d;
766 struct ieee80211_mgmt *mgmt_frame =
767 (struct ieee80211_mgmt *)data->payload;
768 int flen = len - offsetof(struct wmi_tx_mgmt_packet_event, payload);
769
770 wil_hex_dump_wmi("MGMT Tx ", DUMP_PREFIX_OFFSET, 16, 1, mgmt_frame,
771 flen, true);
772}
773
774static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
775 void *d, int len)
776{
777 mutex_lock(&wil->p2p_wdev_mutex);
778 if (wil->scan_request) {
779 struct wmi_scan_complete_event *data = d;
780 int status = le32_to_cpu(data->status);
781 struct cfg80211_scan_info info = {
782 .aborted = ((status != WMI_SCAN_SUCCESS) &&
783 (status != WMI_SCAN_ABORT_REJECTED)),
784 };
785
786 wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", status);
787 wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
788 wil->scan_request, info.aborted);
789 del_timer_sync(&wil->scan_timer);
790 cfg80211_scan_done(wil->scan_request, &info);
791 wil->radio_wdev = wil->wdev;
792 wil->scan_request = NULL;
793 wake_up_interruptible(&wil->wq);
794 if (wil->p2p.pending_listen_wdev) {
795 wil_dbg_misc(wil, "Scheduling delayed listen\n");
796 schedule_work(&wil->p2p.delayed_listen_work);
797 }
798 } else {
799 wil_err(wil, "SCAN_COMPLETE while not scanning\n");
800 }
801 mutex_unlock(&wil->p2p_wdev_mutex);
802}
803
804static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
805{
806 struct net_device *ndev = wil_to_ndev(wil);
807 struct wireless_dev *wdev = wil->wdev;
808 struct wmi_connect_event *evt = d;
809 int ch;
810 struct station_info sinfo;
811 u8 *assoc_req_ie, *assoc_resp_ie;
812 size_t assoc_req_ielen, assoc_resp_ielen;
813
814 const size_t assoc_req_ie_offset = sizeof(u16) * 2;
815
816 const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
817 int rc;
818
819 if (len < sizeof(*evt)) {
820 wil_err(wil, "Connect event too short : %d bytes\n", len);
821 return;
822 }
823 if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len +
824 evt->assoc_resp_len) {
825 wil_err(wil,
826 "Connect event corrupted : %d != %d + %d + %d + %d\n",
827 len, (int)sizeof(*evt), evt->beacon_ie_len,
828 evt->assoc_req_len, evt->assoc_resp_len);
829 return;
830 }
831 if (evt->cid >= WIL6210_MAX_CID) {
832 wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
833 return;
834 }
835
836 ch = evt->channel + 1;
837 wil_info(wil, "Connect %pM channel [%d] cid %d aid %d\n",
838 evt->bssid, ch, evt->cid, evt->aid);
839 wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
840 evt->assoc_info, len - sizeof(*evt), true);
841
842
843 assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len +
844 assoc_req_ie_offset];
845 assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset;
846 if (evt->assoc_req_len <= assoc_req_ie_offset) {
847 assoc_req_ie = NULL;
848 assoc_req_ielen = 0;
849 }
850
851 assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len +
852 evt->assoc_req_len +
853 assoc_resp_ie_offset];
854 assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset;
855 if (evt->assoc_resp_len <= assoc_resp_ie_offset) {
856 assoc_resp_ie = NULL;
857 assoc_resp_ielen = 0;
858 }
859
860 if (test_bit(wil_status_resetting, wil->status) ||
861 !test_bit(wil_status_fwready, wil->status)) {
862 wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
863 evt->cid);
864
865 return;
866 }
867
868 mutex_lock(&wil->mutex);
869
870 if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
871 (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
872 if (!test_bit(wil_status_fwconnecting, wil->status)) {
873 wil_err(wil, "Not in connecting state\n");
874 mutex_unlock(&wil->mutex);
875 return;
876 }
877 del_timer_sync(&wil->connect_timer);
878 } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
879 (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
880 if (wil->sta[evt->cid].status != wil_sta_unused) {
881 wil_err(wil, "AP: Invalid status %d for CID %d\n",
882 wil->sta[evt->cid].status, evt->cid);
883 mutex_unlock(&wil->mutex);
884 return;
885 }
886 }
887
888 ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
889 wil->sta[evt->cid].status = wil_sta_conn_pending;
890
891 rc = wil_tx_init(wil, evt->cid);
892 if (rc) {
893 wil_err(wil, "config tx vring failed for CID %d, rc (%d)\n",
894 evt->cid, rc);
895 wmi_disconnect_sta(wil, wil->sta[evt->cid].addr,
896 WLAN_REASON_UNSPECIFIED, false, false);
897 } else {
898 wil_info(wil, "successful connection to CID %d\n", evt->cid);
899 }
900
901 if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
902 (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
903 if (rc) {
904 netif_carrier_off(ndev);
905 wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
906 wil_err(wil, "cfg80211_connect_result with failure\n");
907 cfg80211_connect_result(ndev, evt->bssid, NULL, 0,
908 NULL, 0,
909 WLAN_STATUS_UNSPECIFIED_FAILURE,
910 GFP_KERNEL);
911 goto out;
912 } else {
913 struct wiphy *wiphy = wil_to_wiphy(wil);
914
915 cfg80211_ref_bss(wiphy, wil->bss);
916 cfg80211_connect_bss(ndev, evt->bssid, wil->bss,
917 assoc_req_ie, assoc_req_ielen,
918 assoc_resp_ie, assoc_resp_ielen,
919 WLAN_STATUS_SUCCESS, GFP_KERNEL,
920 NL80211_TIMEOUT_UNSPECIFIED);
921 }
922 wil->bss = NULL;
923 } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
924 (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
925 if (rc) {
926 if (disable_ap_sme)
927
928 cfg80211_del_sta(ndev, evt->bssid, GFP_KERNEL);
929 goto out;
930 }
931
932 memset(&sinfo, 0, sizeof(sinfo));
933
934 sinfo.generation = wil->sinfo_gen++;
935
936 if (assoc_req_ie) {
937 sinfo.assoc_req_ies = assoc_req_ie;
938 sinfo.assoc_req_ies_len = assoc_req_ielen;
939 }
940
941 cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
942 } else {
943 wil_err(wil, "unhandled iftype %d for CID %d\n", wdev->iftype,
944 evt->cid);
945 goto out;
946 }
947
948 wil->sta[evt->cid].status = wil_sta_connected;
949 wil->sta[evt->cid].aid = evt->aid;
950 set_bit(wil_status_fwconnected, wil->status);
951 wil_update_net_queues_bh(wil, NULL, false);
952
953out:
954 if (rc)
955 wil->sta[evt->cid].status = wil_sta_unused;
956 clear_bit(wil_status_fwconnecting, wil->status);
957 mutex_unlock(&wil->mutex);
958}
959
960static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
961 void *d, int len)
962{
963 struct wmi_disconnect_event *evt = d;
964 u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
965
966 wil_info(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
967 evt->bssid, reason_code, evt->disconnect_reason);
968
969 wil->sinfo_gen++;
970
971 if (test_bit(wil_status_resetting, wil->status) ||
972 !test_bit(wil_status_fwready, wil->status)) {
973 wil_err(wil, "status_resetting, cancel disconnect event\n");
974
975 return;
976 }
977
978 mutex_lock(&wil->mutex);
979 wil6210_disconnect(wil, evt->bssid, reason_code, true);
980 mutex_unlock(&wil->mutex);
981}
982
983
984
985
986
987static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
988 void *d, int len)
989{
990 struct net_device *ndev = wil_to_ndev(wil);
991 struct wmi_eapol_rx_event *evt = d;
992 u16 eapol_len = le16_to_cpu(evt->eapol_len);
993 int sz = eapol_len + ETH_HLEN;
994 struct sk_buff *skb;
995 struct ethhdr *eth;
996 int cid;
997 struct wil_net_stats *stats = NULL;
998
999 wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
1000 evt->src_mac);
1001
1002 cid = wil_find_cid(wil, evt->src_mac);
1003 if (cid >= 0)
1004 stats = &wil->sta[cid].stats;
1005
1006 if (eapol_len > 196) {
1007 wil_err(wil, "EAPOL too large\n");
1008 return;
1009 }
1010
1011 skb = alloc_skb(sz, GFP_KERNEL);
1012 if (!skb) {
1013 wil_err(wil, "Failed to allocate skb\n");
1014 return;
1015 }
1016
1017 eth = skb_put(skb, ETH_HLEN);
1018 ether_addr_copy(eth->h_dest, ndev->dev_addr);
1019 ether_addr_copy(eth->h_source, evt->src_mac);
1020 eth->h_proto = cpu_to_be16(ETH_P_PAE);
1021 skb_put_data(skb, evt->eapol, eapol_len);
1022 skb->protocol = eth_type_trans(skb, ndev);
1023 if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
1024 ndev->stats.rx_packets++;
1025 ndev->stats.rx_bytes += sz;
1026 if (stats) {
1027 stats->rx_packets++;
1028 stats->rx_bytes += sz;
1029 }
1030 } else {
1031 ndev->stats.rx_dropped++;
1032 if (stats)
1033 stats->rx_dropped++;
1034 }
1035}
1036
1037static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
1038{
1039 struct wmi_vring_en_event *evt = d;
1040 u8 vri = evt->vring_index;
1041 struct wireless_dev *wdev = wil_to_wdev(wil);
1042
1043 wil_dbg_wmi(wil, "Enable vring %d\n", vri);
1044
1045 if (vri >= ARRAY_SIZE(wil->vring_tx)) {
1046 wil_err(wil, "Enable for invalid vring %d\n", vri);
1047 return;
1048 }
1049
1050 if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme)
1051
1052
1053
1054 wil->vring_tx_data[vri].dot1x_open = true;
1055 if (vri == wil->bcast_vring)
1056 return;
1057 if (agg_wsize >= 0)
1058 wil_addba_tx_request(wil, vri, agg_wsize);
1059}
1060
1061static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
1062 int len)
1063{
1064 struct wmi_ba_status_event *evt = d;
1065 struct vring_tx_data *txdata;
1066
1067 wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
1068 evt->ringid,
1069 evt->status == WMI_BA_AGREED ? "OK" : "N/A",
1070 evt->agg_wsize, __le16_to_cpu(evt->ba_timeout),
1071 evt->amsdu ? "+" : "-");
1072
1073 if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
1074 wil_err(wil, "invalid ring id %d\n", evt->ringid);
1075 return;
1076 }
1077
1078 if (evt->status != WMI_BA_AGREED) {
1079 evt->ba_timeout = 0;
1080 evt->agg_wsize = 0;
1081 evt->amsdu = 0;
1082 }
1083
1084 txdata = &wil->vring_tx_data[evt->ringid];
1085
1086 txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
1087 txdata->agg_wsize = evt->agg_wsize;
1088 txdata->agg_amsdu = evt->amsdu;
1089 txdata->addba_in_progress = false;
1090}
1091
1092static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
1093 int len)
1094{
1095 struct wmi_rcp_addba_req_event *evt = d;
1096
1097 wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token,
1098 evt->ba_param_set, evt->ba_timeout,
1099 evt->ba_seq_ctrl);
1100}
1101
1102static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
1103__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
1104{
1105 struct wmi_delba_event *evt = d;
1106 u8 cid, tid;
1107 u16 reason = __le16_to_cpu(evt->reason);
1108 struct wil_sta_info *sta;
1109 struct wil_tid_ampdu_rx *r;
1110
1111 might_sleep();
1112 parse_cidxtid(evt->cidxtid, &cid, &tid);
1113 wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n",
1114 cid, tid,
1115 evt->from_initiator ? "originator" : "recipient",
1116 reason);
1117 if (!evt->from_initiator) {
1118 int i;
1119
1120 for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
1121 if ((wil->vring2cid_tid[i][0] == cid) &&
1122 (wil->vring2cid_tid[i][1] == tid)) {
1123 struct vring_tx_data *txdata =
1124 &wil->vring_tx_data[i];
1125
1126 wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
1127 txdata->agg_timeout = 0;
1128 txdata->agg_wsize = 0;
1129 txdata->addba_in_progress = false;
1130
1131 break;
1132 }
1133 }
1134 if (i >= ARRAY_SIZE(wil->vring2cid_tid))
1135 wil_err(wil, "DELBA: unable to find Tx vring\n");
1136 return;
1137 }
1138
1139 sta = &wil->sta[cid];
1140
1141 spin_lock_bh(&sta->tid_rx_lock);
1142
1143 r = sta->tid_rx[tid];
1144 sta->tid_rx[tid] = NULL;
1145 wil_tid_ampdu_rx_free(wil, r);
1146
1147 spin_unlock_bh(&sta->tid_rx_lock);
1148}
1149
1150static void
1151wmi_evt_sched_scan_result(struct wil6210_priv *wil, int id, void *d, int len)
1152{
1153 struct wmi_sched_scan_result_event *data = d;
1154 struct wiphy *wiphy = wil_to_wiphy(wil);
1155 struct ieee80211_mgmt *rx_mgmt_frame =
1156 (struct ieee80211_mgmt *)data->payload;
1157 int flen = len - offsetof(struct wmi_sched_scan_result_event, payload);
1158 int ch_no;
1159 u32 freq;
1160 struct ieee80211_channel *channel;
1161 s32 signal;
1162 __le16 fc;
1163 u32 d_len;
1164 struct cfg80211_bss *bss;
1165
1166 if (flen < 0) {
1167 wil_err(wil, "sched scan result event too short, len %d\n",
1168 len);
1169 return;
1170 }
1171
1172 d_len = le32_to_cpu(data->info.len);
1173 if (d_len != flen) {
1174 wil_err(wil,
1175 "sched scan result length mismatch, d_len %d should be %d\n",
1176 d_len, flen);
1177 return;
1178 }
1179
1180 fc = rx_mgmt_frame->frame_control;
1181 if (!ieee80211_is_probe_resp(fc)) {
1182 wil_err(wil, "sched scan result invalid frame, fc 0x%04x\n",
1183 fc);
1184 return;
1185 }
1186
1187 ch_no = data->info.channel + 1;
1188 freq = ieee80211_channel_to_frequency(ch_no, NL80211_BAND_60GHZ);
1189 channel = ieee80211_get_channel(wiphy, freq);
1190 if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
1191 signal = 100 * data->info.rssi;
1192 else
1193 signal = data->info.sqi;
1194
1195 wil_dbg_wmi(wil, "sched scan result: channel %d MCS %d RSSI %d\n",
1196 data->info.channel, data->info.mcs, data->info.rssi);
1197 wil_dbg_wmi(wil, "len %d qid %d mid %d cid %d\n",
1198 d_len, data->info.qid, data->info.mid, data->info.cid);
1199 wil_hex_dump_wmi("PROBE ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame,
1200 d_len, true);
1201
1202 if (!channel) {
1203 wil_err(wil, "Frame on unsupported channel\n");
1204 return;
1205 }
1206
1207 bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
1208 d_len, signal, GFP_KERNEL);
1209 if (bss) {
1210 wil_dbg_wmi(wil, "Added BSS %pM\n", rx_mgmt_frame->bssid);
1211 cfg80211_put_bss(wiphy, bss);
1212 } else {
1213 wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
1214 }
1215
1216 cfg80211_sched_scan_results(wiphy, 0);
1217}
1218
1219
1220
1221
1222
1223static void wmi_evt_ignore(struct wil6210_priv *wil, int id, void *d, int len)
1224{
1225 wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
1226}
1227
1228static const struct {
1229 int eventid;
1230 void (*handler)(struct wil6210_priv *wil, int eventid,
1231 void *data, int data_len);
1232} wmi_evt_handlers[] = {
1233 {WMI_READY_EVENTID, wmi_evt_ready},
1234 {WMI_FW_READY_EVENTID, wmi_evt_ignore},
1235 {WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt},
1236 {WMI_TX_MGMT_PACKET_EVENTID, wmi_evt_tx_mgmt},
1237 {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
1238 {WMI_CONNECT_EVENTID, wmi_evt_connect},
1239 {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
1240 {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
1241 {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
1242 {WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
1243 {WMI_DELBA_EVENTID, wmi_evt_delba},
1244 {WMI_VRING_EN_EVENTID, wmi_evt_vring_en},
1245 {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore},
1246 {WMI_SCHED_SCAN_RESULT_EVENTID, wmi_evt_sched_scan_result},
1247};
1248
1249
1250
1251
1252
1253
1254
1255void wmi_recv_cmd(struct wil6210_priv *wil)
1256{
1257 struct wil6210_mbox_ring_desc d_tail;
1258 struct wil6210_mbox_hdr hdr;
1259 struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
1260 struct pending_wmi_event *evt;
1261 u8 *cmd;
1262 void __iomem *src;
1263 ulong flags;
1264 unsigned n;
1265 unsigned int num_immed_reply = 0;
1266
1267 if (!test_bit(wil_status_mbox_ready, wil->status)) {
1268 wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
1269 return;
1270 }
1271
1272 if (test_bit(wil_status_suspended, wil->status)) {
1273 wil_err(wil, "suspended. cannot handle WMI event\n");
1274 return;
1275 }
1276
1277 for (n = 0;; n++) {
1278 u16 len;
1279 bool q;
1280 bool immed_reply = false;
1281
1282 r->head = wil_r(wil, RGF_MBOX +
1283 offsetof(struct wil6210_mbox_ctl, rx.head));
1284 if (r->tail == r->head)
1285 break;
1286
1287 wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n",
1288 r->head, r->tail);
1289
1290 wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),
1291 sizeof(struct wil6210_mbox_ring_desc));
1292 if (d_tail.sync == 0) {
1293 wil_err(wil, "Mbox evt not owned by FW?\n");
1294 break;
1295 }
1296
1297
1298 if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
1299 wil_err(wil, "Mbox evt at 0x%08x?\n",
1300 le32_to_cpu(d_tail.addr));
1301 break;
1302 }
1303 len = le16_to_cpu(hdr.len);
1304 wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n",
1305 le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
1306 hdr.flags);
1307
1308
1309 src = wmi_buffer(wil, d_tail.addr) +
1310 sizeof(struct wil6210_mbox_hdr);
1311 evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
1312 event.wmi) + len, 4),
1313 GFP_KERNEL);
1314 if (!evt)
1315 break;
1316
1317 evt->event.hdr = hdr;
1318 cmd = (void *)&evt->event.wmi;
1319 wil_memcpy_fromio_32(cmd, src, len);
1320
1321 wil_w(wil, r->tail +
1322 offsetof(struct wil6210_mbox_ring_desc, sync), 0);
1323
1324 if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
1325 (len >= sizeof(struct wmi_cmd_hdr))) {
1326 struct wmi_cmd_hdr *wmi = &evt->event.wmi;
1327 u16 id = le16_to_cpu(wmi->command_id);
1328 u32 tstamp = le32_to_cpu(wmi->fw_timestamp);
1329 if (test_bit(wil_status_resuming, wil->status)) {
1330 if (id == WMI_TRAFFIC_RESUME_EVENTID)
1331 clear_bit(wil_status_resuming,
1332 wil->status);
1333 else
1334 wil_err(wil,
1335 "WMI evt %d while resuming\n",
1336 id);
1337 }
1338 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1339 if (wil->reply_id && wil->reply_id == id) {
1340 if (wil->reply_buf) {
1341 memcpy(wil->reply_buf, wmi,
1342 min(len, wil->reply_size));
1343 immed_reply = true;
1344 }
1345 if (id == WMI_TRAFFIC_SUSPEND_EVENTID) {
1346 wil_dbg_wmi(wil,
1347 "set suspend_resp_rcvd\n");
1348 wil->suspend_resp_rcvd = true;
1349 }
1350 }
1351 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1352
1353 wil_dbg_wmi(wil, "recv %s (0x%04x) MID %d @%d msec\n",
1354 eventid2name(id), id, wmi->mid, tstamp);
1355 trace_wil6210_wmi_event(wmi, &wmi[1],
1356 len - sizeof(*wmi));
1357 }
1358 wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
1359 &evt->event.hdr, sizeof(hdr) + len, true);
1360
1361
1362 r->tail = r->base + ((r->tail - r->base +
1363 sizeof(struct wil6210_mbox_ring_desc)) % r->size);
1364 wil_w(wil, RGF_MBOX +
1365 offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);
1366
1367 if (immed_reply) {
1368 wil_dbg_wmi(wil, "recv_cmd: Complete WMI 0x%04x\n",
1369 wil->reply_id);
1370 kfree(evt);
1371 num_immed_reply++;
1372 complete(&wil->wmi_call);
1373 } else {
1374
1375 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1376 list_add_tail(&evt->list, &wil->pending_wmi_ev);
1377 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1378 q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
1379 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
1380 }
1381 }
1382
1383 wil_dbg_wmi(wil, "recv_cmd: -> %d events queued, %d completed\n",
1384 n - num_immed_reply, num_immed_reply);
1385}
1386
1387int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
1388 u16 reply_id, void *reply, u8 reply_size, int to_msec)
1389{
1390 int rc;
1391 unsigned long remain;
1392
1393 mutex_lock(&wil->wmi_mutex);
1394
1395 spin_lock(&wil->wmi_ev_lock);
1396 wil->reply_id = reply_id;
1397 wil->reply_buf = reply;
1398 wil->reply_size = reply_size;
1399 reinit_completion(&wil->wmi_call);
1400 spin_unlock(&wil->wmi_ev_lock);
1401
1402 rc = __wmi_send(wil, cmdid, buf, len);
1403 if (rc)
1404 goto out;
1405
1406 remain = wait_for_completion_timeout(&wil->wmi_call,
1407 msecs_to_jiffies(to_msec));
1408 if (0 == remain) {
1409 wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
1410 cmdid, reply_id, to_msec);
1411 rc = -ETIME;
1412 } else {
1413 wil_dbg_wmi(wil,
1414 "wmi_call(0x%04x->0x%04x) completed in %d msec\n",
1415 cmdid, reply_id,
1416 to_msec - jiffies_to_msecs(remain));
1417 }
1418
1419out:
1420 spin_lock(&wil->wmi_ev_lock);
1421 wil->reply_id = 0;
1422 wil->reply_buf = NULL;
1423 wil->reply_size = 0;
1424 spin_unlock(&wil->wmi_ev_lock);
1425
1426 mutex_unlock(&wil->wmi_mutex);
1427
1428 return rc;
1429}
1430
1431int wmi_echo(struct wil6210_priv *wil)
1432{
1433 struct wmi_echo_cmd cmd = {
1434 .value = cpu_to_le32(0x12345678),
1435 };
1436
1437 return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
1438 WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
1439}
1440
1441int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
1442{
1443 struct wmi_set_mac_address_cmd cmd;
1444
1445 ether_addr_copy(cmd.mac, addr);
1446
1447 wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
1448
1449 return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
1450}
1451
1452int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
1453{
1454 int rc = 0;
1455 struct wmi_led_cfg_cmd cmd = {
1456 .led_mode = enable,
1457 .id = led_id,
1458 .slow_blink_cfg.blink_on =
1459 cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].on_ms),
1460 .slow_blink_cfg.blink_off =
1461 cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].off_ms),
1462 .medium_blink_cfg.blink_on =
1463 cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].on_ms),
1464 .medium_blink_cfg.blink_off =
1465 cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].off_ms),
1466 .fast_blink_cfg.blink_on =
1467 cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].on_ms),
1468 .fast_blink_cfg.blink_off =
1469 cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].off_ms),
1470 .led_polarity = led_polarity,
1471 };
1472 struct {
1473 struct wmi_cmd_hdr wmi;
1474 struct wmi_led_cfg_done_event evt;
1475 } __packed reply;
1476
1477 if (led_id == WIL_LED_INVALID_ID)
1478 goto out;
1479
1480 if (led_id > WIL_LED_MAX_ID) {
1481 wil_err(wil, "Invalid led id %d\n", led_id);
1482 rc = -EINVAL;
1483 goto out;
1484 }
1485
1486 wil_dbg_wmi(wil,
1487 "%s led %d\n",
1488 enable ? "enabling" : "disabling", led_id);
1489
1490 rc = wmi_call(wil, WMI_LED_CFG_CMDID, &cmd, sizeof(cmd),
1491 WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply),
1492 100);
1493 if (rc)
1494 goto out;
1495
1496 if (reply.evt.status) {
1497 wil_err(wil, "led %d cfg failed with status %d\n",
1498 led_id, le32_to_cpu(reply.evt.status));
1499 rc = -EINVAL;
1500 }
1501
1502out:
1503 return rc;
1504}
1505
1506int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
1507 u8 chan, u8 hidden_ssid, u8 is_go)
1508{
1509 int rc;
1510
1511 struct wmi_pcp_start_cmd cmd = {
1512 .bcon_interval = cpu_to_le16(bi),
1513 .network_type = wmi_nettype,
1514 .disable_sec_offload = 1,
1515 .channel = chan - 1,
1516 .pcp_max_assoc_sta = max_assoc_sta,
1517 .hidden_ssid = hidden_ssid,
1518 .is_go = is_go,
1519 .disable_ap_sme = disable_ap_sme,
1520 .abft_len = wil->abft_len,
1521 };
1522 struct {
1523 struct wmi_cmd_hdr wmi;
1524 struct wmi_pcp_started_event evt;
1525 } __packed reply;
1526
1527 if (!wil->privacy)
1528 cmd.disable_sec = 1;
1529
1530 if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
1531 (cmd.pcp_max_assoc_sta <= 0)) {
1532 wil_info(wil,
1533 "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
1534 max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID);
1535 cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
1536 }
1537
1538 if (disable_ap_sme &&
1539 !test_bit(WMI_FW_CAPABILITY_DISABLE_AP_SME,
1540 wil->fw_capabilities)) {
1541 wil_err(wil, "disable_ap_sme not supported by FW\n");
1542 return -EOPNOTSUPP;
1543 }
1544
1545
1546
1547
1548
1549 rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
1550 WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000);
1551 if (rc)
1552 return rc;
1553
1554 if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
1555 rc = -EINVAL;
1556
1557 if (wmi_nettype != WMI_NETTYPE_P2P)
1558
1559 wmi_led_cfg(wil, true);
1560
1561 return rc;
1562}
1563
1564int wmi_pcp_stop(struct wil6210_priv *wil)
1565{
1566 int rc;
1567
1568 rc = wmi_led_cfg(wil, false);
1569 if (rc)
1570 return rc;
1571
1572 return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
1573 WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
1574}
1575
1576int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
1577{
1578 struct wmi_set_ssid_cmd cmd = {
1579 .ssid_len = cpu_to_le32(ssid_len),
1580 };
1581
1582 if (ssid_len > sizeof(cmd.ssid))
1583 return -EINVAL;
1584
1585 memcpy(cmd.ssid, ssid, ssid_len);
1586
1587 return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
1588}
1589
1590int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
1591{
1592 int rc;
1593 struct {
1594 struct wmi_cmd_hdr wmi;
1595 struct wmi_set_ssid_cmd cmd;
1596 } __packed reply;
1597 int len;
1598
1599 rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
1600 &reply, sizeof(reply), 20);
1601 if (rc)
1602 return rc;
1603
1604 len = le32_to_cpu(reply.cmd.ssid_len);
1605 if (len > sizeof(reply.cmd.ssid))
1606 return -EINVAL;
1607
1608 *ssid_len = len;
1609 memcpy(ssid, reply.cmd.ssid, len);
1610
1611 return 0;
1612}
1613
1614int wmi_set_channel(struct wil6210_priv *wil, int channel)
1615{
1616 struct wmi_set_pcp_channel_cmd cmd = {
1617 .channel = channel - 1,
1618 };
1619
1620 return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
1621}
1622
1623int wmi_get_channel(struct wil6210_priv *wil, int *channel)
1624{
1625 int rc;
1626 struct {
1627 struct wmi_cmd_hdr wmi;
1628 struct wmi_set_pcp_channel_cmd cmd;
1629 } __packed reply;
1630
1631 rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
1632 WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
1633 if (rc)
1634 return rc;
1635
1636 if (reply.cmd.channel > 3)
1637 return -EINVAL;
1638
1639 *channel = reply.cmd.channel + 1;
1640
1641 return 0;
1642}
1643
1644int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi)
1645{
1646 int rc;
1647 struct wmi_p2p_cfg_cmd cmd = {
1648 .discovery_mode = WMI_DISCOVERY_MODE_PEER2PEER,
1649 .bcon_interval = cpu_to_le16(bi),
1650 .channel = channel - 1,
1651 };
1652 struct {
1653 struct wmi_cmd_hdr wmi;
1654 struct wmi_p2p_cfg_done_event evt;
1655 } __packed reply;
1656
1657 wil_dbg_wmi(wil, "sending WMI_P2P_CFG_CMDID\n");
1658
1659 rc = wmi_call(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd),
1660 WMI_P2P_CFG_DONE_EVENTID, &reply, sizeof(reply), 300);
1661 if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1662 wil_err(wil, "P2P_CFG failed. status %d\n", reply.evt.status);
1663 rc = -EINVAL;
1664 }
1665
1666 return rc;
1667}
1668
1669int wmi_start_listen(struct wil6210_priv *wil)
1670{
1671 int rc;
1672 struct {
1673 struct wmi_cmd_hdr wmi;
1674 struct wmi_listen_started_event evt;
1675 } __packed reply;
1676
1677 wil_dbg_wmi(wil, "sending WMI_START_LISTEN_CMDID\n");
1678
1679 rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
1680 WMI_LISTEN_STARTED_EVENTID, &reply, sizeof(reply), 300);
1681 if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1682 wil_err(wil, "device failed to start listen. status %d\n",
1683 reply.evt.status);
1684 rc = -EINVAL;
1685 }
1686
1687 return rc;
1688}
1689
1690int wmi_start_search(struct wil6210_priv *wil)
1691{
1692 int rc;
1693 struct {
1694 struct wmi_cmd_hdr wmi;
1695 struct wmi_search_started_event evt;
1696 } __packed reply;
1697
1698 wil_dbg_wmi(wil, "sending WMI_START_SEARCH_CMDID\n");
1699
1700 rc = wmi_call(wil, WMI_START_SEARCH_CMDID, NULL, 0,
1701 WMI_SEARCH_STARTED_EVENTID, &reply, sizeof(reply), 300);
1702 if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1703 wil_err(wil, "device failed to start search. status %d\n",
1704 reply.evt.status);
1705 rc = -EINVAL;
1706 }
1707
1708 return rc;
1709}
1710
1711int wmi_stop_discovery(struct wil6210_priv *wil)
1712{
1713 int rc;
1714
1715 wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n");
1716
1717 rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
1718 WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100);
1719
1720 if (rc)
1721 wil_err(wil, "Failed to stop discovery\n");
1722
1723 return rc;
1724}
1725
1726int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
1727 const void *mac_addr, int key_usage)
1728{
1729 struct wmi_delete_cipher_key_cmd cmd = {
1730 .key_index = key_index,
1731 };
1732
1733 if (mac_addr)
1734 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
1735
1736 return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
1737}
1738
1739int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
1740 const void *mac_addr, int key_len, const void *key,
1741 int key_usage)
1742{
1743 struct wmi_add_cipher_key_cmd cmd = {
1744 .key_index = key_index,
1745 .key_usage = key_usage,
1746 .key_len = key_len,
1747 };
1748
1749 if (!key || (key_len > sizeof(cmd.key)))
1750 return -EINVAL;
1751
1752 memcpy(cmd.key, key, key_len);
1753 if (mac_addr)
1754 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
1755
1756 return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
1757}
1758
1759int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
1760{
1761 static const char *const names[] = {
1762 [WMI_FRAME_BEACON] = "BEACON",
1763 [WMI_FRAME_PROBE_REQ] = "PROBE_REQ",
1764 [WMI_FRAME_PROBE_RESP] = "WMI_FRAME_PROBE_RESP",
1765 [WMI_FRAME_ASSOC_REQ] = "WMI_FRAME_ASSOC_REQ",
1766 [WMI_FRAME_ASSOC_RESP] = "WMI_FRAME_ASSOC_RESP",
1767 };
1768 int rc;
1769 u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
1770 struct wmi_set_appie_cmd *cmd;
1771
1772 if (len < ie_len) {
1773 rc = -EINVAL;
1774 goto out;
1775 }
1776
1777 cmd = kzalloc(len, GFP_KERNEL);
1778 if (!cmd) {
1779 rc = -ENOMEM;
1780 goto out;
1781 }
1782 if (!ie)
1783 ie_len = 0;
1784
1785 cmd->mgmt_frm_type = type;
1786
1787 cmd->ie_len = cpu_to_le16(ie_len);
1788 memcpy(cmd->ie_info, ie, ie_len);
1789 rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);
1790 kfree(cmd);
1791out:
1792 if (rc) {
1793 const char *name = type < ARRAY_SIZE(names) ?
1794 names[type] : "??";
1795 wil_err(wil, "set_ie(%d %s) failed : %d\n", type, name, rc);
1796 }
1797
1798 return rc;
1799}
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809int wmi_rxon(struct wil6210_priv *wil, bool on)
1810{
1811 int rc;
1812 struct {
1813 struct wmi_cmd_hdr wmi;
1814 struct wmi_listen_started_event evt;
1815 } __packed reply;
1816
1817 wil_info(wil, "(%s)\n", on ? "on" : "off");
1818
1819 if (on) {
1820 rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
1821 WMI_LISTEN_STARTED_EVENTID,
1822 &reply, sizeof(reply), 100);
1823 if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
1824 rc = -EINVAL;
1825 } else {
1826 rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
1827 WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
1828 }
1829
1830 return rc;
1831}
1832
1833int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
1834{
1835 struct wireless_dev *wdev = wil->wdev;
1836 struct net_device *ndev = wil_to_ndev(wil);
1837 struct wmi_cfg_rx_chain_cmd cmd = {
1838 .action = WMI_RX_CHAIN_ADD,
1839 .rx_sw_ring = {
1840 .max_mpdu_size = cpu_to_le16(
1841 wil_mtu2macbuf(wil->rx_buf_len)),
1842 .ring_mem_base = cpu_to_le64(vring->pa),
1843 .ring_size = cpu_to_le16(vring->size),
1844 },
1845 .mid = 0,
1846 .decap_trans_type = WMI_DECAP_TYPE_802_3,
1847 .reorder_type = WMI_RX_SW_REORDER,
1848 .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
1849 };
1850 struct {
1851 struct wmi_cmd_hdr wmi;
1852 struct wmi_cfg_rx_chain_done_event evt;
1853 } __packed evt;
1854 int rc;
1855
1856 if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
1857 struct ieee80211_channel *ch = wil->monitor_chandef.chan;
1858
1859 cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
1860 if (ch)
1861 cmd.sniffer_cfg.channel = ch->hw_value - 1;
1862 cmd.sniffer_cfg.phy_info_mode =
1863 cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
1864 cmd.sniffer_cfg.phy_support =
1865 cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
1866 ? WMI_SNIFFER_CP : WMI_SNIFFER_BOTH_PHYS);
1867 } else {
1868
1869
1870
1871
1872 cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS);
1873 }
1874
1875 if (rx_align_2)
1876 cmd.l2_802_3_offload_ctrl |=
1877 L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK;
1878
1879
1880 rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
1881 WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
1882 if (rc)
1883 return rc;
1884
1885 vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
1886
1887 wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
1888 le32_to_cpu(evt.evt.status), vring->hwtail);
1889
1890 if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
1891 rc = -EINVAL;
1892
1893 return rc;
1894}
1895
1896int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
1897{
1898 int rc;
1899 struct wmi_temp_sense_cmd cmd = {
1900 .measure_baseband_en = cpu_to_le32(!!t_bb),
1901 .measure_rf_en = cpu_to_le32(!!t_rf),
1902 .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW),
1903 };
1904 struct {
1905 struct wmi_cmd_hdr wmi;
1906 struct wmi_temp_sense_done_event evt;
1907 } __packed reply;
1908
1909 rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd),
1910 WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
1911 if (rc)
1912 return rc;
1913
1914 if (t_bb)
1915 *t_bb = le32_to_cpu(reply.evt.baseband_t1000);
1916 if (t_rf)
1917 *t_rf = le32_to_cpu(reply.evt.rf_t1000);
1918
1919 return 0;
1920}
1921
1922int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
1923 u16 reason, bool full_disconnect, bool del_sta)
1924{
1925 int rc;
1926 u16 reason_code;
1927 struct wmi_disconnect_sta_cmd disc_sta_cmd = {
1928 .disconnect_reason = cpu_to_le16(reason),
1929 };
1930 struct wmi_del_sta_cmd del_sta_cmd = {
1931 .disconnect_reason = cpu_to_le16(reason),
1932 };
1933 struct {
1934 struct wmi_cmd_hdr wmi;
1935 struct wmi_disconnect_event evt;
1936 } __packed reply;
1937
1938 wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason);
1939
1940 wil->locally_generated_disc = true;
1941 if (del_sta) {
1942 ether_addr_copy(del_sta_cmd.dst_mac, mac);
1943 rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd,
1944 sizeof(del_sta_cmd), WMI_DISCONNECT_EVENTID,
1945 &reply, sizeof(reply), 1000);
1946 } else {
1947 ether_addr_copy(disc_sta_cmd.dst_mac, mac);
1948 rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &disc_sta_cmd,
1949 sizeof(disc_sta_cmd), WMI_DISCONNECT_EVENTID,
1950 &reply, sizeof(reply), 1000);
1951 }
1952
1953 if (rc) {
1954 wil_fw_error_recovery(wil);
1955 return rc;
1956 }
1957
1958 if (full_disconnect) {
1959
1960
1961
1962
1963 reason_code = le16_to_cpu(reply.evt.protocol_reason_status);
1964
1965 wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
1966 reply.evt.bssid, reason_code,
1967 reply.evt.disconnect_reason);
1968
1969 wil->sinfo_gen++;
1970 wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
1971 }
1972 return 0;
1973}
1974
1975int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
1976{
1977 struct wmi_vring_ba_en_cmd cmd = {
1978 .ringid = ringid,
1979 .agg_max_wsize = size,
1980 .ba_timeout = cpu_to_le16(timeout),
1981 .amsdu = 0,
1982 };
1983
1984 wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size,
1985 timeout);
1986
1987 return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
1988}
1989
1990int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
1991{
1992 struct wmi_vring_ba_dis_cmd cmd = {
1993 .ringid = ringid,
1994 .reason = cpu_to_le16(reason),
1995 };
1996
1997 wil_dbg_wmi(wil, "delba_tx: (ring %d reason %d)\n", ringid, reason);
1998
1999 return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
2000}
2001
2002int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
2003{
2004 struct wmi_rcp_delba_cmd cmd = {
2005 .cidxtid = cidxtid,
2006 .reason = cpu_to_le16(reason),
2007 };
2008
2009 wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cidxtid & 0xf,
2010 (cidxtid >> 4) & 0xf, reason);
2011
2012 return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
2013}
2014
2015int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
2016 u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
2017{
2018 int rc;
2019 struct wmi_rcp_addba_resp_cmd cmd = {
2020 .cidxtid = mk_cidxtid(cid, tid),
2021 .dialog_token = token,
2022 .status_code = cpu_to_le16(status),
2023
2024
2025
2026
2027
2028 .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
2029 (agg_wsize << 6)),
2030 .ba_timeout = cpu_to_le16(timeout),
2031 };
2032 struct {
2033 struct wmi_cmd_hdr wmi;
2034 struct wmi_rcp_addba_resp_sent_event evt;
2035 } __packed reply;
2036
2037 wil_dbg_wmi(wil,
2038 "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
2039 cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
2040
2041 rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
2042 WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply),
2043 100);
2044 if (rc)
2045 return rc;
2046
2047 if (reply.evt.status) {
2048 wil_err(wil, "ADDBA response failed with status %d\n",
2049 le16_to_cpu(reply.evt.status));
2050 rc = -EINVAL;
2051 }
2052
2053 return rc;
2054}
2055
2056int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
2057 enum wmi_ps_profile_type ps_profile)
2058{
2059 int rc;
2060 struct wmi_ps_dev_profile_cfg_cmd cmd = {
2061 .ps_profile = ps_profile,
2062 };
2063 struct {
2064 struct wmi_cmd_hdr wmi;
2065 struct wmi_ps_dev_profile_cfg_event evt;
2066 } __packed reply;
2067 u32 status;
2068
2069 wil_dbg_wmi(wil, "Setting ps dev profile %d\n", ps_profile);
2070
2071 reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR);
2072
2073 rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, &cmd, sizeof(cmd),
2074 WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply),
2075 100);
2076 if (rc)
2077 return rc;
2078
2079 status = le32_to_cpu(reply.evt.status);
2080
2081 if (status != WMI_PS_CFG_CMD_STATUS_SUCCESS) {
2082 wil_err(wil, "ps dev profile cfg failed with status %d\n",
2083 status);
2084 rc = -EINVAL;
2085 }
2086
2087 return rc;
2088}
2089
2090int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
2091{
2092 int rc;
2093 struct wmi_set_mgmt_retry_limit_cmd cmd = {
2094 .mgmt_retry_limit = retry_short,
2095 };
2096 struct {
2097 struct wmi_cmd_hdr wmi;
2098 struct wmi_set_mgmt_retry_limit_event evt;
2099 } __packed reply;
2100
2101 wil_dbg_wmi(wil, "Setting mgmt retry short %d\n", retry_short);
2102
2103 if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
2104 return -ENOTSUPP;
2105
2106 reply.evt.status = WMI_FW_STATUS_FAILURE;
2107
2108 rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, &cmd, sizeof(cmd),
2109 WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
2110 100);
2111 if (rc)
2112 return rc;
2113
2114 if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
2115 wil_err(wil, "set mgmt retry limit failed with status %d\n",
2116 reply.evt.status);
2117 rc = -EINVAL;
2118 }
2119
2120 return rc;
2121}
2122
2123int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
2124{
2125 int rc;
2126 struct {
2127 struct wmi_cmd_hdr wmi;
2128 struct wmi_get_mgmt_retry_limit_event evt;
2129 } __packed reply;
2130
2131 wil_dbg_wmi(wil, "getting mgmt retry short\n");
2132
2133 if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
2134 return -ENOTSUPP;
2135
2136 reply.evt.mgmt_retry_limit = 0;
2137 rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, NULL, 0,
2138 WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
2139 100);
2140 if (rc)
2141 return rc;
2142
2143 if (retry_short)
2144 *retry_short = reply.evt.mgmt_retry_limit;
2145
2146 return 0;
2147}
2148
2149int wmi_abort_scan(struct wil6210_priv *wil)
2150{
2151 int rc;
2152
2153 wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n");
2154
2155 rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, NULL, 0);
2156 if (rc)
2157 wil_err(wil, "Failed to abort scan (%d)\n", rc);
2158
2159 return rc;
2160}
2161
2162int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
2163{
2164 int rc;
2165 struct wmi_new_sta_cmd cmd = {
2166 .aid = aid,
2167 };
2168
2169 wil_dbg_wmi(wil, "new sta %pM, aid %d\n", mac, aid);
2170
2171 ether_addr_copy(cmd.dst_mac, mac);
2172
2173 rc = wmi_send(wil, WMI_NEW_STA_CMDID, &cmd, sizeof(cmd));
2174 if (rc)
2175 wil_err(wil, "Failed to send new sta (%d)\n", rc);
2176
2177 return rc;
2178}
2179
2180void wmi_event_flush(struct wil6210_priv *wil)
2181{
2182 ulong flags;
2183 struct pending_wmi_event *evt, *t;
2184
2185 wil_dbg_wmi(wil, "event_flush\n");
2186
2187 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2188
2189 list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
2190 list_del(&evt->list);
2191 kfree(evt);
2192 }
2193
2194 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2195}
2196
2197static const char *suspend_status2name(u8 status)
2198{
2199 switch (status) {
2200 case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE:
2201 return "LINK_NOT_IDLE";
2202 default:
2203 return "Untracked status";
2204 }
2205}
2206
2207int wmi_suspend(struct wil6210_priv *wil)
2208{
2209 int rc;
2210 struct wmi_traffic_suspend_cmd cmd = {
2211 .wakeup_trigger = wil->wakeup_trigger,
2212 };
2213 struct {
2214 struct wmi_cmd_hdr wmi;
2215 struct wmi_traffic_suspend_event evt;
2216 } __packed reply;
2217 u32 suspend_to = WIL_WAIT_FOR_SUSPEND_RESUME_COMP;
2218
2219 wil->suspend_resp_rcvd = false;
2220 wil->suspend_resp_comp = false;
2221
2222 reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE;
2223
2224 rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd),
2225 WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply),
2226 suspend_to);
2227 if (rc) {
2228 wil_err(wil, "wmi_call for suspend req failed, rc=%d\n", rc);
2229 if (rc == -ETIME)
2230
2231 wil->suspend_stats.rejected_by_device++;
2232 else
2233 wil->suspend_stats.rejected_by_host++;
2234 goto out;
2235 }
2236
2237 wil_dbg_wmi(wil, "waiting for suspend_response_completed\n");
2238
2239 rc = wait_event_interruptible_timeout(wil->wq,
2240 wil->suspend_resp_comp,
2241 msecs_to_jiffies(suspend_to));
2242 if (rc == 0) {
2243 wil_err(wil, "TO waiting for suspend_response_completed\n");
2244 if (wil->suspend_resp_rcvd)
2245
2246 wil->suspend_stats.rejected_by_host++;
2247 else
2248 wil->suspend_stats.rejected_by_device++;
2249 rc = -EBUSY;
2250 goto out;
2251 }
2252
2253 wil_dbg_wmi(wil, "suspend_response_completed rcvd\n");
2254 if (reply.evt.status != WMI_TRAFFIC_SUSPEND_APPROVED) {
2255 wil_dbg_pm(wil, "device rejected the suspend, %s\n",
2256 suspend_status2name(reply.evt.status));
2257 wil->suspend_stats.rejected_by_device++;
2258 }
2259 rc = reply.evt.status;
2260
2261out:
2262 wil->suspend_resp_rcvd = false;
2263 wil->suspend_resp_comp = false;
2264
2265 return rc;
2266}
2267
2268static void resume_triggers2string(u32 triggers, char *string, int str_size)
2269{
2270 string[0] = '\0';
2271
2272 if (!triggers) {
2273 strlcat(string, " UNKNOWN", str_size);
2274 return;
2275 }
2276
2277 if (triggers & WMI_RESUME_TRIGGER_HOST)
2278 strlcat(string, " HOST", str_size);
2279
2280 if (triggers & WMI_RESUME_TRIGGER_UCAST_RX)
2281 strlcat(string, " UCAST_RX", str_size);
2282
2283 if (triggers & WMI_RESUME_TRIGGER_BCAST_RX)
2284 strlcat(string, " BCAST_RX", str_size);
2285
2286 if (triggers & WMI_RESUME_TRIGGER_WMI_EVT)
2287 strlcat(string, " WMI_EVT", str_size);
2288}
2289
2290int wmi_resume(struct wil6210_priv *wil)
2291{
2292 int rc;
2293 char string[100];
2294 struct {
2295 struct wmi_cmd_hdr wmi;
2296 struct wmi_traffic_resume_event evt;
2297 } __packed reply;
2298
2299 reply.evt.status = WMI_TRAFFIC_RESUME_FAILED;
2300 reply.evt.resume_triggers = WMI_RESUME_TRIGGER_UNKNOWN;
2301
2302 rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0,
2303 WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply),
2304 WIL_WAIT_FOR_SUSPEND_RESUME_COMP);
2305 if (rc)
2306 return rc;
2307 resume_triggers2string(le32_to_cpu(reply.evt.resume_triggers), string,
2308 sizeof(string));
2309 wil_dbg_pm(wil, "device resume %s, resume triggers:%s (0x%x)\n",
2310 reply.evt.status ? "failed" : "passed", string,
2311 le32_to_cpu(reply.evt.resume_triggers));
2312
2313 return reply.evt.status;
2314}
2315
2316static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
2317 void *d, int len)
2318{
2319 uint i;
2320
2321 for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
2322 if (wmi_evt_handlers[i].eventid == id) {
2323 wmi_evt_handlers[i].handler(wil, id, d, len);
2324 return true;
2325 }
2326 }
2327
2328 return false;
2329}
2330
2331static void wmi_event_handle(struct wil6210_priv *wil,
2332 struct wil6210_mbox_hdr *hdr)
2333{
2334 u16 len = le16_to_cpu(hdr->len);
2335
2336 if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
2337 (len >= sizeof(struct wmi_cmd_hdr))) {
2338 struct wmi_cmd_hdr *wmi = (void *)(&hdr[1]);
2339 void *evt_data = (void *)(&wmi[1]);
2340 u16 id = le16_to_cpu(wmi->command_id);
2341
2342 wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x)\n",
2343 eventid2name(id), id, wil->reply_id);
2344
2345 if (wil->reply_id && wil->reply_id == id) {
2346 WARN_ON(wil->reply_buf);
2347 wmi_evt_call_handler(wil, id, evt_data,
2348 len - sizeof(*wmi));
2349 wil_dbg_wmi(wil, "event_handle: Complete WMI 0x%04x\n",
2350 id);
2351 complete(&wil->wmi_call);
2352 return;
2353 }
2354
2355
2356 if (!wmi_evt_call_handler(wil, id, evt_data,
2357 len - sizeof(*wmi))) {
2358 wil_info(wil, "Unhandled event 0x%04x\n", id);
2359 }
2360 } else {
2361 wil_err(wil, "Unknown event type\n");
2362 print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
2363 hdr, sizeof(*hdr) + len, true);
2364 }
2365}
2366
2367
2368
2369
2370static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
2371{
2372 ulong flags;
2373 struct list_head *ret = NULL;
2374
2375 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2376
2377 if (!list_empty(&wil->pending_wmi_ev)) {
2378 ret = wil->pending_wmi_ev.next;
2379 list_del(ret);
2380 }
2381
2382 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2383
2384 return ret;
2385}
2386
2387
2388
2389
2390void wmi_event_worker(struct work_struct *work)
2391{
2392 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
2393 wmi_event_worker);
2394 struct pending_wmi_event *evt;
2395 struct list_head *lh;
2396
2397 wil_dbg_wmi(wil, "event_worker: Start\n");
2398 while ((lh = next_wmi_ev(wil)) != NULL) {
2399 evt = list_entry(lh, struct pending_wmi_event, list);
2400 wmi_event_handle(wil, &evt->event.hdr);
2401 kfree(evt);
2402 }
2403 wil_dbg_wmi(wil, "event_worker: Finished\n");
2404}
2405
2406bool wil_is_wmi_idle(struct wil6210_priv *wil)
2407{
2408 ulong flags;
2409 struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
2410 bool rc = false;
2411
2412 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2413
2414
2415 if (!list_empty(&wil->pending_wmi_ev)) {
2416 wil_dbg_pm(wil, "Pending WMI events in queue\n");
2417 goto out;
2418 }
2419
2420
2421 if (wil->reply_id) {
2422 wil_dbg_pm(wil, "Pending WMI call\n");
2423 goto out;
2424 }
2425
2426
2427 r->head = wil_r(wil, RGF_MBOX +
2428 offsetof(struct wil6210_mbox_ctl, rx.head));
2429 if (r->tail != r->head)
2430 wil_dbg_pm(wil, "Pending WMI mbox events\n");
2431 else
2432 rc = true;
2433
2434out:
2435 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2436 return rc;
2437}
2438
2439static void
2440wmi_sched_scan_set_ssids(struct wil6210_priv *wil,
2441 struct wmi_start_sched_scan_cmd *cmd,
2442 struct cfg80211_ssid *ssids, int n_ssids,
2443 struct cfg80211_match_set *match_sets,
2444 int n_match_sets)
2445{
2446 int i;
2447
2448 if (n_match_sets > WMI_MAX_PNO_SSID_NUM) {
2449 wil_dbg_wmi(wil, "too many match sets (%d), use first %d\n",
2450 n_match_sets, WMI_MAX_PNO_SSID_NUM);
2451 n_match_sets = WMI_MAX_PNO_SSID_NUM;
2452 }
2453 cmd->num_of_ssids = n_match_sets;
2454
2455 for (i = 0; i < n_match_sets; i++) {
2456 struct wmi_sched_scan_ssid_match *wmi_match =
2457 &cmd->ssid_for_match[i];
2458 struct cfg80211_match_set *cfg_match = &match_sets[i];
2459 int j;
2460
2461 wmi_match->ssid_len = cfg_match->ssid.ssid_len;
2462 memcpy(wmi_match->ssid, cfg_match->ssid.ssid,
2463 min_t(u8, wmi_match->ssid_len, WMI_MAX_SSID_LEN));
2464 wmi_match->rssi_threshold = S8_MIN;
2465 if (cfg_match->rssi_thold >= S8_MIN &&
2466 cfg_match->rssi_thold <= S8_MAX)
2467 wmi_match->rssi_threshold = cfg_match->rssi_thold;
2468
2469 for (j = 0; j < n_ssids; j++)
2470 if (wmi_match->ssid_len == ssids[j].ssid_len &&
2471 memcmp(wmi_match->ssid, ssids[j].ssid,
2472 wmi_match->ssid_len) == 0)
2473 wmi_match->add_ssid_to_probe = true;
2474 }
2475}
2476
2477static void
2478wmi_sched_scan_set_channels(struct wil6210_priv *wil,
2479 struct wmi_start_sched_scan_cmd *cmd,
2480 u32 n_channels,
2481 struct ieee80211_channel **channels)
2482{
2483 int i;
2484
2485 if (n_channels > WMI_MAX_CHANNEL_NUM) {
2486 wil_dbg_wmi(wil, "too many channels (%d), use first %d\n",
2487 n_channels, WMI_MAX_CHANNEL_NUM);
2488 n_channels = WMI_MAX_CHANNEL_NUM;
2489 }
2490 cmd->num_of_channels = n_channels;
2491
2492 for (i = 0; i < n_channels; i++) {
2493 struct ieee80211_channel *cfg_chan = channels[i];
2494
2495 cmd->channel_list[i] = cfg_chan->hw_value - 1;
2496 }
2497}
2498
2499static void
2500wmi_sched_scan_set_plans(struct wil6210_priv *wil,
2501 struct wmi_start_sched_scan_cmd *cmd,
2502 struct cfg80211_sched_scan_plan *scan_plans,
2503 int n_scan_plans)
2504{
2505 int i;
2506
2507 if (n_scan_plans > WMI_MAX_PLANS_NUM) {
2508 wil_dbg_wmi(wil, "too many plans (%d), use first %d\n",
2509 n_scan_plans, WMI_MAX_PLANS_NUM);
2510 n_scan_plans = WMI_MAX_PLANS_NUM;
2511 }
2512
2513 for (i = 0; i < n_scan_plans; i++) {
2514 struct cfg80211_sched_scan_plan *cfg_plan = &scan_plans[i];
2515
2516 cmd->scan_plans[i].interval_sec =
2517 cpu_to_le16(cfg_plan->interval);
2518 cmd->scan_plans[i].num_of_iterations =
2519 cpu_to_le16(cfg_plan->iterations);
2520 }
2521}
2522
2523int wmi_start_sched_scan(struct wil6210_priv *wil,
2524 struct cfg80211_sched_scan_request *request)
2525{
2526 int rc;
2527 struct wmi_start_sched_scan_cmd cmd = {
2528 .min_rssi_threshold = S8_MIN,
2529 .initial_delay_sec = cpu_to_le16(request->delay),
2530 };
2531 struct {
2532 struct wmi_cmd_hdr wmi;
2533 struct wmi_start_sched_scan_event evt;
2534 } __packed reply;
2535
2536 if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
2537 return -ENOTSUPP;
2538
2539 if (request->min_rssi_thold >= S8_MIN &&
2540 request->min_rssi_thold <= S8_MAX)
2541 cmd.min_rssi_threshold = request->min_rssi_thold;
2542
2543 wmi_sched_scan_set_ssids(wil, &cmd, request->ssids, request->n_ssids,
2544 request->match_sets, request->n_match_sets);
2545 wmi_sched_scan_set_channels(wil, &cmd,
2546 request->n_channels, request->channels);
2547 wmi_sched_scan_set_plans(wil, &cmd,
2548 request->scan_plans, request->n_scan_plans);
2549
2550 reply.evt.result = WMI_PNO_REJECT;
2551
2552 rc = wmi_call(wil, WMI_START_SCHED_SCAN_CMDID, &cmd, sizeof(cmd),
2553 WMI_START_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
2554 WIL_WMI_CALL_GENERAL_TO_MS);
2555 if (rc)
2556 return rc;
2557
2558 if (reply.evt.result != WMI_PNO_SUCCESS) {
2559 wil_err(wil, "start sched scan failed, result %d\n",
2560 reply.evt.result);
2561 return -EINVAL;
2562 }
2563
2564 return 0;
2565}
2566
2567int wmi_stop_sched_scan(struct wil6210_priv *wil)
2568{
2569 int rc;
2570 struct {
2571 struct wmi_cmd_hdr wmi;
2572 struct wmi_stop_sched_scan_event evt;
2573 } __packed reply;
2574
2575 if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
2576 return -ENOTSUPP;
2577
2578 reply.evt.result = WMI_PNO_REJECT;
2579
2580 rc = wmi_call(wil, WMI_STOP_SCHED_SCAN_CMDID, NULL, 0,
2581 WMI_STOP_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
2582 WIL_WMI_CALL_GENERAL_TO_MS);
2583 if (rc)
2584 return rc;
2585
2586 if (reply.evt.result != WMI_PNO_SUCCESS) {
2587 wil_err(wil, "stop sched scan failed, result %d\n",
2588 reply.evt.result);
2589 return -EINVAL;
2590 }
2591
2592 return 0;
2593}
2594