Linux 4.16.11
[linux/fpc-iii.git] / drivers / net / wireless / ath / wil6210 / wmi.c
blobb31e2514f8c21143f968f945875c7394fd80ceb3
1 /*
2 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <linux/moduleparam.h>
19 #include <linux/etherdevice.h>
20 #include <linux/if_arp.h>
22 #include "wil6210.h"
23 #include "txrx.h"
24 #include "wmi.h"
25 #include "trace.h"
27 static uint max_assoc_sta = WIL6210_MAX_CID;
28 module_param(max_assoc_sta, uint, 0644);
29 MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
31 int agg_wsize; /* = 0; */
32 module_param(agg_wsize, int, 0644);
33 MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
34 " 0 - use default; < 0 - don't auto-establish");
36 u8 led_id = WIL_LED_INVALID_ID;
37 module_param(led_id, byte, 0444);
38 MODULE_PARM_DESC(led_id,
39 " 60G device led enablement. Set the led ID (0-2) to enable");
41 #define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
42 #define WIL_WMI_CALL_GENERAL_TO_MS 100
44 /**
45 * WMI event receiving - theory of operations
47 * When firmware about to report WMI event, it fills memory area
48 * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for
49 * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler.
51 * @wmi_recv_cmd reads event, allocates memory chunk and attaches it to the
52 * event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up
53 * and handles events within the @wmi_event_worker. Every event get detached
54 * from list, processed and deleted.
56 * Purpose for this mechanism is to release IRQ thread; otherwise,
57 * if WMI event handling involves another WMI command flow, this 2-nd flow
58 * won't be completed because of blocked IRQ thread.
61 /**
62 * Addressing - theory of operations
64 * There are several buses present on the WIL6210 card.
65 * Same memory areas are visible at different address on
66 * the different busses. There are 3 main bus masters:
67 * - MAC CPU (ucode)
68 * - User CPU (firmware)
69 * - AHB (host)
71 * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
72 * AHB addresses starting from 0x880000
74 * Internally, firmware uses addresses that allow faster access but
75 * are invisible from the host. To read from these addresses, alternative
76 * AHB address must be used.
79 /**
80 * @sparrow_fw_mapping provides memory remapping table for sparrow
82 * array size should be in sync with the declaration in the wil6210.h
84 * Sparrow memory mapping:
85 * Linker address PCI/Host address
86 * 0x880000 .. 0xa80000 2Mb BAR0
87 * 0x800000 .. 0x808000 0x900000 .. 0x908000 32k DCCM
88 * 0x840000 .. 0x860000 0x908000 .. 0x928000 128k PERIPH
90 const struct fw_map sparrow_fw_mapping[] = {
91 /* FW code RAM 256k */
92 {0x000000, 0x040000, 0x8c0000, "fw_code", true},
93 /* FW data RAM 32k */
94 {0x800000, 0x808000, 0x900000, "fw_data", true},
95 /* periph data 128k */
96 {0x840000, 0x860000, 0x908000, "fw_peri", true},
97 /* various RGF 40k */
98 {0x880000, 0x88a000, 0x880000, "rgf", true},
99 /* AGC table 4k */
100 {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
101 /* Pcie_ext_rgf 4k */
102 {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
103 /* mac_ext_rgf 512b */
104 {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext", true},
105 /* upper area 548k */
106 {0x8c0000, 0x949000, 0x8c0000, "upper", true},
107 /* UCODE areas - accessible by debugfs blobs but not by
108 * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
110 /* ucode code RAM 128k */
111 {0x000000, 0x020000, 0x920000, "uc_code", false},
112 /* ucode data RAM 16k */
113 {0x800000, 0x804000, 0x940000, "uc_data", false},
117 * @sparrow_d0_mac_rgf_ext - mac_rgf_ext section for Sparrow D0
118 * it is a bit larger to support extra features
120 const struct fw_map sparrow_d0_mac_rgf_ext = {
121 0x88c000, 0x88c500, 0x88c000, "mac_rgf_ext", true
125 * @talyn_fw_mapping provides memory remapping table for Talyn
127 * array size should be in sync with the declaration in the wil6210.h
129 * Talyn memory mapping:
130 * Linker address PCI/Host address
131 * 0x880000 .. 0xc80000 4Mb BAR0
132 * 0x800000 .. 0x820000 0xa00000 .. 0xa20000 128k DCCM
133 * 0x840000 .. 0x858000 0xa20000 .. 0xa38000 96k PERIPH
135 const struct fw_map talyn_fw_mapping[] = {
136 /* FW code RAM 1M */
137 {0x000000, 0x100000, 0x900000, "fw_code", true},
138 /* FW data RAM 128k */
139 {0x800000, 0x820000, 0xa00000, "fw_data", true},
140 /* periph. data RAM 96k */
141 {0x840000, 0x858000, 0xa20000, "fw_peri", true},
142 /* various RGF 40k */
143 {0x880000, 0x88a000, 0x880000, "rgf", true},
144 /* AGC table 4k */
145 {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
146 /* Pcie_ext_rgf 4k */
147 {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
148 /* mac_ext_rgf 1344b */
149 {0x88c000, 0x88c540, 0x88c000, "mac_rgf_ext", true},
150 /* ext USER RGF 4k */
151 {0x88d000, 0x88e000, 0x88d000, "ext_user_rgf", true},
152 /* OTP 4k */
153 {0x8a0000, 0x8a1000, 0x8a0000, "otp", true},
154 /* DMA EXT RGF 64k */
155 {0x8b0000, 0x8c0000, 0x8b0000, "dma_ext_rgf", true},
156 /* upper area 1536k */
157 {0x900000, 0xa80000, 0x900000, "upper", true},
158 /* UCODE areas - accessible by debugfs blobs but not by
159 * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
161 /* ucode code RAM 256k */
162 {0x000000, 0x040000, 0xa38000, "uc_code", false},
163 /* ucode data RAM 32k */
164 {0x800000, 0x808000, 0xa78000, "uc_data", false},
167 struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
169 struct 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},
175 u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
178 * return AHB address for given firmware internal (linker) address
179 * @x - internal address
180 * If address have no valid AHB mapping, return 0
182 static u32 wmi_addr_remap(u32 x)
184 uint i;
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;
192 return 0;
196 * find fw_mapping entry by section name
197 * @section - section name
199 * Return pointer to section or NULL if not found
201 struct fw_map *wil_find_fw_mapping(const char *section)
203 int i;
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];
210 return NULL;
214 * Check address validity for WMI buffer; remap if needed
215 * @ptr - internal (linker) fw/ucode address
216 * @size - if non zero, validate the block does not
217 * exceed the device memory (bar)
219 * Valid buffer should be DWORD aligned
221 * return address for accessing buffer from the host;
222 * if buffer is not valid, return NULL.
224 void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size)
226 u32 off;
227 u32 ptr = le32_to_cpu(ptr_);
229 if (ptr % 4)
230 return NULL;
232 ptr = wmi_addr_remap(ptr);
233 if (ptr < WIL6210_FW_HOST_OFF)
234 return NULL;
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;
242 return wil->csr + off;
245 void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
247 return wmi_buffer_block(wil, ptr_, 0);
251 * Check address validity
253 void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
255 u32 off;
257 if (ptr % 4)
258 return NULL;
260 if (ptr < WIL6210_FW_HOST_OFF)
261 return NULL;
263 off = HOSTADDR(ptr);
264 if (off > wil->bar_size - 4)
265 return NULL;
267 return wil->csr + off;
270 int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
271 struct wil6210_mbox_hdr *hdr)
273 void __iomem *src = wmi_buffer(wil, ptr);
275 if (!src)
276 return -EINVAL;
278 wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
280 return 0;
283 static const char *cmdid2name(u16 cmdid)
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";
399 static const char *eventid2name(u16 eventid)
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";
519 static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
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),
530 .wmi = {
531 .mid = 0,
532 .command_id = cpu_to_le16(cmdid),
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;
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;
549 might_sleep();
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;
556 /* Allow sending only suspend / resume commands during susepnd flow */
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;
566 if (!head) {
567 wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
568 return -EINVAL;
571 wil_halp_vote(wil);
573 /* read Tx head till it is not busy */
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);
580 if (d_head.sync != 0) {
581 wil_err(wil, "WMI head busy\n");
582 rc = -EBUSY;
583 goto out;
585 /* next head */
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 /* wait till FW finish with previous command */
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;
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);
601 if (next_head == r->tail) {
602 wil_err(wil, "WMI ring full\n");
603 rc = -EBUSY;
604 goto out;
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;
613 cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
614 /* set command */
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 /* mark entry as full */
624 wil_w(wil, r->head + offsetof(struct wil6210_mbox_ring_desc, sync), 1);
625 /* advance next ptr */
626 wil_w(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, tx.head),
627 r->head = next_head);
629 trace_wil6210_wmi_cmd(&cmd.wmi, buf, len);
631 /* interrupt to FW */
632 wil_w(wil, RGF_USER_USER_ICR + offsetof(struct RGF_ICR, ICS),
633 SW_INT_MBOX);
635 out:
636 wil_halp_unvote(wil);
637 return rc;
640 int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
642 int rc;
644 mutex_lock(&wil->wmi_mutex);
645 rc = __wmi_send(wil, cmdid, buf, len);
646 mutex_unlock(&wil->wmi_mutex);
648 return rc;
651 /*=== Event handlers ===*/
652 static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
654 struct wireless_dev *wdev = wil->wdev;
655 struct wmi_ready_event *evt = d;
657 wil->n_mids = evt->numof_additional_mids;
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 /* ignore MAC address, we already have it from the boot loader */
663 strlcpy(wdev->wiphy->fw_version, wil->fw_version,
664 sizeof(wdev->wiphy->fw_version));
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;
671 wil_set_recovery_state(wil, fw_recovery_idle);
672 set_bit(wil_status_fwready, wil->status);
673 /* let the reset sequence continue */
674 complete(&wil->wmi_ready);
677 static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
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;
692 if (flen < 0) {
693 wil_err(wil, "MGMT Rx: short event, len %d\n", len);
694 return;
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;
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;
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);
725 if (!channel) {
726 wil_err(wil, "Frame on unsupported channel\n");
727 return;
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);
744 wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
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");
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);
763 static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
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);
770 wil_hex_dump_wmi("MGMT Tx ", DUMP_PREFIX_OFFSET, 16, 1, mgmt_frame,
771 flen, true);
774 static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
775 void *d, int len)
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)),
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);
798 } else {
799 wil_err(wil, "SCAN_COMPLETE while not scanning\n");
801 mutex_unlock(&wil->p2p_wdev_mutex);
804 static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
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; /* channel number */
810 struct station_info sinfo;
811 u8 *assoc_req_ie, *assoc_resp_ie;
812 size_t assoc_req_ielen, assoc_resp_ielen;
813 /* capinfo(u16) + listen_interval(u16) + IEs */
814 const size_t assoc_req_ie_offset = sizeof(u16) * 2;
815 /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
816 const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
817 int rc;
819 if (len < sizeof(*evt)) {
820 wil_err(wil, "Connect event too short : %d bytes\n", len);
821 return;
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;
831 if (evt->cid >= WIL6210_MAX_CID) {
832 wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
833 return;
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);
842 /* figure out IE's */
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;
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;
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 /* no need for cleanup, wil_reset will do that */
865 return;
868 mutex_lock(&wil->mutex);
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;
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;
888 ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
889 wil->sta[evt->cid].status = wil_sta_conn_pending;
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);
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);
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);
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 /* notify new_sta has failed */
928 cfg80211_del_sta(ndev, evt->bssid, GFP_KERNEL);
929 goto out;
932 memset(&sinfo, 0, sizeof(sinfo));
934 sinfo.generation = wil->sinfo_gen++;
936 if (assoc_req_ie) {
937 sinfo.assoc_req_ies = assoc_req_ie;
938 sinfo.assoc_req_ies_len = assoc_req_ielen;
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;
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);
953 out:
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);
960 static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
961 void *d, int len)
963 struct wmi_disconnect_event *evt = d;
964 u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
966 wil_info(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
967 evt->bssid, reason_code, evt->disconnect_reason);
969 wil->sinfo_gen++;
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 /* no need for cleanup, wil_reset will do that */
975 return;
978 mutex_lock(&wil->mutex);
979 wil6210_disconnect(wil, evt->bssid, reason_code, true);
980 mutex_unlock(&wil->mutex);
984 * Firmware reports EAPOL frame using WME event.
985 * Reconstruct Ethernet frame and deliver it via normal Rx
987 static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
988 void *d, int len)
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;
999 wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
1000 evt->src_mac);
1002 cid = wil_find_cid(wil, evt->src_mac);
1003 if (cid >= 0)
1004 stats = &wil->sta[cid].stats;
1006 if (eapol_len > 196) { /* TODO: revisit size limit */
1007 wil_err(wil, "EAPOL too large\n");
1008 return;
1011 skb = alloc_skb(sz, GFP_KERNEL);
1012 if (!skb) {
1013 wil_err(wil, "Failed to allocate skb\n");
1014 return;
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;
1030 } else {
1031 ndev->stats.rx_dropped++;
1032 if (stats)
1033 stats->rx_dropped++;
1037 static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
1039 struct wmi_vring_en_event *evt = d;
1040 u8 vri = evt->vring_index;
1041 struct wireless_dev *wdev = wil_to_wdev(wil);
1043 wil_dbg_wmi(wil, "Enable vring %d\n", vri);
1045 if (vri >= ARRAY_SIZE(wil->vring_tx)) {
1046 wil_err(wil, "Enable for invalid vring %d\n", vri);
1047 return;
1050 if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme)
1051 /* in AP mode with disable_ap_sme, this is done by
1052 * wil_cfg80211_change_station()
1054 wil->vring_tx_data[vri].dot1x_open = true;
1055 if (vri == wil->bcast_vring) /* no BA for bcast */
1056 return;
1057 if (agg_wsize >= 0)
1058 wil_addba_tx_request(wil, vri, agg_wsize);
1061 static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
1062 int len)
1064 struct wmi_ba_status_event *evt = d;
1065 struct vring_tx_data *txdata;
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 ? "+" : "-");
1073 if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
1074 wil_err(wil, "invalid ring id %d\n", evt->ringid);
1075 return;
1078 if (evt->status != WMI_BA_AGREED) {
1079 evt->ba_timeout = 0;
1080 evt->agg_wsize = 0;
1081 evt->amsdu = 0;
1084 txdata = &wil->vring_tx_data[evt->ringid];
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;
1092 static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
1093 int len)
1095 struct wmi_rcp_addba_req_event *evt = d;
1097 wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token,
1098 evt->ba_param_set, evt->ba_timeout,
1099 evt->ba_seq_ctrl);
1102 static 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)
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;
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 /* find Tx vring it belongs to */
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];
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;
1131 break; /* max. 1 matching ring */
1134 if (i >= ARRAY_SIZE(wil->vring2cid_tid))
1135 wil_err(wil, "DELBA: unable to find Tx vring\n");
1136 return;
1139 sta = &wil->sta[cid];
1141 spin_lock_bh(&sta->tid_rx_lock);
1143 r = sta->tid_rx[tid];
1144 sta->tid_rx[tid] = NULL;
1145 wil_tid_ampdu_rx_free(wil, r);
1147 spin_unlock_bh(&sta->tid_rx_lock);
1150 static void
1151 wmi_evt_sched_scan_result(struct wil6210_priv *wil, int id, void *d, int len)
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;
1166 if (flen < 0) {
1167 wil_err(wil, "sched scan result event too short, len %d\n",
1168 len);
1169 return;
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;
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;
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;
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);
1202 if (!channel) {
1203 wil_err(wil, "Frame on unsupported channel\n");
1204 return;
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");
1216 cfg80211_sched_scan_results(wiphy, 0);
1220 * Some events are ignored for purpose; and need not be interpreted as
1221 * "unhandled events"
1223 static void wmi_evt_ignore(struct wil6210_priv *wil, int id, void *d, int len)
1225 wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
1228 static 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},
1250 * Run in IRQ context
1251 * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev
1252 * that will be eventually handled by the @wmi_event_worker in the thread
1253 * context of thread "wil6210_wmi"
1255 void wmi_recv_cmd(struct wil6210_priv *wil)
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;
1267 if (!test_bit(wil_status_mbox_ready, wil->status)) {
1268 wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
1269 return;
1272 if (test_bit(wil_status_suspended, wil->status)) {
1273 wil_err(wil, "suspended. cannot handle WMI event\n");
1274 return;
1277 for (n = 0;; n++) {
1278 u16 len;
1279 bool q;
1280 bool immed_reply = false;
1282 r->head = wil_r(wil, RGF_MBOX +
1283 offsetof(struct wil6210_mbox_ctl, rx.head));
1284 if (r->tail == r->head)
1285 break;
1287 wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n",
1288 r->head, r->tail);
1289 /* read cmd descriptor from tail */
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;
1297 /* read cmd header from descriptor */
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;
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);
1308 /* read cmd buffer from descriptor */
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;
1317 evt->event.hdr = hdr;
1318 cmd = (void *)&evt->event.wmi;
1319 wil_memcpy_fromio_32(cmd, src, len);
1320 /* mark entry as empty */
1321 wil_w(wil, r->tail +
1322 offsetof(struct wil6210_mbox_ring_desc, sync), 0);
1323 /* indicate */
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);
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;
1345 if (id == WMI_TRAFFIC_SUSPEND_EVENTID) {
1346 wil_dbg_wmi(wil,
1347 "set suspend_resp_rcvd\n");
1348 wil->suspend_resp_rcvd = true;
1351 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
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));
1358 wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
1359 &evt->event.hdr, sizeof(hdr) + len, true);
1361 /* advance tail */
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);
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 /* add to the pending list */
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);
1382 /* normally, 1 event per IRQ should be processed */
1383 wil_dbg_wmi(wil, "recv_cmd: -> %d events queued, %d completed\n",
1384 n - num_immed_reply, num_immed_reply);
1387 int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
1388 u16 reply_id, void *reply, u8 reply_size, int to_msec)
1390 int rc;
1391 unsigned long remain;
1393 mutex_lock(&wil->wmi_mutex);
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);
1402 rc = __wmi_send(wil, cmdid, buf, len);
1403 if (rc)
1404 goto out;
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));
1419 out:
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);
1426 mutex_unlock(&wil->wmi_mutex);
1428 return rc;
1431 int wmi_echo(struct wil6210_priv *wil)
1433 struct wmi_echo_cmd cmd = {
1434 .value = cpu_to_le32(0x12345678),
1437 return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
1438 WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
1441 int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
1443 struct wmi_set_mac_address_cmd cmd;
1445 ether_addr_copy(cmd.mac, addr);
1447 wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
1449 return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
1452 int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
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,
1472 struct {
1473 struct wmi_cmd_hdr wmi;
1474 struct wmi_led_cfg_done_event evt;
1475 } __packed reply;
1477 if (led_id == WIL_LED_INVALID_ID)
1478 goto out;
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;
1486 wil_dbg_wmi(wil,
1487 "%s led %d\n",
1488 enable ? "enabling" : "disabling", led_id);
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;
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;
1502 out:
1503 return rc;
1506 int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
1507 u8 chan, u8 hidden_ssid, u8 is_go)
1509 int rc;
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,
1522 struct {
1523 struct wmi_cmd_hdr wmi;
1524 struct wmi_pcp_started_event evt;
1525 } __packed reply;
1527 if (!wil->privacy)
1528 cmd.disable_sec = 1;
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;
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;
1546 * Processing time may be huge, in case of secure AP it takes about
1547 * 3500ms for FW to start AP
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;
1554 if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
1555 rc = -EINVAL;
1557 if (wmi_nettype != WMI_NETTYPE_P2P)
1558 /* Don't fail due to error in the led configuration */
1559 wmi_led_cfg(wil, true);
1561 return rc;
1564 int wmi_pcp_stop(struct wil6210_priv *wil)
1566 int rc;
1568 rc = wmi_led_cfg(wil, false);
1569 if (rc)
1570 return rc;
1572 return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
1573 WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
1576 int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
1578 struct wmi_set_ssid_cmd cmd = {
1579 .ssid_len = cpu_to_le32(ssid_len),
1582 if (ssid_len > sizeof(cmd.ssid))
1583 return -EINVAL;
1585 memcpy(cmd.ssid, ssid, ssid_len);
1587 return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
1590 int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
1592 int rc;
1593 struct {
1594 struct wmi_cmd_hdr wmi;
1595 struct wmi_set_ssid_cmd cmd;
1596 } __packed reply;
1597 int len; /* reply.cmd.ssid_len in CPU order */
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;
1604 len = le32_to_cpu(reply.cmd.ssid_len);
1605 if (len > sizeof(reply.cmd.ssid))
1606 return -EINVAL;
1608 *ssid_len = len;
1609 memcpy(ssid, reply.cmd.ssid, len);
1611 return 0;
1614 int wmi_set_channel(struct wil6210_priv *wil, int channel)
1616 struct wmi_set_pcp_channel_cmd cmd = {
1617 .channel = channel - 1,
1620 return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
1623 int wmi_get_channel(struct wil6210_priv *wil, int *channel)
1625 int rc;
1626 struct {
1627 struct wmi_cmd_hdr wmi;
1628 struct wmi_set_pcp_channel_cmd cmd;
1629 } __packed reply;
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;
1636 if (reply.cmd.channel > 3)
1637 return -EINVAL;
1639 *channel = reply.cmd.channel + 1;
1641 return 0;
1644 int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi)
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,
1652 struct {
1653 struct wmi_cmd_hdr wmi;
1654 struct wmi_p2p_cfg_done_event evt;
1655 } __packed reply;
1657 wil_dbg_wmi(wil, "sending WMI_P2P_CFG_CMDID\n");
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;
1666 return rc;
1669 int wmi_start_listen(struct wil6210_priv *wil)
1671 int rc;
1672 struct {
1673 struct wmi_cmd_hdr wmi;
1674 struct wmi_listen_started_event evt;
1675 } __packed reply;
1677 wil_dbg_wmi(wil, "sending WMI_START_LISTEN_CMDID\n");
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;
1687 return rc;
1690 int wmi_start_search(struct wil6210_priv *wil)
1692 int rc;
1693 struct {
1694 struct wmi_cmd_hdr wmi;
1695 struct wmi_search_started_event evt;
1696 } __packed reply;
1698 wil_dbg_wmi(wil, "sending WMI_START_SEARCH_CMDID\n");
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;
1708 return rc;
1711 int wmi_stop_discovery(struct wil6210_priv *wil)
1713 int rc;
1715 wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n");
1717 rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
1718 WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100);
1720 if (rc)
1721 wil_err(wil, "Failed to stop discovery\n");
1723 return rc;
1726 int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
1727 const void *mac_addr, int key_usage)
1729 struct wmi_delete_cipher_key_cmd cmd = {
1730 .key_index = key_index,
1733 if (mac_addr)
1734 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
1736 return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
1739 int 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)
1743 struct wmi_add_cipher_key_cmd cmd = {
1744 .key_index = key_index,
1745 .key_usage = key_usage,
1746 .key_len = key_len,
1749 if (!key || (key_len > sizeof(cmd.key)))
1750 return -EINVAL;
1752 memcpy(cmd.key, key, key_len);
1753 if (mac_addr)
1754 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
1756 return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
1759 int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
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",
1768 int rc;
1769 u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
1770 struct wmi_set_appie_cmd *cmd;
1772 if (len < ie_len) {
1773 rc = -EINVAL;
1774 goto out;
1777 cmd = kzalloc(len, GFP_KERNEL);
1778 if (!cmd) {
1779 rc = -ENOMEM;
1780 goto out;
1782 if (!ie)
1783 ie_len = 0;
1785 cmd->mgmt_frm_type = type;
1786 /* BUG: FW API define ieLen as u8. Will fix FW */
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);
1791 out:
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);
1798 return rc;
1802 * wmi_rxon - turn radio on/off
1803 * @on: turn on if true, off otherwise
1805 * Only switch radio. Channel should be set separately.
1806 * No timeout for rxon - radio turned on forever unless some other call
1807 * turns it off
1809 int wmi_rxon(struct wil6210_priv *wil, bool on)
1811 int rc;
1812 struct {
1813 struct wmi_cmd_hdr wmi;
1814 struct wmi_listen_started_event evt;
1815 } __packed reply;
1817 wil_info(wil, "(%s)\n", on ? "on" : "off");
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);
1830 return rc;
1833 int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
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),
1845 .mid = 0, /* TODO - what is it? */
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),
1850 struct {
1851 struct wmi_cmd_hdr wmi;
1852 struct wmi_cfg_rx_chain_done_event evt;
1853 } __packed evt;
1854 int rc;
1856 if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
1857 struct ieee80211_channel *ch = wil->monitor_chandef.chan;
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 /* Initialize offload (in non-sniffer mode).
1869 * Linux IP stack always calculates IP checksum
1870 * HW always calculate TCP/UDP checksum
1872 cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS);
1875 if (rx_align_2)
1876 cmd.l2_802_3_offload_ctrl |=
1877 L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK;
1879 /* typical time for secure PCP is 840ms */
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;
1885 vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
1887 wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
1888 le32_to_cpu(evt.evt.status), vring->hwtail);
1890 if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
1891 rc = -EINVAL;
1893 return rc;
1896 int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
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),
1904 struct {
1905 struct wmi_cmd_hdr wmi;
1906 struct wmi_temp_sense_done_event evt;
1907 } __packed reply;
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;
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);
1919 return 0;
1922 int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
1923 u16 reason, bool full_disconnect, bool del_sta)
1925 int rc;
1926 u16 reason_code;
1927 struct wmi_disconnect_sta_cmd disc_sta_cmd = {
1928 .disconnect_reason = cpu_to_le16(reason),
1930 struct wmi_del_sta_cmd del_sta_cmd = {
1931 .disconnect_reason = cpu_to_le16(reason),
1933 struct {
1934 struct wmi_cmd_hdr wmi;
1935 struct wmi_disconnect_event evt;
1936 } __packed reply;
1938 wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason);
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);
1952 /* failure to disconnect in reasonable time treated as FW error */
1953 if (rc) {
1954 wil_fw_error_recovery(wil);
1955 return rc;
1958 if (full_disconnect) {
1959 /* call event handler manually after processing wmi_call,
1960 * to avoid deadlock - disconnect event handler acquires
1961 * wil->mutex while it is already held here
1963 reason_code = le16_to_cpu(reply.evt.protocol_reason_status);
1965 wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
1966 reply.evt.bssid, reason_code,
1967 reply.evt.disconnect_reason);
1969 wil->sinfo_gen++;
1970 wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
1972 return 0;
1975 int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
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,
1984 wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size,
1985 timeout);
1987 return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
1990 int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
1992 struct wmi_vring_ba_dis_cmd cmd = {
1993 .ringid = ringid,
1994 .reason = cpu_to_le16(reason),
1997 wil_dbg_wmi(wil, "delba_tx: (ring %d reason %d)\n", ringid, reason);
1999 return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
2002 int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
2004 struct wmi_rcp_delba_cmd cmd = {
2005 .cidxtid = cidxtid,
2006 .reason = cpu_to_le16(reason),
2009 wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cidxtid & 0xf,
2010 (cidxtid >> 4) & 0xf, reason);
2012 return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
2015 int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
2016 u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
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 /* bit 0: A-MSDU supported
2024 * bit 1: policy (should be 0 for us)
2025 * bits 2..5: TID
2026 * bits 6..15: buffer size
2028 .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
2029 (agg_wsize << 6)),
2030 .ba_timeout = cpu_to_le16(timeout),
2032 struct {
2033 struct wmi_cmd_hdr wmi;
2034 struct wmi_rcp_addba_resp_sent_event evt;
2035 } __packed reply;
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 ? "+" : "-");
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;
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;
2053 return rc;
2056 int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
2057 enum wmi_ps_profile_type ps_profile)
2059 int rc;
2060 struct wmi_ps_dev_profile_cfg_cmd cmd = {
2061 .ps_profile = ps_profile,
2063 struct {
2064 struct wmi_cmd_hdr wmi;
2065 struct wmi_ps_dev_profile_cfg_event evt;
2066 } __packed reply;
2067 u32 status;
2069 wil_dbg_wmi(wil, "Setting ps dev profile %d\n", ps_profile);
2071 reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR);
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;
2079 status = le32_to_cpu(reply.evt.status);
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;
2087 return rc;
2090 int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
2092 int rc;
2093 struct wmi_set_mgmt_retry_limit_cmd cmd = {
2094 .mgmt_retry_limit = retry_short,
2096 struct {
2097 struct wmi_cmd_hdr wmi;
2098 struct wmi_set_mgmt_retry_limit_event evt;
2099 } __packed reply;
2101 wil_dbg_wmi(wil, "Setting mgmt retry short %d\n", retry_short);
2103 if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
2104 return -ENOTSUPP;
2106 reply.evt.status = WMI_FW_STATUS_FAILURE;
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;
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;
2120 return rc;
2123 int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
2125 int rc;
2126 struct {
2127 struct wmi_cmd_hdr wmi;
2128 struct wmi_get_mgmt_retry_limit_event evt;
2129 } __packed reply;
2131 wil_dbg_wmi(wil, "getting mgmt retry short\n");
2133 if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
2134 return -ENOTSUPP;
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;
2143 if (retry_short)
2144 *retry_short = reply.evt.mgmt_retry_limit;
2146 return 0;
2149 int wmi_abort_scan(struct wil6210_priv *wil)
2151 int rc;
2153 wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n");
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);
2159 return rc;
2162 int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
2164 int rc;
2165 struct wmi_new_sta_cmd cmd = {
2166 .aid = aid,
2169 wil_dbg_wmi(wil, "new sta %pM, aid %d\n", mac, aid);
2171 ether_addr_copy(cmd.dst_mac, mac);
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);
2177 return rc;
2180 void wmi_event_flush(struct wil6210_priv *wil)
2182 ulong flags;
2183 struct pending_wmi_event *evt, *t;
2185 wil_dbg_wmi(wil, "event_flush\n");
2187 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2189 list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
2190 list_del(&evt->list);
2191 kfree(evt);
2194 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2197 static const char *suspend_status2name(u8 status)
2199 switch (status) {
2200 case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE:
2201 return "LINK_NOT_IDLE";
2202 default:
2203 return "Untracked status";
2207 int wmi_suspend(struct wil6210_priv *wil)
2209 int rc;
2210 struct wmi_traffic_suspend_cmd cmd = {
2211 .wakeup_trigger = wil->wakeup_trigger,
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;
2219 wil->suspend_resp_rcvd = false;
2220 wil->suspend_resp_comp = false;
2222 reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE;
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 /* wmi_call TO */
2231 wil->suspend_stats.rejected_by_device++;
2232 else
2233 wil->suspend_stats.rejected_by_host++;
2234 goto out;
2237 wil_dbg_wmi(wil, "waiting for suspend_response_completed\n");
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 /* Device responded but we TO due to another reason */
2246 wil->suspend_stats.rejected_by_host++;
2247 else
2248 wil->suspend_stats.rejected_by_device++;
2249 rc = -EBUSY;
2250 goto out;
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++;
2259 rc = reply.evt.status;
2261 out:
2262 wil->suspend_resp_rcvd = false;
2263 wil->suspend_resp_comp = false;
2265 return rc;
2268 static void resume_triggers2string(u32 triggers, char *string, int str_size)
2270 string[0] = '\0';
2272 if (!triggers) {
2273 strlcat(string, " UNKNOWN", str_size);
2274 return;
2277 if (triggers & WMI_RESUME_TRIGGER_HOST)
2278 strlcat(string, " HOST", str_size);
2280 if (triggers & WMI_RESUME_TRIGGER_UCAST_RX)
2281 strlcat(string, " UCAST_RX", str_size);
2283 if (triggers & WMI_RESUME_TRIGGER_BCAST_RX)
2284 strlcat(string, " BCAST_RX", str_size);
2286 if (triggers & WMI_RESUME_TRIGGER_WMI_EVT)
2287 strlcat(string, " WMI_EVT", str_size);
2290 int wmi_resume(struct wil6210_priv *wil)
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;
2299 reply.evt.status = WMI_TRAFFIC_RESUME_FAILED;
2300 reply.evt.resume_triggers = WMI_RESUME_TRIGGER_UNKNOWN;
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));
2313 return reply.evt.status;
2316 static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
2317 void *d, int len)
2319 uint i;
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;
2328 return false;
2331 static void wmi_event_handle(struct wil6210_priv *wil,
2332 struct wil6210_mbox_hdr *hdr)
2334 u16 len = le16_to_cpu(hdr->len);
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);
2342 wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x)\n",
2343 eventid2name(id), id, wil->reply_id);
2344 /* check if someone waits for this event */
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;
2354 /* unsolicited event */
2355 /* search for handler */
2356 if (!wmi_evt_call_handler(wil, id, evt_data,
2357 len - sizeof(*wmi))) {
2358 wil_info(wil, "Unhandled event 0x%04x\n", id);
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);
2368 * Retrieve next WMI event from the pending list
2370 static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
2372 ulong flags;
2373 struct list_head *ret = NULL;
2375 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2377 if (!list_empty(&wil->pending_wmi_ev)) {
2378 ret = wil->pending_wmi_ev.next;
2379 list_del(ret);
2382 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2384 return ret;
2388 * Handler for the WMI events
2390 void wmi_event_worker(struct work_struct *work)
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;
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);
2403 wil_dbg_wmi(wil, "event_worker: Finished\n");
2406 bool wil_is_wmi_idle(struct wil6210_priv *wil)
2408 ulong flags;
2409 struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
2410 bool rc = false;
2412 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
2414 /* Check if there are pending WMI events in the events queue */
2415 if (!list_empty(&wil->pending_wmi_ev)) {
2416 wil_dbg_pm(wil, "Pending WMI events in queue\n");
2417 goto out;
2420 /* Check if there is a pending WMI call */
2421 if (wil->reply_id) {
2422 wil_dbg_pm(wil, "Pending WMI call\n");
2423 goto out;
2426 /* Check if there are pending RX events in mbox */
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;
2434 out:
2435 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2436 return rc;
2439 static void
2440 wmi_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)
2446 int i;
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;
2453 cmd->num_of_ssids = n_match_sets;
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;
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;
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;
2477 static void
2478 wmi_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)
2483 int i;
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;
2490 cmd->num_of_channels = n_channels;
2492 for (i = 0; i < n_channels; i++) {
2493 struct ieee80211_channel *cfg_chan = channels[i];
2495 cmd->channel_list[i] = cfg_chan->hw_value - 1;
2499 static void
2500 wmi_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)
2505 int i;
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;
2513 for (i = 0; i < n_scan_plans; i++) {
2514 struct cfg80211_sched_scan_plan *cfg_plan = &scan_plans[i];
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);
2523 int wmi_start_sched_scan(struct wil6210_priv *wil,
2524 struct cfg80211_sched_scan_request *request)
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),
2531 struct {
2532 struct wmi_cmd_hdr wmi;
2533 struct wmi_start_sched_scan_event evt;
2534 } __packed reply;
2536 if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
2537 return -ENOTSUPP;
2539 if (request->min_rssi_thold >= S8_MIN &&
2540 request->min_rssi_thold <= S8_MAX)
2541 cmd.min_rssi_threshold = request->min_rssi_thold;
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);
2550 reply.evt.result = WMI_PNO_REJECT;
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;
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;
2564 return 0;
2567 int wmi_stop_sched_scan(struct wil6210_priv *wil)
2569 int rc;
2570 struct {
2571 struct wmi_cmd_hdr wmi;
2572 struct wmi_stop_sched_scan_event evt;
2573 } __packed reply;
2575 if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities))
2576 return -ENOTSUPP;
2578 reply.evt.result = WMI_PNO_REJECT;
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;
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;
2592 return 0;