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 .id = cpu_to_le16(cmdid),
176 .info1 = 0,
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(cmdid, 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, 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 u16 id = le16_to_cpu(evt->event.wmi.id);
644 wil_dbg_wmi(wil, "WMI event 0x%04x\n", id);
645 trace_wil6210_wmi_event(id, &evt->event.wmi, len);
646 }
647 wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
648 &evt->event.hdr, sizeof(hdr) + len, true);
649
650
651 r->tail = r->base + ((r->tail - r->base +
652 sizeof(struct wil6210_mbox_ring_desc)) % r->size);
653 iowrite32(r->tail, wil->csr + HOST_MBOX +
654 offsetof(struct wil6210_mbox_ctl, rx.tail));
655
656
657 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
658 list_add_tail(&evt->list, &wil->pending_wmi_ev);
659 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
660 {
661 int q = queue_work(wil->wmi_wq,
662 &wil->wmi_event_worker);
663 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
664 }
665 }
666}
667
668int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
669 u16 reply_id, void *reply, u8 reply_size, int to_msec)
670{
671 int rc;
672 int remain;
673
674 mutex_lock(&wil->wmi_mutex);
675
676 rc = __wmi_send(wil, cmdid, buf, len);
677 if (rc)
678 goto out;
679
680 wil->reply_id = reply_id;
681 wil->reply_buf = reply;
682 wil->reply_size = reply_size;
683 remain = wait_for_completion_timeout(&wil->wmi_ready,
684 msecs_to_jiffies(to_msec));
685 if (0 == remain) {
686 wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
687 cmdid, reply_id, to_msec);
688 rc = -ETIME;
689 } else {
690 wil_dbg_wmi(wil,
691 "wmi_call(0x%04x->0x%04x) completed in %d msec\n",
692 cmdid, reply_id,
693 to_msec - jiffies_to_msecs(remain));
694 }
695 wil->reply_id = 0;
696 wil->reply_buf = NULL;
697 wil->reply_size = 0;
698 out:
699 mutex_unlock(&wil->wmi_mutex);
700
701 return rc;
702}
703
704int wmi_echo(struct wil6210_priv *wil)
705{
706 struct wmi_echo_cmd cmd = {
707 .value = cpu_to_le32(0x12345678),
708 };
709
710 return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
711 WMI_ECHO_RSP_EVENTID, NULL, 0, 20);
712}
713
714int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
715{
716 struct wmi_set_mac_address_cmd cmd;
717
718 memcpy(cmd.mac, addr, ETH_ALEN);
719
720 wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
721
722 return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
723}
724
725int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
726{
727 int rc;
728
729 struct wmi_pcp_start_cmd cmd = {
730 .bcon_interval = cpu_to_le16(bi),
731 .network_type = wmi_nettype,
732 .disable_sec_offload = 1,
733 .channel = chan - 1,
734 };
735 struct {
736 struct wil6210_mbox_hdr_wmi wmi;
737 struct wmi_pcp_started_event evt;
738 } __packed reply;
739
740 if (!wil->secure_pcp)
741 cmd.disable_sec = 1;
742
743
744
745
746
747 rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
748 WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000);
749 if (rc)
750 return rc;
751
752 if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
753 rc = -EINVAL;
754
755 return rc;
756}
757
758int wmi_pcp_stop(struct wil6210_priv *wil)
759{
760 return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
761 WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
762}
763
764int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
765{
766 struct wmi_set_ssid_cmd cmd = {
767 .ssid_len = cpu_to_le32(ssid_len),
768 };
769
770 if (ssid_len > sizeof(cmd.ssid))
771 return -EINVAL;
772
773 memcpy(cmd.ssid, ssid, ssid_len);
774
775 return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
776}
777
778int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
779{
780 int rc;
781 struct {
782 struct wil6210_mbox_hdr_wmi wmi;
783 struct wmi_set_ssid_cmd cmd;
784 } __packed reply;
785 int len;
786
787 rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
788 &reply, sizeof(reply), 20);
789 if (rc)
790 return rc;
791
792 len = le32_to_cpu(reply.cmd.ssid_len);
793 if (len > sizeof(reply.cmd.ssid))
794 return -EINVAL;
795
796 *ssid_len = len;
797 memcpy(ssid, reply.cmd.ssid, len);
798
799 return 0;
800}
801
802int wmi_set_channel(struct wil6210_priv *wil, int channel)
803{
804 struct wmi_set_pcp_channel_cmd cmd = {
805 .channel = channel - 1,
806 };
807
808 return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
809}
810
811int wmi_get_channel(struct wil6210_priv *wil, int *channel)
812{
813 int rc;
814 struct {
815 struct wil6210_mbox_hdr_wmi wmi;
816 struct wmi_set_pcp_channel_cmd cmd;
817 } __packed reply;
818
819 rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
820 WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
821 if (rc)
822 return rc;
823
824 if (reply.cmd.channel > 3)
825 return -EINVAL;
826
827 *channel = reply.cmd.channel + 1;
828
829 return 0;
830}
831
832int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
833{
834 struct wmi_p2p_cfg_cmd cmd = {
835 .discovery_mode = WMI_DISCOVERY_MODE_NON_OFFLOAD,
836 .channel = channel - 1,
837 };
838
839 return wmi_send(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd));
840}
841
842int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
843 const void *mac_addr)
844{
845 struct wmi_delete_cipher_key_cmd cmd = {
846 .key_index = key_index,
847 };
848
849 if (mac_addr)
850 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
851
852 return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
853}
854
855int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
856 const void *mac_addr, int key_len, const void *key)
857{
858 struct wmi_add_cipher_key_cmd cmd = {
859 .key_index = key_index,
860 .key_usage = WMI_KEY_USE_PAIRWISE,
861 .key_len = key_len,
862 };
863
864 if (!key || (key_len > sizeof(cmd.key)))
865 return -EINVAL;
866
867 memcpy(cmd.key, key, key_len);
868 if (mac_addr)
869 memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
870
871 return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
872}
873
874int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
875{
876 int rc;
877 u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
878 struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
879 if (!cmd)
880 return -ENOMEM;
881
882 cmd->mgmt_frm_type = type;
883
884 cmd->ie_len = cpu_to_le16(ie_len);
885 memcpy(cmd->ie_info, ie, ie_len);
886 rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);
887 kfree(cmd);
888
889 return rc;
890}
891
892int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
893{
894 struct wireless_dev *wdev = wil->wdev;
895 struct net_device *ndev = wil_to_ndev(wil);
896 struct wmi_cfg_rx_chain_cmd cmd = {
897 .action = WMI_RX_CHAIN_ADD,
898 .rx_sw_ring = {
899 .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
900 .ring_mem_base = cpu_to_le64(vring->pa),
901 .ring_size = cpu_to_le16(vring->size),
902 },
903 .mid = 0,
904 .decap_trans_type = WMI_DECAP_TYPE_802_3,
905 };
906 struct {
907 struct wil6210_mbox_hdr_wmi wmi;
908 struct wmi_cfg_rx_chain_done_event evt;
909 } __packed evt;
910 int rc;
911
912 if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
913 struct ieee80211_channel *ch = wdev->preset_chandef.chan;
914
915 cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
916 if (ch)
917 cmd.sniffer_cfg.channel = ch->hw_value - 1;
918 cmd.sniffer_cfg.phy_info_mode =
919 cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
920 cmd.sniffer_cfg.phy_support =
921 cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
922 ? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
923 }
924
925 rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
926 WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
927 if (rc)
928 return rc;
929
930 vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
931
932 wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
933 le32_to_cpu(evt.evt.status), vring->hwtail);
934
935 if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
936 rc = -EINVAL;
937
938 return rc;
939}
940
941int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
942{
943 int rc;
944 struct wmi_temp_sense_cmd cmd = {
945 .measure_marlon_m_en = cpu_to_le32(!!t_m),
946 .measure_marlon_r_en = cpu_to_le32(!!t_r),
947 };
948 struct {
949 struct wil6210_mbox_hdr_wmi wmi;
950 struct wmi_temp_sense_done_event evt;
951 } __packed reply;
952
953 rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd),
954 WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
955 if (rc)
956 return rc;
957
958 if (t_m)
959 *t_m = le32_to_cpu(reply.evt.marlon_m_t1000);
960 if (t_r)
961 *t_r = le32_to_cpu(reply.evt.marlon_r_t1000);
962
963 return 0;
964}
965
966void wmi_event_flush(struct wil6210_priv *wil)
967{
968 struct pending_wmi_event *evt, *t;
969
970 wil_dbg_wmi(wil, "%s()\n", __func__);
971
972 list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
973 list_del(&evt->list);
974 kfree(evt);
975 }
976}
977
978static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
979 void *d, int len)
980{
981 uint i;
982
983 for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
984 if (wmi_evt_handlers[i].eventid == id) {
985 wmi_evt_handlers[i].handler(wil, id, d, len);
986 return true;
987 }
988 }
989
990 return false;
991}
992
993static void wmi_event_handle(struct wil6210_priv *wil,
994 struct wil6210_mbox_hdr *hdr)
995{
996 u16 len = le16_to_cpu(hdr->len);
997
998 if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
999 (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
1000 struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
1001 void *evt_data = (void *)(&wmi[1]);
1002 u16 id = le16_to_cpu(wmi->id);
1003
1004 if (wil->reply_id && wil->reply_id == id) {
1005 if (wil->reply_buf) {
1006 memcpy(wil->reply_buf, wmi,
1007 min(len, wil->reply_size));
1008 } else {
1009 wmi_evt_call_handler(wil, id, evt_data,
1010 len - sizeof(*wmi));
1011 }
1012 wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
1013 complete(&wil->wmi_ready);
1014 return;
1015 }
1016
1017
1018 if (!wmi_evt_call_handler(wil, id, evt_data,
1019 len - sizeof(*wmi))) {
1020 wil_err(wil, "Unhandled event 0x%04x\n", id);
1021 }
1022 } else {
1023 wil_err(wil, "Unknown event type\n");
1024 print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
1025 hdr, sizeof(*hdr) + len, true);
1026 }
1027}
1028
1029
1030
1031
1032static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
1033{
1034 ulong flags;
1035 struct list_head *ret = NULL;
1036
1037 spin_lock_irqsave(&wil->wmi_ev_lock, flags);
1038
1039 if (!list_empty(&wil->pending_wmi_ev)) {
1040 ret = wil->pending_wmi_ev.next;
1041 list_del(ret);
1042 }
1043
1044 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
1045
1046 return ret;
1047}
1048
1049
1050
1051
1052void wmi_event_worker(struct work_struct *work)
1053{
1054 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
1055 wmi_event_worker);
1056 struct pending_wmi_event *evt;
1057 struct list_head *lh;
1058
1059 while ((lh = next_wmi_ev(wil)) != NULL) {
1060 evt = list_entry(lh, struct pending_wmi_event, list);
1061 wmi_event_handle(wil, &evt->event.hdr);
1062 kfree(evt);
1063 }
1064}
1065