1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/etherdevice.h>
18#include <linux/if_arp.h>
19
20#include "wil6210.h"
21#include "txrx.h"
22#include "wmi.h"
23#include "trace.h"
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
69static const struct {
70 u32 from;
71 u32 to;
72 u32 host;
73} fw_mapping[] = {
74 {0x000000, 0x040000, 0x8c0000},
75 {0x800000, 0x808000, 0x900000},
76 {0x840000, 0x860000, 0x908000},
77 {0x880000, 0x88a000, 0x880000},
78 {0x8c0000, 0x949000, 0x8c0000},
79
80
81
82
83
84};
85
86
87
88
89
90
91static u32 wmi_addr_remap(u32 x)
92{
93 uint i;
94
95 for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
96 if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to))
97 return x + fw_mapping[i].host - fw_mapping[i].from;
98 }
99
100 return 0;
101}
102
103
104
105
106
107
108
109
110
111
112void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
113{
114 u32 off;
115 u32 ptr = le32_to_cpu(ptr_);
116
117 if (ptr % 4)
118 return NULL;
119
120 ptr = wmi_addr_remap(ptr);
121 if (ptr < WIL6210_FW_HOST_OFF)
122 return NULL;
123
124 off = HOSTADDR(ptr);
125 if (off > WIL6210_MEM_SIZE - 4)
126 return NULL;
127
128 return wil->csr + off;
129}
130
131
132
133
134void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
135{
136 u32 off;
137
138 if (ptr % 4)
139 return NULL;
140
141 if (ptr < WIL6210_FW_HOST_OFF)
142 return NULL;
143
144 off = HOSTADDR(ptr);
145 if (off > WIL6210_MEM_SIZE - 4)
146 return NULL;
147
148 return wil->csr + off;
149}
150
151int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
152 struct wil6210_mbox_hdr *hdr)
153{
154 void __iomem *src = wmi_buffer(wil, ptr);
155 if (!src)
156 return -EINVAL;
157
158 wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
159
160 return 0;
161}
162
163static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
164{
165 struct {
166 struct wil6210_mbox_hdr hdr;
167 struct wil6210_mbox_hdr_wmi wmi;
168 } __packed cmd = {
169 .hdr = {
170 .type = WIL_MBOX_HDR_TYPE_WMI,
171 .flags = 0,
172 .len = cpu_to_le16(sizeof(cmd.wmi) + len),
173 },
174 .wmi = {
175 .mid = 0,
176 .id = cpu_to_le16(cmdid),
177 },
178 };
179 struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
180 struct wil6210_mbox_ring_desc d_head;
181 u32 next_head;
182 void __iomem *dst;
183 void __iomem *head = wmi_addr(wil, r->head);
184 uint retry;
185
186 if (sizeof(cmd) + len > r->entry_size) {
187 wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
188 (int)(sizeof(cmd) + len), r->entry_size);
189 return -ERANGE;
190 }
191
192 might_sleep();
193
194 if (!test_bit(wil_status_fwready, &wil->status)) {
195 wil_err(wil, "FW not ready\n");
196 return -EAGAIN;
197 }
198
199 if (!head) {
200 wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
201 return -EINVAL;
202 }
203
204 for (retry = 5; retry > 0; retry--) {
205 wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
206 if (d_head.sync == 0)
207 break;
208 msleep(20);
209 }
210 if (d_head.sync != 0) {
211 wil_err(wil, "WMI head busy\n");
212 return -EBUSY;
213 }
214
215 next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
216 wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
217
218 for (retry = 5; retry > 0; retry--) {
219 r->tail = ioread32(wil->csr + HOST_MBOX +
220 offsetof(struct wil6210_mbox_ctl, tx.tail));
221 if (next_head != r->tail)
222 break;
223 msleep(20);
224 }
225 if (next_head == r->tail) {
226 wil_err(wil, "WMI ring full\n");
227 return -EBUSY;
228 }
229 dst = wmi_buffer(wil, d_head.addr);
230 if (!dst) {
231 wil_err(wil, "invalid WMI buffer: 0x%08x\n",
232 le32_to_cpu(d_head.addr));
233 return -EINVAL;
234 }
235 cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
236
237 wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
238 wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
239 sizeof(cmd), true);
240 wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
241 len, true);
242 wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
243 wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
244
245 iowrite32(1, wil->csr + HOSTADDR(r->head) +
246 offsetof(struct wil6210_mbox_ring_desc, sync));
247
248 iowrite32(r->head = next_head, wil->csr + HOST_MBOX +
249 offsetof(struct wil6210_mbox_ctl, tx.head));
250
251 trace_wil6210_wmi_cmd(&cmd.wmi, buf, len);
252
253
254 iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT);
255
256 return 0;
257}
258
259int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
260{
261 int rc;
262
263 mutex_lock(&wil->wmi_mutex);
264 rc = __wmi_send(wil, cmdid, buf, len);
265 mutex_unlock(&wil->wmi_mutex);
266
267 return rc;
268}
269
270
271static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
272{
273 struct net_device *ndev = wil_to_ndev(wil);
274 struct wireless_dev *wdev = wil->wdev;
275 struct wmi_ready_event *evt = d;
276 wil->fw_version = le32_to_cpu(evt->sw_version);
277 wil->n_mids = evt->numof_additional_mids;
278
279 wil_dbg_wmi(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version,
280 evt->mac, wil->n_mids);
281
282 if (!is_valid_ether_addr(ndev->dev_addr)) {
283 memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
284 memcpy(ndev->perm_addr, evt->mac, ETH_ALEN);
285 }
286 snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version),
287 "%d", wil->fw_version);
288}
289
290static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
291 int len)
292{
293 wil_dbg_wmi(wil, "WMI: FW ready\n");
294
295 set_bit(wil_status_fwready, &wil->status);
296
297 complete(&wil->wmi_ready);
298}
299
300static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
301{
302 struct wmi_rx_mgmt_packet_event *data = d;
303 struct wiphy *wiphy = wil_to_wiphy(wil);
304 struct ieee80211_mgmt *rx_mgmt_frame =
305 (struct ieee80211_mgmt *)data->payload;
306 int ch_no = data->info.channel+1;
307 u32 freq = ieee80211_channel_to_frequency(ch_no,
308 IEEE80211_BAND_60GHZ);
309 struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq);
310
311 s32 signal = 0;
312 __le16 fc = rx_mgmt_frame->frame_control;
313 u32 d_len = le32_to_cpu(data->info.len);
314 u16 d_status = le16_to_cpu(data->info.status);
315
316 wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n",
317 data->info.channel, data->info.mcs, data->info.snr);
318 wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
319 le16_to_cpu(fc));
320 wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
321 data->info.qid, data->info.mid, data->info.cid);
322
323 if (!channel) {
324 wil_err(wil, "Frame on unsupported channel\n");
325 return;
326 }
327
328 if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
329 struct cfg80211_bss *bss;
330
331 bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
332 d_len, signal, GFP_KERNEL);
333 if (bss) {
334 wil_dbg_wmi(wil, "Added BSS %pM\n",
335 rx_mgmt_frame->bssid);
336 cfg80211_put_bss(wiphy, bss);
337 } else {
338 wil_err(wil, "cfg80211_inform_bss() failed\n");
339 }
340 } else {
341 cfg80211_rx_mgmt(wil->wdev, freq, signal,
342 (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL);
343 }
344}
345
346static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
347 void *d, int len)
348{
349 if (wil->scan_request) {
350 struct wmi_scan_complete_event *data = d;
351 bool aborted = (data->status != 0);
352
353 wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
354 cfg80211_scan_done(wil->scan_request, aborted);
355 wil->scan_request = NULL;
356 } else {
357 wil_err(wil, "SCAN_COMPLETE while not scanning\n");
358 }
359}
360
361static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
362{
363 struct net_device *ndev = wil_to_ndev(wil);
364 struct wireless_dev *wdev = wil->wdev;
365 struct wmi_connect_event *evt = d;
366 int ch;
367 struct station_info sinfo;
368 u8 *assoc_req_ie, *assoc_resp_ie;
369 size_t assoc_req_ielen, assoc_resp_ielen;
370
371 const size_t assoc_req_ie_offset = sizeof(u16) * 2;
372
373 const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
374
375 if (len < sizeof(*evt)) {
376 wil_err(wil, "Connect event too short : %d bytes\n", len);
377 return;
378 }
379 if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len +
380 evt->assoc_resp_len) {
381 wil_err(wil,
382 "Connect event corrupted : %d != %d + %d + %d + %d\n",
383 len, (int)sizeof(*evt), evt->beacon_ie_len,
384 evt->assoc_req_len, evt->assoc_resp_len);
385 return;
386 }
387 ch = evt->channel + 1;
388 wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
389 evt->bssid, ch, evt->cid);
390 wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
391 evt->assoc_info, len - sizeof(*evt), true);
392
393
394 assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len +
395 assoc_req_ie_offset];
396 assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset;
397 if (evt->assoc_req_len <= assoc_req_ie_offset) {
398 assoc_req_ie = NULL;
399 assoc_req_ielen = 0;
400 }
401
402 assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len +
403 evt->assoc_req_len +
404 assoc_resp_ie_offset];
405 assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset;
406 if (evt->assoc_resp_len <= assoc_resp_ie_offset) {
407 assoc_resp_ie = NULL;
408 assoc_resp_ielen = 0;
409 }
410
411 if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
412 (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
413 if (!test_bit(wil_status_fwconnecting, &wil->status)) {
414 wil_err(wil, "Not in connecting state\n");
415 return;
416 }
417 del_timer_sync(&wil->connect_timer);
418 cfg80211_connect_result(ndev, evt->bssid,
419 assoc_req_ie, assoc_req_ielen,
420 assoc_resp_ie, assoc_resp_ielen,
421 WLAN_STATUS_SUCCESS, GFP_KERNEL);
422
423 } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
424 (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
425 memset(&sinfo, 0, sizeof(sinfo));
426
427 sinfo.generation = wil->sinfo_gen++;
428
429 if (assoc_req_ie) {
430 sinfo.assoc_req_ies = assoc_req_ie;
431 sinfo.assoc_req_ies_len = assoc_req_ielen;
432 sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
433 }
434
435 cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
436 }
437 clear_bit(wil_status_fwconnecting, &wil->status);
438 set_bit(wil_status_fwconnected, &wil->status);
439
440
441
442 memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
443
444 wil->pending_connect_cid = evt->cid;
445 queue_work(wil->wmi_wq_conn, &wil->connect_worker);
446}
447
448static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
449 void *d, int len)
450{
451 struct wmi_disconnect_event *evt = d;
452
453 wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n",
454 evt->bssid,
455 evt->protocol_reason_status, evt->disconnect_reason);
456
457 wil->sinfo_gen++;
458
459 wil6210_disconnect(wil, evt->bssid);
460}
461
462static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
463{
464 struct wmi_notify_req_done_event *evt = d;
465
466 if (len < sizeof(*evt)) {
467 wil_err(wil, "Short NOTIFY event\n");
468 return;
469 }
470
471 wil->stats.tsf = le64_to_cpu(evt->tsf);
472 wil->stats.snr = le32_to_cpu(evt->snr_val);
473 wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs);
474 wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector);
475 wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
476 wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
477 wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
478 wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
479 "BF status 0x%08x SNR 0x%08x\n"
480 "Tx Tpt %d goodput %d Rx goodput %d\n"
481 "Sectors(rx:tx) my %d:%d peer %d:%d\n",
482 wil->stats.bf_mcs, wil->stats.tsf, evt->status,
483 wil->stats.snr, le32_to_cpu(evt->tx_tpt),
484 le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
485 wil->stats.my_rx_sector, wil->stats.my_tx_sector,
486 wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
487}
488
489
490
491
492
493static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
494 void *d, int len)
495{
496 struct net_device *ndev = wil_to_ndev(wil);
497 struct wmi_eapol_rx_event *evt = d;
498 u16 eapol_len = le16_to_cpu(evt->eapol_len);
499 int sz = eapol_len + ETH_HLEN;
500 struct sk_buff *skb;
501 struct ethhdr *eth;
502
503 wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
504 evt->src_mac);
505
506 if (eapol_len > 196) {
507 wil_err(wil, "EAPOL too large\n");
508 return;
509 }
510
511 skb = alloc_skb(sz, GFP_KERNEL);
512 if (!skb) {
513 wil_err(wil, "Failed to allocate skb\n");
514 return;
515 }
516 eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);
517 memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);
518 memcpy(eth->h_source, evt->src_mac, ETH_ALEN);
519 eth->h_proto = cpu_to_be16(ETH_P_PAE);
520 memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len);
521 skb->protocol = eth_type_trans(skb, ndev);
522 if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
523 ndev->stats.rx_packets++;
524 ndev->stats.rx_bytes += skb->len;
525 } else {
526 ndev->stats.rx_dropped++;
527 }
528}
529
530static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
531{
532 struct net_device *ndev = wil_to_ndev(wil);
533 struct wmi_data_port_open_event *evt = d;
534
535 wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid);
536
537 netif_carrier_on(ndev);
538}
539
540static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
541{
542 struct net_device *ndev = wil_to_ndev(wil);
543 struct wmi_wbe_link_down_event *evt = d;
544
545 wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n",
546 evt->cid, le32_to_cpu(evt->reason));
547
548 netif_carrier_off(ndev);
549}
550
551static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
552 int len)
553{
554 struct wmi_vring_ba_status_event *evt = d;
555
556 wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
557 evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize,
558 __le16_to_cpu(evt->ba_timeout));
559}
560
561static const struct {
562 int eventid;
563 void (*handler)(struct wil6210_priv *wil, int eventid,
564 void *data, int data_len);
565} wmi_evt_handlers[] = {
566 {WMI_READY_EVENTID, wmi_evt_ready},
567 {WMI_FW_READY_EVENTID, wmi_evt_fw_ready},
568 {WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt},
569 {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
570 {WMI_CONNECT_EVENTID, wmi_evt_connect},
571 {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
572 {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify},
573 {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
574 {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
575 {WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
576 {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
577};
578
579
580
581
582
583
584
585void wmi_recv_cmd(struct wil6210_priv *wil)
586{
587 struct wil6210_mbox_ring_desc d_tail;
588 struct wil6210_mbox_hdr hdr;
589 struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
590 struct pending_wmi_event *evt;
591 u8 *cmd;
592 void __iomem *src;
593 ulong flags;
594
595 if (!test_bit(wil_status_reset_done, &wil->status)) {
596 wil_err(wil, "Reset not completed\n");
597 return;
598 }
599
600 for (;;) {
601 u16 len;
602
603 r->head = ioread32(wil->csr + HOST_MBOX +
604 offsetof(struct wil6210_mbox_ctl, rx.head));
605 if (r->tail == r->head)
606 return;
607
608
609 wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),
610 sizeof(struct wil6210_mbox_ring_desc));
611 if (d_tail.sync == 0) {
612 wil_err(wil, "Mbox evt not owned by FW?\n");
613 return;
614 }
615
616 if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
617 wil_err(wil, "Mbox evt at 0x%08x?\n",
618 le32_to_cpu(d_tail.addr));
619 return;
620 }
621
622 len = le16_to_cpu(hdr.len);
623 src = wmi_buffer(wil, d_tail.addr) +
624 sizeof(struct wil6210_mbox_hdr);
625 evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
626 event.wmi) + len, 4),
627 GFP_KERNEL);
628 if (!evt)
629 return;
630
631 evt->event.hdr = hdr;
632 cmd = (void *)&evt->event.wmi;
633 wil_memcpy_fromio_32(cmd, src, len);
634
635 iowrite32(0, wil->csr + HOSTADDR(r->tail) +
636 offsetof(struct wil6210_mbox_ring_desc, sync));
637
638 wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n",
639 le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
640 hdr.flags);
641 if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
642 (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
643 struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
644 u16 id = le16_to_cpu(wmi->id);
645 u32 tstamp = le32_to_cpu(wmi->timestamp);
646 wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
647 id, wmi->mid, tstamp);
648 trace_wil6210_wmi_event(wmi, &wmi[1],
649 len - sizeof(*wmi));
650 }
651 wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
652 &evt->event.hdr, sizeof(hdr) + len, true);
653
654
655 r->tail = r->base + ((r->tail - r->base +
656 sizeof(struct wil6210_mbox_ring_desc)) % r->size);
657 iowrite32(r->tail, wil->csr + HOST_MBOX +
658 offsetof(struct wil6210_mbox_ctl, rx.tail));
659
660
661 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
662 list_add_tail(&evt->list, &wil->pending_wmi_ev);
663 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
664 {
665 int q = queue_work(wil->wmi_wq,
666 &wil->wmi_event_worker);
667 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
668 }
669 }
670}
671
672int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
673 u16 reply_id, void *reply, u8 reply_size, int to_msec)
674{
675 int rc;
676 int remain;
677
678 mutex_lock(&wil->wmi_mutex);
679
680 rc = __wmi_send(wil, cmdid, buf, len);
681 if (rc)
682 goto out;
683
684 wil->reply_id = reply_id;
685 wil->reply_buf = reply;
686 wil->reply_size = reply_size;
687 remain = wait_for_completion_timeout(&wil->wmi_ready,
688 msecs_to_jiffies(to_msec));
689 if (0 == remain) {
690 wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
691 cmdid, reply_id, to_msec);
692 rc = -ETIME;
693 } else {
694 wil_dbg_wmi(wil,
695 "wmi_call(0x%04x->0x%04x) completed in %d msec\n",
696 cmdid, reply_id,
697 to_msec - jiffies_to_msecs(remain));
698 }
699 wil->reply_id = 0;
700 wil->reply_buf = NULL;
701 wil->reply_size = 0;
702 out:
703 mutex_unlock(&wil->wmi_mutex);
704
705 return rc;
706}
707
708int wmi_echo(struct wil6210_priv *wil)
709{
710 struct wmi_echo_cmd cmd = {
711 .value = cpu_to_le32(0x12345678),
712 };
713
714 return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
715 WMI_ECHO_RSP_EVENTID, NULL, 0, 20);
716}
717
718int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
719{
720 struct wmi_set_mac_address_cmd cmd;
721
722 memcpy(cmd.mac, addr, ETH_ALEN);
723
724 wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
725
726 return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
727}
728
729int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
730{
731 int rc;
732
733 struct wmi_pcp_start_cmd cmd = {
734 .bcon_interval = cpu_to_le16(bi),
735 .network_type = wmi_nettype,
736 .disable_sec_offload = 1,
737 .channel = chan - 1,
738 };
739 struct {
740 struct wil6210_mbox_hdr_wmi wmi;
741 struct wmi_pcp_started_event evt;
742 } __packed reply;
743
744 if (!wil->secure_pcp)
745 cmd.disable_sec = 1;
746
747
748
749
750
751 rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
752 WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000);
753 if (rc)
754 return rc;
755
756 if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
757 rc = -EINVAL;
758
759 return rc;
760}
761
762int wmi_pcp_stop(struct wil6210_priv *wil)
763{
764 return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
765 WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
766}
767
768int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
769{
770 struct wmi_set_ssid_cmd cmd = {
771 .ssid_len = cpu_to_le32(ssid_len),
772 };
773
774 if (ssid_len > sizeof(cmd.ssid))
775 return -EINVAL;
776
777 memcpy(cmd.ssid, ssid, ssid_len);
778
779 return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
780}
781
782int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
783{
784 int rc;
785 struct {
786 struct wil6210_mbox_hdr_wmi wmi;
787 struct wmi_set_ssid_cmd cmd;
788 } __packed reply;
789 int len;
790
791 rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
792 &reply, sizeof(reply), 20);
793 if (rc)
794 return rc;
795
796 len = le32_to_cpu(reply.cmd.ssid_len);
797 if (len > sizeof(reply.cmd.ssid))
798 return -EINVAL;
799
800 *ssid_len = len;
801 memcpy(ssid, reply.cmd.ssid, len);
802
803 return 0;
804}
805
806int wmi_set_channel(struct wil6210_priv *wil, int channel)
807{
808 struct wmi_set_pcp_channel_cmd cmd = {
809 .channel = channel - 1,
810 };
811
812 return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
813}
814
815int wmi_get_channel(struct wil6210_priv *wil, int *channel)
816{
817 int rc;
818 struct {
819 struct wil6210_mbox_hdr_wmi wmi;
820 struct wmi_set_pcp_channel_cmd cmd;
821 } __packed reply;
822
823 rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
824 WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
825 if (rc)
826 return rc;
827
828 if (reply.cmd.channel > 3)
829 return -EINVAL;
830
831 *channel = reply.cmd.channel + 1;
832
833 return 0;
834}
835
836int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
837{
838 struct wmi_p2p_cfg_cmd cmd = {
839 .discovery_mode = WMI_DISCOVERY_MODE_NON_OFFLOAD,
840 .channel = channel - 1,
841 };
842
843 return wmi_send(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd));
844}
845
846int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
847 const void *mac_addr)
848{
849 struct wmi_delete_cipher_key_cmd cmd = {
850 .key_index = key_index,
851 };
852
853 if (mac_addr)
854 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
855
856 return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
857}
858
859int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
860 const void *mac_addr, int key_len, const void *key)
861{
862 struct wmi_add_cipher_key_cmd cmd = {
863 .key_index = key_index,
864 .key_usage = WMI_KEY_USE_PAIRWISE,
865 .key_len = key_len,
866 };
867
868 if (!key || (key_len > sizeof(cmd.key)))
869 return -EINVAL;
870
871 memcpy(cmd.key, key, key_len);
872 if (mac_addr)
873 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
874
875 return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
876}
877
878int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
879{
880 int rc;
881 u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
882 struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
883 if (!cmd)
884 return -ENOMEM;
885
886 cmd->mgmt_frm_type = type;
887
888 cmd->ie_len = cpu_to_le16(ie_len);
889 memcpy(cmd->ie_info, ie, ie_len);
890 rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);
891 kfree(cmd);
892
893 return rc;
894}
895
896int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
897{
898 struct wireless_dev *wdev = wil->wdev;
899 struct net_device *ndev = wil_to_ndev(wil);
900 struct wmi_cfg_rx_chain_cmd cmd = {
901 .action = WMI_RX_CHAIN_ADD,
902 .rx_sw_ring = {
903 .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
904 .ring_mem_base = cpu_to_le64(vring->pa),
905 .ring_size = cpu_to_le16(vring->size),
906 },
907 .mid = 0,
908 .decap_trans_type = WMI_DECAP_TYPE_802_3,
909 };
910 struct {
911 struct wil6210_mbox_hdr_wmi wmi;
912 struct wmi_cfg_rx_chain_done_event evt;
913 } __packed evt;
914 int rc;
915
916 if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
917 struct ieee80211_channel *ch = wdev->preset_chandef.chan;
918
919 cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
920 if (ch)
921 cmd.sniffer_cfg.channel = ch->hw_value - 1;
922 cmd.sniffer_cfg.phy_info_mode =
923 cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
924 cmd.sniffer_cfg.phy_support =
925 cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
926 ? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
927 } else {
928
929
930
931
932 cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS);
933 }
934
935 rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
936 WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
937 if (rc)
938 return rc;
939
940 vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
941
942 wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
943 le32_to_cpu(evt.evt.status), vring->hwtail);
944
945 if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
946 rc = -EINVAL;
947
948 return rc;
949}
950
951int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
952{
953 int rc;
954 struct wmi_temp_sense_cmd cmd = {
955 .measure_marlon_m_en = cpu_to_le32(!!t_m),
956 .measure_marlon_r_en = cpu_to_le32(!!t_r),
957 };
958 struct {
959 struct wil6210_mbox_hdr_wmi wmi;
960 struct wmi_temp_sense_done_event evt;
961 } __packed reply;
962
963 rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd),
964 WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
965 if (rc)
966 return rc;
967
968 if (t_m)
969 *t_m = le32_to_cpu(reply.evt.marlon_m_t1000);
970 if (t_r)
971 *t_r = le32_to_cpu(reply.evt.marlon_r_t1000);
972
973 return 0;
974}
975
976void wmi_event_flush(struct wil6210_priv *wil)
977{
978 struct pending_wmi_event *evt, *t;
979
980 wil_dbg_wmi(wil, "%s()\n", __func__);
981
982 list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
983 list_del(&evt->list);
984 kfree(evt);
985 }
986}
987
988static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
989 void *d, int len)
990{
991 uint i;
992
993 for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
994 if (wmi_evt_handlers[i].eventid == id) {
995 wmi_evt_handlers[i].handler(wil, id, d, len);
996 return true;
997 }
998 }
999
1000 return false;
1001}
1002
1003static void wmi_event_handle(struct wil6210_priv *wil,
1004 struct wil6210_mbox_hdr *hdr)
1005{
1006 u16 len = le16_to_cpu(hdr->len);
1007
1008 if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
1009 (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
1010 struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
1011 void *evt_data = (void *)(&wmi[1]);
1012 u16 id = le16_to_cpu(wmi->id);
1013
1014 if (wil->reply_id && wil->reply_id == id) {
1015 if (wil->reply_buf) {
1016 memcpy(wil->reply_buf, wmi,
1017 min(len, wil->reply_size));
1018 } else {
1019 wmi_evt_call_handler(wil, id, evt_data,
1020 len - sizeof(*wmi));
1021 }
1022 wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
1023 complete(&wil->wmi_ready);
1024 return;
1025 }
1026
1027
1028 if (!wmi_evt_call_handler(wil, id, evt_data,
1029 len - sizeof(*wmi))) {
1030 wil_err(wil, "Unhandled event 0x%04x\n", id);
1031 }
1032 } else {
1033 wil_err(wil, "Unknown event type\n");
1034 print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
1035 hdr, sizeof(*hdr) + len, true);
1036 }
1037}
1038
1039
1040
1041
1042static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
1043{
1044 ulong flags;
1045 struct list_head *ret = NULL;
1046
1047 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1048
1049 if (!list_empty(&wil->pending_wmi_ev)) {
1050 ret = wil->pending_wmi_ev.next;
1051 list_del(ret);
1052 }
1053
1054 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1055
1056 return ret;
1057}
1058
1059
1060
1061
1062void wmi_event_worker(struct work_struct *work)
1063{
1064 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
1065 wmi_event_worker);
1066 struct pending_wmi_event *evt;
1067 struct list_head *lh;
1068
1069 while ((lh = next_wmi_ev(wil)) != NULL) {
1070 evt = list_entry(lh, struct pending_wmi_event, list);
1071 wmi_event_handle(wil, &evt->event.hdr);
1072 kfree(evt);
1073 }
1074}
1075