diff options
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/wmi.c')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wmi.c | 136 |
1 files changed, 124 insertions, 12 deletions
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 063963ee422a..2ba56eef0c45 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -307,14 +307,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | |||
307 | u32 freq = ieee80211_channel_to_frequency(ch_no, | 307 | u32 freq = ieee80211_channel_to_frequency(ch_no, |
308 | IEEE80211_BAND_60GHZ); | 308 | IEEE80211_BAND_60GHZ); |
309 | struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); | 309 | struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); |
310 | /* TODO convert LE to CPU */ | 310 | s32 signal = data->info.sqi; |
311 | s32 signal = 0; /* TODO */ | ||
312 | __le16 fc = rx_mgmt_frame->frame_control; | 311 | __le16 fc = rx_mgmt_frame->frame_control; |
313 | u32 d_len = le32_to_cpu(data->info.len); | 312 | u32 d_len = le32_to_cpu(data->info.len); |
314 | u16 d_status = le16_to_cpu(data->info.status); | 313 | u16 d_status = le16_to_cpu(data->info.status); |
315 | 314 | ||
316 | wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n", | 315 | wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n", |
317 | data->info.channel, data->info.mcs, data->info.snr); | 316 | data->info.channel, data->info.mcs, data->info.snr, |
317 | data->info.sqi); | ||
318 | wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, | 318 | wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, |
319 | le16_to_cpu(fc)); | 319 | le16_to_cpu(fc)); |
320 | wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", | 320 | wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", |
@@ -384,6 +384,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) | |||
384 | evt->assoc_req_len, evt->assoc_resp_len); | 384 | evt->assoc_req_len, evt->assoc_resp_len); |
385 | return; | 385 | return; |
386 | } | 386 | } |
387 | if (evt->cid >= WIL6210_MAX_CID) { | ||
388 | wil_err(wil, "Connect CID invalid : %d\n", evt->cid); | ||
389 | return; | ||
390 | } | ||
391 | |||
387 | ch = evt->channel + 1; | 392 | ch = evt->channel + 1; |
388 | wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", | 393 | wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", |
389 | evt->bssid, ch, evt->cid); | 394 | evt->bssid, ch, evt->cid); |
@@ -439,7 +444,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) | |||
439 | 444 | ||
440 | /* FIXME FW can transmit only ucast frames to peer */ | 445 | /* FIXME FW can transmit only ucast frames to peer */ |
441 | /* FIXME real ring_id instead of hard coded 0 */ | 446 | /* FIXME real ring_id instead of hard coded 0 */ |
442 | memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); | 447 | memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN); |
448 | wil->sta[evt->cid].status = wil_sta_conn_pending; | ||
443 | 449 | ||
444 | wil->pending_connect_cid = evt->cid; | 450 | wil->pending_connect_cid = evt->cid; |
445 | queue_work(wil->wmi_wq_conn, &wil->connect_worker); | 451 | queue_work(wil->wmi_wq_conn, &wil->connect_worker); |
@@ -456,7 +462,9 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, | |||
456 | 462 | ||
457 | wil->sinfo_gen++; | 463 | wil->sinfo_gen++; |
458 | 464 | ||
465 | mutex_lock(&wil->mutex); | ||
459 | wil6210_disconnect(wil, evt->bssid); | 466 | wil6210_disconnect(wil, evt->bssid); |
467 | mutex_unlock(&wil->mutex); | ||
460 | } | 468 | } |
461 | 469 | ||
462 | static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) | 470 | static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) |
@@ -476,11 +484,11 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) | |||
476 | wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); | 484 | 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); | 485 | 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" | 486 | wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n" |
479 | "BF status 0x%08x SNR 0x%08x\n" | 487 | "BF status 0x%08x SNR 0x%08x SQI %d%%\n" |
480 | "Tx Tpt %d goodput %d Rx goodput %d\n" | 488 | "Tx Tpt %d goodput %d Rx goodput %d\n" |
481 | "Sectors(rx:tx) my %d:%d peer %d:%d\n", | 489 | "Sectors(rx:tx) my %d:%d peer %d:%d\n", |
482 | wil->stats.bf_mcs, wil->stats.tsf, evt->status, | 490 | wil->stats.bf_mcs, wil->stats.tsf, evt->status, |
483 | wil->stats.snr, le32_to_cpu(evt->tx_tpt), | 491 | wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt), |
484 | le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput), | 492 | le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput), |
485 | wil->stats.my_rx_sector, wil->stats.my_tx_sector, | 493 | wil->stats.my_rx_sector, wil->stats.my_tx_sector, |
486 | wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); | 494 | wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); |
@@ -499,10 +507,16 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, | |||
499 | int sz = eapol_len + ETH_HLEN; | 507 | int sz = eapol_len + ETH_HLEN; |
500 | struct sk_buff *skb; | 508 | struct sk_buff *skb; |
501 | struct ethhdr *eth; | 509 | struct ethhdr *eth; |
510 | int cid; | ||
511 | struct wil_net_stats *stats = NULL; | ||
502 | 512 | ||
503 | wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, | 513 | wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, |
504 | evt->src_mac); | 514 | evt->src_mac); |
505 | 515 | ||
516 | cid = wil_find_cid(wil, evt->src_mac); | ||
517 | if (cid >= 0) | ||
518 | stats = &wil->sta[cid].stats; | ||
519 | |||
506 | if (eapol_len > 196) { /* TODO: revisit size limit */ | 520 | if (eapol_len > 196) { /* TODO: revisit size limit */ |
507 | wil_err(wil, "EAPOL too large\n"); | 521 | wil_err(wil, "EAPOL too large\n"); |
508 | return; | 522 | return; |
@@ -513,6 +527,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, | |||
513 | wil_err(wil, "Failed to allocate skb\n"); | 527 | wil_err(wil, "Failed to allocate skb\n"); |
514 | return; | 528 | return; |
515 | } | 529 | } |
530 | |||
516 | eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); | 531 | eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); |
517 | memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); | 532 | memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); |
518 | memcpy(eth->h_source, evt->src_mac, ETH_ALEN); | 533 | memcpy(eth->h_source, evt->src_mac, ETH_ALEN); |
@@ -521,9 +536,15 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, | |||
521 | skb->protocol = eth_type_trans(skb, ndev); | 536 | skb->protocol = eth_type_trans(skb, ndev); |
522 | if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { | 537 | if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { |
523 | ndev->stats.rx_packets++; | 538 | ndev->stats.rx_packets++; |
524 | ndev->stats.rx_bytes += skb->len; | 539 | ndev->stats.rx_bytes += sz; |
540 | if (stats) { | ||
541 | stats->rx_packets++; | ||
542 | stats->rx_bytes += sz; | ||
543 | } | ||
525 | } else { | 544 | } else { |
526 | ndev->stats.rx_dropped++; | 545 | ndev->stats.rx_dropped++; |
546 | if (stats) | ||
547 | stats->rx_dropped++; | ||
527 | } | 548 | } |
528 | } | 549 | } |
529 | 550 | ||
@@ -531,9 +552,16 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) | |||
531 | { | 552 | { |
532 | struct net_device *ndev = wil_to_ndev(wil); | 553 | struct net_device *ndev = wil_to_ndev(wil); |
533 | struct wmi_data_port_open_event *evt = d; | 554 | struct wmi_data_port_open_event *evt = d; |
555 | u8 cid = evt->cid; | ||
534 | 556 | ||
535 | wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid); | 557 | wil_dbg_wmi(wil, "Link UP for CID %d\n", cid); |
536 | 558 | ||
559 | if (cid >= ARRAY_SIZE(wil->sta)) { | ||
560 | wil_err(wil, "Link UP for invalid CID %d\n", cid); | ||
561 | return; | ||
562 | } | ||
563 | |||
564 | wil->sta[cid].data_port_open = true; | ||
537 | netif_carrier_on(ndev); | 565 | netif_carrier_on(ndev); |
538 | } | 566 | } |
539 | 567 | ||
@@ -541,10 +569,17 @@ static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len) | |||
541 | { | 569 | { |
542 | struct net_device *ndev = wil_to_ndev(wil); | 570 | struct net_device *ndev = wil_to_ndev(wil); |
543 | struct wmi_wbe_link_down_event *evt = d; | 571 | struct wmi_wbe_link_down_event *evt = d; |
572 | u8 cid = evt->cid; | ||
544 | 573 | ||
545 | wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n", | 574 | wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n", |
546 | evt->cid, le32_to_cpu(evt->reason)); | 575 | cid, le32_to_cpu(evt->reason)); |
576 | |||
577 | if (cid >= ARRAY_SIZE(wil->sta)) { | ||
578 | wil_err(wil, "Link DOWN for invalid CID %d\n", cid); | ||
579 | return; | ||
580 | } | ||
547 | 581 | ||
582 | wil->sta[cid].data_port_open = false; | ||
548 | netif_carrier_off(ndev); | 583 | netif_carrier_off(ndev); |
549 | } | 584 | } |
550 | 585 | ||
@@ -552,10 +587,42 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, | |||
552 | int len) | 587 | int len) |
553 | { | 588 | { |
554 | struct wmi_vring_ba_status_event *evt = d; | 589 | struct wmi_vring_ba_status_event *evt = d; |
590 | struct wil_sta_info *sta; | ||
591 | uint i, cid; | ||
592 | |||
593 | /* TODO: use Rx BA status, not Tx one */ | ||
555 | 594 | ||
556 | wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", | 595 | wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", |
557 | evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize, | 596 | evt->ringid, |
558 | __le16_to_cpu(evt->ba_timeout)); | 597 | evt->status == WMI_BA_AGREED ? "OK" : "N/A", |
598 | evt->agg_wsize, __le16_to_cpu(evt->ba_timeout)); | ||
599 | |||
600 | if (evt->ringid >= WIL6210_MAX_TX_RINGS) { | ||
601 | wil_err(wil, "invalid ring id %d\n", evt->ringid); | ||
602 | return; | ||
603 | } | ||
604 | |||
605 | cid = wil->vring2cid_tid[evt->ringid][0]; | ||
606 | if (cid >= WIL6210_MAX_CID) { | ||
607 | wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid); | ||
608 | return; | ||
609 | } | ||
610 | |||
611 | sta = &wil->sta[cid]; | ||
612 | if (sta->status == wil_sta_unused) { | ||
613 | wil_err(wil, "CID %d unused\n", cid); | ||
614 | return; | ||
615 | } | ||
616 | |||
617 | wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr); | ||
618 | for (i = 0; i < WIL_STA_TID_NUM; i++) { | ||
619 | struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; | ||
620 | sta->tid_rx[i] = NULL; | ||
621 | wil_tid_ampdu_rx_free(wil, r); | ||
622 | if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) | ||
623 | sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, | ||
624 | evt->agg_wsize, 0); | ||
625 | } | ||
559 | } | 626 | } |
560 | 627 | ||
561 | static const struct { | 628 | static const struct { |
@@ -893,6 +960,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) | |||
893 | return rc; | 960 | return rc; |
894 | } | 961 | } |
895 | 962 | ||
963 | /** | ||
964 | * wmi_rxon - turn radio on/off | ||
965 | * @on: turn on if true, off otherwise | ||
966 | * | ||
967 | * Only switch radio. Channel should be set separately. | ||
968 | * No timeout for rxon - radio turned on forever unless some other call | ||
969 | * turns it off | ||
970 | */ | ||
971 | int wmi_rxon(struct wil6210_priv *wil, bool on) | ||
972 | { | ||
973 | int rc; | ||
974 | struct { | ||
975 | struct wil6210_mbox_hdr_wmi wmi; | ||
976 | struct wmi_listen_started_event evt; | ||
977 | } __packed reply; | ||
978 | |||
979 | wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off"); | ||
980 | |||
981 | if (on) { | ||
982 | rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0, | ||
983 | WMI_LISTEN_STARTED_EVENTID, | ||
984 | &reply, sizeof(reply), 100); | ||
985 | if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS)) | ||
986 | rc = -EINVAL; | ||
987 | } else { | ||
988 | rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0, | ||
989 | WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20); | ||
990 | } | ||
991 | |||
992 | return rc; | ||
993 | } | ||
994 | |||
896 | int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) | 995 | int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) |
897 | { | 996 | { |
898 | struct wireless_dev *wdev = wil->wdev; | 997 | struct wireless_dev *wdev = wil->wdev; |
@@ -906,6 +1005,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) | |||
906 | }, | 1005 | }, |
907 | .mid = 0, /* TODO - what is it? */ | 1006 | .mid = 0, /* TODO - what is it? */ |
908 | .decap_trans_type = WMI_DECAP_TYPE_802_3, | 1007 | .decap_trans_type = WMI_DECAP_TYPE_802_3, |
1008 | .reorder_type = WMI_RX_SW_REORDER, | ||
909 | }; | 1009 | }; |
910 | struct { | 1010 | struct { |
911 | struct wil6210_mbox_hdr_wmi wmi; | 1011 | struct wil6210_mbox_hdr_wmi wmi; |
@@ -973,6 +1073,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) | |||
973 | return 0; | 1073 | return 0; |
974 | } | 1074 | } |
975 | 1075 | ||
1076 | int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) | ||
1077 | { | ||
1078 | struct wmi_disconnect_sta_cmd cmd = { | ||
1079 | .disconnect_reason = cpu_to_le16(reason), | ||
1080 | }; | ||
1081 | memcpy(cmd.dst_mac, mac, ETH_ALEN); | ||
1082 | |||
1083 | wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason); | ||
1084 | |||
1085 | return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); | ||
1086 | } | ||
1087 | |||
976 | void wmi_event_flush(struct wil6210_priv *wil) | 1088 | void wmi_event_flush(struct wil6210_priv *wil) |
977 | { | 1089 | { |
978 | struct pending_wmi_event *evt, *t; | 1090 | struct pending_wmi_event *evt, *t; |