diff options
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/wmi.c')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/wmi.c | 154 |
1 files changed, 111 insertions, 43 deletions
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 0bb3b76b4b58..45b04e383f9a 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -14,9 +14,6 @@ | |||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/pci.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/etherdevice.h> | 17 | #include <linux/etherdevice.h> |
21 | #include <linux/if_arp.h> | 18 | #include <linux/if_arp.h> |
22 | 19 | ||
@@ -272,16 +269,18 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) | |||
272 | struct net_device *ndev = wil_to_ndev(wil); | 269 | struct net_device *ndev = wil_to_ndev(wil); |
273 | struct wireless_dev *wdev = wil->wdev; | 270 | struct wireless_dev *wdev = wil->wdev; |
274 | struct wmi_ready_event *evt = d; | 271 | struct wmi_ready_event *evt = d; |
275 | u32 ver = le32_to_cpu(evt->sw_version); | 272 | wil->fw_version = le32_to_cpu(evt->sw_version); |
273 | wil->n_mids = evt->numof_additional_mids; | ||
276 | 274 | ||
277 | wil_dbg_wmi(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); | 275 | wil_dbg_wmi(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, |
276 | evt->mac, wil->n_mids); | ||
278 | 277 | ||
279 | if (!is_valid_ether_addr(ndev->dev_addr)) { | 278 | if (!is_valid_ether_addr(ndev->dev_addr)) { |
280 | memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); | 279 | memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); |
281 | memcpy(ndev->perm_addr, evt->mac, ETH_ALEN); | 280 | memcpy(ndev->perm_addr, evt->mac, ETH_ALEN); |
282 | } | 281 | } |
283 | snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version), | 282 | snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version), |
284 | "%d", ver); | 283 | "%d", wil->fw_version); |
285 | } | 284 | } |
286 | 285 | ||
287 | static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, | 286 | static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, |
@@ -324,17 +323,9 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | |||
324 | 323 | ||
325 | if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { | 324 | if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { |
326 | struct cfg80211_bss *bss; | 325 | struct cfg80211_bss *bss; |
327 | u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp); | 326 | |
328 | u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info); | 327 | bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame, |
329 | u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int); | 328 | d_len, signal, GFP_KERNEL); |
330 | const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; | ||
331 | size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, | ||
332 | u.beacon.variable); | ||
333 | wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); | ||
334 | |||
335 | bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid, | ||
336 | tsf, cap, bi, ie_buf, ie_len, | ||
337 | signal, GFP_KERNEL); | ||
338 | if (bss) { | 329 | if (bss) { |
339 | wil_dbg_wmi(wil, "Added BSS %pM\n", | 330 | wil_dbg_wmi(wil, "Added BSS %pM\n", |
340 | rx_mgmt_frame->bssid); | 331 | rx_mgmt_frame->bssid); |
@@ -342,6 +333,9 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | |||
342 | } else { | 333 | } else { |
343 | wil_err(wil, "cfg80211_inform_bss() failed\n"); | 334 | wil_err(wil, "cfg80211_inform_bss() failed\n"); |
344 | } | 335 | } |
336 | } else { | ||
337 | cfg80211_rx_mgmt(wil->wdev, freq, signal, | ||
338 | (void *)rx_mgmt_frame, d_len, GFP_KERNEL); | ||
345 | } | 339 | } |
346 | } | 340 | } |
347 | 341 | ||
@@ -443,7 +437,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) | |||
443 | memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); | 437 | memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); |
444 | 438 | ||
445 | wil->pending_connect_cid = evt->cid; | 439 | wil->pending_connect_cid = evt->cid; |
446 | queue_work(wil->wmi_wq_conn, &wil->wmi_connect_worker); | 440 | queue_work(wil->wmi_wq_conn, &wil->connect_worker); |
447 | } | 441 | } |
448 | 442 | ||
449 | static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, | 443 | static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, |
@@ -528,6 +522,37 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, | |||
528 | } | 522 | } |
529 | } | 523 | } |
530 | 524 | ||
525 | static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) | ||
526 | { | ||
527 | struct net_device *ndev = wil_to_ndev(wil); | ||
528 | struct wmi_data_port_open_event *evt = d; | ||
529 | |||
530 | wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid); | ||
531 | |||
532 | netif_carrier_on(ndev); | ||
533 | } | ||
534 | |||
535 | static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len) | ||
536 | { | ||
537 | struct net_device *ndev = wil_to_ndev(wil); | ||
538 | struct wmi_wbe_link_down_event *evt = d; | ||
539 | |||
540 | wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n", | ||
541 | evt->cid, le32_to_cpu(evt->reason)); | ||
542 | |||
543 | netif_carrier_off(ndev); | ||
544 | } | ||
545 | |||
546 | static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, | ||
547 | int len) | ||
548 | { | ||
549 | struct wmi_vring_ba_status_event *evt = d; | ||
550 | |||
551 | wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", | ||
552 | evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize, | ||
553 | __le16_to_cpu(evt->ba_timeout)); | ||
554 | } | ||
555 | |||
531 | static const struct { | 556 | static const struct { |
532 | int eventid; | 557 | int eventid; |
533 | void (*handler)(struct wil6210_priv *wil, int eventid, | 558 | void (*handler)(struct wil6210_priv *wil, int eventid, |
@@ -541,6 +566,9 @@ static const struct { | |||
541 | {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect}, | 566 | {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect}, |
542 | {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify}, | 567 | {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify}, |
543 | {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx}, | 568 | {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx}, |
569 | {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup}, | ||
570 | {WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown}, | ||
571 | {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status}, | ||
544 | }; | 572 | }; |
545 | 573 | ||
546 | /* | 574 | /* |
@@ -559,6 +587,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) | |||
559 | void __iomem *src; | 587 | void __iomem *src; |
560 | ulong flags; | 588 | ulong flags; |
561 | 589 | ||
590 | if (!test_bit(wil_status_reset_done, &wil->status)) { | ||
591 | wil_err(wil, "Reset not completed\n"); | ||
592 | return; | ||
593 | } | ||
594 | |||
562 | for (;;) { | 595 | for (;;) { |
563 | u16 len; | 596 | u16 len; |
564 | 597 | ||
@@ -683,18 +716,39 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) | |||
683 | return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); | 716 | return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); |
684 | } | 717 | } |
685 | 718 | ||
686 | int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype) | 719 | int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) |
687 | { | 720 | { |
688 | struct wmi_bcon_ctrl_cmd cmd = { | 721 | int rc; |
722 | |||
723 | struct wmi_pcp_start_cmd cmd = { | ||
689 | .bcon_interval = cpu_to_le16(bi), | 724 | .bcon_interval = cpu_to_le16(bi), |
690 | .network_type = wmi_nettype, | 725 | .network_type = wmi_nettype, |
691 | .disable_sec_offload = 1, | 726 | .disable_sec_offload = 1, |
727 | .channel = chan, | ||
692 | }; | 728 | }; |
729 | struct { | ||
730 | struct wil6210_mbox_hdr_wmi wmi; | ||
731 | struct wmi_pcp_started_event evt; | ||
732 | } __packed reply; | ||
693 | 733 | ||
694 | if (!wil->secure_pcp) | 734 | if (!wil->secure_pcp) |
695 | cmd.disable_sec = 1; | 735 | cmd.disable_sec = 1; |
696 | 736 | ||
697 | return wmi_send(wil, WMI_BCON_CTRL_CMDID, &cmd, sizeof(cmd)); | 737 | rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd), |
738 | WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 100); | ||
739 | if (rc) | ||
740 | return rc; | ||
741 | |||
742 | if (reply.evt.status != WMI_FW_STATUS_SUCCESS) | ||
743 | rc = -EINVAL; | ||
744 | |||
745 | return rc; | ||
746 | } | ||
747 | |||
748 | int wmi_pcp_stop(struct wil6210_priv *wil) | ||
749 | { | ||
750 | return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0, | ||
751 | WMI_PCP_STOPPED_EVENTID, NULL, 0, 20); | ||
698 | } | 752 | } |
699 | 753 | ||
700 | int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid) | 754 | int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid) |
@@ -765,6 +819,16 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel) | |||
765 | return 0; | 819 | return 0; |
766 | } | 820 | } |
767 | 821 | ||
822 | int wmi_p2p_cfg(struct wil6210_priv *wil, int channel) | ||
823 | { | ||
824 | struct wmi_p2p_cfg_cmd cmd = { | ||
825 | .discovery_mode = WMI_DISCOVERY_MODE_NON_OFFLOAD, | ||
826 | .channel = channel - 1, | ||
827 | }; | ||
828 | |||
829 | return wmi_send(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd)); | ||
830 | } | ||
831 | |||
768 | int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb) | 832 | int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb) |
769 | { | 833 | { |
770 | struct wmi_eapol_tx_cmd *cmd; | 834 | struct wmi_eapol_tx_cmd *cmd; |
@@ -843,7 +907,7 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) | |||
843 | /* BUG: FW API define ieLen as u8. Will fix FW */ | 907 | /* BUG: FW API define ieLen as u8. Will fix FW */ |
844 | cmd->ie_len = cpu_to_le16(ie_len); | 908 | cmd->ie_len = cpu_to_le16(ie_len); |
845 | memcpy(cmd->ie_info, ie, ie_len); | 909 | memcpy(cmd->ie_info, ie, ie_len); |
846 | rc = wmi_send(wil, WMI_SET_APPIE_CMDID, &cmd, len); | 910 | rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len); |
847 | kfree(cmd); | 911 | kfree(cmd); |
848 | 912 | ||
849 | return rc; | 913 | return rc; |
@@ -898,6 +962,31 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) | |||
898 | return rc; | 962 | return rc; |
899 | } | 963 | } |
900 | 964 | ||
965 | int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) | ||
966 | { | ||
967 | int rc; | ||
968 | struct wmi_temp_sense_cmd cmd = { | ||
969 | .measure_marlon_m_en = cpu_to_le32(!!t_m), | ||
970 | .measure_marlon_r_en = cpu_to_le32(!!t_r), | ||
971 | }; | ||
972 | struct { | ||
973 | struct wil6210_mbox_hdr_wmi wmi; | ||
974 | struct wmi_temp_sense_done_event evt; | ||
975 | } __packed reply; | ||
976 | |||
977 | rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd), | ||
978 | WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100); | ||
979 | if (rc) | ||
980 | return rc; | ||
981 | |||
982 | if (t_m) | ||
983 | *t_m = le32_to_cpu(reply.evt.marlon_m_t1000); | ||
984 | if (t_r) | ||
985 | *t_r = le32_to_cpu(reply.evt.marlon_r_t1000); | ||
986 | |||
987 | return 0; | ||
988 | } | ||
989 | |||
901 | void wmi_event_flush(struct wil6210_priv *wil) | 990 | void wmi_event_flush(struct wil6210_priv *wil) |
902 | { | 991 | { |
903 | struct pending_wmi_event *evt, *t; | 992 | struct pending_wmi_event *evt, *t; |
@@ -997,24 +1086,3 @@ void wmi_event_worker(struct work_struct *work) | |||
997 | kfree(evt); | 1086 | kfree(evt); |
998 | } | 1087 | } |
999 | } | 1088 | } |
1000 | |||
1001 | void wmi_connect_worker(struct work_struct *work) | ||
1002 | { | ||
1003 | int rc; | ||
1004 | struct wil6210_priv *wil = container_of(work, struct wil6210_priv, | ||
1005 | wmi_connect_worker); | ||
1006 | |||
1007 | if (wil->pending_connect_cid < 0) { | ||
1008 | wil_err(wil, "No connection pending\n"); | ||
1009 | return; | ||
1010 | } | ||
1011 | |||
1012 | wil_dbg_wmi(wil, "Configure for connection CID %d\n", | ||
1013 | wil->pending_connect_cid); | ||
1014 | |||
1015 | rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, | ||
1016 | wil->pending_connect_cid, 0); | ||
1017 | wil->pending_connect_cid = -1; | ||
1018 | if (rc == 0) | ||
1019 | wil_link_on(wil); | ||
1020 | } | ||