1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/moduleparam.h>
18#include <linux/etherdevice.h>
19#include <linux/if_arp.h>
20
21#include "wil6210.h"
22#include "txrx.h"
23#include "wmi.h"
24#include "trace.h"
25
26static uint max_assoc_sta = WIL6210_MAX_CID;
27module_param(max_assoc_sta, uint, 0644);
28MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
29
30int agg_wsize;
31module_param(agg_wsize, int, 0644);
32MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
33 " 0 - use default; < 0 - don't auto-establish");
34
35u8 led_id = WIL_LED_INVALID_ID;
36module_param(led_id, byte, 0444);
37MODULE_PARM_DESC(led_id,
38 " 60G device led enablement. Set the led ID (0-2) to enable");
39
40#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200
41
42
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
88const struct fw_map fw_mapping[] = {
89
90 {0x000000, 0x040000, 0x8c0000, "fw_code", true},
91
92 {0x800000, 0x808000, 0x900000, "fw_data", true},
93
94 {0x840000, 0x860000, 0x908000, "fw_peri", true},
95
96 {0x880000, 0x88a000, 0x880000, "rgf", true},
97
98 {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
99
100 {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
101
102 {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext", true},
103
104 {0x8c0000, 0x949000, 0x8c0000, "upper", true},
105
106
107
108
109 {0x000000, 0x020000, 0x920000, "uc_code", false},
110
111 {0x800000, 0x804000, 0x940000, "uc_data", false},
112};
113
114struct blink_on_off_time led_blink_time[] = {
115 {WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
116 {WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
117 {WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS},
118};
119
120u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
121
122
123
124
125
126
127static u32 wmi_addr_remap(u32 x)
128{
129 uint i;
130
131 for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
132 if (fw_mapping[i].fw &&
133 ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)))
134 return x + fw_mapping[i].host - fw_mapping[i].from;
135 }
136
137 return 0;
138}
139
140
141
142
143
144
145
146
147
148
149void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
150{
151 u32 off;
152 u32 ptr = le32_to_cpu(ptr_);
153
154 if (ptr % 4)
155 return NULL;
156
157 ptr = wmi_addr_remap(ptr);
158 if (ptr < WIL6210_FW_HOST_OFF)
159 return NULL;
160
161 off = HOSTADDR(ptr);
162 if (off > wil->bar_size - 4)
163 return NULL;
164
165 return wil->csr + off;
166}
167
168
169
170
171void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
172{
173 u32 off;
174
175 if (ptr % 4)
176 return NULL;
177
178 if (ptr < WIL6210_FW_HOST_OFF)
179 return NULL;
180
181 off = HOSTADDR(ptr);
182 if (off > wil->bar_size - 4)
183 return NULL;
184
185 return wil->csr + off;
186}
187
188int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
189 struct wil6210_mbox_hdr *hdr)
190{
191 void __iomem *src = wmi_buffer(wil, ptr);
192
193 if (!src)
194 return -EINVAL;
195
196 wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
197
198 return 0;
199}
200
201static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
202{
203 struct {
204 struct wil6210_mbox_hdr hdr;
205 struct wmi_cmd_hdr wmi;
206 } __packed cmd = {
207 .hdr = {
208 .type = WIL_MBOX_HDR_TYPE_WMI,
209 .flags = 0,
210 .len = cpu_to_le16(sizeof(cmd.wmi) + len),
211 },
212 .wmi = {
213 .mid = 0,
214 .command_id = cpu_to_le16(cmdid),
215 },
216 };
217 struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
218 struct wil6210_mbox_ring_desc d_head;
219 u32 next_head;
220 void __iomem *dst;
221 void __iomem *head = wmi_addr(wil, r->head);
222 uint retry;
223 int rc = 0;
224
225 if (sizeof(cmd) + len > r->entry_size) {
226 wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
227 (int)(sizeof(cmd) + len), r->entry_size);
228 return -ERANGE;
229 }
230
231 might_sleep();
232
233 if (!test_bit(wil_status_fwready, wil->status)) {
234 wil_err(wil, "WMI: cannot send command while FW not ready\n");
235 return -EAGAIN;
236 }
237
238
239 if ((test_bit(wil_status_suspending, wil->status) ||
240 test_bit(wil_status_suspended, wil->status) ||
241 test_bit(wil_status_resuming, wil->status)) &&
242 ((cmdid != WMI_TRAFFIC_SUSPEND_CMDID) &&
243 (cmdid != WMI_TRAFFIC_RESUME_CMDID))) {
244 wil_err(wil, "WMI: reject send_command during suspend\n");
245 return -EINVAL;
246 }
247
248 if (!head) {
249 wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
250 return -EINVAL;
251 }
252
253 wil_halp_vote(wil);
254
255
256 for (retry = 5; retry > 0; retry--) {
257 wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
258 if (d_head.sync == 0)
259 break;
260 msleep(20);
261 }
262 if (d_head.sync != 0) {
263 wil_err(wil, "WMI head busy\n");
264 rc = -EBUSY;
265 goto out;
266 }
267
268 next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
269 wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
270
271 for (retry = 5; retry > 0; retry--) {
272 if (!test_bit(wil_status_fwready, wil->status)) {
273 wil_err(wil, "WMI: cannot send command while FW not ready\n");
274 rc = -EAGAIN;
275 goto out;
276 }
277 r->tail = wil_r(wil, RGF_MBOX +
278 offsetof(struct wil6210_mbox_ctl, tx.tail));
279 if (next_head != r->tail)
280 break;
281 msleep(20);
282 }
283 if (next_head == r->tail) {
284 wil_err(wil, "WMI ring full\n");
285 rc = -EBUSY;
286 goto out;
287 }
288 dst = wmi_buffer(wil, d_head.addr);
289 if (!dst) {
290 wil_err(wil, "invalid WMI buffer: 0x%08x\n",
291 le32_to_cpu(d_head.addr));
292 rc = -EAGAIN;
293 goto out;
294 }
295 cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
296
297 wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
298 wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
299 sizeof(cmd), true);
300 wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
301 len, true);
302 wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
303 wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
304
305 wil_w(wil, r->head + offsetof(struct wil6210_mbox_ring_desc, sync), 1);
306
307 wil_w(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, tx.head),
308 r->head = next_head);
309
310 trace_wil6210_wmi_cmd(&cmd.wmi, buf, len);
311
312
313 wil_w(wil, RGF_USER_USER_ICR + offsetof(struct RGF_ICR, ICS),
314 SW_INT_MBOX);
315
316out:
317 wil_halp_unvote(wil);
318 return rc;
319}
320
321int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
322{
323 int rc;
324
325 mutex_lock(&wil->wmi_mutex);
326 rc = __wmi_send(wil, cmdid, buf, len);
327 mutex_unlock(&wil->wmi_mutex);
328
329 return rc;
330}
331
332
333static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
334{
335 struct wireless_dev *wdev = wil->wdev;
336 struct wmi_ready_event *evt = d;
337
338 wil->n_mids = evt->numof_additional_mids;
339
340 wil_info(wil, "FW ver. %s(SW %d); MAC %pM; %d MID's\n",
341 wil->fw_version, le32_to_cpu(evt->sw_version),
342 evt->mac, wil->n_mids);
343
344 strlcpy(wdev->wiphy->fw_version, wil->fw_version,
345 sizeof(wdev->wiphy->fw_version));
346
347 if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) {
348 wil_dbg_wmi(wil, "rfc calibration result %d\n",
349 evt->rfc_read_calib_result);
350 wil->fw_calib_result = evt->rfc_read_calib_result;
351 }
352 wil_set_recovery_state(wil, fw_recovery_idle);
353 set_bit(wil_status_fwready, wil->status);
354
355 complete(&wil->wmi_ready);
356}
357
358static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
359{
360 struct wmi_rx_mgmt_packet_event *data = d;
361 struct wiphy *wiphy = wil_to_wiphy(wil);
362 struct ieee80211_mgmt *rx_mgmt_frame =
363 (struct ieee80211_mgmt *)data->payload;
364 int flen = len - offsetof(struct wmi_rx_mgmt_packet_event, payload);
365 int ch_no;
366 u32 freq;
367 struct ieee80211_channel *channel;
368 s32 signal;
369 __le16 fc;
370 u32 d_len;
371 u16 d_status;
372
373 if (flen < 0) {
374 wil_err(wil, "MGMT Rx: short event, len %d\n", len);
375 return;
376 }
377
378 d_len = le32_to_cpu(data->info.len);
379 if (d_len != flen) {
380 wil_err(wil,
381 "MGMT Rx: length mismatch, d_len %d should be %d\n",
382 d_len, flen);
383 return;
384 }
385
386 ch_no = data->info.channel + 1;
387 freq = ieee80211_channel_to_frequency(ch_no, NL80211_BAND_60GHZ);
388 channel = ieee80211_get_channel(wiphy, freq);
389 if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
390 signal = 100 * data->info.rssi;
391 else
392 signal = data->info.sqi;
393 d_status = le16_to_cpu(data->info.status);
394 fc = rx_mgmt_frame->frame_control;
395
396 wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d RSSI %d SQI %d%%\n",
397 data->info.channel, data->info.mcs, data->info.rssi,
398 data->info.sqi);
399 wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
400 le16_to_cpu(fc));
401 wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
402 data->info.qid, data->info.mid, data->info.cid);
403 wil_hex_dump_wmi("MGMT Rx ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame,
404 d_len, true);
405
406 if (!channel) {
407 wil_err(wil, "Frame on unsupported channel\n");
408 return;
409 }
410
411 if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
412 struct cfg80211_bss *bss;
413 u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
414 u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
415 u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
416 const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
417 size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
418 u.beacon.variable);
419 wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
420 wil_dbg_wmi(wil, "TSF : 0x%016llx\n", tsf);
421 wil_dbg_wmi(wil, "Beacon interval : %d\n", bi);
422 wil_hex_dump_wmi("IE ", DUMP_PREFIX_OFFSET, 16, 1, ie_buf,
423 ie_len, true);
424
425 wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
426
427 bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
428 d_len, signal, GFP_KERNEL);
429 if (bss) {
430 wil_dbg_wmi(wil, "Added BSS %pM\n",
431 rx_mgmt_frame->bssid);
432 cfg80211_put_bss(wiphy, bss);
433 } else {
434 wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
435 }
436 } else {
437 mutex_lock(&wil->p2p_wdev_mutex);
438 cfg80211_rx_mgmt(wil->radio_wdev, freq, signal,
439 (void *)rx_mgmt_frame, d_len, 0);
440 mutex_unlock(&wil->p2p_wdev_mutex);
441 }
442}
443
444static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
445{
446 struct wmi_tx_mgmt_packet_event *data = d;
447 struct ieee80211_mgmt *mgmt_frame =
448 (struct ieee80211_mgmt *)data->payload;
449 int flen = len - offsetof(struct wmi_tx_mgmt_packet_event, payload);
450
451 wil_hex_dump_wmi("MGMT Tx ", DUMP_PREFIX_OFFSET, 16, 1, mgmt_frame,
452 flen, true);
453}
454
455static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
456 void *d, int len)
457{
458 mutex_lock(&wil->p2p_wdev_mutex);
459 if (wil->scan_request) {
460 struct wmi_scan_complete_event *data = d;
461 int status = le32_to_cpu(data->status);
462 struct cfg80211_scan_info info = {
463 .aborted = ((status != WMI_SCAN_SUCCESS) &&
464 (status != WMI_SCAN_ABORT_REJECTED)),
465 };
466
467 wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", status);
468 wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
469 wil->scan_request, info.aborted);
470 del_timer_sync(&wil->scan_timer);
471 cfg80211_scan_done(wil->scan_request, &info);
472 wil->radio_wdev = wil->wdev;
473 wil->scan_request = NULL;
474 wake_up_interruptible(&wil->wq);
475 if (wil->p2p.pending_listen_wdev) {
476 wil_dbg_misc(wil, "Scheduling delayed listen\n");
477 schedule_work(&wil->p2p.delayed_listen_work);
478 }
479 } else {
480 wil_err(wil, "SCAN_COMPLETE while not scanning\n");
481 }
482 mutex_unlock(&wil->p2p_wdev_mutex);
483}
484
485static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
486{
487 struct net_device *ndev = wil_to_ndev(wil);
488 struct wireless_dev *wdev = wil->wdev;
489 struct wmi_connect_event *evt = d;
490 int ch;
491 struct station_info sinfo;
492 u8 *assoc_req_ie, *assoc_resp_ie;
493 size_t assoc_req_ielen, assoc_resp_ielen;
494
495 const size_t assoc_req_ie_offset = sizeof(u16) * 2;
496
497 const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
498 int rc;
499
500 if (len < sizeof(*evt)) {
501 wil_err(wil, "Connect event too short : %d bytes\n", len);
502 return;
503 }
504 if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len +
505 evt->assoc_resp_len) {
506 wil_err(wil,
507 "Connect event corrupted : %d != %d + %d + %d + %d\n",
508 len, (int)sizeof(*evt), evt->beacon_ie_len,
509 evt->assoc_req_len, evt->assoc_resp_len);
510 return;
511 }
512 if (evt->cid >= WIL6210_MAX_CID) {
513 wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
514 return;
515 }
516
517 ch = evt->channel + 1;
518 wil_info(wil, "Connect %pM channel [%d] cid %d aid %d\n",
519 evt->bssid, ch, evt->cid, evt->aid);
520 wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
521 evt->assoc_info, len - sizeof(*evt), true);
522
523
524 assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len +
525 assoc_req_ie_offset];
526 assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset;
527 if (evt->assoc_req_len <= assoc_req_ie_offset) {
528 assoc_req_ie = NULL;
529 assoc_req_ielen = 0;
530 }
531
532 assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len +
533 evt->assoc_req_len +
534 assoc_resp_ie_offset];
535 assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset;
536 if (evt->assoc_resp_len <= assoc_resp_ie_offset) {
537 assoc_resp_ie = NULL;
538 assoc_resp_ielen = 0;
539 }
540
541 if (test_bit(wil_status_resetting, wil->status) ||
542 !test_bit(wil_status_fwready, wil->status)) {
543 wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
544 evt->cid);
545
546 return;
547 }
548
549 mutex_lock(&wil->mutex);
550
551 if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
552 (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
553 if (!test_bit(wil_status_fwconnecting, wil->status)) {
554 wil_err(wil, "Not in connecting state\n");
555 mutex_unlock(&wil->mutex);
556 return;
557 }
558 del_timer_sync(&wil->connect_timer);
559 } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
560 (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
561 if (wil->sta[evt->cid].status != wil_sta_unused) {
562 wil_err(wil, "AP: Invalid status %d for CID %d\n",
563 wil->sta[evt->cid].status, evt->cid);
564 mutex_unlock(&wil->mutex);
565 return;
566 }
567 }
568
569
570
571 ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
572 wil->sta[evt->cid].status = wil_sta_conn_pending;
573
574 rc = wil_tx_init(wil, evt->cid);
575 if (rc) {
576 wil_err(wil, "config tx vring failed for CID %d, rc (%d)\n",
577 evt->cid, rc);
578 wmi_disconnect_sta(wil, wil->sta[evt->cid].addr,
579 WLAN_REASON_UNSPECIFIED, false, false);
580 } else {
581 wil_info(wil, "successful connection to CID %d\n", evt->cid);
582 }
583
584 if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
585 (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
586 if (rc) {
587 netif_carrier_off(ndev);
588 wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
589 wil_err(wil, "cfg80211_connect_result with failure\n");
590 cfg80211_connect_result(ndev, evt->bssid, NULL, 0,
591 NULL, 0,
592 WLAN_STATUS_UNSPECIFIED_FAILURE,
593 GFP_KERNEL);
594 goto out;
595 } else {
596 struct wiphy *wiphy = wil_to_wiphy(wil);
597
598 cfg80211_ref_bss(wiphy, wil->bss);
599 cfg80211_connect_bss(ndev, evt->bssid, wil->bss,
600 assoc_req_ie, assoc_req_ielen,
601 assoc_resp_ie, assoc_resp_ielen,
602 WLAN_STATUS_SUCCESS, GFP_KERNEL,
603 NL80211_TIMEOUT_UNSPECIFIED);
604 }
605 wil->bss = NULL;
606 } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
607 (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
608 if (rc) {
609 if (disable_ap_sme)
610
611 cfg80211_del_sta(ndev, evt->bssid, GFP_KERNEL);
612 goto out;
613 }
614
615 memset(&sinfo, 0, sizeof(sinfo));
616
617 sinfo.generation = wil->sinfo_gen++;
618
619 if (assoc_req_ie) {
620 sinfo.assoc_req_ies = assoc_req_ie;
621 sinfo.assoc_req_ies_len = assoc_req_ielen;
622 }
623
624 cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
625 } else {
626 wil_err(wil, "unhandled iftype %d for CID %d\n", wdev->iftype,
627 evt->cid);
628 goto out;
629 }
630
631 wil->sta[evt->cid].status = wil_sta_connected;
632 wil->sta[evt->cid].aid = evt->aid;
633 set_bit(wil_status_fwconnected, wil->status);
634 wil_update_net_queues_bh(wil, NULL, false);
635
636out:
637 if (rc)
638 wil->sta[evt->cid].status = wil_sta_unused;
639 clear_bit(wil_status_fwconnecting, wil->status);
640 mutex_unlock(&wil->mutex);
641}
642
643static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
644 void *d, int len)
645{
646 struct wmi_disconnect_event *evt = d;
647 u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
648
649 wil_info(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
650 evt->bssid, reason_code, evt->disconnect_reason);
651
652 wil->sinfo_gen++;
653
654 if (test_bit(wil_status_resetting, wil->status) ||
655 !test_bit(wil_status_fwready, wil->status)) {
656 wil_err(wil, "status_resetting, cancel disconnect event\n");
657
658 return;
659 }
660
661 mutex_lock(&wil->mutex);
662 wil6210_disconnect(wil, evt->bssid, reason_code, true);
663 mutex_unlock(&wil->mutex);
664}
665
666
667
668
669
670static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
671 void *d, int len)
672{
673 struct net_device *ndev = wil_to_ndev(wil);
674 struct wmi_eapol_rx_event *evt = d;
675 u16 eapol_len = le16_to_cpu(evt->eapol_len);
676 int sz = eapol_len + ETH_HLEN;
677 struct sk_buff *skb;
678 struct ethhdr *eth;
679 int cid;
680 struct wil_net_stats *stats = NULL;
681
682 wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
683 evt->src_mac);
684
685 cid = wil_find_cid(wil, evt->src_mac);
686 if (cid >= 0)
687 stats = &wil->sta[cid].stats;
688
689 if (eapol_len > 196) {
690 wil_err(wil, "EAPOL too large\n");
691 return;
692 }
693
694 skb = alloc_skb(sz, GFP_KERNEL);
695 if (!skb) {
696 wil_err(wil, "Failed to allocate skb\n");
697 return;
698 }
699
700 eth = skb_put(skb, ETH_HLEN);
701 ether_addr_copy(eth->h_dest, ndev->dev_addr);
702 ether_addr_copy(eth->h_source, evt->src_mac);
703 eth->h_proto = cpu_to_be16(ETH_P_PAE);
704 skb_put_data(skb, evt->eapol, eapol_len);
705 skb->protocol = eth_type_trans(skb, ndev);
706 if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
707 ndev->stats.rx_packets++;
708 ndev->stats.rx_bytes += sz;
709 if (stats) {
710 stats->rx_packets++;
711 stats->rx_bytes += sz;
712 }
713 } else {
714 ndev->stats.rx_dropped++;
715 if (stats)
716 stats->rx_dropped++;
717 }
718}
719
720static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
721{
722 struct wmi_vring_en_event *evt = d;
723 u8 vri = evt->vring_index;
724 struct wireless_dev *wdev = wil_to_wdev(wil);
725
726 wil_dbg_wmi(wil, "Enable vring %d\n", vri);
727
728 if (vri >= ARRAY_SIZE(wil->vring_tx)) {
729 wil_err(wil, "Enable for invalid vring %d\n", vri);
730 return;
731 }
732
733 if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme)
734
735
736
737 wil->vring_tx_data[vri].dot1x_open = true;
738 if (vri == wil->bcast_vring)
739 return;
740 if (agg_wsize >= 0)
741 wil_addba_tx_request(wil, vri, agg_wsize);
742}
743
744static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
745 int len)
746{
747 struct wmi_ba_status_event *evt = d;
748 struct vring_tx_data *txdata;
749
750 wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
751 evt->ringid,
752 evt->status == WMI_BA_AGREED ? "OK" : "N/A",
753 evt->agg_wsize, __le16_to_cpu(evt->ba_timeout),
754 evt->amsdu ? "+" : "-");
755
756 if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
757 wil_err(wil, "invalid ring id %d\n", evt->ringid);
758 return;
759 }
760
761 if (evt->status != WMI_BA_AGREED) {
762 evt->ba_timeout = 0;
763 evt->agg_wsize = 0;
764 evt->amsdu = 0;
765 }
766
767 txdata = &wil->vring_tx_data[evt->ringid];
768
769 txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
770 txdata->agg_wsize = evt->agg_wsize;
771 txdata->agg_amsdu = evt->amsdu;
772 txdata->addba_in_progress = false;
773}
774
775static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
776 int len)
777{
778 struct wmi_rcp_addba_req_event *evt = d;
779
780 wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token,
781 evt->ba_param_set, evt->ba_timeout,
782 evt->ba_seq_ctrl);
783}
784
785static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
786__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
787{
788 struct wmi_delba_event *evt = d;
789 u8 cid, tid;
790 u16 reason = __le16_to_cpu(evt->reason);
791 struct wil_sta_info *sta;
792 struct wil_tid_ampdu_rx *r;
793
794 might_sleep();
795 parse_cidxtid(evt->cidxtid, &cid, &tid);
796 wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n",
797 cid, tid,
798 evt->from_initiator ? "originator" : "recipient",
799 reason);
800 if (!evt->from_initiator) {
801 int i;
802
803 for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
804 if ((wil->vring2cid_tid[i][0] == cid) &&
805 (wil->vring2cid_tid[i][1] == tid)) {
806 struct vring_tx_data *txdata =
807 &wil->vring_tx_data[i];
808
809 wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
810 txdata->agg_timeout = 0;
811 txdata->agg_wsize = 0;
812 txdata->addba_in_progress = false;
813
814 break;
815 }
816 }
817 if (i >= ARRAY_SIZE(wil->vring2cid_tid))
818 wil_err(wil, "DELBA: unable to find Tx vring\n");
819 return;
820 }
821
822 sta = &wil->sta[cid];
823
824 spin_lock_bh(&sta->tid_rx_lock);
825
826 r = sta->tid_rx[tid];
827 sta->tid_rx[tid] = NULL;
828 wil_tid_ampdu_rx_free(wil, r);
829
830 spin_unlock_bh(&sta->tid_rx_lock);
831}
832
833
834
835
836
837static void wmi_evt_ignore(struct wil6210_priv *wil, int id, void *d, int len)
838{
839 wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
840}
841
842static const struct {
843 int eventid;
844 void (*handler)(struct wil6210_priv *wil, int eventid,
845 void *data, int data_len);
846} wmi_evt_handlers[] = {
847 {WMI_READY_EVENTID, wmi_evt_ready},
848 {WMI_FW_READY_EVENTID, wmi_evt_ignore},
849 {WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt},
850 {WMI_TX_MGMT_PACKET_EVENTID, wmi_evt_tx_mgmt},
851 {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
852 {WMI_CONNECT_EVENTID, wmi_evt_connect},
853 {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
854 {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
855 {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
856 {WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
857 {WMI_DELBA_EVENTID, wmi_evt_delba},
858 {WMI_VRING_EN_EVENTID, wmi_evt_vring_en},
859 {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore},
860};
861
862
863
864
865
866
867
868void wmi_recv_cmd(struct wil6210_priv *wil)
869{
870 struct wil6210_mbox_ring_desc d_tail;
871 struct wil6210_mbox_hdr hdr;
872 struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
873 struct pending_wmi_event *evt;
874 u8 *cmd;
875 void __iomem *src;
876 ulong flags;
877 unsigned n;
878 unsigned int num_immed_reply = 0;
879
880 if (!test_bit(wil_status_mbox_ready, wil->status)) {
881 wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
882 return;
883 }
884
885 if (test_bit(wil_status_suspended, wil->status)) {
886 wil_err(wil, "suspended. cannot handle WMI event\n");
887 return;
888 }
889
890 for (n = 0;; n++) {
891 u16 len;
892 bool q;
893 bool immed_reply = false;
894
895 r->head = wil_r(wil, RGF_MBOX +
896 offsetof(struct wil6210_mbox_ctl, rx.head));
897 if (r->tail == r->head)
898 break;
899
900 wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n",
901 r->head, r->tail);
902
903 wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),
904 sizeof(struct wil6210_mbox_ring_desc));
905 if (d_tail.sync == 0) {
906 wil_err(wil, "Mbox evt not owned by FW?\n");
907 break;
908 }
909
910
911 if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
912 wil_err(wil, "Mbox evt at 0x%08x?\n",
913 le32_to_cpu(d_tail.addr));
914 break;
915 }
916 len = le16_to_cpu(hdr.len);
917 wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n",
918 le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
919 hdr.flags);
920
921
922 src = wmi_buffer(wil, d_tail.addr) +
923 sizeof(struct wil6210_mbox_hdr);
924 evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
925 event.wmi) + len, 4),
926 GFP_KERNEL);
927 if (!evt)
928 break;
929
930 evt->event.hdr = hdr;
931 cmd = (void *)&evt->event.wmi;
932 wil_memcpy_fromio_32(cmd, src, len);
933
934 wil_w(wil, r->tail +
935 offsetof(struct wil6210_mbox_ring_desc, sync), 0);
936
937 if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
938 (len >= sizeof(struct wmi_cmd_hdr))) {
939 struct wmi_cmd_hdr *wmi = &evt->event.wmi;
940 u16 id = le16_to_cpu(wmi->command_id);
941 u32 tstamp = le32_to_cpu(wmi->fw_timestamp);
942 if (test_bit(wil_status_resuming, wil->status)) {
943 if (id == WMI_TRAFFIC_RESUME_EVENTID)
944 clear_bit(wil_status_resuming,
945 wil->status);
946 else
947 wil_err(wil,
948 "WMI evt %d while resuming\n",
949 id);
950 }
951 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
952 if (wil->reply_id && wil->reply_id == id) {
953 if (wil->reply_buf) {
954 memcpy(wil->reply_buf, wmi,
955 min(len, wil->reply_size));
956 immed_reply = true;
957 }
958 if (id == WMI_TRAFFIC_SUSPEND_EVENTID) {
959 wil_dbg_wmi(wil,
960 "set suspend_resp_rcvd\n");
961 wil->suspend_resp_rcvd = true;
962 }
963 }
964 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
965
966 wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
967 id, wmi->mid, tstamp);
968 trace_wil6210_wmi_event(wmi, &wmi[1],
969 len - sizeof(*wmi));
970 }
971 wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
972 &evt->event.hdr, sizeof(hdr) + len, true);
973
974
975 r->tail = r->base + ((r->tail - r->base +
976 sizeof(struct wil6210_mbox_ring_desc)) % r->size);
977 wil_w(wil, RGF_MBOX +
978 offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);
979
980 if (immed_reply) {
981 wil_dbg_wmi(wil, "recv_cmd: Complete WMI 0x%04x\n",
982 wil->reply_id);
983 kfree(evt);
984 num_immed_reply++;
985 complete(&wil->wmi_call);
986 } else {
987
988 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
989 list_add_tail(&evt->list, &wil->pending_wmi_ev);
990 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
991 q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
992 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
993 }
994 }
995
996 wil_dbg_wmi(wil, "recv_cmd: -> %d events queued, %d completed\n",
997 n - num_immed_reply, num_immed_reply);
998}
999
1000int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
1001 u16 reply_id, void *reply, u8 reply_size, int to_msec)
1002{
1003 int rc;
1004 unsigned long remain;
1005
1006 mutex_lock(&wil->wmi_mutex);
1007
1008 spin_lock(&wil->wmi_ev_lock);
1009 wil->reply_id = reply_id;
1010 wil->reply_buf = reply;
1011 wil->reply_size = reply_size;
1012 reinit_completion(&wil->wmi_call);
1013 spin_unlock(&wil->wmi_ev_lock);
1014
1015 rc = __wmi_send(wil, cmdid, buf, len);
1016 if (rc)
1017 goto out;
1018
1019 remain = wait_for_completion_timeout(&wil->wmi_call,
1020 msecs_to_jiffies(to_msec));
1021 if (0 == remain) {
1022 wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
1023 cmdid, reply_id, to_msec);
1024 rc = -ETIME;
1025 } else {
1026 wil_dbg_wmi(wil,
1027 "wmi_call(0x%04x->0x%04x) completed in %d msec\n",
1028 cmdid, reply_id,
1029 to_msec - jiffies_to_msecs(remain));
1030 }
1031
1032out:
1033 spin_lock(&wil->wmi_ev_lock);
1034 wil->reply_id = 0;
1035 wil->reply_buf = NULL;
1036 wil->reply_size = 0;
1037 spin_unlock(&wil->wmi_ev_lock);
1038
1039 mutex_unlock(&wil->wmi_mutex);
1040
1041 return rc;
1042}
1043
1044int wmi_echo(struct wil6210_priv *wil)
1045{
1046 struct wmi_echo_cmd cmd = {
1047 .value = cpu_to_le32(0x12345678),
1048 };
1049
1050 return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
1051 WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
1052}
1053
1054int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
1055{
1056 struct wmi_set_mac_address_cmd cmd;
1057
1058 ether_addr_copy(cmd.mac, addr);
1059
1060 wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
1061
1062 return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
1063}
1064
1065int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
1066{
1067 int rc = 0;
1068 struct wmi_led_cfg_cmd cmd = {
1069 .led_mode = enable,
1070 .id = led_id,
1071 .slow_blink_cfg.blink_on =
1072 cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].on_ms),
1073 .slow_blink_cfg.blink_off =
1074 cpu_to_le32(led_blink_time[WIL_LED_TIME_SLOW].off_ms),
1075 .medium_blink_cfg.blink_on =
1076 cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].on_ms),
1077 .medium_blink_cfg.blink_off =
1078 cpu_to_le32(led_blink_time[WIL_LED_TIME_MED].off_ms),
1079 .fast_blink_cfg.blink_on =
1080 cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].on_ms),
1081 .fast_blink_cfg.blink_off =
1082 cpu_to_le32(led_blink_time[WIL_LED_TIME_FAST].off_ms),
1083 .led_polarity = led_polarity,
1084 };
1085 struct {
1086 struct wmi_cmd_hdr wmi;
1087 struct wmi_led_cfg_done_event evt;
1088 } __packed reply;
1089
1090 if (led_id == WIL_LED_INVALID_ID)
1091 goto out;
1092
1093 if (led_id > WIL_LED_MAX_ID) {
1094 wil_err(wil, "Invalid led id %d\n", led_id);
1095 rc = -EINVAL;
1096 goto out;
1097 }
1098
1099 wil_dbg_wmi(wil,
1100 "%s led %d\n",
1101 enable ? "enabling" : "disabling", led_id);
1102
1103 rc = wmi_call(wil, WMI_LED_CFG_CMDID, &cmd, sizeof(cmd),
1104 WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply),
1105 100);
1106 if (rc)
1107 goto out;
1108
1109 if (reply.evt.status) {
1110 wil_err(wil, "led %d cfg failed with status %d\n",
1111 led_id, le32_to_cpu(reply.evt.status));
1112 rc = -EINVAL;
1113 }
1114
1115out:
1116 return rc;
1117}
1118
1119int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
1120 u8 chan, u8 hidden_ssid, u8 is_go)
1121{
1122 int rc;
1123
1124 struct wmi_pcp_start_cmd cmd = {
1125 .bcon_interval = cpu_to_le16(bi),
1126 .network_type = wmi_nettype,
1127 .disable_sec_offload = 1,
1128 .channel = chan - 1,
1129 .pcp_max_assoc_sta = max_assoc_sta,
1130 .hidden_ssid = hidden_ssid,
1131 .is_go = is_go,
1132 .disable_ap_sme = disable_ap_sme,
1133 .abft_len = wil->abft_len,
1134 };
1135 struct {
1136 struct wmi_cmd_hdr wmi;
1137 struct wmi_pcp_started_event evt;
1138 } __packed reply;
1139
1140 if (!wil->privacy)
1141 cmd.disable_sec = 1;
1142
1143 if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
1144 (cmd.pcp_max_assoc_sta <= 0)) {
1145 wil_info(wil,
1146 "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
1147 max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID);
1148 cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
1149 }
1150
1151 if (disable_ap_sme &&
1152 !test_bit(WMI_FW_CAPABILITY_DISABLE_AP_SME,
1153 wil->fw_capabilities)) {
1154 wil_err(wil, "disable_ap_sme not supported by FW\n");
1155 return -EOPNOTSUPP;
1156 }
1157
1158
1159
1160
1161
1162 rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
1163 WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000);
1164 if (rc)
1165 return rc;
1166
1167 if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
1168 rc = -EINVAL;
1169
1170 if (wmi_nettype != WMI_NETTYPE_P2P)
1171
1172 wmi_led_cfg(wil, true);
1173
1174 return rc;
1175}
1176
1177int wmi_pcp_stop(struct wil6210_priv *wil)
1178{
1179 int rc;
1180
1181 rc = wmi_led_cfg(wil, false);
1182 if (rc)
1183 return rc;
1184
1185 return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
1186 WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
1187}
1188
1189int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
1190{
1191 struct wmi_set_ssid_cmd cmd = {
1192 .ssid_len = cpu_to_le32(ssid_len),
1193 };
1194
1195 if (ssid_len > sizeof(cmd.ssid))
1196 return -EINVAL;
1197
1198 memcpy(cmd.ssid, ssid, ssid_len);
1199
1200 return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
1201}
1202
1203int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
1204{
1205 int rc;
1206 struct {
1207 struct wmi_cmd_hdr wmi;
1208 struct wmi_set_ssid_cmd cmd;
1209 } __packed reply;
1210 int len;
1211
1212 rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
1213 &reply, sizeof(reply), 20);
1214 if (rc)
1215 return rc;
1216
1217 len = le32_to_cpu(reply.cmd.ssid_len);
1218 if (len > sizeof(reply.cmd.ssid))
1219 return -EINVAL;
1220
1221 *ssid_len = len;
1222 memcpy(ssid, reply.cmd.ssid, len);
1223
1224 return 0;
1225}
1226
1227int wmi_set_channel(struct wil6210_priv *wil, int channel)
1228{
1229 struct wmi_set_pcp_channel_cmd cmd = {
1230 .channel = channel - 1,
1231 };
1232
1233 return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
1234}
1235
1236int wmi_get_channel(struct wil6210_priv *wil, int *channel)
1237{
1238 int rc;
1239 struct {
1240 struct wmi_cmd_hdr wmi;
1241 struct wmi_set_pcp_channel_cmd cmd;
1242 } __packed reply;
1243
1244 rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
1245 WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
1246 if (rc)
1247 return rc;
1248
1249 if (reply.cmd.channel > 3)
1250 return -EINVAL;
1251
1252 *channel = reply.cmd.channel + 1;
1253
1254 return 0;
1255}
1256
1257int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi)
1258{
1259 int rc;
1260 struct wmi_p2p_cfg_cmd cmd = {
1261 .discovery_mode = WMI_DISCOVERY_MODE_PEER2PEER,
1262 .bcon_interval = cpu_to_le16(bi),
1263 .channel = channel - 1,
1264 };
1265 struct {
1266 struct wmi_cmd_hdr wmi;
1267 struct wmi_p2p_cfg_done_event evt;
1268 } __packed reply;
1269
1270 wil_dbg_wmi(wil, "sending WMI_P2P_CFG_CMDID\n");
1271
1272 rc = wmi_call(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd),
1273 WMI_P2P_CFG_DONE_EVENTID, &reply, sizeof(reply), 300);
1274 if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1275 wil_err(wil, "P2P_CFG failed. status %d\n", reply.evt.status);
1276 rc = -EINVAL;
1277 }
1278
1279 return rc;
1280}
1281
1282int wmi_start_listen(struct wil6210_priv *wil)
1283{
1284 int rc;
1285 struct {
1286 struct wmi_cmd_hdr wmi;
1287 struct wmi_listen_started_event evt;
1288 } __packed reply;
1289
1290 wil_dbg_wmi(wil, "sending WMI_START_LISTEN_CMDID\n");
1291
1292 rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
1293 WMI_LISTEN_STARTED_EVENTID, &reply, sizeof(reply), 300);
1294 if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1295 wil_err(wil, "device failed to start listen. status %d\n",
1296 reply.evt.status);
1297 rc = -EINVAL;
1298 }
1299
1300 return rc;
1301}
1302
1303int wmi_start_search(struct wil6210_priv *wil)
1304{
1305 int rc;
1306 struct {
1307 struct wmi_cmd_hdr wmi;
1308 struct wmi_search_started_event evt;
1309 } __packed reply;
1310
1311 wil_dbg_wmi(wil, "sending WMI_START_SEARCH_CMDID\n");
1312
1313 rc = wmi_call(wil, WMI_START_SEARCH_CMDID, NULL, 0,
1314 WMI_SEARCH_STARTED_EVENTID, &reply, sizeof(reply), 300);
1315 if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1316 wil_err(wil, "device failed to start search. status %d\n",
1317 reply.evt.status);
1318 rc = -EINVAL;
1319 }
1320
1321 return rc;
1322}
1323
1324int wmi_stop_discovery(struct wil6210_priv *wil)
1325{
1326 int rc;
1327
1328 wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n");
1329
1330 rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
1331 WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100);
1332
1333 if (rc)
1334 wil_err(wil, "Failed to stop discovery\n");
1335
1336 return rc;
1337}
1338
1339int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
1340 const void *mac_addr, int key_usage)
1341{
1342 struct wmi_delete_cipher_key_cmd cmd = {
1343 .key_index = key_index,
1344 };
1345
1346 if (mac_addr)
1347 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
1348
1349 return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
1350}
1351
1352int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
1353 const void *mac_addr, int key_len, const void *key,
1354 int key_usage)
1355{
1356 struct wmi_add_cipher_key_cmd cmd = {
1357 .key_index = key_index,
1358 .key_usage = key_usage,
1359 .key_len = key_len,
1360 };
1361
1362 if (!key || (key_len > sizeof(cmd.key)))
1363 return -EINVAL;
1364
1365 memcpy(cmd.key, key, key_len);
1366 if (mac_addr)
1367 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
1368
1369 return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
1370}
1371
1372int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
1373{
1374 static const char *const names[] = {
1375 [WMI_FRAME_BEACON] = "BEACON",
1376 [WMI_FRAME_PROBE_REQ] = "PROBE_REQ",
1377 [WMI_FRAME_PROBE_RESP] = "WMI_FRAME_PROBE_RESP",
1378 [WMI_FRAME_ASSOC_REQ] = "WMI_FRAME_ASSOC_REQ",
1379 [WMI_FRAME_ASSOC_RESP] = "WMI_FRAME_ASSOC_RESP",
1380 };
1381 int rc;
1382 u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
1383 struct wmi_set_appie_cmd *cmd;
1384
1385 if (len < ie_len) {
1386 rc = -EINVAL;
1387 goto out;
1388 }
1389
1390 cmd = kzalloc(len, GFP_KERNEL);
1391 if (!cmd) {
1392 rc = -ENOMEM;
1393 goto out;
1394 }
1395 if (!ie)
1396 ie_len = 0;
1397
1398 cmd->mgmt_frm_type = type;
1399
1400 cmd->ie_len = cpu_to_le16(ie_len);
1401 memcpy(cmd->ie_info, ie, ie_len);
1402 rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);
1403 kfree(cmd);
1404out:
1405 if (rc) {
1406 const char *name = type < ARRAY_SIZE(names) ?
1407 names[type] : "??";
1408 wil_err(wil, "set_ie(%d %s) failed : %d\n", type, name, rc);
1409 }
1410
1411 return rc;
1412}
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422int wmi_rxon(struct wil6210_priv *wil, bool on)
1423{
1424 int rc;
1425 struct {
1426 struct wmi_cmd_hdr wmi;
1427 struct wmi_listen_started_event evt;
1428 } __packed reply;
1429
1430 wil_info(wil, "(%s)\n", on ? "on" : "off");
1431
1432 if (on) {
1433 rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
1434 WMI_LISTEN_STARTED_EVENTID,
1435 &reply, sizeof(reply), 100);
1436 if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
1437 rc = -EINVAL;
1438 } else {
1439 rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
1440 WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
1441 }
1442
1443 return rc;
1444}
1445
1446int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
1447{
1448 struct wireless_dev *wdev = wil->wdev;
1449 struct net_device *ndev = wil_to_ndev(wil);
1450 struct wmi_cfg_rx_chain_cmd cmd = {
1451 .action = WMI_RX_CHAIN_ADD,
1452 .rx_sw_ring = {
1453 .max_mpdu_size = cpu_to_le16(
1454 wil_mtu2macbuf(wil->rx_buf_len)),
1455 .ring_mem_base = cpu_to_le64(vring->pa),
1456 .ring_size = cpu_to_le16(vring->size),
1457 },
1458 .mid = 0,
1459 .decap_trans_type = WMI_DECAP_TYPE_802_3,
1460 .reorder_type = WMI_RX_SW_REORDER,
1461 .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
1462 };
1463 struct {
1464 struct wmi_cmd_hdr wmi;
1465 struct wmi_cfg_rx_chain_done_event evt;
1466 } __packed evt;
1467 int rc;
1468
1469 if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
1470 struct ieee80211_channel *ch = wdev->preset_chandef.chan;
1471
1472 cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
1473 if (ch)
1474 cmd.sniffer_cfg.channel = ch->hw_value - 1;
1475 cmd.sniffer_cfg.phy_info_mode =
1476 cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
1477 cmd.sniffer_cfg.phy_support =
1478 cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
1479 ? WMI_SNIFFER_CP : WMI_SNIFFER_BOTH_PHYS);
1480 } else {
1481
1482
1483
1484
1485 cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS);
1486 }
1487
1488 if (rx_align_2)
1489 cmd.l2_802_3_offload_ctrl |=
1490 L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK;
1491
1492
1493 rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
1494 WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
1495 if (rc)
1496 return rc;
1497
1498 vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
1499
1500 wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
1501 le32_to_cpu(evt.evt.status), vring->hwtail);
1502
1503 if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
1504 rc = -EINVAL;
1505
1506 return rc;
1507}
1508
1509int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
1510{
1511 int rc;
1512 struct wmi_temp_sense_cmd cmd = {
1513 .measure_baseband_en = cpu_to_le32(!!t_bb),
1514 .measure_rf_en = cpu_to_le32(!!t_rf),
1515 .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW),
1516 };
1517 struct {
1518 struct wmi_cmd_hdr wmi;
1519 struct wmi_temp_sense_done_event evt;
1520 } __packed reply;
1521
1522 rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd),
1523 WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
1524 if (rc)
1525 return rc;
1526
1527 if (t_bb)
1528 *t_bb = le32_to_cpu(reply.evt.baseband_t1000);
1529 if (t_rf)
1530 *t_rf = le32_to_cpu(reply.evt.rf_t1000);
1531
1532 return 0;
1533}
1534
1535int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
1536 u16 reason, bool full_disconnect, bool del_sta)
1537{
1538 int rc;
1539 u16 reason_code;
1540 struct wmi_disconnect_sta_cmd disc_sta_cmd = {
1541 .disconnect_reason = cpu_to_le16(reason),
1542 };
1543 struct wmi_del_sta_cmd del_sta_cmd = {
1544 .disconnect_reason = cpu_to_le16(reason),
1545 };
1546 struct {
1547 struct wmi_cmd_hdr wmi;
1548 struct wmi_disconnect_event evt;
1549 } __packed reply;
1550
1551 wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason);
1552
1553 wil->locally_generated_disc = true;
1554 if (del_sta) {
1555 ether_addr_copy(del_sta_cmd.dst_mac, mac);
1556 rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd,
1557 sizeof(del_sta_cmd), WMI_DISCONNECT_EVENTID,
1558 &reply, sizeof(reply), 1000);
1559 } else {
1560 ether_addr_copy(disc_sta_cmd.dst_mac, mac);
1561 rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &disc_sta_cmd,
1562 sizeof(disc_sta_cmd), WMI_DISCONNECT_EVENTID,
1563 &reply, sizeof(reply), 1000);
1564 }
1565
1566 if (rc) {
1567 wil_fw_error_recovery(wil);
1568 return rc;
1569 }
1570
1571 if (full_disconnect) {
1572
1573
1574
1575
1576 reason_code = le16_to_cpu(reply.evt.protocol_reason_status);
1577
1578 wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
1579 reply.evt.bssid, reason_code,
1580 reply.evt.disconnect_reason);
1581
1582 wil->sinfo_gen++;
1583 wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
1584 }
1585 return 0;
1586}
1587
1588int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
1589{
1590 struct wmi_vring_ba_en_cmd cmd = {
1591 .ringid = ringid,
1592 .agg_max_wsize = size,
1593 .ba_timeout = cpu_to_le16(timeout),
1594 .amsdu = 0,
1595 };
1596
1597 wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size,
1598 timeout);
1599
1600 return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
1601}
1602
1603int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
1604{
1605 struct wmi_vring_ba_dis_cmd cmd = {
1606 .ringid = ringid,
1607 .reason = cpu_to_le16(reason),
1608 };
1609
1610 wil_dbg_wmi(wil, "delba_tx: (ring %d reason %d)\n", ringid, reason);
1611
1612 return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
1613}
1614
1615int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
1616{
1617 struct wmi_rcp_delba_cmd cmd = {
1618 .cidxtid = cidxtid,
1619 .reason = cpu_to_le16(reason),
1620 };
1621
1622 wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cidxtid & 0xf,
1623 (cidxtid >> 4) & 0xf, reason);
1624
1625 return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
1626}
1627
1628int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
1629 u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
1630{
1631 int rc;
1632 struct wmi_rcp_addba_resp_cmd cmd = {
1633 .cidxtid = mk_cidxtid(cid, tid),
1634 .dialog_token = token,
1635 .status_code = cpu_to_le16(status),
1636
1637
1638
1639
1640
1641 .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
1642 (agg_wsize << 6)),
1643 .ba_timeout = cpu_to_le16(timeout),
1644 };
1645 struct {
1646 struct wmi_cmd_hdr wmi;
1647 struct wmi_rcp_addba_resp_sent_event evt;
1648 } __packed reply;
1649
1650 wil_dbg_wmi(wil,
1651 "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
1652 cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
1653
1654 rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
1655 WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply),
1656 100);
1657 if (rc)
1658 return rc;
1659
1660 if (reply.evt.status) {
1661 wil_err(wil, "ADDBA response failed with status %d\n",
1662 le16_to_cpu(reply.evt.status));
1663 rc = -EINVAL;
1664 }
1665
1666 return rc;
1667}
1668
1669int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
1670 enum wmi_ps_profile_type ps_profile)
1671{
1672 int rc;
1673 struct wmi_ps_dev_profile_cfg_cmd cmd = {
1674 .ps_profile = ps_profile,
1675 };
1676 struct {
1677 struct wmi_cmd_hdr wmi;
1678 struct wmi_ps_dev_profile_cfg_event evt;
1679 } __packed reply;
1680 u32 status;
1681
1682 wil_dbg_wmi(wil, "Setting ps dev profile %d\n", ps_profile);
1683
1684 reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR);
1685
1686 rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, &cmd, sizeof(cmd),
1687 WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply),
1688 100);
1689 if (rc)
1690 return rc;
1691
1692 status = le32_to_cpu(reply.evt.status);
1693
1694 if (status != WMI_PS_CFG_CMD_STATUS_SUCCESS) {
1695 wil_err(wil, "ps dev profile cfg failed with status %d\n",
1696 status);
1697 rc = -EINVAL;
1698 }
1699
1700 return rc;
1701}
1702
1703int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
1704{
1705 int rc;
1706 struct wmi_set_mgmt_retry_limit_cmd cmd = {
1707 .mgmt_retry_limit = retry_short,
1708 };
1709 struct {
1710 struct wmi_cmd_hdr wmi;
1711 struct wmi_set_mgmt_retry_limit_event evt;
1712 } __packed reply;
1713
1714 wil_dbg_wmi(wil, "Setting mgmt retry short %d\n", retry_short);
1715
1716 if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
1717 return -ENOTSUPP;
1718
1719 reply.evt.status = WMI_FW_STATUS_FAILURE;
1720
1721 rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, &cmd, sizeof(cmd),
1722 WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
1723 100);
1724 if (rc)
1725 return rc;
1726
1727 if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
1728 wil_err(wil, "set mgmt retry limit failed with status %d\n",
1729 reply.evt.status);
1730 rc = -EINVAL;
1731 }
1732
1733 return rc;
1734}
1735
1736int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
1737{
1738 int rc;
1739 struct {
1740 struct wmi_cmd_hdr wmi;
1741 struct wmi_get_mgmt_retry_limit_event evt;
1742 } __packed reply;
1743
1744 wil_dbg_wmi(wil, "getting mgmt retry short\n");
1745
1746 if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
1747 return -ENOTSUPP;
1748
1749 reply.evt.mgmt_retry_limit = 0;
1750 rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, NULL, 0,
1751 WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
1752 100);
1753 if (rc)
1754 return rc;
1755
1756 if (retry_short)
1757 *retry_short = reply.evt.mgmt_retry_limit;
1758
1759 return 0;
1760}
1761
1762int wmi_abort_scan(struct wil6210_priv *wil)
1763{
1764 int rc;
1765
1766 wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n");
1767
1768 rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, NULL, 0);
1769 if (rc)
1770 wil_err(wil, "Failed to abort scan (%d)\n", rc);
1771
1772 return rc;
1773}
1774
1775int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
1776{
1777 int rc;
1778 struct wmi_new_sta_cmd cmd = {
1779 .aid = aid,
1780 };
1781
1782 wil_dbg_wmi(wil, "new sta %pM, aid %d\n", mac, aid);
1783
1784 ether_addr_copy(cmd.dst_mac, mac);
1785
1786 rc = wmi_send(wil, WMI_NEW_STA_CMDID, &cmd, sizeof(cmd));
1787 if (rc)
1788 wil_err(wil, "Failed to send new sta (%d)\n", rc);
1789
1790 return rc;
1791}
1792
1793void wmi_event_flush(struct wil6210_priv *wil)
1794{
1795 ulong flags;
1796 struct pending_wmi_event *evt, *t;
1797
1798 wil_dbg_wmi(wil, "event_flush\n");
1799
1800 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1801
1802 list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
1803 list_del(&evt->list);
1804 kfree(evt);
1805 }
1806
1807 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1808}
1809
1810int wmi_suspend(struct wil6210_priv *wil)
1811{
1812 int rc;
1813 struct wmi_traffic_suspend_cmd cmd = {
1814 .wakeup_trigger = wil->wakeup_trigger,
1815 };
1816 struct {
1817 struct wmi_cmd_hdr wmi;
1818 struct wmi_traffic_suspend_event evt;
1819 } __packed reply;
1820 u32 suspend_to = WIL_WAIT_FOR_SUSPEND_RESUME_COMP;
1821
1822 wil->suspend_resp_rcvd = false;
1823 wil->suspend_resp_comp = false;
1824
1825 reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED;
1826
1827 rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd),
1828 WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply),
1829 suspend_to);
1830 if (rc) {
1831 wil_err(wil, "wmi_call for suspend req failed, rc=%d\n", rc);
1832 if (rc == -ETIME)
1833
1834 wil->suspend_stats.rejected_by_device++;
1835 else
1836 wil->suspend_stats.rejected_by_host++;
1837 goto out;
1838 }
1839
1840 wil_dbg_wmi(wil, "waiting for suspend_response_completed\n");
1841
1842 rc = wait_event_interruptible_timeout(wil->wq,
1843 wil->suspend_resp_comp,
1844 msecs_to_jiffies(suspend_to));
1845 if (rc == 0) {
1846 wil_err(wil, "TO waiting for suspend_response_completed\n");
1847 if (wil->suspend_resp_rcvd)
1848
1849 wil->suspend_stats.rejected_by_host++;
1850 else
1851 wil->suspend_stats.rejected_by_device++;
1852 rc = -EBUSY;
1853 goto out;
1854 }
1855
1856 wil_dbg_wmi(wil, "suspend_response_completed rcvd\n");
1857 if (reply.evt.status == WMI_TRAFFIC_SUSPEND_REJECTED) {
1858 wil_dbg_pm(wil, "device rejected the suspend\n");
1859 wil->suspend_stats.rejected_by_device++;
1860 }
1861 rc = reply.evt.status;
1862
1863out:
1864 wil->suspend_resp_rcvd = false;
1865 wil->suspend_resp_comp = false;
1866
1867 return rc;
1868}
1869
1870int wmi_resume(struct wil6210_priv *wil)
1871{
1872 int rc;
1873 struct {
1874 struct wmi_cmd_hdr wmi;
1875 struct wmi_traffic_resume_event evt;
1876 } __packed reply;
1877
1878 reply.evt.status = WMI_TRAFFIC_RESUME_FAILED;
1879
1880 rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0,
1881 WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply),
1882 WIL_WAIT_FOR_SUSPEND_RESUME_COMP);
1883 if (rc)
1884 return rc;
1885
1886 return reply.evt.status;
1887}
1888
1889static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
1890 void *d, int len)
1891{
1892 uint i;
1893
1894 for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
1895 if (wmi_evt_handlers[i].eventid == id) {
1896 wmi_evt_handlers[i].handler(wil, id, d, len);
1897 return true;
1898 }
1899 }
1900
1901 return false;
1902}
1903
1904static void wmi_event_handle(struct wil6210_priv *wil,
1905 struct wil6210_mbox_hdr *hdr)
1906{
1907 u16 len = le16_to_cpu(hdr->len);
1908
1909 if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
1910 (len >= sizeof(struct wmi_cmd_hdr))) {
1911 struct wmi_cmd_hdr *wmi = (void *)(&hdr[1]);
1912 void *evt_data = (void *)(&wmi[1]);
1913 u16 id = le16_to_cpu(wmi->command_id);
1914
1915 wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n",
1916 id, wil->reply_id);
1917
1918 if (wil->reply_id && wil->reply_id == id) {
1919 WARN_ON(wil->reply_buf);
1920 wmi_evt_call_handler(wil, id, evt_data,
1921 len - sizeof(*wmi));
1922 wil_dbg_wmi(wil, "event_handle: Complete WMI 0x%04x\n",
1923 id);
1924 complete(&wil->wmi_call);
1925 return;
1926 }
1927
1928
1929 if (!wmi_evt_call_handler(wil, id, evt_data,
1930 len - sizeof(*wmi))) {
1931 wil_info(wil, "Unhandled event 0x%04x\n", id);
1932 }
1933 } else {
1934 wil_err(wil, "Unknown event type\n");
1935 print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
1936 hdr, sizeof(*hdr) + len, true);
1937 }
1938}
1939
1940
1941
1942
1943static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
1944{
1945 ulong flags;
1946 struct list_head *ret = NULL;
1947
1948 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1949
1950 if (!list_empty(&wil->pending_wmi_ev)) {
1951 ret = wil->pending_wmi_ev.next;
1952 list_del(ret);
1953 }
1954
1955 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1956
1957 return ret;
1958}
1959
1960
1961
1962
1963void wmi_event_worker(struct work_struct *work)
1964{
1965 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
1966 wmi_event_worker);
1967 struct pending_wmi_event *evt;
1968 struct list_head *lh;
1969
1970 wil_dbg_wmi(wil, "event_worker: Start\n");
1971 while ((lh = next_wmi_ev(wil)) != NULL) {
1972 evt = list_entry(lh, struct pending_wmi_event, list);
1973 wmi_event_handle(wil, &evt->event.hdr);
1974 kfree(evt);
1975 }
1976 wil_dbg_wmi(wil, "event_worker: Finished\n");
1977}
1978
1979bool wil_is_wmi_idle(struct wil6210_priv *wil)
1980{
1981 ulong flags;
1982 struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
1983 bool rc = false;
1984
1985 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1986
1987
1988 if (!list_empty(&wil->pending_wmi_ev)) {
1989 wil_dbg_pm(wil, "Pending WMI events in queue\n");
1990 goto out;
1991 }
1992
1993
1994 if (wil->reply_id) {
1995 wil_dbg_pm(wil, "Pending WMI call\n");
1996 goto out;
1997 }
1998
1999
2000 r->head = wil_r(wil, RGF_MBOX +
2001 offsetof(struct wil6210_mbox_ctl, rx.head));
2002 if (r->tail != r->head)
2003 wil_dbg_pm(wil, "Pending WMI mbox events\n");
2004 else
2005 rc = true;
2006
2007out:
2008 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
2009 return rc;
2010}
2011