diff options
Diffstat (limited to 'drivers/net/wireless/ath')
23 files changed, 2439 insertions, 924 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index 3d5f8be20eac..d755a5e7ed20 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig | |||
@@ -1,12 +1,29 @@ | |||
1 | config ATH6KL | 1 | config ATH6KL |
2 | tristate "Atheros ath6kl support" | 2 | tristate "Atheros mobile chipsets support" |
3 | |||
4 | config ATH6KL_SDIO | ||
5 | tristate "Atheros ath6kl SDIO support" | ||
6 | depends on ATH6KL | ||
3 | depends on MMC | 7 | depends on MMC |
4 | depends on CFG80211 | 8 | depends on CFG80211 |
5 | ---help--- | 9 | ---help--- |
6 | This module adds support for wireless adapters based on | 10 | This module adds support for wireless adapters based on |
7 | Atheros AR6003 chipset running over SDIO. If you choose to | 11 | Atheros AR6003 and AR6004 chipsets running over SDIO. If you |
8 | build it as a module, it will be called ath6kl. Pls note | 12 | choose to build it as a module, it will be called ath6kl_sdio. |
9 | that AR6002 and AR6001 are not supported by this driver. | 13 | Please note that AR6002 and AR6001 are not supported by this |
14 | driver. | ||
15 | |||
16 | config ATH6KL_USB | ||
17 | tristate "Atheros ath6kl USB support" | ||
18 | depends on ATH6KL | ||
19 | depends on USB | ||
20 | depends on CFG80211 | ||
21 | depends on EXPERIMENTAL | ||
22 | ---help--- | ||
23 | This module adds support for wireless adapters based on | ||
24 | Atheros AR6004 chipset running over USB. This is still under | ||
25 | implementation and it isn't functional. If you choose to | ||
26 | build it as a module, it will be called ath6kl_usb. | ||
10 | 27 | ||
11 | config ATH6KL_DEBUG | 28 | config ATH6KL_DEBUG |
12 | bool "Atheros ath6kl debugging" | 29 | bool "Atheros ath6kl debugging" |
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 707069303550..9ba42fa04962 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile | |||
@@ -21,17 +21,21 @@ | |||
21 | # Author(s): ="Atheros" | 21 | # Author(s): ="Atheros" |
22 | #------------------------------------------------------------------------------ | 22 | #------------------------------------------------------------------------------ |
23 | 23 | ||
24 | obj-$(CONFIG_ATH6KL) := ath6kl.o | 24 | obj-$(CONFIG_ATH6KL) += ath6kl_core.o |
25 | ath6kl-y += debug.o | 25 | ath6kl_core-y += debug.o |
26 | ath6kl-y += hif.o | 26 | ath6kl_core-y += hif.o |
27 | ath6kl-y += htc.o | 27 | ath6kl_core-y += htc.o |
28 | ath6kl-y += bmi.o | 28 | ath6kl_core-y += bmi.o |
29 | ath6kl-y += cfg80211.o | 29 | ath6kl_core-y += cfg80211.o |
30 | ath6kl-y += init.o | 30 | ath6kl_core-y += init.o |
31 | ath6kl-y += main.o | 31 | ath6kl_core-y += main.o |
32 | ath6kl-y += txrx.o | 32 | ath6kl_core-y += txrx.o |
33 | ath6kl-y += wmi.o | 33 | ath6kl_core-y += wmi.o |
34 | ath6kl-y += sdio.o | 34 | ath6kl_core-y += core.o |
35 | ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o | 35 | ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o |
36 | 36 | ||
37 | ccflags-y += -D__CHECK_ENDIAN__ | 37 | obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o |
38 | ath6kl_sdio-y += sdio.o | ||
39 | |||
40 | obj-$(CONFIG_ATH6KL_USB) += ath6kl_usb.o | ||
41 | ath6kl_usb-y += usb.o | ||
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c index bce3575c310a..aef00d5a1438 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.c +++ b/drivers/net/wireless/ath/ath6kl/bmi.c | |||
@@ -57,8 +57,14 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, | |||
57 | return ret; | 57 | return ret; |
58 | } | 58 | } |
59 | 59 | ||
60 | ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version, | 60 | if (ar->hif_type == ATH6KL_HIF_TYPE_USB) { |
61 | sizeof(targ_info->version)); | 61 | ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info, |
62 | sizeof(*targ_info)); | ||
63 | } else { | ||
64 | ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version, | ||
65 | sizeof(targ_info->version)); | ||
66 | } | ||
67 | |||
62 | if (ret) { | 68 | if (ret) { |
63 | ath6kl_err("Unable to recv target info: %d\n", ret); | 69 | ath6kl_err("Unable to recv target info: %d\n", ret); |
64 | return ret; | 70 | return ret; |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 6c59a217b1a1..d1922d8eb3bb 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -15,6 +15,8 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/moduleparam.h> | 17 | #include <linux/moduleparam.h> |
18 | #include <linux/inetdevice.h> | ||
19 | #include <linux/export.h> | ||
18 | 20 | ||
19 | #include "core.h" | 21 | #include "core.h" |
20 | #include "cfg80211.h" | 22 | #include "cfg80211.h" |
@@ -22,10 +24,6 @@ | |||
22 | #include "hif-ops.h" | 24 | #include "hif-ops.h" |
23 | #include "testmode.h" | 25 | #include "testmode.h" |
24 | 26 | ||
25 | static unsigned int ath6kl_p2p; | ||
26 | |||
27 | module_param(ath6kl_p2p, uint, 0644); | ||
28 | |||
29 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ | 27 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ |
30 | .bitrate = (_rate), \ | 28 | .bitrate = (_rate), \ |
31 | .flags = (_flags), \ | 29 | .flags = (_flags), \ |
@@ -196,7 +194,7 @@ static int ath6kl_set_auth_type(struct ath6kl_vif *vif, | |||
196 | break; | 194 | break; |
197 | 195 | ||
198 | default: | 196 | default: |
199 | ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type); | 197 | ath6kl_err("%s: 0x%x not supported\n", __func__, auth_type); |
200 | return -ENOTSUPP; | 198 | return -ENOTSUPP; |
201 | } | 199 | } |
202 | 200 | ||
@@ -461,13 +459,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
461 | } | 459 | } |
462 | } | 460 | } |
463 | 461 | ||
464 | if (sme->ie && (sme->ie_len > 0)) { | 462 | status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len); |
465 | status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len); | 463 | if (status) { |
466 | if (status) { | 464 | up(&ar->sem); |
467 | up(&ar->sem); | 465 | return status; |
468 | return status; | 466 | } |
469 | } | 467 | |
470 | } else | 468 | if (sme->ie == NULL || sme->ie_len == 0) |
471 | ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG; | 469 | ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG; |
472 | 470 | ||
473 | if (test_bit(CONNECTED, &vif->flags) && | 471 | if (test_bit(CONNECTED, &vif->flags) && |
@@ -523,8 +521,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
523 | (vif->prwise_crypto == WEP_CRYPT)) { | 521 | (vif->prwise_crypto == WEP_CRYPT)) { |
524 | struct ath6kl_key *key = NULL; | 522 | struct ath6kl_key *key = NULL; |
525 | 523 | ||
526 | if (sme->key_idx < WMI_MIN_KEY_INDEX || | 524 | if (sme->key_idx > WMI_MAX_KEY_INDEX) { |
527 | sme->key_idx > WMI_MAX_KEY_INDEX) { | ||
528 | ath6kl_err("key index %d out of bounds\n", | 525 | ath6kl_err("key index %d out of bounds\n", |
529 | sme->key_idx); | 526 | sme->key_idx); |
530 | up(&ar->sem); | 527 | up(&ar->sem); |
@@ -605,11 +602,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
605 | return 0; | 602 | return 0; |
606 | } | 603 | } |
607 | 604 | ||
608 | static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, | 605 | static struct cfg80211_bss * |
609 | enum network_type nw_type, | 606 | ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, |
610 | const u8 *bssid, | 607 | enum network_type nw_type, |
611 | struct ieee80211_channel *chan, | 608 | const u8 *bssid, |
612 | const u8 *beacon_ie, size_t beacon_ie_len) | 609 | struct ieee80211_channel *chan, |
610 | const u8 *beacon_ie, | ||
611 | size_t beacon_ie_len) | ||
613 | { | 612 | { |
614 | struct ath6kl *ar = vif->ar; | 613 | struct ath6kl *ar = vif->ar; |
615 | struct cfg80211_bss *bss; | 614 | struct cfg80211_bss *bss; |
@@ -638,7 +637,7 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, | |||
638 | */ | 637 | */ |
639 | ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL); | 638 | ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL); |
640 | if (ie == NULL) | 639 | if (ie == NULL) |
641 | return -ENOMEM; | 640 | return NULL; |
642 | ie[0] = WLAN_EID_SSID; | 641 | ie[0] = WLAN_EID_SSID; |
643 | ie[1] = vif->ssid_len; | 642 | ie[1] = vif->ssid_len; |
644 | memcpy(ie + 2, vif->ssid, vif->ssid_len); | 643 | memcpy(ie + 2, vif->ssid, vif->ssid_len); |
@@ -652,15 +651,9 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, | |||
652 | "cfg80211\n", bssid); | 651 | "cfg80211\n", bssid); |
653 | kfree(ie); | 652 | kfree(ie); |
654 | } else | 653 | } else |
655 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss " | 654 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n"); |
656 | "entry\n"); | ||
657 | |||
658 | if (bss == NULL) | ||
659 | return -ENOMEM; | ||
660 | 655 | ||
661 | cfg80211_put_bss(bss); | 656 | return bss; |
662 | |||
663 | return 0; | ||
664 | } | 657 | } |
665 | 658 | ||
666 | void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | 659 | void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, |
@@ -672,6 +665,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | |||
672 | { | 665 | { |
673 | struct ieee80211_channel *chan; | 666 | struct ieee80211_channel *chan; |
674 | struct ath6kl *ar = vif->ar; | 667 | struct ath6kl *ar = vif->ar; |
668 | struct cfg80211_bss *bss; | ||
675 | 669 | ||
676 | /* capinfo + listen interval */ | 670 | /* capinfo + listen interval */ |
677 | u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); | 671 | u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); |
@@ -712,8 +706,9 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | |||
712 | 706 | ||
713 | chan = ieee80211_get_channel(ar->wiphy, (int) channel); | 707 | chan = ieee80211_get_channel(ar->wiphy, (int) channel); |
714 | 708 | ||
715 | if (ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, assoc_info, | 709 | bss = ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, |
716 | beacon_ie_len) < 0) { | 710 | assoc_info, beacon_ie_len); |
711 | if (!bss) { | ||
717 | ath6kl_err("could not add cfg80211 bss entry\n"); | 712 | ath6kl_err("could not add cfg80211 bss entry\n"); |
718 | return; | 713 | return; |
719 | } | 714 | } |
@@ -722,6 +717,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | |||
722 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", | 717 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", |
723 | nw_type & ADHOC_CREATOR ? "creator" : "joiner"); | 718 | nw_type & ADHOC_CREATOR ? "creator" : "joiner"); |
724 | cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); | 719 | cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); |
720 | cfg80211_put_bss(bss); | ||
725 | return; | 721 | return; |
726 | } | 722 | } |
727 | 723 | ||
@@ -732,11 +728,11 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | |||
732 | assoc_req_ie, assoc_req_len, | 728 | assoc_req_ie, assoc_req_len, |
733 | assoc_resp_ie, assoc_resp_len, | 729 | assoc_resp_ie, assoc_resp_len, |
734 | WLAN_STATUS_SUCCESS, GFP_KERNEL); | 730 | WLAN_STATUS_SUCCESS, GFP_KERNEL); |
731 | cfg80211_put_bss(bss); | ||
735 | } else if (vif->sme_state == SME_CONNECTED) { | 732 | } else if (vif->sme_state == SME_CONNECTED) { |
736 | /* inform roam event to cfg80211 */ | 733 | /* inform roam event to cfg80211 */ |
737 | cfg80211_roamed(vif->ndev, chan, bssid, | 734 | cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len, |
738 | assoc_req_ie, assoc_req_len, | 735 | assoc_resp_ie, assoc_resp_len, GFP_KERNEL); |
739 | assoc_resp_ie, assoc_resp_len, GFP_KERNEL); | ||
740 | } | 736 | } |
741 | } | 737 | } |
742 | 738 | ||
@@ -984,6 +980,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
984 | struct ath6kl *ar = ath6kl_priv(ndev); | 980 | struct ath6kl *ar = ath6kl_priv(ndev); |
985 | struct ath6kl_vif *vif = netdev_priv(ndev); | 981 | struct ath6kl_vif *vif = netdev_priv(ndev); |
986 | struct ath6kl_key *key = NULL; | 982 | struct ath6kl_key *key = NULL; |
983 | int seq_len; | ||
987 | u8 key_usage; | 984 | u8 key_usage; |
988 | u8 key_type; | 985 | u8 key_type; |
989 | 986 | ||
@@ -997,7 +994,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
997 | params->key); | 994 | params->key); |
998 | } | 995 | } |
999 | 996 | ||
1000 | if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { | 997 | if (key_index > WMI_MAX_KEY_INDEX) { |
1001 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 998 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
1002 | "%s: key index %d out of bounds\n", __func__, | 999 | "%s: key index %d out of bounds\n", __func__, |
1003 | key_index); | 1000 | key_index); |
@@ -1012,23 +1009,21 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
1012 | else | 1009 | else |
1013 | key_usage = GROUP_USAGE; | 1010 | key_usage = GROUP_USAGE; |
1014 | 1011 | ||
1015 | if (params) { | 1012 | seq_len = params->seq_len; |
1016 | int seq_len = params->seq_len; | 1013 | if (params->cipher == WLAN_CIPHER_SUITE_SMS4 && |
1017 | if (params->cipher == WLAN_CIPHER_SUITE_SMS4 && | 1014 | seq_len > ATH6KL_KEY_SEQ_LEN) { |
1018 | seq_len > ATH6KL_KEY_SEQ_LEN) { | 1015 | /* Only first half of the WPI PN is configured */ |
1019 | /* Only first half of the WPI PN is configured */ | 1016 | seq_len = ATH6KL_KEY_SEQ_LEN; |
1020 | seq_len = ATH6KL_KEY_SEQ_LEN; | ||
1021 | } | ||
1022 | if (params->key_len > WLAN_MAX_KEY_LEN || | ||
1023 | seq_len > sizeof(key->seq)) | ||
1024 | return -EINVAL; | ||
1025 | |||
1026 | key->key_len = params->key_len; | ||
1027 | memcpy(key->key, params->key, key->key_len); | ||
1028 | key->seq_len = seq_len; | ||
1029 | memcpy(key->seq, params->seq, key->seq_len); | ||
1030 | key->cipher = params->cipher; | ||
1031 | } | 1017 | } |
1018 | if (params->key_len > WLAN_MAX_KEY_LEN || | ||
1019 | seq_len > sizeof(key->seq)) | ||
1020 | return -EINVAL; | ||
1021 | |||
1022 | key->key_len = params->key_len; | ||
1023 | memcpy(key->key, params->key, key->key_len); | ||
1024 | key->seq_len = seq_len; | ||
1025 | memcpy(key->seq, params->seq, key->seq_len); | ||
1026 | key->cipher = params->cipher; | ||
1032 | 1027 | ||
1033 | switch (key->cipher) { | 1028 | switch (key->cipher) { |
1034 | case WLAN_CIPHER_SUITE_WEP40: | 1029 | case WLAN_CIPHER_SUITE_WEP40: |
@@ -1115,7 +1110,7 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, | |||
1115 | if (!ath6kl_cfg80211_ready(vif)) | 1110 | if (!ath6kl_cfg80211_ready(vif)) |
1116 | return -EIO; | 1111 | return -EIO; |
1117 | 1112 | ||
1118 | if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { | 1113 | if (key_index > WMI_MAX_KEY_INDEX) { |
1119 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 1114 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
1120 | "%s: key index %d out of bounds\n", __func__, | 1115 | "%s: key index %d out of bounds\n", __func__, |
1121 | key_index); | 1116 | key_index); |
@@ -1148,7 +1143,7 @@ static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, | |||
1148 | if (!ath6kl_cfg80211_ready(vif)) | 1143 | if (!ath6kl_cfg80211_ready(vif)) |
1149 | return -EIO; | 1144 | return -EIO; |
1150 | 1145 | ||
1151 | if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { | 1146 | if (key_index > WMI_MAX_KEY_INDEX) { |
1152 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 1147 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
1153 | "%s: key index %d out of bounds\n", __func__, | 1148 | "%s: key index %d out of bounds\n", __func__, |
1154 | key_index); | 1149 | key_index); |
@@ -1184,7 +1179,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy, | |||
1184 | if (!ath6kl_cfg80211_ready(vif)) | 1179 | if (!ath6kl_cfg80211_ready(vif)) |
1185 | return -EIO; | 1180 | return -EIO; |
1186 | 1181 | ||
1187 | if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { | 1182 | if (key_index > WMI_MAX_KEY_INDEX) { |
1188 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 1183 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
1189 | "%s: key index %d out of bounds\n", | 1184 | "%s: key index %d out of bounds\n", |
1190 | __func__, key_index); | 1185 | __func__, key_index); |
@@ -1403,7 +1398,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, | |||
1403 | 1398 | ||
1404 | ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); | 1399 | ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); |
1405 | 1400 | ||
1406 | ath6kl_deinit_if_data(vif); | 1401 | ath6kl_cfg80211_vif_cleanup(vif); |
1407 | 1402 | ||
1408 | return 0; | 1403 | return 0; |
1409 | } | 1404 | } |
@@ -1728,29 +1723,14 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) | |||
1728 | return 0; | 1723 | return 0; |
1729 | } | 1724 | } |
1730 | 1725 | ||
1731 | static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | 1726 | static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif, |
1727 | struct cfg80211_wowlan *wow, u32 *filter) | ||
1732 | { | 1728 | { |
1733 | struct ath6kl_vif *vif; | 1729 | int ret, pos; |
1734 | int ret, pos, left; | ||
1735 | u32 filter = 0; | ||
1736 | u16 i; | ||
1737 | u8 mask[WOW_MASK_SIZE]; | 1730 | u8 mask[WOW_MASK_SIZE]; |
1731 | u16 i; | ||
1738 | 1732 | ||
1739 | vif = ath6kl_vif_first(ar); | 1733 | /* Configure the patterns that we received from the user. */ |
1740 | if (!vif) | ||
1741 | return -EIO; | ||
1742 | |||
1743 | if (!ath6kl_cfg80211_ready(vif)) | ||
1744 | return -EIO; | ||
1745 | |||
1746 | if (!test_bit(CONNECTED, &vif->flags)) | ||
1747 | return -EINVAL; | ||
1748 | |||
1749 | /* Clear existing WOW patterns */ | ||
1750 | for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) | ||
1751 | ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, | ||
1752 | WOW_LIST_ID, i); | ||
1753 | /* Configure new WOW patterns */ | ||
1754 | for (i = 0; i < wow->n_patterns; i++) { | 1734 | for (i = 0; i < wow->n_patterns; i++) { |
1755 | 1735 | ||
1756 | /* | 1736 | /* |
@@ -1773,29 +1753,221 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
1773 | * matched from the first byte of received pkt in the firmware. | 1753 | * matched from the first byte of received pkt in the firmware. |
1774 | */ | 1754 | */ |
1775 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | 1755 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, |
1776 | vif->fw_vif_idx, WOW_LIST_ID, | 1756 | vif->fw_vif_idx, WOW_LIST_ID, |
1777 | wow->patterns[i].pattern_len, | 1757 | wow->patterns[i].pattern_len, |
1778 | 0 /* pattern offset */, | 1758 | 0 /* pattern offset */, |
1779 | wow->patterns[i].pattern, mask); | 1759 | wow->patterns[i].pattern, mask); |
1780 | if (ret) | 1760 | if (ret) |
1781 | return ret; | 1761 | return ret; |
1782 | } | 1762 | } |
1783 | 1763 | ||
1784 | if (wow->disconnect) | 1764 | if (wow->disconnect) |
1785 | filter |= WOW_FILTER_OPTION_NWK_DISASSOC; | 1765 | *filter |= WOW_FILTER_OPTION_NWK_DISASSOC; |
1786 | 1766 | ||
1787 | if (wow->magic_pkt) | 1767 | if (wow->magic_pkt) |
1788 | filter |= WOW_FILTER_OPTION_MAGIC_PACKET; | 1768 | *filter |= WOW_FILTER_OPTION_MAGIC_PACKET; |
1789 | 1769 | ||
1790 | if (wow->gtk_rekey_failure) | 1770 | if (wow->gtk_rekey_failure) |
1791 | filter |= WOW_FILTER_OPTION_GTK_ERROR; | 1771 | *filter |= WOW_FILTER_OPTION_GTK_ERROR; |
1792 | 1772 | ||
1793 | if (wow->eap_identity_req) | 1773 | if (wow->eap_identity_req) |
1794 | filter |= WOW_FILTER_OPTION_EAP_REQ; | 1774 | *filter |= WOW_FILTER_OPTION_EAP_REQ; |
1795 | 1775 | ||
1796 | if (wow->four_way_handshake) | 1776 | if (wow->four_way_handshake) |
1797 | filter |= WOW_FILTER_OPTION_8021X_4WAYHS; | 1777 | *filter |= WOW_FILTER_OPTION_8021X_4WAYHS; |
1778 | |||
1779 | return 0; | ||
1780 | } | ||
1781 | |||
1782 | static int ath6kl_wow_ap(struct ath6kl *ar, struct ath6kl_vif *vif) | ||
1783 | { | ||
1784 | static const u8 unicst_pattern[] = { 0x00, 0x00, 0x00, | ||
1785 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1786 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1787 | 0x00, 0x08 }; | ||
1788 | static const u8 unicst_mask[] = { 0x01, 0x00, 0x00, | ||
1789 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1790 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1791 | 0x00, 0x7f }; | ||
1792 | u8 unicst_offset = 0; | ||
1793 | static const u8 arp_pattern[] = { 0x08, 0x06 }; | ||
1794 | static const u8 arp_mask[] = { 0xff, 0xff }; | ||
1795 | u8 arp_offset = 20; | ||
1796 | static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 }; | ||
1797 | static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 }; | ||
1798 | u8 discvr_offset = 38; | ||
1799 | static const u8 dhcp_pattern[] = { 0xff, 0xff, 0xff, 0xff, | ||
1800 | 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1801 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, | ||
1802 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1803 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1804 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 /* port 67 */ }; | ||
1805 | static const u8 dhcp_mask[] = { 0xff, 0xff, 0xff, 0xff, | ||
1806 | 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1807 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, | ||
1808 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1809 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
1810 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xff /* port 67 */ }; | ||
1811 | u8 dhcp_offset = 0; | ||
1812 | int ret; | ||
1813 | |||
1814 | /* Setup unicast IP, EAPOL-like and ARP pkt pattern */ | ||
1815 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1816 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1817 | sizeof(unicst_pattern), unicst_offset, | ||
1818 | unicst_pattern, unicst_mask); | ||
1819 | if (ret) { | ||
1820 | ath6kl_err("failed to add WOW unicast IP pattern\n"); | ||
1821 | return ret; | ||
1822 | } | ||
1823 | |||
1824 | /* Setup all ARP pkt pattern */ | ||
1825 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1826 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1827 | sizeof(arp_pattern), arp_offset, | ||
1828 | arp_pattern, arp_mask); | ||
1829 | if (ret) { | ||
1830 | ath6kl_err("failed to add WOW ARP pattern\n"); | ||
1831 | return ret; | ||
1832 | } | ||
1798 | 1833 | ||
1834 | /* | ||
1835 | * Setup multicast pattern for mDNS 224.0.0.251, | ||
1836 | * SSDP 239.255.255.250 and LLMNR 224.0.0.252 | ||
1837 | */ | ||
1838 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1839 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1840 | sizeof(discvr_pattern), discvr_offset, | ||
1841 | discvr_pattern, discvr_mask); | ||
1842 | if (ret) { | ||
1843 | ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n"); | ||
1844 | return ret; | ||
1845 | } | ||
1846 | |||
1847 | /* Setup all DHCP broadcast pkt pattern */ | ||
1848 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1849 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1850 | sizeof(dhcp_pattern), dhcp_offset, | ||
1851 | dhcp_pattern, dhcp_mask); | ||
1852 | if (ret) { | ||
1853 | ath6kl_err("failed to add WOW DHCP broadcast pattern\n"); | ||
1854 | return ret; | ||
1855 | } | ||
1856 | |||
1857 | return 0; | ||
1858 | } | ||
1859 | |||
1860 | static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) | ||
1861 | { | ||
1862 | struct net_device *ndev = vif->ndev; | ||
1863 | static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 }; | ||
1864 | static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 }; | ||
1865 | u8 discvr_offset = 38; | ||
1866 | u8 mac_mask[ETH_ALEN]; | ||
1867 | int ret; | ||
1868 | |||
1869 | /* Setup unicast pkt pattern */ | ||
1870 | memset(mac_mask, 0xff, ETH_ALEN); | ||
1871 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1872 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1873 | ETH_ALEN, 0, ndev->dev_addr, | ||
1874 | mac_mask); | ||
1875 | if (ret) { | ||
1876 | ath6kl_err("failed to add WOW unicast pattern\n"); | ||
1877 | return ret; | ||
1878 | } | ||
1879 | |||
1880 | /* | ||
1881 | * Setup multicast pattern for mDNS 224.0.0.251, | ||
1882 | * SSDP 239.255.255.250 and LLMNR 224.0.0.252 | ||
1883 | */ | ||
1884 | if ((ndev->flags & IFF_ALLMULTI) || | ||
1885 | (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) { | ||
1886 | ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, | ||
1887 | vif->fw_vif_idx, WOW_LIST_ID, | ||
1888 | sizeof(discvr_pattern), discvr_offset, | ||
1889 | discvr_pattern, discvr_mask); | ||
1890 | if (ret) { | ||
1891 | ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR " | ||
1892 | "pattern\n"); | ||
1893 | return ret; | ||
1894 | } | ||
1895 | } | ||
1896 | |||
1897 | return 0; | ||
1898 | } | ||
1899 | |||
1900 | static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | ||
1901 | { | ||
1902 | struct in_device *in_dev; | ||
1903 | struct in_ifaddr *ifa; | ||
1904 | struct ath6kl_vif *vif; | ||
1905 | int ret, left; | ||
1906 | u32 filter = 0; | ||
1907 | u16 i; | ||
1908 | u8 index = 0; | ||
1909 | __be32 ips[MAX_IP_ADDRS]; | ||
1910 | |||
1911 | vif = ath6kl_vif_first(ar); | ||
1912 | if (!vif) | ||
1913 | return -EIO; | ||
1914 | |||
1915 | if (!ath6kl_cfg80211_ready(vif)) | ||
1916 | return -EIO; | ||
1917 | |||
1918 | if (!test_bit(CONNECTED, &vif->flags)) | ||
1919 | return -ENOTCONN; | ||
1920 | |||
1921 | if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) | ||
1922 | return -EINVAL; | ||
1923 | |||
1924 | /* Clear existing WOW patterns */ | ||
1925 | for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) | ||
1926 | ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, | ||
1927 | WOW_LIST_ID, i); | ||
1928 | |||
1929 | /* | ||
1930 | * Skip the default WOW pattern configuration | ||
1931 | * if the driver receives any WOW patterns from | ||
1932 | * the user. | ||
1933 | */ | ||
1934 | if (wow) | ||
1935 | ret = ath6kl_wow_usr(ar, vif, wow, &filter); | ||
1936 | else if (vif->nw_type == AP_NETWORK) | ||
1937 | ret = ath6kl_wow_ap(ar, vif); | ||
1938 | else | ||
1939 | ret = ath6kl_wow_sta(ar, vif); | ||
1940 | |||
1941 | if (ret) | ||
1942 | return ret; | ||
1943 | |||
1944 | /* Setup own IP addr for ARP agent. */ | ||
1945 | in_dev = __in_dev_get_rtnl(vif->ndev); | ||
1946 | if (!in_dev) | ||
1947 | goto skip_arp; | ||
1948 | |||
1949 | ifa = in_dev->ifa_list; | ||
1950 | memset(&ips, 0, sizeof(ips)); | ||
1951 | |||
1952 | /* Configure IP addr only if IP address count < MAX_IP_ADDRS */ | ||
1953 | while (index < MAX_IP_ADDRS && ifa) { | ||
1954 | ips[index] = ifa->ifa_local; | ||
1955 | ifa = ifa->ifa_next; | ||
1956 | index++; | ||
1957 | } | ||
1958 | |||
1959 | if (ifa) { | ||
1960 | ath6kl_err("total IP addr count is exceeding fw limit\n"); | ||
1961 | return -EINVAL; | ||
1962 | } | ||
1963 | |||
1964 | ret = ath6kl_wmi_set_ip_cmd(ar->wmi, vif->fw_vif_idx, ips[0], ips[1]); | ||
1965 | if (ret) { | ||
1966 | ath6kl_err("fail to setup ip for arp agent\n"); | ||
1967 | return ret; | ||
1968 | } | ||
1969 | |||
1970 | skip_arp: | ||
1799 | ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, | 1971 | ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, |
1800 | ATH6KL_WOW_MODE_ENABLE, | 1972 | ATH6KL_WOW_MODE_ENABLE, |
1801 | filter, | 1973 | filter, |
@@ -1803,11 +1975,26 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
1803 | if (ret) | 1975 | if (ret) |
1804 | return ret; | 1976 | return ret; |
1805 | 1977 | ||
1978 | clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); | ||
1979 | |||
1806 | ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, | 1980 | ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, |
1807 | ATH6KL_HOST_MODE_ASLEEP); | 1981 | ATH6KL_HOST_MODE_ASLEEP); |
1808 | if (ret) | 1982 | if (ret) |
1809 | return ret; | 1983 | return ret; |
1810 | 1984 | ||
1985 | left = wait_event_interruptible_timeout(ar->event_wq, | ||
1986 | test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags), | ||
1987 | WMI_TIMEOUT); | ||
1988 | if (left == 0) { | ||
1989 | ath6kl_warn("timeout, didn't get host sleep cmd " | ||
1990 | "processed event\n"); | ||
1991 | ret = -ETIMEDOUT; | ||
1992 | } else if (left < 0) { | ||
1993 | ath6kl_warn("error while waiting for host sleep cmd " | ||
1994 | "processed event %d\n", left); | ||
1995 | ret = left; | ||
1996 | } | ||
1997 | |||
1811 | if (ar->tx_pending[ar->ctrl_ep]) { | 1998 | if (ar->tx_pending[ar->ctrl_ep]) { |
1812 | left = wait_event_interruptible_timeout(ar->event_wq, | 1999 | left = wait_event_interruptible_timeout(ar->event_wq, |
1813 | ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT); | 2000 | ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT); |
@@ -1911,6 +2098,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, | |||
1911 | 2098 | ||
1912 | return 0; | 2099 | return 0; |
1913 | } | 2100 | } |
2101 | EXPORT_SYMBOL(ath6kl_cfg80211_suspend); | ||
1914 | 2102 | ||
1915 | int ath6kl_cfg80211_resume(struct ath6kl *ar) | 2103 | int ath6kl_cfg80211_resume(struct ath6kl *ar) |
1916 | { | 2104 | { |
@@ -1962,6 +2150,7 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) | |||
1962 | 2150 | ||
1963 | return 0; | 2151 | return 0; |
1964 | } | 2152 | } |
2153 | EXPORT_SYMBOL(ath6kl_cfg80211_resume); | ||
1965 | 2154 | ||
1966 | #ifdef CONFIG_PM | 2155 | #ifdef CONFIG_PM |
1967 | 2156 | ||
@@ -2014,7 +2203,18 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, | |||
2014 | struct ieee80211_channel *chan, | 2203 | struct ieee80211_channel *chan, |
2015 | enum nl80211_channel_type channel_type) | 2204 | enum nl80211_channel_type channel_type) |
2016 | { | 2205 | { |
2017 | struct ath6kl_vif *vif = netdev_priv(dev); | 2206 | struct ath6kl_vif *vif; |
2207 | |||
2208 | /* | ||
2209 | * 'dev' could be NULL if a channel change is required for the hardware | ||
2210 | * device itself, instead of a particular VIF. | ||
2211 | * | ||
2212 | * FIXME: To be handled properly when monitor mode is supported. | ||
2213 | */ | ||
2214 | if (!dev) | ||
2215 | return -EBUSY; | ||
2216 | |||
2217 | vif = netdev_priv(dev); | ||
2018 | 2218 | ||
2019 | if (!ath6kl_cfg80211_ready(vif)) | 2219 | if (!ath6kl_cfg80211_ready(vif)) |
2020 | return -EIO; | 2220 | return -EIO; |
@@ -2214,6 +2414,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
2214 | p.dot11_auth_mode = vif->dot11_auth_mode; | 2414 | p.dot11_auth_mode = vif->dot11_auth_mode; |
2215 | p.ch = cpu_to_le16(vif->next_chan); | 2415 | p.ch = cpu_to_le16(vif->next_chan); |
2216 | 2416 | ||
2417 | /* Enable uAPSD support by default */ | ||
2418 | res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true); | ||
2419 | if (res < 0) | ||
2420 | return res; | ||
2421 | |||
2217 | if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) { | 2422 | if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) { |
2218 | p.nw_subtype = SUBTYPE_P2PGO; | 2423 | p.nw_subtype = SUBTYPE_P2PGO; |
2219 | } else { | 2424 | } else { |
@@ -2259,6 +2464,19 @@ static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) | |||
2259 | return 0; | 2464 | return 0; |
2260 | } | 2465 | } |
2261 | 2466 | ||
2467 | static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
2468 | |||
2469 | static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, | ||
2470 | u8 *mac) | ||
2471 | { | ||
2472 | struct ath6kl *ar = ath6kl_priv(dev); | ||
2473 | struct ath6kl_vif *vif = netdev_priv(dev); | ||
2474 | const u8 *addr = mac ? mac : bcast_addr; | ||
2475 | |||
2476 | return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH, | ||
2477 | addr, WLAN_REASON_PREV_AUTH_NOT_VALID); | ||
2478 | } | ||
2479 | |||
2262 | static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, | 2480 | static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, |
2263 | u8 *mac, struct station_parameters *params) | 2481 | u8 *mac, struct station_parameters *params) |
2264 | { | 2482 | { |
@@ -2518,6 +2736,12 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { | |||
2518 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | 2736 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | |
2519 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | 2737 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
2520 | }, | 2738 | }, |
2739 | [NL80211_IFTYPE_AP] = { | ||
2740 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
2741 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
2742 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
2743 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
2744 | }, | ||
2521 | [NL80211_IFTYPE_P2P_CLIENT] = { | 2745 | [NL80211_IFTYPE_P2P_CLIENT] = { |
2522 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | 2746 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | |
2523 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | 2747 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), |
@@ -2562,6 +2786,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { | |||
2562 | .add_beacon = ath6kl_add_beacon, | 2786 | .add_beacon = ath6kl_add_beacon, |
2563 | .set_beacon = ath6kl_set_beacon, | 2787 | .set_beacon = ath6kl_set_beacon, |
2564 | .del_beacon = ath6kl_del_beacon, | 2788 | .del_beacon = ath6kl_del_beacon, |
2789 | .del_station = ath6kl_del_station, | ||
2565 | .change_station = ath6kl_change_station, | 2790 | .change_station = ath6kl_change_station, |
2566 | .remain_on_channel = ath6kl_remain_on_channel, | 2791 | .remain_on_channel = ath6kl_remain_on_channel, |
2567 | .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, | 2792 | .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, |
@@ -2629,122 +2854,9 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) | |||
2629 | ath6kl_cfg80211_stop(vif); | 2854 | ath6kl_cfg80211_stop(vif); |
2630 | } | 2855 | } |
2631 | 2856 | ||
2632 | struct ath6kl *ath6kl_core_alloc(struct device *dev) | 2857 | static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) |
2633 | { | ||
2634 | struct ath6kl *ar; | ||
2635 | struct wiphy *wiphy; | ||
2636 | u8 ctr; | ||
2637 | |||
2638 | /* create a new wiphy for use with cfg80211 */ | ||
2639 | wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl)); | ||
2640 | |||
2641 | if (!wiphy) { | ||
2642 | ath6kl_err("couldn't allocate wiphy device\n"); | ||
2643 | return NULL; | ||
2644 | } | ||
2645 | |||
2646 | ar = wiphy_priv(wiphy); | ||
2647 | ar->p2p = !!ath6kl_p2p; | ||
2648 | ar->wiphy = wiphy; | ||
2649 | ar->dev = dev; | ||
2650 | |||
2651 | ar->vif_max = 1; | ||
2652 | |||
2653 | ar->max_norm_iface = 1; | ||
2654 | |||
2655 | spin_lock_init(&ar->lock); | ||
2656 | spin_lock_init(&ar->mcastpsq_lock); | ||
2657 | spin_lock_init(&ar->list_lock); | ||
2658 | |||
2659 | init_waitqueue_head(&ar->event_wq); | ||
2660 | sema_init(&ar->sem, 1); | ||
2661 | |||
2662 | INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); | ||
2663 | INIT_LIST_HEAD(&ar->vif_list); | ||
2664 | |||
2665 | clear_bit(WMI_ENABLED, &ar->flag); | ||
2666 | clear_bit(SKIP_SCAN, &ar->flag); | ||
2667 | clear_bit(DESTROY_IN_PROGRESS, &ar->flag); | ||
2668 | |||
2669 | ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL; | ||
2670 | ar->listen_intvl_b = 0; | ||
2671 | ar->tx_pwr = 0; | ||
2672 | |||
2673 | ar->intra_bss = 1; | ||
2674 | ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; | ||
2675 | |||
2676 | ar->state = ATH6KL_STATE_OFF; | ||
2677 | |||
2678 | memset((u8 *)ar->sta_list, 0, | ||
2679 | AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); | ||
2680 | |||
2681 | /* Init the PS queues */ | ||
2682 | for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { | ||
2683 | spin_lock_init(&ar->sta_list[ctr].psq_lock); | ||
2684 | skb_queue_head_init(&ar->sta_list[ctr].psq); | ||
2685 | } | ||
2686 | |||
2687 | skb_queue_head_init(&ar->mcastpsq); | ||
2688 | |||
2689 | memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3); | ||
2690 | |||
2691 | return ar; | ||
2692 | } | ||
2693 | |||
2694 | int ath6kl_register_ieee80211_hw(struct ath6kl *ar) | ||
2695 | { | ||
2696 | struct wiphy *wiphy = ar->wiphy; | ||
2697 | int ret; | ||
2698 | |||
2699 | wiphy->mgmt_stypes = ath6kl_mgmt_stypes; | ||
2700 | |||
2701 | wiphy->max_remain_on_channel_duration = 5000; | ||
2702 | |||
2703 | /* set device pointer for wiphy */ | ||
2704 | set_wiphy_dev(wiphy, ar->dev); | ||
2705 | |||
2706 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
2707 | BIT(NL80211_IFTYPE_ADHOC) | | ||
2708 | BIT(NL80211_IFTYPE_AP); | ||
2709 | if (ar->p2p) { | ||
2710 | wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | | ||
2711 | BIT(NL80211_IFTYPE_P2P_CLIENT); | ||
2712 | } | ||
2713 | |||
2714 | /* max num of ssids that can be probed during scanning */ | ||
2715 | wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; | ||
2716 | wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ | ||
2717 | wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; | ||
2718 | wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; | ||
2719 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
2720 | |||
2721 | wiphy->cipher_suites = cipher_suites; | ||
2722 | wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
2723 | |||
2724 | wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | ||
2725 | WIPHY_WOWLAN_DISCONNECT | | ||
2726 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | | ||
2727 | WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | | ||
2728 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | | ||
2729 | WIPHY_WOWLAN_4WAY_HANDSHAKE; | ||
2730 | wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST; | ||
2731 | wiphy->wowlan.pattern_min_len = 1; | ||
2732 | wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; | ||
2733 | |||
2734 | wiphy->max_sched_scan_ssids = 10; | ||
2735 | |||
2736 | ret = wiphy_register(wiphy); | ||
2737 | if (ret < 0) { | ||
2738 | ath6kl_err("couldn't register wiphy device\n"); | ||
2739 | return ret; | ||
2740 | } | ||
2741 | |||
2742 | return 0; | ||
2743 | } | ||
2744 | |||
2745 | static int ath6kl_init_if_data(struct ath6kl_vif *vif) | ||
2746 | { | 2858 | { |
2747 | vif->aggr_cntxt = aggr_init(vif->ndev); | 2859 | vif->aggr_cntxt = aggr_init(vif); |
2748 | if (!vif->aggr_cntxt) { | 2860 | if (!vif->aggr_cntxt) { |
2749 | ath6kl_err("failed to initialize aggr\n"); | 2861 | ath6kl_err("failed to initialize aggr\n"); |
2750 | return -ENOMEM; | 2862 | return -ENOMEM; |
@@ -2758,12 +2870,15 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif) | |||
2758 | set_bit(WMM_ENABLED, &vif->flags); | 2870 | set_bit(WMM_ENABLED, &vif->flags); |
2759 | spin_lock_init(&vif->if_lock); | 2871 | spin_lock_init(&vif->if_lock); |
2760 | 2872 | ||
2873 | INIT_LIST_HEAD(&vif->mc_filter); | ||
2874 | |||
2761 | return 0; | 2875 | return 0; |
2762 | } | 2876 | } |
2763 | 2877 | ||
2764 | void ath6kl_deinit_if_data(struct ath6kl_vif *vif) | 2878 | void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) |
2765 | { | 2879 | { |
2766 | struct ath6kl *ar = vif->ar; | 2880 | struct ath6kl *ar = vif->ar; |
2881 | struct ath6kl_mc_filter *mc_filter, *tmp; | ||
2767 | 2882 | ||
2768 | aggr_module_destroy(vif->aggr_cntxt); | 2883 | aggr_module_destroy(vif->aggr_cntxt); |
2769 | 2884 | ||
@@ -2772,6 +2887,11 @@ void ath6kl_deinit_if_data(struct ath6kl_vif *vif) | |||
2772 | if (vif->nw_type == ADHOC_NETWORK) | 2887 | if (vif->nw_type == ADHOC_NETWORK) |
2773 | ar->ibss_if_active = false; | 2888 | ar->ibss_if_active = false; |
2774 | 2889 | ||
2890 | list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { | ||
2891 | list_del(&mc_filter->list); | ||
2892 | kfree(mc_filter); | ||
2893 | } | ||
2894 | |||
2775 | unregister_netdevice(vif->ndev); | 2895 | unregister_netdevice(vif->ndev); |
2776 | 2896 | ||
2777 | ar->num_vif--; | 2897 | ar->num_vif--; |
@@ -2808,8 +2928,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, | |||
2808 | 2928 | ||
2809 | ath6kl_init_control_info(vif); | 2929 | ath6kl_init_control_info(vif); |
2810 | 2930 | ||
2811 | /* TODO: Pass interface specific pointer instead of ar */ | 2931 | if (ath6kl_cfg80211_vif_init(vif)) |
2812 | if (ath6kl_init_if_data(vif)) | ||
2813 | goto err; | 2932 | goto err; |
2814 | 2933 | ||
2815 | if (register_netdevice(ndev)) | 2934 | if (register_netdevice(ndev)) |
@@ -2836,8 +2955,89 @@ err: | |||
2836 | return NULL; | 2955 | return NULL; |
2837 | } | 2956 | } |
2838 | 2957 | ||
2839 | void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar) | 2958 | int ath6kl_cfg80211_init(struct ath6kl *ar) |
2959 | { | ||
2960 | struct wiphy *wiphy = ar->wiphy; | ||
2961 | int ret; | ||
2962 | |||
2963 | wiphy->mgmt_stypes = ath6kl_mgmt_stypes; | ||
2964 | |||
2965 | wiphy->max_remain_on_channel_duration = 5000; | ||
2966 | |||
2967 | /* set device pointer for wiphy */ | ||
2968 | set_wiphy_dev(wiphy, ar->dev); | ||
2969 | |||
2970 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
2971 | BIT(NL80211_IFTYPE_ADHOC) | | ||
2972 | BIT(NL80211_IFTYPE_AP); | ||
2973 | if (ar->p2p) { | ||
2974 | wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | | ||
2975 | BIT(NL80211_IFTYPE_P2P_CLIENT); | ||
2976 | } | ||
2977 | |||
2978 | /* max num of ssids that can be probed during scanning */ | ||
2979 | wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; | ||
2980 | wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ | ||
2981 | wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; | ||
2982 | wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; | ||
2983 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
2984 | |||
2985 | wiphy->cipher_suites = cipher_suites; | ||
2986 | wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
2987 | |||
2988 | wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | ||
2989 | WIPHY_WOWLAN_DISCONNECT | | ||
2990 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | | ||
2991 | WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | | ||
2992 | WIPHY_WOWLAN_EAP_IDENTITY_REQ | | ||
2993 | WIPHY_WOWLAN_4WAY_HANDSHAKE; | ||
2994 | wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST; | ||
2995 | wiphy->wowlan.pattern_min_len = 1; | ||
2996 | wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; | ||
2997 | |||
2998 | wiphy->max_sched_scan_ssids = 10; | ||
2999 | |||
3000 | ret = wiphy_register(wiphy); | ||
3001 | if (ret < 0) { | ||
3002 | ath6kl_err("couldn't register wiphy device\n"); | ||
3003 | return ret; | ||
3004 | } | ||
3005 | |||
3006 | return 0; | ||
3007 | } | ||
3008 | |||
3009 | void ath6kl_cfg80211_cleanup(struct ath6kl *ar) | ||
2840 | { | 3010 | { |
2841 | wiphy_unregister(ar->wiphy); | 3011 | wiphy_unregister(ar->wiphy); |
3012 | } | ||
3013 | |||
3014 | struct ath6kl *ath6kl_cfg80211_create(void) | ||
3015 | { | ||
3016 | struct ath6kl *ar; | ||
3017 | struct wiphy *wiphy; | ||
3018 | |||
3019 | /* create a new wiphy for use with cfg80211 */ | ||
3020 | wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl)); | ||
3021 | |||
3022 | if (!wiphy) { | ||
3023 | ath6kl_err("couldn't allocate wiphy device\n"); | ||
3024 | return NULL; | ||
3025 | } | ||
3026 | |||
3027 | ar = wiphy_priv(wiphy); | ||
3028 | ar->wiphy = wiphy; | ||
3029 | |||
3030 | return ar; | ||
3031 | } | ||
3032 | |||
3033 | /* Note: ar variable must not be accessed after calling this! */ | ||
3034 | void ath6kl_cfg80211_destroy(struct ath6kl *ar) | ||
3035 | { | ||
3036 | int i; | ||
3037 | |||
3038 | for (i = 0; i < AP_MAX_NUM_STA; i++) | ||
3039 | kfree(ar->sta_list[i].aggr_conn); | ||
3040 | |||
2842 | wiphy_free(ar->wiphy); | 3041 | wiphy_free(ar->wiphy); |
2843 | } | 3042 | } |
3043 | |||
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 81f20a572315..3c693b7c0efd 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h | |||
@@ -27,10 +27,6 @@ enum ath6kl_cfg_suspend_mode { | |||
27 | struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, | 27 | struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, |
28 | enum nl80211_iftype type, | 28 | enum nl80211_iftype type, |
29 | u8 fw_vif_idx, u8 nw_type); | 29 | u8 fw_vif_idx, u8 nw_type); |
30 | int ath6kl_register_ieee80211_hw(struct ath6kl *ar); | ||
31 | struct ath6kl *ath6kl_core_alloc(struct device *dev); | ||
32 | void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar); | ||
33 | |||
34 | void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted); | 30 | void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted); |
35 | 31 | ||
36 | void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | 32 | void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, |
@@ -53,7 +49,15 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, | |||
53 | 49 | ||
54 | int ath6kl_cfg80211_resume(struct ath6kl *ar); | 50 | int ath6kl_cfg80211_resume(struct ath6kl *ar); |
55 | 51 | ||
52 | void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif); | ||
53 | |||
56 | void ath6kl_cfg80211_stop(struct ath6kl_vif *vif); | 54 | void ath6kl_cfg80211_stop(struct ath6kl_vif *vif); |
57 | void ath6kl_cfg80211_stop_all(struct ath6kl *ar); | 55 | void ath6kl_cfg80211_stop_all(struct ath6kl *ar); |
58 | 56 | ||
57 | int ath6kl_cfg80211_init(struct ath6kl *ar); | ||
58 | void ath6kl_cfg80211_cleanup(struct ath6kl *ar); | ||
59 | |||
60 | struct ath6kl *ath6kl_cfg80211_create(void); | ||
61 | void ath6kl_cfg80211_destroy(struct ath6kl *ar); | ||
62 | |||
59 | #endif /* ATH6KL_CFG80211_H */ | 63 | #endif /* ATH6KL_CFG80211_H */ |
diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h index bfd6597763da..f89f1e180da3 100644 --- a/drivers/net/wireless/ath/ath6kl/common.h +++ b/drivers/net/wireless/ath/ath6kl/common.h | |||
@@ -79,8 +79,5 @@ struct ath6kl; | |||
79 | enum htc_credit_dist_reason; | 79 | enum htc_credit_dist_reason; |
80 | struct ath6kl_htc_credit_info; | 80 | struct ath6kl_htc_credit_info; |
81 | 81 | ||
82 | struct ath6kl *ath6kl_core_alloc(struct device *sdev); | ||
83 | int ath6kl_core_init(struct ath6kl *ar); | ||
84 | void ath6kl_core_cleanup(struct ath6kl *ar); | ||
85 | struct sk_buff *ath6kl_buf_alloc(int size); | 82 | struct sk_buff *ath6kl_buf_alloc(int size); |
86 | #endif /* COMMON_H */ | 83 | #endif /* COMMON_H */ |
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c new file mode 100644 index 000000000000..722ca59b88ce --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/core.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "core.h" | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/export.h> | ||
22 | |||
23 | #include "debug.h" | ||
24 | #include "hif-ops.h" | ||
25 | #include "cfg80211.h" | ||
26 | |||
27 | unsigned int debug_mask; | ||
28 | static unsigned int suspend_mode; | ||
29 | static unsigned int uart_debug; | ||
30 | static unsigned int ath6kl_p2p; | ||
31 | static unsigned int testmode; | ||
32 | |||
33 | module_param(debug_mask, uint, 0644); | ||
34 | module_param(suspend_mode, uint, 0644); | ||
35 | module_param(uart_debug, uint, 0644); | ||
36 | module_param(ath6kl_p2p, uint, 0644); | ||
37 | module_param(testmode, uint, 0644); | ||
38 | |||
39 | int ath6kl_core_init(struct ath6kl *ar) | ||
40 | { | ||
41 | struct ath6kl_bmi_target_info targ_info; | ||
42 | struct net_device *ndev; | ||
43 | int ret = 0, i; | ||
44 | |||
45 | ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); | ||
46 | if (!ar->ath6kl_wq) | ||
47 | return -ENOMEM; | ||
48 | |||
49 | ret = ath6kl_bmi_init(ar); | ||
50 | if (ret) | ||
51 | goto err_wq; | ||
52 | |||
53 | /* | ||
54 | * Turn on power to get hardware (target) version and leave power | ||
55 | * on delibrately as we will boot the hardware anyway within few | ||
56 | * seconds. | ||
57 | */ | ||
58 | ret = ath6kl_hif_power_on(ar); | ||
59 | if (ret) | ||
60 | goto err_bmi_cleanup; | ||
61 | |||
62 | ret = ath6kl_bmi_get_target_info(ar, &targ_info); | ||
63 | if (ret) | ||
64 | goto err_power_off; | ||
65 | |||
66 | ar->version.target_ver = le32_to_cpu(targ_info.version); | ||
67 | ar->target_type = le32_to_cpu(targ_info.type); | ||
68 | ar->wiphy->hw_version = le32_to_cpu(targ_info.version); | ||
69 | |||
70 | ret = ath6kl_init_hw_params(ar); | ||
71 | if (ret) | ||
72 | goto err_power_off; | ||
73 | |||
74 | ar->htc_target = ath6kl_htc_create(ar); | ||
75 | |||
76 | if (!ar->htc_target) { | ||
77 | ret = -ENOMEM; | ||
78 | goto err_power_off; | ||
79 | } | ||
80 | |||
81 | ar->testmode = testmode; | ||
82 | |||
83 | ret = ath6kl_init_fetch_firmwares(ar); | ||
84 | if (ret) | ||
85 | goto err_htc_cleanup; | ||
86 | |||
87 | /* FIXME: we should free all firmwares in the error cases below */ | ||
88 | |||
89 | /* Indicate that WMI is enabled (although not ready yet) */ | ||
90 | set_bit(WMI_ENABLED, &ar->flag); | ||
91 | ar->wmi = ath6kl_wmi_init(ar); | ||
92 | if (!ar->wmi) { | ||
93 | ath6kl_err("failed to initialize wmi\n"); | ||
94 | ret = -EIO; | ||
95 | goto err_htc_cleanup; | ||
96 | } | ||
97 | |||
98 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); | ||
99 | |||
100 | ret = ath6kl_cfg80211_init(ar); | ||
101 | if (ret) | ||
102 | goto err_node_cleanup; | ||
103 | |||
104 | ret = ath6kl_debug_init(ar); | ||
105 | if (ret) { | ||
106 | wiphy_unregister(ar->wiphy); | ||
107 | goto err_node_cleanup; | ||
108 | } | ||
109 | |||
110 | for (i = 0; i < ar->vif_max; i++) | ||
111 | ar->avail_idx_map |= BIT(i); | ||
112 | |||
113 | rtnl_lock(); | ||
114 | |||
115 | /* Add an initial station interface */ | ||
116 | ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, | ||
117 | INFRA_NETWORK); | ||
118 | |||
119 | rtnl_unlock(); | ||
120 | |||
121 | if (!ndev) { | ||
122 | ath6kl_err("Failed to instantiate a network device\n"); | ||
123 | ret = -ENOMEM; | ||
124 | wiphy_unregister(ar->wiphy); | ||
125 | goto err_debug_init; | ||
126 | } | ||
127 | |||
128 | |||
129 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", | ||
130 | __func__, ndev->name, ndev, ar); | ||
131 | |||
132 | /* setup access class priority mappings */ | ||
133 | ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ | ||
134 | ar->ac_stream_pri_map[WMM_AC_BE] = 1; | ||
135 | ar->ac_stream_pri_map[WMM_AC_VI] = 2; | ||
136 | ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ | ||
137 | |||
138 | /* give our connected endpoints some buffers */ | ||
139 | ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); | ||
140 | ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); | ||
141 | |||
142 | /* allocate some buffers that handle larger AMSDU frames */ | ||
143 | ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); | ||
144 | |||
145 | ath6kl_cookie_init(ar); | ||
146 | |||
147 | ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | | ||
148 | ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; | ||
149 | |||
150 | if (suspend_mode && | ||
151 | suspend_mode >= WLAN_POWER_STATE_CUT_PWR && | ||
152 | suspend_mode <= WLAN_POWER_STATE_WOW) | ||
153 | ar->suspend_mode = suspend_mode; | ||
154 | else | ||
155 | ar->suspend_mode = 0; | ||
156 | |||
157 | if (uart_debug) | ||
158 | ar->conf_flags |= ATH6KL_CONF_UART_DEBUG; | ||
159 | |||
160 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | | ||
161 | WIPHY_FLAG_HAVE_AP_SME | | ||
162 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | | ||
163 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | ||
164 | |||
165 | if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) | ||
166 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | ||
167 | |||
168 | ar->wiphy->probe_resp_offload = | ||
169 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | ||
170 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | | ||
171 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | | ||
172 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; | ||
173 | |||
174 | set_bit(FIRST_BOOT, &ar->flag); | ||
175 | |||
176 | ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; | ||
177 | |||
178 | ret = ath6kl_init_hw_start(ar); | ||
179 | if (ret) { | ||
180 | ath6kl_err("Failed to start hardware: %d\n", ret); | ||
181 | goto err_rxbuf_cleanup; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Set mac address which is received in ready event | ||
186 | * FIXME: Move to ath6kl_interface_add() | ||
187 | */ | ||
188 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); | ||
189 | |||
190 | return ret; | ||
191 | |||
192 | err_rxbuf_cleanup: | ||
193 | ath6kl_htc_flush_rx_buf(ar->htc_target); | ||
194 | ath6kl_cleanup_amsdu_rxbufs(ar); | ||
195 | rtnl_lock(); | ||
196 | ath6kl_cfg80211_vif_cleanup(netdev_priv(ndev)); | ||
197 | rtnl_unlock(); | ||
198 | wiphy_unregister(ar->wiphy); | ||
199 | err_debug_init: | ||
200 | ath6kl_debug_cleanup(ar); | ||
201 | err_node_cleanup: | ||
202 | ath6kl_wmi_shutdown(ar->wmi); | ||
203 | clear_bit(WMI_ENABLED, &ar->flag); | ||
204 | ar->wmi = NULL; | ||
205 | err_htc_cleanup: | ||
206 | ath6kl_htc_cleanup(ar->htc_target); | ||
207 | err_power_off: | ||
208 | ath6kl_hif_power_off(ar); | ||
209 | err_bmi_cleanup: | ||
210 | ath6kl_bmi_cleanup(ar); | ||
211 | err_wq: | ||
212 | destroy_workqueue(ar->ath6kl_wq); | ||
213 | |||
214 | return ret; | ||
215 | } | ||
216 | EXPORT_SYMBOL(ath6kl_core_init); | ||
217 | |||
218 | struct ath6kl *ath6kl_core_create(struct device *dev) | ||
219 | { | ||
220 | struct ath6kl *ar; | ||
221 | u8 ctr; | ||
222 | |||
223 | ar = ath6kl_cfg80211_create(); | ||
224 | if (!ar) | ||
225 | return NULL; | ||
226 | |||
227 | ar->p2p = !!ath6kl_p2p; | ||
228 | ar->dev = dev; | ||
229 | |||
230 | ar->vif_max = 1; | ||
231 | |||
232 | ar->max_norm_iface = 1; | ||
233 | |||
234 | spin_lock_init(&ar->lock); | ||
235 | spin_lock_init(&ar->mcastpsq_lock); | ||
236 | spin_lock_init(&ar->list_lock); | ||
237 | |||
238 | init_waitqueue_head(&ar->event_wq); | ||
239 | sema_init(&ar->sem, 1); | ||
240 | |||
241 | INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); | ||
242 | INIT_LIST_HEAD(&ar->vif_list); | ||
243 | |||
244 | clear_bit(WMI_ENABLED, &ar->flag); | ||
245 | clear_bit(SKIP_SCAN, &ar->flag); | ||
246 | clear_bit(DESTROY_IN_PROGRESS, &ar->flag); | ||
247 | |||
248 | ar->listen_intvl_b = A_DEFAULT_LISTEN_INTERVAL; | ||
249 | ar->tx_pwr = 0; | ||
250 | |||
251 | ar->intra_bss = 1; | ||
252 | ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; | ||
253 | |||
254 | ar->state = ATH6KL_STATE_OFF; | ||
255 | |||
256 | memset((u8 *)ar->sta_list, 0, | ||
257 | AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); | ||
258 | |||
259 | /* Init the PS queues */ | ||
260 | for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { | ||
261 | spin_lock_init(&ar->sta_list[ctr].psq_lock); | ||
262 | skb_queue_head_init(&ar->sta_list[ctr].psq); | ||
263 | skb_queue_head_init(&ar->sta_list[ctr].apsdq); | ||
264 | ar->sta_list[ctr].aggr_conn = | ||
265 | kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); | ||
266 | if (!ar->sta_list[ctr].aggr_conn) { | ||
267 | ath6kl_err("Failed to allocate memory for sta aggregation information\n"); | ||
268 | ath6kl_core_destroy(ar); | ||
269 | return NULL; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | skb_queue_head_init(&ar->mcastpsq); | ||
274 | |||
275 | memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3); | ||
276 | |||
277 | return ar; | ||
278 | } | ||
279 | EXPORT_SYMBOL(ath6kl_core_create); | ||
280 | |||
281 | void ath6kl_core_cleanup(struct ath6kl *ar) | ||
282 | { | ||
283 | ath6kl_hif_power_off(ar); | ||
284 | |||
285 | destroy_workqueue(ar->ath6kl_wq); | ||
286 | |||
287 | if (ar->htc_target) | ||
288 | ath6kl_htc_cleanup(ar->htc_target); | ||
289 | |||
290 | ath6kl_cookie_cleanup(ar); | ||
291 | |||
292 | ath6kl_cleanup_amsdu_rxbufs(ar); | ||
293 | |||
294 | ath6kl_bmi_cleanup(ar); | ||
295 | |||
296 | ath6kl_debug_cleanup(ar); | ||
297 | |||
298 | kfree(ar->fw_board); | ||
299 | kfree(ar->fw_otp); | ||
300 | kfree(ar->fw); | ||
301 | kfree(ar->fw_patch); | ||
302 | kfree(ar->fw_testscript); | ||
303 | |||
304 | ath6kl_cfg80211_cleanup(ar); | ||
305 | } | ||
306 | EXPORT_SYMBOL(ath6kl_core_cleanup); | ||
307 | |||
308 | void ath6kl_core_destroy(struct ath6kl *ar) | ||
309 | { | ||
310 | ath6kl_cfg80211_destroy(ar); | ||
311 | } | ||
312 | EXPORT_SYMBOL(ath6kl_core_destroy); | ||
313 | |||
314 | MODULE_AUTHOR("Qualcomm Atheros"); | ||
315 | MODULE_DESCRIPTION("Core module for AR600x SDIO and USB devices."); | ||
316 | MODULE_LICENSE("Dual BSD/GPL"); | ||
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index c863a28f2e0c..c4d66e066dc9 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -44,6 +44,10 @@ | |||
44 | #define ATH6KL_MAX_ENDPOINTS 4 | 44 | #define ATH6KL_MAX_ENDPOINTS 4 |
45 | #define MAX_NODE_NUM 15 | 45 | #define MAX_NODE_NUM 15 |
46 | 46 | ||
47 | #define ATH6KL_APSD_ALL_FRAME 0xFFFF | ||
48 | #define ATH6KL_APSD_NUM_OF_AC 0x4 | ||
49 | #define ATH6KL_APSD_FRAME_MASK 0xF | ||
50 | |||
47 | /* Extra bytes for htc header alignment */ | 51 | /* Extra bytes for htc header alignment */ |
48 | #define ATH6KL_HTC_ALIGN_BYTES 3 | 52 | #define ATH6KL_HTC_ALIGN_BYTES 3 |
49 | 53 | ||
@@ -55,7 +59,7 @@ | |||
55 | #define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC) | 59 | #define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC) |
56 | 60 | ||
57 | #define DISCON_TIMER_INTVAL 10000 /* in msec */ | 61 | #define DISCON_TIMER_INTVAL 10000 /* in msec */ |
58 | #define A_DEFAULT_LISTEN_INTERVAL 100 | 62 | #define A_DEFAULT_LISTEN_INTERVAL 1 /* beacon intervals */ |
59 | #define A_MAX_WOW_LISTEN_INTERVAL 1000 | 63 | #define A_MAX_WOW_LISTEN_INTERVAL 1000 |
60 | 64 | ||
61 | /* includes also the null byte */ | 65 | /* includes also the null byte */ |
@@ -97,45 +101,49 @@ struct ath6kl_fw_ie { | |||
97 | u8 data[0]; | 101 | u8 data[0]; |
98 | }; | 102 | }; |
99 | 103 | ||
104 | #define ATH6KL_FW_API2_FILE "fw-2.bin" | ||
105 | #define ATH6KL_FW_API3_FILE "fw-3.bin" | ||
106 | |||
100 | /* AR6003 1.0 definitions */ | 107 | /* AR6003 1.0 definitions */ |
101 | #define AR6003_HW_1_0_VERSION 0x300002ba | 108 | #define AR6003_HW_1_0_VERSION 0x300002ba |
102 | 109 | ||
103 | /* AR6003 2.0 definitions */ | 110 | /* AR6003 2.0 definitions */ |
104 | #define AR6003_HW_2_0_VERSION 0x30000384 | 111 | #define AR6003_HW_2_0_VERSION 0x30000384 |
105 | #define AR6003_HW_2_0_PATCH_DOWNLOAD_ADDRESS 0x57e910 | 112 | #define AR6003_HW_2_0_PATCH_DOWNLOAD_ADDRESS 0x57e910 |
106 | #define AR6003_HW_2_0_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77" | 113 | #define AR6003_HW_2_0_FW_DIR "ath6k/AR6003/hw2.0" |
107 | #define AR6003_HW_2_0_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77" | 114 | #define AR6003_HW_2_0_OTP_FILE "otp.bin.z77" |
108 | #define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin" | 115 | #define AR6003_HW_2_0_FIRMWARE_FILE "athwlan.bin.z77" |
109 | #define AR6003_HW_2_0_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin" | 116 | #define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "athtcmd_ram.bin" |
110 | #define AR6003_HW_2_0_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin" | 117 | #define AR6003_HW_2_0_PATCH_FILE "data.patch.bin" |
111 | #define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" | 118 | #define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" |
112 | #define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \ | 119 | #define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \ |
113 | "ath6k/AR6003/hw2.0/bdata.SD31.bin" | 120 | "ath6k/AR6003/hw2.0/bdata.SD31.bin" |
114 | 121 | ||
115 | /* AR6003 3.0 definitions */ | 122 | /* AR6003 3.0 definitions */ |
116 | #define AR6003_HW_2_1_1_VERSION 0x30000582 | 123 | #define AR6003_HW_2_1_1_VERSION 0x30000582 |
117 | #define AR6003_HW_2_1_1_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin" | 124 | #define AR6003_HW_2_1_1_FW_DIR "ath6k/AR6003/hw2.1.1" |
118 | #define AR6003_HW_2_1_1_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin" | 125 | #define AR6003_HW_2_1_1_OTP_FILE "otp.bin" |
119 | #define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE \ | 126 | #define AR6003_HW_2_1_1_FIRMWARE_FILE "athwlan.bin" |
120 | "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin" | 127 | #define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE "athtcmd_ram.bin" |
121 | #define AR6003_HW_2_1_1_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin" | 128 | #define AR6003_HW_2_1_1_UTF_FIRMWARE_FILE "utf.bin" |
122 | #define AR6003_HW_2_1_1_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin" | 129 | #define AR6003_HW_2_1_1_TESTSCRIPT_FILE "nullTestFlow.bin" |
130 | #define AR6003_HW_2_1_1_PATCH_FILE "data.patch.bin" | ||
123 | #define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" | 131 | #define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" |
124 | #define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \ | 132 | #define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \ |
125 | "ath6k/AR6003/hw2.1.1/bdata.SD31.bin" | 133 | "ath6k/AR6003/hw2.1.1/bdata.SD31.bin" |
126 | 134 | ||
127 | /* AR6004 1.0 definitions */ | 135 | /* AR6004 1.0 definitions */ |
128 | #define AR6004_HW_1_0_VERSION 0x30000623 | 136 | #define AR6004_HW_1_0_VERSION 0x30000623 |
129 | #define AR6004_HW_1_0_FIRMWARE_2_FILE "ath6k/AR6004/hw1.0/fw-2.bin" | 137 | #define AR6004_HW_1_0_FW_DIR "ath6k/AR6004/hw1.0" |
130 | #define AR6004_HW_1_0_FIRMWARE_FILE "ath6k/AR6004/hw1.0/fw.ram.bin" | 138 | #define AR6004_HW_1_0_FIRMWARE_FILE "fw.ram.bin" |
131 | #define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin" | 139 | #define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin" |
132 | #define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \ | 140 | #define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \ |
133 | "ath6k/AR6004/hw1.0/bdata.DB132.bin" | 141 | "ath6k/AR6004/hw1.0/bdata.DB132.bin" |
134 | 142 | ||
135 | /* AR6004 1.1 definitions */ | 143 | /* AR6004 1.1 definitions */ |
136 | #define AR6004_HW_1_1_VERSION 0x30000001 | 144 | #define AR6004_HW_1_1_VERSION 0x30000001 |
137 | #define AR6004_HW_1_1_FIRMWARE_2_FILE "ath6k/AR6004/hw1.1/fw-2.bin" | 145 | #define AR6004_HW_1_1_FW_DIR "ath6k/AR6004/hw1.1" |
138 | #define AR6004_HW_1_1_FIRMWARE_FILE "ath6k/AR6004/hw1.1/fw.ram.bin" | 146 | #define AR6004_HW_1_1_FIRMWARE_FILE "fw.ram.bin" |
139 | #define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin" | 147 | #define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin" |
140 | #define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \ | 148 | #define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \ |
141 | "ath6k/AR6004/hw1.1/bdata.DB132.bin" | 149 | "ath6k/AR6004/hw1.1/bdata.DB132.bin" |
@@ -144,6 +152,8 @@ struct ath6kl_fw_ie { | |||
144 | #define STA_PS_AWAKE BIT(0) | 152 | #define STA_PS_AWAKE BIT(0) |
145 | #define STA_PS_SLEEP BIT(1) | 153 | #define STA_PS_SLEEP BIT(1) |
146 | #define STA_PS_POLLED BIT(2) | 154 | #define STA_PS_POLLED BIT(2) |
155 | #define STA_PS_APSD_TRIGGER BIT(3) | ||
156 | #define STA_PS_APSD_EOSP BIT(4) | ||
147 | 157 | ||
148 | /* HTC TX packet tagging definitions */ | 158 | /* HTC TX packet tagging definitions */ |
149 | #define ATH6KL_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED | 159 | #define ATH6KL_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED |
@@ -186,7 +196,7 @@ struct ath6kl_fw_ie { | |||
186 | #define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1) | 196 | #define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1) |
187 | #define ATH6KL_CONF_ENABLE_11N BIT(2) | 197 | #define ATH6KL_CONF_ENABLE_11N BIT(2) |
188 | #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) | 198 | #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) |
189 | #define ATH6KL_CONF_SUSPEND_CUTPOWER BIT(4) | 199 | #define ATH6KL_CONF_UART_DEBUG BIT(4) |
190 | 200 | ||
191 | enum wlan_low_pwr_state { | 201 | enum wlan_low_pwr_state { |
192 | WLAN_POWER_STATE_ON, | 202 | WLAN_POWER_STATE_ON, |
@@ -231,14 +241,19 @@ struct rxtid_stats { | |||
231 | u32 num_bar; | 241 | u32 num_bar; |
232 | }; | 242 | }; |
233 | 243 | ||
234 | struct aggr_info { | 244 | struct aggr_info_conn { |
235 | u8 aggr_sz; | 245 | u8 aggr_sz; |
236 | u8 timer_scheduled; | 246 | u8 timer_scheduled; |
237 | struct timer_list timer; | 247 | struct timer_list timer; |
238 | struct net_device *dev; | 248 | struct net_device *dev; |
239 | struct rxtid rx_tid[NUM_OF_TIDS]; | 249 | struct rxtid rx_tid[NUM_OF_TIDS]; |
240 | struct sk_buff_head free_q; | ||
241 | struct rxtid_stats stat[NUM_OF_TIDS]; | 250 | struct rxtid_stats stat[NUM_OF_TIDS]; |
251 | struct aggr_info *aggr_info; | ||
252 | }; | ||
253 | |||
254 | struct aggr_info { | ||
255 | struct aggr_info_conn *aggr_conn; | ||
256 | struct sk_buff_head rx_amsdu_freeq; | ||
242 | }; | 257 | }; |
243 | 258 | ||
244 | struct ath6kl_wep_key { | 259 | struct ath6kl_wep_key { |
@@ -280,6 +295,9 @@ struct ath6kl_sta { | |||
280 | u8 wpa_ie[ATH6KL_MAX_IE]; | 295 | u8 wpa_ie[ATH6KL_MAX_IE]; |
281 | struct sk_buff_head psq; | 296 | struct sk_buff_head psq; |
282 | spinlock_t psq_lock; | 297 | spinlock_t psq_lock; |
298 | u8 apsd_info; | ||
299 | struct sk_buff_head apsdq; | ||
300 | struct aggr_info_conn *aggr_conn; | ||
283 | }; | 301 | }; |
284 | 302 | ||
285 | struct ath6kl_version { | 303 | struct ath6kl_version { |
@@ -408,6 +426,13 @@ enum ath6kl_hif_type { | |||
408 | ATH6KL_HIF_TYPE_USB, | 426 | ATH6KL_HIF_TYPE_USB, |
409 | }; | 427 | }; |
410 | 428 | ||
429 | /* Max number of filters that hw supports */ | ||
430 | #define ATH6K_MAX_MC_FILTERS_PER_LIST 7 | ||
431 | struct ath6kl_mc_filter { | ||
432 | struct list_head list; | ||
433 | char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; | ||
434 | }; | ||
435 | |||
411 | /* | 436 | /* |
412 | * Driver's maximum limit, note that some firmwares support only one vif | 437 | * Driver's maximum limit, note that some firmwares support only one vif |
413 | * and the runtime (current) limit must be checked from ar->vif_max. | 438 | * and the runtime (current) limit must be checked from ar->vif_max. |
@@ -426,6 +451,7 @@ enum ath6kl_vif_state { | |||
426 | DTIM_PERIOD_AVAIL, | 451 | DTIM_PERIOD_AVAIL, |
427 | WLAN_ENABLED, | 452 | WLAN_ENABLED, |
428 | STATS_UPDATE_PEND, | 453 | STATS_UPDATE_PEND, |
454 | HOST_SLEEP_MODE_CMD_PROCESSED, | ||
429 | }; | 455 | }; |
430 | 456 | ||
431 | struct ath6kl_vif { | 457 | struct ath6kl_vif { |
@@ -471,6 +497,8 @@ struct ath6kl_vif { | |||
471 | u8 assoc_bss_dtim_period; | 497 | u8 assoc_bss_dtim_period; |
472 | struct net_device_stats net_stats; | 498 | struct net_device_stats net_stats; |
473 | struct target_stats target_stats; | 499 | struct target_stats target_stats; |
500 | |||
501 | struct list_head mc_filter; | ||
474 | }; | 502 | }; |
475 | 503 | ||
476 | #define WOW_LIST_ID 0 | 504 | #define WOW_LIST_ID 0 |
@@ -504,6 +532,7 @@ struct ath6kl { | |||
504 | struct wiphy *wiphy; | 532 | struct wiphy *wiphy; |
505 | 533 | ||
506 | enum ath6kl_state state; | 534 | enum ath6kl_state state; |
535 | unsigned int testmode; | ||
507 | 536 | ||
508 | struct ath6kl_bmi bmi; | 537 | struct ath6kl_bmi bmi; |
509 | const struct ath6kl_hif_ops *hif_ops; | 538 | const struct ath6kl_hif_ops *hif_ops; |
@@ -523,7 +552,6 @@ struct ath6kl { | |||
523 | spinlock_t lock; | 552 | spinlock_t lock; |
524 | struct semaphore sem; | 553 | struct semaphore sem; |
525 | u16 listen_intvl_b; | 554 | u16 listen_intvl_b; |
526 | u16 listen_intvl_t; | ||
527 | u8 lrssi_roam_threshold; | 555 | u8 lrssi_roam_threshold; |
528 | struct ath6kl_version version; | 556 | struct ath6kl_version version; |
529 | u32 target_type; | 557 | u32 target_type; |
@@ -574,17 +602,24 @@ struct ath6kl { | |||
574 | u32 board_addr; | 602 | u32 board_addr; |
575 | u32 refclk_hz; | 603 | u32 refclk_hz; |
576 | u32 uarttx_pin; | 604 | u32 uarttx_pin; |
605 | u32 testscript_addr; | ||
606 | |||
607 | struct ath6kl_hw_fw { | ||
608 | const char *dir; | ||
609 | const char *otp; | ||
610 | const char *fw; | ||
611 | const char *tcmd; | ||
612 | const char *patch; | ||
613 | const char *utf; | ||
614 | const char *testscript; | ||
615 | } fw; | ||
577 | 616 | ||
578 | const char *fw_otp; | ||
579 | const char *fw; | ||
580 | const char *fw_tcmd; | ||
581 | const char *fw_patch; | ||
582 | const char *fw_api2; | ||
583 | const char *fw_board; | 617 | const char *fw_board; |
584 | const char *fw_default_board; | 618 | const char *fw_default_board; |
585 | } hw; | 619 | } hw; |
586 | 620 | ||
587 | u16 conf_flags; | 621 | u16 conf_flags; |
622 | u16 suspend_mode; | ||
588 | wait_queue_head_t event_wq; | 623 | wait_queue_head_t event_wq; |
589 | struct ath6kl_mbox_info mbox_info; | 624 | struct ath6kl_mbox_info mbox_info; |
590 | 625 | ||
@@ -603,6 +638,10 @@ struct ath6kl { | |||
603 | u8 *fw_patch; | 638 | u8 *fw_patch; |
604 | size_t fw_patch_len; | 639 | size_t fw_patch_len; |
605 | 640 | ||
641 | u8 *fw_testscript; | ||
642 | size_t fw_testscript_len; | ||
643 | |||
644 | unsigned int fw_api; | ||
606 | unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN]; | 645 | unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN]; |
607 | 646 | ||
608 | struct workqueue_struct *ath6kl_wq; | 647 | struct workqueue_struct *ath6kl_wq; |
@@ -676,7 +715,9 @@ struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar); | |||
676 | void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie); | 715 | void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie); |
677 | int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev); | 716 | int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev); |
678 | 717 | ||
679 | struct aggr_info *aggr_init(struct net_device *dev); | 718 | struct aggr_info *aggr_init(struct ath6kl_vif *vif); |
719 | void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info, | ||
720 | struct aggr_info_conn *aggr_conn); | ||
680 | void ath6kl_rx_refill(struct htc_target *target, | 721 | void ath6kl_rx_refill(struct htc_target *target, |
681 | enum htc_endpoint_id endpoint); | 722 | enum htc_endpoint_id endpoint); |
682 | void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count); | 723 | void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count); |
@@ -684,7 +725,7 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target, | |||
684 | enum htc_endpoint_id endpoint, | 725 | enum htc_endpoint_id endpoint, |
685 | int len); | 726 | int len); |
686 | void aggr_module_destroy(struct aggr_info *aggr_info); | 727 | void aggr_module_destroy(struct aggr_info *aggr_info); |
687 | void aggr_reset_state(struct aggr_info *aggr_info); | 728 | void aggr_reset_state(struct aggr_info_conn *aggr_conn); |
688 | 729 | ||
689 | struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 * node_addr); | 730 | struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 * node_addr); |
690 | struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); | 731 | struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); |
@@ -700,7 +741,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, | |||
700 | void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel); | 741 | void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel); |
701 | void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, | 742 | void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, |
702 | u8 keymgmt, u8 ucipher, u8 auth, | 743 | u8 keymgmt, u8 ucipher, u8 auth, |
703 | u8 assoc_req_len, u8 *assoc_info); | 744 | u8 assoc_req_len, u8 *assoc_info, u8 apsd_info); |
704 | void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, | 745 | void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, |
705 | u8 *bssid, u8 assoc_resp_len, | 746 | u8 *bssid, u8 assoc_resp_len, |
706 | u8 *assoc_info, u16 prot_reason_status); | 747 | u8 *assoc_info, u16 prot_reason_status); |
@@ -723,12 +764,18 @@ void ath6kl_wakeup_event(void *dev); | |||
723 | void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, | 764 | void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, |
724 | bool wait_fot_compltn, bool cold_reset); | 765 | bool wait_fot_compltn, bool cold_reset); |
725 | void ath6kl_init_control_info(struct ath6kl_vif *vif); | 766 | void ath6kl_init_control_info(struct ath6kl_vif *vif); |
726 | void ath6kl_deinit_if_data(struct ath6kl_vif *vif); | ||
727 | void ath6kl_core_free(struct ath6kl *ar); | ||
728 | struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); | 767 | struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); |
729 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready); | 768 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready); |
730 | int ath6kl_init_hw_start(struct ath6kl *ar); | 769 | int ath6kl_init_hw_start(struct ath6kl *ar); |
731 | int ath6kl_init_hw_stop(struct ath6kl *ar); | 770 | int ath6kl_init_hw_stop(struct ath6kl *ar); |
771 | int ath6kl_init_fetch_firmwares(struct ath6kl *ar); | ||
772 | int ath6kl_init_hw_params(struct ath6kl *ar); | ||
773 | |||
732 | void ath6kl_check_wow_status(struct ath6kl *ar); | 774 | void ath6kl_check_wow_status(struct ath6kl *ar); |
733 | 775 | ||
776 | struct ath6kl *ath6kl_core_create(struct device *dev); | ||
777 | int ath6kl_core_init(struct ath6kl *ar); | ||
778 | void ath6kl_core_cleanup(struct ath6kl *ar); | ||
779 | void ath6kl_core_destroy(struct ath6kl *ar); | ||
780 | |||
734 | #endif /* CORE_H */ | 781 | #endif /* CORE_H */ |
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index eb808b46f94c..d832058816fe 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c | |||
@@ -54,9 +54,42 @@ int ath6kl_printk(const char *level, const char *fmt, ...) | |||
54 | 54 | ||
55 | return rtn; | 55 | return rtn; |
56 | } | 56 | } |
57 | EXPORT_SYMBOL(ath6kl_printk); | ||
57 | 58 | ||
58 | #ifdef CONFIG_ATH6KL_DEBUG | 59 | #ifdef CONFIG_ATH6KL_DEBUG |
59 | 60 | ||
61 | void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...) | ||
62 | { | ||
63 | struct va_format vaf; | ||
64 | va_list args; | ||
65 | |||
66 | if (!(debug_mask & mask)) | ||
67 | return; | ||
68 | |||
69 | va_start(args, fmt); | ||
70 | |||
71 | vaf.fmt = fmt; | ||
72 | vaf.va = &args; | ||
73 | |||
74 | ath6kl_printk(KERN_DEBUG, "%pV", &vaf); | ||
75 | |||
76 | va_end(args); | ||
77 | } | ||
78 | EXPORT_SYMBOL(ath6kl_dbg); | ||
79 | |||
80 | void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, | ||
81 | const char *msg, const char *prefix, | ||
82 | const void *buf, size_t len) | ||
83 | { | ||
84 | if (debug_mask & mask) { | ||
85 | if (msg) | ||
86 | ath6kl_dbg(mask, "%s\n", msg); | ||
87 | |||
88 | print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); | ||
89 | } | ||
90 | } | ||
91 | EXPORT_SYMBOL(ath6kl_dbg_dump); | ||
92 | |||
60 | #define REG_OUTPUT_LEN_PER_LINE 25 | 93 | #define REG_OUTPUT_LEN_PER_LINE 25 |
61 | #define REGTYPE_STR_LEN 100 | 94 | #define REGTYPE_STR_LEN 100 |
62 | 95 | ||
@@ -82,31 +115,31 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, | |||
82 | struct ath6kl_irq_enable_reg *irq_enable_reg) | 115 | struct ath6kl_irq_enable_reg *irq_enable_reg) |
83 | { | 116 | { |
84 | 117 | ||
85 | ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n")); | 118 | ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n")); |
86 | 119 | ||
87 | if (irq_proc_reg != NULL) { | 120 | if (irq_proc_reg != NULL) { |
88 | ath6kl_dbg(ATH6KL_DBG_ANY, | 121 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
89 | "Host Int status: 0x%x\n", | 122 | "Host Int status: 0x%x\n", |
90 | irq_proc_reg->host_int_status); | 123 | irq_proc_reg->host_int_status); |
91 | ath6kl_dbg(ATH6KL_DBG_ANY, | 124 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
92 | "CPU Int status: 0x%x\n", | 125 | "CPU Int status: 0x%x\n", |
93 | irq_proc_reg->cpu_int_status); | 126 | irq_proc_reg->cpu_int_status); |
94 | ath6kl_dbg(ATH6KL_DBG_ANY, | 127 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
95 | "Error Int status: 0x%x\n", | 128 | "Error Int status: 0x%x\n", |
96 | irq_proc_reg->error_int_status); | 129 | irq_proc_reg->error_int_status); |
97 | ath6kl_dbg(ATH6KL_DBG_ANY, | 130 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
98 | "Counter Int status: 0x%x\n", | 131 | "Counter Int status: 0x%x\n", |
99 | irq_proc_reg->counter_int_status); | 132 | irq_proc_reg->counter_int_status); |
100 | ath6kl_dbg(ATH6KL_DBG_ANY, | 133 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
101 | "Mbox Frame: 0x%x\n", | 134 | "Mbox Frame: 0x%x\n", |
102 | irq_proc_reg->mbox_frame); | 135 | irq_proc_reg->mbox_frame); |
103 | ath6kl_dbg(ATH6KL_DBG_ANY, | 136 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
104 | "Rx Lookahead Valid: 0x%x\n", | 137 | "Rx Lookahead Valid: 0x%x\n", |
105 | irq_proc_reg->rx_lkahd_valid); | 138 | irq_proc_reg->rx_lkahd_valid); |
106 | ath6kl_dbg(ATH6KL_DBG_ANY, | 139 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
107 | "Rx Lookahead 0: 0x%x\n", | 140 | "Rx Lookahead 0: 0x%x\n", |
108 | irq_proc_reg->rx_lkahd[0]); | 141 | irq_proc_reg->rx_lkahd[0]); |
109 | ath6kl_dbg(ATH6KL_DBG_ANY, | 142 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
110 | "Rx Lookahead 1: 0x%x\n", | 143 | "Rx Lookahead 1: 0x%x\n", |
111 | irq_proc_reg->rx_lkahd[1]); | 144 | irq_proc_reg->rx_lkahd[1]); |
112 | 145 | ||
@@ -115,16 +148,16 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, | |||
115 | * If the target supports GMBOX hardware, dump some | 148 | * If the target supports GMBOX hardware, dump some |
116 | * additional state. | 149 | * additional state. |
117 | */ | 150 | */ |
118 | ath6kl_dbg(ATH6KL_DBG_ANY, | 151 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
119 | "GMBOX Host Int status 2: 0x%x\n", | 152 | "GMBOX Host Int status 2: 0x%x\n", |
120 | irq_proc_reg->host_int_status2); | 153 | irq_proc_reg->host_int_status2); |
121 | ath6kl_dbg(ATH6KL_DBG_ANY, | 154 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
122 | "GMBOX RX Avail: 0x%x\n", | 155 | "GMBOX RX Avail: 0x%x\n", |
123 | irq_proc_reg->gmbox_rx_avail); | 156 | irq_proc_reg->gmbox_rx_avail); |
124 | ath6kl_dbg(ATH6KL_DBG_ANY, | 157 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
125 | "GMBOX lookahead alias 0: 0x%x\n", | 158 | "GMBOX lookahead alias 0: 0x%x\n", |
126 | irq_proc_reg->rx_gmbox_lkahd_alias[0]); | 159 | irq_proc_reg->rx_gmbox_lkahd_alias[0]); |
127 | ath6kl_dbg(ATH6KL_DBG_ANY, | 160 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
128 | "GMBOX lookahead alias 1: 0x%x\n", | 161 | "GMBOX lookahead alias 1: 0x%x\n", |
129 | irq_proc_reg->rx_gmbox_lkahd_alias[1]); | 162 | irq_proc_reg->rx_gmbox_lkahd_alias[1]); |
130 | } | 163 | } |
@@ -132,13 +165,13 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, | |||
132 | } | 165 | } |
133 | 166 | ||
134 | if (irq_enable_reg != NULL) { | 167 | if (irq_enable_reg != NULL) { |
135 | ath6kl_dbg(ATH6KL_DBG_ANY, | 168 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
136 | "Int status Enable: 0x%x\n", | 169 | "Int status Enable: 0x%x\n", |
137 | irq_enable_reg->int_status_en); | 170 | irq_enable_reg->int_status_en); |
138 | ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n", | 171 | ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n", |
139 | irq_enable_reg->cntr_int_status_en); | 172 | irq_enable_reg->cntr_int_status_en); |
140 | } | 173 | } |
141 | ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n"); | 174 | ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n"); |
142 | } | 175 | } |
143 | 176 | ||
144 | static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) | 177 | static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) |
@@ -175,9 +208,6 @@ void dump_cred_dist_stats(struct htc_target *target) | |||
175 | { | 208 | { |
176 | struct htc_endpoint_credit_dist *ep_list; | 209 | struct htc_endpoint_credit_dist *ep_list; |
177 | 210 | ||
178 | if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_CREDIT)) | ||
179 | return; | ||
180 | |||
181 | list_for_each_entry(ep_list, &target->cred_dist_list, list) | 211 | list_for_each_entry(ep_list, &target->cred_dist_list, list) |
182 | dump_cred_dist(ep_list); | 212 | dump_cred_dist(ep_list); |
183 | 213 | ||
@@ -1411,6 +1441,8 @@ static ssize_t ath6kl_create_qos_write(struct file *file, | |||
1411 | return -EINVAL; | 1441 | return -EINVAL; |
1412 | pstream.medium_time = cpu_to_le32(val32); | 1442 | pstream.medium_time = cpu_to_le32(val32); |
1413 | 1443 | ||
1444 | pstream.nominal_phy = le32_to_cpu(pstream.min_phy_rate) / 1000000; | ||
1445 | |||
1414 | ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream); | 1446 | ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream); |
1415 | 1447 | ||
1416 | return count; | 1448 | return count; |
@@ -1505,57 +1537,46 @@ static const struct file_operations fops_bgscan_int = { | |||
1505 | }; | 1537 | }; |
1506 | 1538 | ||
1507 | static ssize_t ath6kl_listen_int_write(struct file *file, | 1539 | static ssize_t ath6kl_listen_int_write(struct file *file, |
1508 | const char __user *user_buf, | 1540 | const char __user *user_buf, |
1509 | size_t count, loff_t *ppos) | 1541 | size_t count, loff_t *ppos) |
1510 | { | 1542 | { |
1511 | struct ath6kl *ar = file->private_data; | 1543 | struct ath6kl *ar = file->private_data; |
1512 | u16 listen_int_t, listen_int_b; | 1544 | struct ath6kl_vif *vif; |
1545 | u16 listen_interval; | ||
1513 | char buf[32]; | 1546 | char buf[32]; |
1514 | char *sptr, *token; | ||
1515 | ssize_t len; | 1547 | ssize_t len; |
1516 | 1548 | ||
1549 | vif = ath6kl_vif_first(ar); | ||
1550 | if (!vif) | ||
1551 | return -EIO; | ||
1552 | |||
1517 | len = min(count, sizeof(buf) - 1); | 1553 | len = min(count, sizeof(buf) - 1); |
1518 | if (copy_from_user(buf, user_buf, len)) | 1554 | if (copy_from_user(buf, user_buf, len)) |
1519 | return -EFAULT; | 1555 | return -EFAULT; |
1520 | 1556 | ||
1521 | buf[len] = '\0'; | 1557 | buf[len] = '\0'; |
1522 | sptr = buf; | 1558 | if (kstrtou16(buf, 0, &listen_interval)) |
1523 | |||
1524 | token = strsep(&sptr, " "); | ||
1525 | if (!token) | ||
1526 | return -EINVAL; | ||
1527 | |||
1528 | if (kstrtou16(token, 0, &listen_int_t)) | ||
1529 | return -EINVAL; | ||
1530 | |||
1531 | if (kstrtou16(sptr, 0, &listen_int_b)) | ||
1532 | return -EINVAL; | ||
1533 | |||
1534 | if ((listen_int_t < 15) || (listen_int_t > 5000)) | ||
1535 | return -EINVAL; | 1559 | return -EINVAL; |
1536 | 1560 | ||
1537 | if ((listen_int_b < 1) || (listen_int_b > 50)) | 1561 | if ((listen_interval < 1) || (listen_interval > 50)) |
1538 | return -EINVAL; | 1562 | return -EINVAL; |
1539 | 1563 | ||
1540 | ar->listen_intvl_t = listen_int_t; | 1564 | ar->listen_intvl_b = listen_interval; |
1541 | ar->listen_intvl_b = listen_int_b; | 1565 | ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, 0, |
1542 | |||
1543 | ath6kl_wmi_listeninterval_cmd(ar->wmi, 0, ar->listen_intvl_t, | ||
1544 | ar->listen_intvl_b); | 1566 | ar->listen_intvl_b); |
1545 | 1567 | ||
1546 | return count; | 1568 | return count; |
1547 | } | 1569 | } |
1548 | 1570 | ||
1549 | static ssize_t ath6kl_listen_int_read(struct file *file, | 1571 | static ssize_t ath6kl_listen_int_read(struct file *file, |
1550 | char __user *user_buf, | 1572 | char __user *user_buf, |
1551 | size_t count, loff_t *ppos) | 1573 | size_t count, loff_t *ppos) |
1552 | { | 1574 | { |
1553 | struct ath6kl *ar = file->private_data; | 1575 | struct ath6kl *ar = file->private_data; |
1554 | char buf[32]; | 1576 | char buf[32]; |
1555 | int len; | 1577 | int len; |
1556 | 1578 | ||
1557 | len = scnprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t, | 1579 | len = scnprintf(buf, sizeof(buf), "%u\n", ar->listen_intvl_b); |
1558 | ar->listen_intvl_b); | ||
1559 | 1580 | ||
1560 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 1581 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); |
1561 | } | 1582 | } |
@@ -1710,6 +1731,9 @@ int ath6kl_debug_init(struct ath6kl *ar) | |||
1710 | debugfs_create_file("bgscan_interval", S_IWUSR, | 1731 | debugfs_create_file("bgscan_interval", S_IWUSR, |
1711 | ar->debugfs_phy, ar, &fops_bgscan_int); | 1732 | ar->debugfs_phy, ar, &fops_bgscan_int); |
1712 | 1733 | ||
1734 | debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR, | ||
1735 | ar->debugfs_phy, ar, &fops_listen_int); | ||
1736 | |||
1713 | debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar, | 1737 | debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar, |
1714 | &fops_power_params); | 1738 | &fops_power_params); |
1715 | 1739 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 9853c9c125c1..c4be6e50996b 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h | |||
@@ -41,6 +41,7 @@ enum ATH6K_DEBUG_MASK { | |||
41 | ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */ | 41 | ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */ |
42 | ATH6KL_DBG_WMI_DUMP = BIT(19), | 42 | ATH6KL_DBG_WMI_DUMP = BIT(19), |
43 | ATH6KL_DBG_SUSPEND = BIT(20), | 43 | ATH6KL_DBG_SUSPEND = BIT(20), |
44 | ATH6KL_DBG_USB = BIT(21), | ||
44 | ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ | 45 | ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ |
45 | }; | 46 | }; |
46 | 47 | ||
@@ -55,35 +56,16 @@ int ath6kl_printk(const char *level, const char *fmt, ...); | |||
55 | #define ath6kl_warn(fmt, ...) \ | 56 | #define ath6kl_warn(fmt, ...) \ |
56 | ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__) | 57 | ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__) |
57 | 58 | ||
58 | #define AR_DBG_LVL_CHECK(mask) (debug_mask & mask) | ||
59 | |||
60 | enum ath6kl_war { | 59 | enum ath6kl_war { |
61 | ATH6KL_WAR_INVALID_RATE, | 60 | ATH6KL_WAR_INVALID_RATE, |
62 | }; | 61 | }; |
63 | 62 | ||
64 | #ifdef CONFIG_ATH6KL_DEBUG | 63 | #ifdef CONFIG_ATH6KL_DEBUG |
65 | #define ath6kl_dbg(mask, fmt, ...) \ | ||
66 | ({ \ | ||
67 | int rtn; \ | ||
68 | if (debug_mask & mask) \ | ||
69 | rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__); \ | ||
70 | else \ | ||
71 | rtn = 0; \ | ||
72 | \ | ||
73 | rtn; \ | ||
74 | }) | ||
75 | 64 | ||
76 | static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, | 65 | void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...); |
77 | const char *msg, const char *prefix, | 66 | void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, |
78 | const void *buf, size_t len) | 67 | const char *msg, const char *prefix, |
79 | { | 68 | const void *buf, size_t len); |
80 | if (debug_mask & mask) { | ||
81 | if (msg) | ||
82 | ath6kl_dbg(mask, "%s\n", msg); | ||
83 | |||
84 | print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); | ||
85 | } | ||
86 | } | ||
87 | 69 | ||
88 | void ath6kl_dump_registers(struct ath6kl_device *dev, | 70 | void ath6kl_dump_registers(struct ath6kl_device *dev, |
89 | struct ath6kl_irq_proc_registers *irq_proc_reg, | 71 | struct ath6kl_irq_proc_registers *irq_proc_reg, |
diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index e57da35e59fa..e911737ab345 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c | |||
@@ -15,6 +15,8 @@ | |||
15 | */ | 15 | */ |
16 | #include "hif.h" | 16 | #include "hif.h" |
17 | 17 | ||
18 | #include <linux/export.h> | ||
19 | |||
18 | #include "core.h" | 20 | #include "core.h" |
19 | #include "target.h" | 21 | #include "target.h" |
20 | #include "hif-ops.h" | 22 | #include "hif-ops.h" |
@@ -59,6 +61,8 @@ int ath6kl_hif_rw_comp_handler(void *context, int status) | |||
59 | 61 | ||
60 | return 0; | 62 | return 0; |
61 | } | 63 | } |
64 | EXPORT_SYMBOL(ath6kl_hif_rw_comp_handler); | ||
65 | |||
62 | #define REG_DUMP_COUNT_AR6003 60 | 66 | #define REG_DUMP_COUNT_AR6003 60 |
63 | #define REGISTER_DUMP_LEN_MAX 60 | 67 | #define REGISTER_DUMP_LEN_MAX 60 |
64 | 68 | ||
@@ -429,9 +433,8 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done) | |||
429 | if (status) | 433 | if (status) |
430 | goto out; | 434 | goto out; |
431 | 435 | ||
432 | if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ)) | 436 | ath6kl_dump_registers(dev, &dev->irq_proc_reg, |
433 | ath6kl_dump_registers(dev, &dev->irq_proc_reg, | 437 | &dev->irq_en_reg); |
434 | &dev->irq_en_reg); | ||
435 | 438 | ||
436 | /* Update only those registers that are enabled */ | 439 | /* Update only those registers that are enabled */ |
437 | host_int_status = dev->irq_proc_reg.host_int_status & | 440 | host_int_status = dev->irq_proc_reg.host_int_status & |
@@ -561,6 +564,7 @@ int ath6kl_hif_intr_bh_handler(struct ath6kl *ar) | |||
561 | 564 | ||
562 | return status; | 565 | return status; |
563 | } | 566 | } |
567 | EXPORT_SYMBOL(ath6kl_hif_intr_bh_handler); | ||
564 | 568 | ||
565 | static int ath6kl_hif_enable_intrs(struct ath6kl_device *dev) | 569 | static int ath6kl_hif_enable_intrs(struct ath6kl_device *dev) |
566 | { | 570 | { |
@@ -689,6 +693,11 @@ int ath6kl_hif_setup(struct ath6kl_device *dev) | |||
689 | ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n", | 693 | ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n", |
690 | dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); | 694 | dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); |
691 | 695 | ||
696 | /* usb doesn't support enabling interrupts */ | ||
697 | /* FIXME: remove check once USB support is implemented */ | ||
698 | if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) | ||
699 | return 0; | ||
700 | |||
692 | status = ath6kl_hif_disable_intrs(dev); | 701 | status = ath6kl_hif_disable_intrs(dev); |
693 | 702 | ||
694 | fail_setup: | 703 | fail_setup: |
diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index f3b63ca25c7e..2d721903640b 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c | |||
@@ -2062,6 +2062,7 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, | |||
2062 | enum htc_endpoint_id id; | 2062 | enum htc_endpoint_id id; |
2063 | int n_fetched = 0; | 2063 | int n_fetched = 0; |
2064 | 2064 | ||
2065 | INIT_LIST_HEAD(&comp_pktq); | ||
2065 | *num_pkts = 0; | 2066 | *num_pkts = 0; |
2066 | 2067 | ||
2067 | /* | 2068 | /* |
@@ -2543,6 +2544,12 @@ int ath6kl_htc_wait_target(struct htc_target *target) | |||
2543 | struct htc_service_connect_resp resp; | 2544 | struct htc_service_connect_resp resp; |
2544 | int status; | 2545 | int status; |
2545 | 2546 | ||
2547 | /* FIXME: remove once USB support is implemented */ | ||
2548 | if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) { | ||
2549 | ath6kl_err("HTC doesn't support USB yet. Patience!\n"); | ||
2550 | return -EOPNOTSUPP; | ||
2551 | } | ||
2552 | |||
2546 | /* we should be getting 1 control message that the target is ready */ | 2553 | /* we should be getting 1 control message that the target is ready */ |
2547 | packet = htc_wait_for_ctrl_msg(target); | 2554 | packet = htc_wait_for_ctrl_msg(target); |
2548 | 2555 | ||
@@ -2772,7 +2779,9 @@ void ath6kl_htc_cleanup(struct htc_target *target) | |||
2772 | { | 2779 | { |
2773 | struct htc_packet *packet, *tmp_packet; | 2780 | struct htc_packet *packet, *tmp_packet; |
2774 | 2781 | ||
2775 | ath6kl_hif_cleanup_scatter(target->dev->ar); | 2782 | /* FIXME: remove check once USB support is implemented */ |
2783 | if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB) | ||
2784 | ath6kl_hif_cleanup_scatter(target->dev->ar); | ||
2776 | 2785 | ||
2777 | list_for_each_entry_safe(packet, tmp_packet, | 2786 | list_for_each_entry_safe(packet, tmp_packet, |
2778 | &target->free_ctrl_txbuf, list) { | 2787 | &target->free_ctrl_txbuf, list) { |
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 7f55be3092d1..0d76c3778106 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c | |||
@@ -17,22 +17,16 @@ | |||
17 | 17 | ||
18 | #include <linux/moduleparam.h> | 18 | #include <linux/moduleparam.h> |
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/export.h> | ||
20 | #include <linux/of.h> | 21 | #include <linux/of.h> |
21 | #include <linux/mmc/sdio_func.h> | 22 | #include <linux/mmc/sdio_func.h> |
23 | |||
22 | #include "core.h" | 24 | #include "core.h" |
23 | #include "cfg80211.h" | 25 | #include "cfg80211.h" |
24 | #include "target.h" | 26 | #include "target.h" |
25 | #include "debug.h" | 27 | #include "debug.h" |
26 | #include "hif-ops.h" | 28 | #include "hif-ops.h" |
27 | 29 | ||
28 | unsigned int debug_mask; | ||
29 | static unsigned int testmode; | ||
30 | static bool suspend_cutpower; | ||
31 | |||
32 | module_param(debug_mask, uint, 0644); | ||
33 | module_param(testmode, uint, 0644); | ||
34 | module_param(suspend_cutpower, bool, 0444); | ||
35 | |||
36 | static const struct ath6kl_hw hw_list[] = { | 30 | static const struct ath6kl_hw hw_list[] = { |
37 | { | 31 | { |
38 | .id = AR6003_HW_2_0_VERSION, | 32 | .id = AR6003_HW_2_0_VERSION, |
@@ -47,11 +41,14 @@ static const struct ath6kl_hw hw_list[] = { | |||
47 | /* hw2.0 needs override address hardcoded */ | 41 | /* hw2.0 needs override address hardcoded */ |
48 | .app_start_override_addr = 0x944C00, | 42 | .app_start_override_addr = 0x944C00, |
49 | 43 | ||
50 | .fw_otp = AR6003_HW_2_0_OTP_FILE, | 44 | .fw = { |
51 | .fw = AR6003_HW_2_0_FIRMWARE_FILE, | 45 | .dir = AR6003_HW_2_0_FW_DIR, |
52 | .fw_tcmd = AR6003_HW_2_0_TCMD_FIRMWARE_FILE, | 46 | .otp = AR6003_HW_2_0_OTP_FILE, |
53 | .fw_patch = AR6003_HW_2_0_PATCH_FILE, | 47 | .fw = AR6003_HW_2_0_FIRMWARE_FILE, |
54 | .fw_api2 = AR6003_HW_2_0_FIRMWARE_2_FILE, | 48 | .tcmd = AR6003_HW_2_0_TCMD_FIRMWARE_FILE, |
49 | .patch = AR6003_HW_2_0_PATCH_FILE, | ||
50 | }, | ||
51 | |||
55 | .fw_board = AR6003_HW_2_0_BOARD_DATA_FILE, | 52 | .fw_board = AR6003_HW_2_0_BOARD_DATA_FILE, |
56 | .fw_default_board = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE, | 53 | .fw_default_board = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE, |
57 | }, | 54 | }, |
@@ -64,12 +61,18 @@ static const struct ath6kl_hw hw_list[] = { | |||
64 | .reserved_ram_size = 512, | 61 | .reserved_ram_size = 512, |
65 | .refclk_hz = 26000000, | 62 | .refclk_hz = 26000000, |
66 | .uarttx_pin = 8, | 63 | .uarttx_pin = 8, |
64 | .testscript_addr = 0x57ef74, | ||
65 | |||
66 | .fw = { | ||
67 | .dir = AR6003_HW_2_1_1_FW_DIR, | ||
68 | .otp = AR6003_HW_2_1_1_OTP_FILE, | ||
69 | .fw = AR6003_HW_2_1_1_FIRMWARE_FILE, | ||
70 | .tcmd = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE, | ||
71 | .patch = AR6003_HW_2_1_1_PATCH_FILE, | ||
72 | .utf = AR6003_HW_2_1_1_UTF_FIRMWARE_FILE, | ||
73 | .testscript = AR6003_HW_2_1_1_TESTSCRIPT_FILE, | ||
74 | }, | ||
67 | 75 | ||
68 | .fw_otp = AR6003_HW_2_1_1_OTP_FILE, | ||
69 | .fw = AR6003_HW_2_1_1_FIRMWARE_FILE, | ||
70 | .fw_tcmd = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE, | ||
71 | .fw_patch = AR6003_HW_2_1_1_PATCH_FILE, | ||
72 | .fw_api2 = AR6003_HW_2_1_1_FIRMWARE_2_FILE, | ||
73 | .fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE, | 76 | .fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE, |
74 | .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, | 77 | .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, |
75 | }, | 78 | }, |
@@ -84,8 +87,11 @@ static const struct ath6kl_hw hw_list[] = { | |||
84 | .refclk_hz = 26000000, | 87 | .refclk_hz = 26000000, |
85 | .uarttx_pin = 11, | 88 | .uarttx_pin = 11, |
86 | 89 | ||
87 | .fw = AR6004_HW_1_0_FIRMWARE_FILE, | 90 | .fw = { |
88 | .fw_api2 = AR6004_HW_1_0_FIRMWARE_2_FILE, | 91 | .dir = AR6004_HW_1_0_FW_DIR, |
92 | .fw = AR6004_HW_1_0_FIRMWARE_FILE, | ||
93 | }, | ||
94 | |||
89 | .fw_board = AR6004_HW_1_0_BOARD_DATA_FILE, | 95 | .fw_board = AR6004_HW_1_0_BOARD_DATA_FILE, |
90 | .fw_default_board = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE, | 96 | .fw_default_board = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE, |
91 | }, | 97 | }, |
@@ -100,8 +106,11 @@ static const struct ath6kl_hw hw_list[] = { | |||
100 | .refclk_hz = 40000000, | 106 | .refclk_hz = 40000000, |
101 | .uarttx_pin = 11, | 107 | .uarttx_pin = 11, |
102 | 108 | ||
103 | .fw = AR6004_HW_1_1_FIRMWARE_FILE, | 109 | .fw = { |
104 | .fw_api2 = AR6004_HW_1_1_FIRMWARE_2_FILE, | 110 | .dir = AR6004_HW_1_1_FW_DIR, |
111 | .fw = AR6004_HW_1_1_FIRMWARE_FILE, | ||
112 | }, | ||
113 | |||
105 | .fw_board = AR6004_HW_1_1_BOARD_DATA_FILE, | 114 | .fw_board = AR6004_HW_1_1_BOARD_DATA_FILE, |
106 | .fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE, | 115 | .fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE, |
107 | }, | 116 | }, |
@@ -452,6 +461,13 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
452 | u8 fw_iftype, fw_mode = 0, fw_submode = 0; | 461 | u8 fw_iftype, fw_mode = 0, fw_submode = 0; |
453 | int i, status; | 462 | int i, status; |
454 | 463 | ||
464 | param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG); | ||
465 | if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, | ||
466 | HI_ITEM(hi_serial_enable)), (u8 *)¶m, 4)) { | ||
467 | ath6kl_err("bmi_write_memory for uart debug failed\n"); | ||
468 | return -EIO; | ||
469 | } | ||
470 | |||
455 | /* | 471 | /* |
456 | * Note: Even though the firmware interface type is | 472 | * Note: Even though the firmware interface type is |
457 | * chosen as BSS_STA for all three interfaces, can | 473 | * chosen as BSS_STA for all three interfaces, can |
@@ -573,36 +589,6 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
573 | return 0; | 589 | return 0; |
574 | } | 590 | } |
575 | 591 | ||
576 | void ath6kl_core_free(struct ath6kl *ar) | ||
577 | { | ||
578 | wiphy_free(ar->wiphy); | ||
579 | } | ||
580 | |||
581 | void ath6kl_core_cleanup(struct ath6kl *ar) | ||
582 | { | ||
583 | ath6kl_hif_power_off(ar); | ||
584 | |||
585 | destroy_workqueue(ar->ath6kl_wq); | ||
586 | |||
587 | if (ar->htc_target) | ||
588 | ath6kl_htc_cleanup(ar->htc_target); | ||
589 | |||
590 | ath6kl_cookie_cleanup(ar); | ||
591 | |||
592 | ath6kl_cleanup_amsdu_rxbufs(ar); | ||
593 | |||
594 | ath6kl_bmi_cleanup(ar); | ||
595 | |||
596 | ath6kl_debug_cleanup(ar); | ||
597 | |||
598 | kfree(ar->fw_board); | ||
599 | kfree(ar->fw_otp); | ||
600 | kfree(ar->fw); | ||
601 | kfree(ar->fw_patch); | ||
602 | |||
603 | ath6kl_deinit_ieee80211_hw(ar); | ||
604 | } | ||
605 | |||
606 | /* firmware upload */ | 592 | /* firmware upload */ |
607 | static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, | 593 | static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, |
608 | u8 **fw, size_t *fw_len) | 594 | u8 **fw, size_t *fw_len) |
@@ -626,21 +612,6 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, | |||
626 | } | 612 | } |
627 | 613 | ||
628 | #ifdef CONFIG_OF | 614 | #ifdef CONFIG_OF |
629 | static const char *get_target_ver_dir(const struct ath6kl *ar) | ||
630 | { | ||
631 | switch (ar->version.target_ver) { | ||
632 | case AR6003_HW_1_0_VERSION: | ||
633 | return "ath6k/AR6003/hw1.0"; | ||
634 | case AR6003_HW_2_0_VERSION: | ||
635 | return "ath6k/AR6003/hw2.0"; | ||
636 | case AR6003_HW_2_1_1_VERSION: | ||
637 | return "ath6k/AR6003/hw2.1.1"; | ||
638 | } | ||
639 | ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__, | ||
640 | ar->version.target_ver); | ||
641 | return NULL; | ||
642 | } | ||
643 | |||
644 | /* | 615 | /* |
645 | * Check the device tree for a board-id and use it to construct | 616 | * Check the device tree for a board-id and use it to construct |
646 | * the pathname to the firmware file. Used (for now) to find a | 617 | * the pathname to the firmware file. Used (for now) to find a |
@@ -663,7 +634,7 @@ static bool check_device_tree(struct ath6kl *ar) | |||
663 | continue; | 634 | continue; |
664 | } | 635 | } |
665 | snprintf(board_filename, sizeof(board_filename), | 636 | snprintf(board_filename, sizeof(board_filename), |
666 | "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id); | 637 | "%s/bdata.%s.bin", ar->hw.fw.dir, board_id); |
667 | 638 | ||
668 | ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board, | 639 | ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board, |
669 | &ar->fw_board_len); | 640 | &ar->fw_board_len); |
@@ -730,19 +701,20 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) | |||
730 | 701 | ||
731 | static int ath6kl_fetch_otp_file(struct ath6kl *ar) | 702 | static int ath6kl_fetch_otp_file(struct ath6kl *ar) |
732 | { | 703 | { |
733 | const char *filename; | 704 | char filename[100]; |
734 | int ret; | 705 | int ret; |
735 | 706 | ||
736 | if (ar->fw_otp != NULL) | 707 | if (ar->fw_otp != NULL) |
737 | return 0; | 708 | return 0; |
738 | 709 | ||
739 | if (ar->hw.fw_otp == NULL) { | 710 | if (ar->hw.fw.otp == NULL) { |
740 | ath6kl_dbg(ATH6KL_DBG_BOOT, | 711 | ath6kl_dbg(ATH6KL_DBG_BOOT, |
741 | "no OTP file configured for this hw\n"); | 712 | "no OTP file configured for this hw\n"); |
742 | return 0; | 713 | return 0; |
743 | } | 714 | } |
744 | 715 | ||
745 | filename = ar->hw.fw_otp; | 716 | snprintf(filename, sizeof(filename), "%s/%s", |
717 | ar->hw.fw.dir, ar->hw.fw.otp); | ||
746 | 718 | ||
747 | ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, | 719 | ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, |
748 | &ar->fw_otp_len); | 720 | &ar->fw_otp_len); |
@@ -755,33 +727,61 @@ static int ath6kl_fetch_otp_file(struct ath6kl *ar) | |||
755 | return 0; | 727 | return 0; |
756 | } | 728 | } |
757 | 729 | ||
758 | static int ath6kl_fetch_fw_file(struct ath6kl *ar) | 730 | static int ath6kl_fetch_testmode_file(struct ath6kl *ar) |
759 | { | 731 | { |
760 | const char *filename; | 732 | char filename[100]; |
761 | int ret; | 733 | int ret; |
762 | 734 | ||
763 | if (ar->fw != NULL) | 735 | if (ar->testmode == 0) |
764 | return 0; | 736 | return 0; |
765 | 737 | ||
766 | if (testmode) { | 738 | ath6kl_dbg(ATH6KL_DBG_BOOT, "testmode %d\n", ar->testmode); |
767 | if (ar->hw.fw_tcmd == NULL) { | 739 | |
768 | ath6kl_warn("testmode not supported\n"); | 740 | if (ar->testmode == 2) { |
741 | if (ar->hw.fw.utf == NULL) { | ||
742 | ath6kl_warn("testmode 2 not supported\n"); | ||
743 | return -EOPNOTSUPP; | ||
744 | } | ||
745 | |||
746 | snprintf(filename, sizeof(filename), "%s/%s", | ||
747 | ar->hw.fw.dir, ar->hw.fw.utf); | ||
748 | } else { | ||
749 | if (ar->hw.fw.tcmd == NULL) { | ||
750 | ath6kl_warn("testmode 1 not supported\n"); | ||
769 | return -EOPNOTSUPP; | 751 | return -EOPNOTSUPP; |
770 | } | 752 | } |
771 | 753 | ||
772 | filename = ar->hw.fw_tcmd; | 754 | snprintf(filename, sizeof(filename), "%s/%s", |
755 | ar->hw.fw.dir, ar->hw.fw.tcmd); | ||
756 | } | ||
773 | 757 | ||
774 | set_bit(TESTMODE, &ar->flag); | 758 | set_bit(TESTMODE, &ar->flag); |
775 | 759 | ||
776 | goto get_fw; | 760 | ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); |
761 | if (ret) { | ||
762 | ath6kl_err("Failed to get testmode %d firmware file %s: %d\n", | ||
763 | ar->testmode, filename, ret); | ||
764 | return ret; | ||
777 | } | 765 | } |
778 | 766 | ||
779 | if (WARN_ON(ar->hw.fw == NULL)) | 767 | return 0; |
768 | } | ||
769 | |||
770 | static int ath6kl_fetch_fw_file(struct ath6kl *ar) | ||
771 | { | ||
772 | char filename[100]; | ||
773 | int ret; | ||
774 | |||
775 | if (ar->fw != NULL) | ||
776 | return 0; | ||
777 | |||
778 | /* FIXME: remove WARN_ON() as we won't support FW API 1 for long */ | ||
779 | if (WARN_ON(ar->hw.fw.fw == NULL)) | ||
780 | return -EINVAL; | 780 | return -EINVAL; |
781 | 781 | ||
782 | filename = ar->hw.fw; | 782 | snprintf(filename, sizeof(filename), "%s/%s", |
783 | ar->hw.fw.dir, ar->hw.fw.fw); | ||
783 | 784 | ||
784 | get_fw: | ||
785 | ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); | 785 | ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); |
786 | if (ret) { | 786 | if (ret) { |
787 | ath6kl_err("Failed to get firmware file %s: %d\n", | 787 | ath6kl_err("Failed to get firmware file %s: %d\n", |
@@ -794,16 +794,17 @@ get_fw: | |||
794 | 794 | ||
795 | static int ath6kl_fetch_patch_file(struct ath6kl *ar) | 795 | static int ath6kl_fetch_patch_file(struct ath6kl *ar) |
796 | { | 796 | { |
797 | const char *filename; | 797 | char filename[100]; |
798 | int ret; | 798 | int ret; |
799 | 799 | ||
800 | if (ar->fw_patch != NULL) | 800 | if (ar->fw_patch != NULL) |
801 | return 0; | 801 | return 0; |
802 | 802 | ||
803 | if (ar->hw.fw_patch == NULL) | 803 | if (ar->hw.fw.patch == NULL) |
804 | return 0; | 804 | return 0; |
805 | 805 | ||
806 | filename = ar->hw.fw_patch; | 806 | snprintf(filename, sizeof(filename), "%s/%s", |
807 | ar->hw.fw.dir, ar->hw.fw.patch); | ||
807 | 808 | ||
808 | ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, | 809 | ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, |
809 | &ar->fw_patch_len); | 810 | &ar->fw_patch_len); |
@@ -816,6 +817,34 @@ static int ath6kl_fetch_patch_file(struct ath6kl *ar) | |||
816 | return 0; | 817 | return 0; |
817 | } | 818 | } |
818 | 819 | ||
820 | static int ath6kl_fetch_testscript_file(struct ath6kl *ar) | ||
821 | { | ||
822 | char filename[100]; | ||
823 | int ret; | ||
824 | |||
825 | if (ar->testmode != 2) | ||
826 | return 0; | ||
827 | |||
828 | if (ar->fw_testscript != NULL) | ||
829 | return 0; | ||
830 | |||
831 | if (ar->hw.fw.testscript == NULL) | ||
832 | return 0; | ||
833 | |||
834 | snprintf(filename, sizeof(filename), "%s/%s", | ||
835 | ar->hw.fw.dir, ar->hw.fw.testscript); | ||
836 | |||
837 | ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript, | ||
838 | &ar->fw_testscript_len); | ||
839 | if (ret) { | ||
840 | ath6kl_err("Failed to get testscript file %s: %d\n", | ||
841 | filename, ret); | ||
842 | return ret; | ||
843 | } | ||
844 | |||
845 | return 0; | ||
846 | } | ||
847 | |||
819 | static int ath6kl_fetch_fw_api1(struct ath6kl *ar) | 848 | static int ath6kl_fetch_fw_api1(struct ath6kl *ar) |
820 | { | 849 | { |
821 | int ret; | 850 | int ret; |
@@ -832,23 +861,24 @@ static int ath6kl_fetch_fw_api1(struct ath6kl *ar) | |||
832 | if (ret) | 861 | if (ret) |
833 | return ret; | 862 | return ret; |
834 | 863 | ||
864 | ret = ath6kl_fetch_testscript_file(ar); | ||
865 | if (ret) | ||
866 | return ret; | ||
867 | |||
835 | return 0; | 868 | return 0; |
836 | } | 869 | } |
837 | 870 | ||
838 | static int ath6kl_fetch_fw_api2(struct ath6kl *ar) | 871 | static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) |
839 | { | 872 | { |
840 | size_t magic_len, len, ie_len; | 873 | size_t magic_len, len, ie_len; |
841 | const struct firmware *fw; | 874 | const struct firmware *fw; |
842 | struct ath6kl_fw_ie *hdr; | 875 | struct ath6kl_fw_ie *hdr; |
843 | const char *filename; | 876 | char filename[100]; |
844 | const u8 *data; | 877 | const u8 *data; |
845 | int ret, ie_id, i, index, bit; | 878 | int ret, ie_id, i, index, bit; |
846 | __le32 *val; | 879 | __le32 *val; |
847 | 880 | ||
848 | if (ar->hw.fw_api2 == NULL) | 881 | snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name); |
849 | return -EOPNOTSUPP; | ||
850 | |||
851 | filename = ar->hw.fw_api2; | ||
852 | 882 | ||
853 | ret = request_firmware(&fw, filename, ar->dev); | 883 | ret = request_firmware(&fw, filename, ar->dev); |
854 | if (ret) | 884 | if (ret) |
@@ -907,6 +937,10 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar) | |||
907 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", | 937 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", |
908 | ie_len); | 938 | ie_len); |
909 | 939 | ||
940 | /* in testmode we already might have a fw file */ | ||
941 | if (ar->fw != NULL) | ||
942 | break; | ||
943 | |||
910 | ar->fw = kmemdup(data, ie_len, GFP_KERNEL); | 944 | ar->fw = kmemdup(data, ie_len, GFP_KERNEL); |
911 | 945 | ||
912 | if (ar->fw == NULL) { | 946 | if (ar->fw == NULL) { |
@@ -1010,7 +1044,7 @@ out: | |||
1010 | return ret; | 1044 | return ret; |
1011 | } | 1045 | } |
1012 | 1046 | ||
1013 | static int ath6kl_fetch_firmwares(struct ath6kl *ar) | 1047 | int ath6kl_init_fetch_firmwares(struct ath6kl *ar) |
1014 | { | 1048 | { |
1015 | int ret; | 1049 | int ret; |
1016 | 1050 | ||
@@ -1018,17 +1052,30 @@ static int ath6kl_fetch_firmwares(struct ath6kl *ar) | |||
1018 | if (ret) | 1052 | if (ret) |
1019 | return ret; | 1053 | return ret; |
1020 | 1054 | ||
1021 | ret = ath6kl_fetch_fw_api2(ar); | 1055 | ret = ath6kl_fetch_testmode_file(ar); |
1056 | if (ret) | ||
1057 | return ret; | ||
1058 | |||
1059 | ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); | ||
1022 | if (ret == 0) { | 1060 | if (ret == 0) { |
1023 | ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n"); | 1061 | ar->fw_api = 3; |
1024 | return 0; | 1062 | goto out; |
1063 | } | ||
1064 | |||
1065 | ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API2_FILE); | ||
1066 | if (ret == 0) { | ||
1067 | ar->fw_api = 2; | ||
1068 | goto out; | ||
1025 | } | 1069 | } |
1026 | 1070 | ||
1027 | ret = ath6kl_fetch_fw_api1(ar); | 1071 | ret = ath6kl_fetch_fw_api1(ar); |
1028 | if (ret) | 1072 | if (ret) |
1029 | return ret; | 1073 | return ret; |
1030 | 1074 | ||
1031 | ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n"); | 1075 | ar->fw_api = 1; |
1076 | |||
1077 | out: | ||
1078 | ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api %d\n", ar->fw_api); | ||
1032 | 1079 | ||
1033 | return 0; | 1080 | return 0; |
1034 | } | 1081 | } |
@@ -1249,6 +1296,50 @@ static int ath6kl_upload_patch(struct ath6kl *ar) | |||
1249 | return 0; | 1296 | return 0; |
1250 | } | 1297 | } |
1251 | 1298 | ||
1299 | static int ath6kl_upload_testscript(struct ath6kl *ar) | ||
1300 | { | ||
1301 | u32 address, param; | ||
1302 | int ret; | ||
1303 | |||
1304 | if (ar->testmode != 2) | ||
1305 | return 0; | ||
1306 | |||
1307 | if (ar->fw_testscript == NULL) | ||
1308 | return 0; | ||
1309 | |||
1310 | address = ar->hw.testscript_addr; | ||
1311 | |||
1312 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n", | ||
1313 | address, ar->fw_testscript_len); | ||
1314 | |||
1315 | ret = ath6kl_bmi_write(ar, address, ar->fw_testscript, | ||
1316 | ar->fw_testscript_len); | ||
1317 | if (ret) { | ||
1318 | ath6kl_err("Failed to write testscript file: %d\n", ret); | ||
1319 | return ret; | ||
1320 | } | ||
1321 | |||
1322 | param = address; | ||
1323 | ath6kl_bmi_write(ar, | ||
1324 | ath6kl_get_hi_item_addr(ar, | ||
1325 | HI_ITEM(hi_ota_testscript)), | ||
1326 | (unsigned char *) ¶m, 4); | ||
1327 | |||
1328 | param = 4096; | ||
1329 | ath6kl_bmi_write(ar, | ||
1330 | ath6kl_get_hi_item_addr(ar, | ||
1331 | HI_ITEM(hi_end_ram_reserve_sz)), | ||
1332 | (unsigned char *) ¶m, 4); | ||
1333 | |||
1334 | param = 1; | ||
1335 | ath6kl_bmi_write(ar, | ||
1336 | ath6kl_get_hi_item_addr(ar, | ||
1337 | HI_ITEM(hi_test_apps_related)), | ||
1338 | (unsigned char *) ¶m, 4); | ||
1339 | |||
1340 | return 0; | ||
1341 | } | ||
1342 | |||
1252 | static int ath6kl_init_upload(struct ath6kl *ar) | 1343 | static int ath6kl_init_upload(struct ath6kl *ar) |
1253 | { | 1344 | { |
1254 | u32 param, options, sleep, address; | 1345 | u32 param, options, sleep, address; |
@@ -1357,6 +1448,11 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
1357 | if (status) | 1448 | if (status) |
1358 | return status; | 1449 | return status; |
1359 | 1450 | ||
1451 | /* Download the test script */ | ||
1452 | status = ath6kl_upload_testscript(ar); | ||
1453 | if (status) | ||
1454 | return status; | ||
1455 | |||
1360 | /* Restore system sleep */ | 1456 | /* Restore system sleep */ |
1361 | address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; | 1457 | address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; |
1362 | status = ath6kl_bmi_reg_write(ar, address, sleep); | 1458 | status = ath6kl_bmi_reg_write(ar, address, sleep); |
@@ -1372,9 +1468,9 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
1372 | return status; | 1468 | return status; |
1373 | } | 1469 | } |
1374 | 1470 | ||
1375 | static int ath6kl_init_hw_params(struct ath6kl *ar) | 1471 | int ath6kl_init_hw_params(struct ath6kl *ar) |
1376 | { | 1472 | { |
1377 | const struct ath6kl_hw *hw; | 1473 | const struct ath6kl_hw *uninitialized_var(hw); |
1378 | int i; | 1474 | int i; |
1379 | 1475 | ||
1380 | for (i = 0; i < ARRAY_SIZE(hw_list); i++) { | 1476 | for (i = 0; i < ARRAY_SIZE(hw_list); i++) { |
@@ -1481,10 +1577,11 @@ int ath6kl_init_hw_start(struct ath6kl *ar) | |||
1481 | 1577 | ||
1482 | 1578 | ||
1483 | if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) { | 1579 | if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) { |
1484 | ath6kl_info("%s %s fw %s%s\n", | 1580 | ath6kl_info("%s %s fw %s api %d%s\n", |
1485 | ar->hw.name, | 1581 | ar->hw.name, |
1486 | ath6kl_init_get_hif_name(ar->hif_type), | 1582 | ath6kl_init_get_hif_name(ar->hif_type), |
1487 | ar->wiphy->fw_version, | 1583 | ar->wiphy->fw_version, |
1584 | ar->fw_api, | ||
1488 | test_bit(TESTMODE, &ar->flag) ? " testmode" : ""); | 1585 | test_bit(TESTMODE, &ar->flag) ? " testmode" : ""); |
1489 | } | 1586 | } |
1490 | 1587 | ||
@@ -1549,173 +1646,7 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) | |||
1549 | return 0; | 1646 | return 0; |
1550 | } | 1647 | } |
1551 | 1648 | ||
1552 | int ath6kl_core_init(struct ath6kl *ar) | 1649 | /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ |
1553 | { | ||
1554 | struct ath6kl_bmi_target_info targ_info; | ||
1555 | struct net_device *ndev; | ||
1556 | int ret = 0, i; | ||
1557 | |||
1558 | ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); | ||
1559 | if (!ar->ath6kl_wq) | ||
1560 | return -ENOMEM; | ||
1561 | |||
1562 | ret = ath6kl_bmi_init(ar); | ||
1563 | if (ret) | ||
1564 | goto err_wq; | ||
1565 | |||
1566 | /* | ||
1567 | * Turn on power to get hardware (target) version and leave power | ||
1568 | * on delibrately as we will boot the hardware anyway within few | ||
1569 | * seconds. | ||
1570 | */ | ||
1571 | ret = ath6kl_hif_power_on(ar); | ||
1572 | if (ret) | ||
1573 | goto err_bmi_cleanup; | ||
1574 | |||
1575 | ret = ath6kl_bmi_get_target_info(ar, &targ_info); | ||
1576 | if (ret) | ||
1577 | goto err_power_off; | ||
1578 | |||
1579 | ar->version.target_ver = le32_to_cpu(targ_info.version); | ||
1580 | ar->target_type = le32_to_cpu(targ_info.type); | ||
1581 | ar->wiphy->hw_version = le32_to_cpu(targ_info.version); | ||
1582 | |||
1583 | ret = ath6kl_init_hw_params(ar); | ||
1584 | if (ret) | ||
1585 | goto err_power_off; | ||
1586 | |||
1587 | ar->htc_target = ath6kl_htc_create(ar); | ||
1588 | |||
1589 | if (!ar->htc_target) { | ||
1590 | ret = -ENOMEM; | ||
1591 | goto err_power_off; | ||
1592 | } | ||
1593 | |||
1594 | ret = ath6kl_fetch_firmwares(ar); | ||
1595 | if (ret) | ||
1596 | goto err_htc_cleanup; | ||
1597 | |||
1598 | /* FIXME: we should free all firmwares in the error cases below */ | ||
1599 | |||
1600 | /* Indicate that WMI is enabled (although not ready yet) */ | ||
1601 | set_bit(WMI_ENABLED, &ar->flag); | ||
1602 | ar->wmi = ath6kl_wmi_init(ar); | ||
1603 | if (!ar->wmi) { | ||
1604 | ath6kl_err("failed to initialize wmi\n"); | ||
1605 | ret = -EIO; | ||
1606 | goto err_htc_cleanup; | ||
1607 | } | ||
1608 | |||
1609 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); | ||
1610 | |||
1611 | ret = ath6kl_register_ieee80211_hw(ar); | ||
1612 | if (ret) | ||
1613 | goto err_node_cleanup; | ||
1614 | |||
1615 | ret = ath6kl_debug_init(ar); | ||
1616 | if (ret) { | ||
1617 | wiphy_unregister(ar->wiphy); | ||
1618 | goto err_node_cleanup; | ||
1619 | } | ||
1620 | |||
1621 | for (i = 0; i < ar->vif_max; i++) | ||
1622 | ar->avail_idx_map |= BIT(i); | ||
1623 | |||
1624 | rtnl_lock(); | ||
1625 | |||
1626 | /* Add an initial station interface */ | ||
1627 | ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, | ||
1628 | INFRA_NETWORK); | ||
1629 | |||
1630 | rtnl_unlock(); | ||
1631 | |||
1632 | if (!ndev) { | ||
1633 | ath6kl_err("Failed to instantiate a network device\n"); | ||
1634 | ret = -ENOMEM; | ||
1635 | wiphy_unregister(ar->wiphy); | ||
1636 | goto err_debug_init; | ||
1637 | } | ||
1638 | |||
1639 | |||
1640 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", | ||
1641 | __func__, ndev->name, ndev, ar); | ||
1642 | |||
1643 | /* setup access class priority mappings */ | ||
1644 | ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ | ||
1645 | ar->ac_stream_pri_map[WMM_AC_BE] = 1; | ||
1646 | ar->ac_stream_pri_map[WMM_AC_VI] = 2; | ||
1647 | ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ | ||
1648 | |||
1649 | /* give our connected endpoints some buffers */ | ||
1650 | ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); | ||
1651 | ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); | ||
1652 | |||
1653 | /* allocate some buffers that handle larger AMSDU frames */ | ||
1654 | ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); | ||
1655 | |||
1656 | ath6kl_cookie_init(ar); | ||
1657 | |||
1658 | ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | | ||
1659 | ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; | ||
1660 | |||
1661 | if (suspend_cutpower) | ||
1662 | ar->conf_flags |= ATH6KL_CONF_SUSPEND_CUTPOWER; | ||
1663 | |||
1664 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | | ||
1665 | WIPHY_FLAG_HAVE_AP_SME | | ||
1666 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | | ||
1667 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | ||
1668 | |||
1669 | if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) | ||
1670 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | ||
1671 | |||
1672 | ar->wiphy->probe_resp_offload = | ||
1673 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | ||
1674 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | | ||
1675 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | | ||
1676 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; | ||
1677 | |||
1678 | set_bit(FIRST_BOOT, &ar->flag); | ||
1679 | |||
1680 | ret = ath6kl_init_hw_start(ar); | ||
1681 | if (ret) { | ||
1682 | ath6kl_err("Failed to start hardware: %d\n", ret); | ||
1683 | goto err_rxbuf_cleanup; | ||
1684 | } | ||
1685 | |||
1686 | /* | ||
1687 | * Set mac address which is received in ready event | ||
1688 | * FIXME: Move to ath6kl_interface_add() | ||
1689 | */ | ||
1690 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); | ||
1691 | |||
1692 | return ret; | ||
1693 | |||
1694 | err_rxbuf_cleanup: | ||
1695 | ath6kl_htc_flush_rx_buf(ar->htc_target); | ||
1696 | ath6kl_cleanup_amsdu_rxbufs(ar); | ||
1697 | rtnl_lock(); | ||
1698 | ath6kl_deinit_if_data(netdev_priv(ndev)); | ||
1699 | rtnl_unlock(); | ||
1700 | wiphy_unregister(ar->wiphy); | ||
1701 | err_debug_init: | ||
1702 | ath6kl_debug_cleanup(ar); | ||
1703 | err_node_cleanup: | ||
1704 | ath6kl_wmi_shutdown(ar->wmi); | ||
1705 | clear_bit(WMI_ENABLED, &ar->flag); | ||
1706 | ar->wmi = NULL; | ||
1707 | err_htc_cleanup: | ||
1708 | ath6kl_htc_cleanup(ar->htc_target); | ||
1709 | err_power_off: | ||
1710 | ath6kl_hif_power_off(ar); | ||
1711 | err_bmi_cleanup: | ||
1712 | ath6kl_bmi_cleanup(ar); | ||
1713 | err_wq: | ||
1714 | destroy_workqueue(ar->ath6kl_wq); | ||
1715 | |||
1716 | return ret; | ||
1717 | } | ||
1718 | |||
1719 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) | 1650 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) |
1720 | { | 1651 | { |
1721 | static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 1652 | static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
@@ -1747,6 +1678,7 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) | |||
1747 | void ath6kl_stop_txrx(struct ath6kl *ar) | 1678 | void ath6kl_stop_txrx(struct ath6kl *ar) |
1748 | { | 1679 | { |
1749 | struct ath6kl_vif *vif, *tmp_vif; | 1680 | struct ath6kl_vif *vif, *tmp_vif; |
1681 | int i; | ||
1750 | 1682 | ||
1751 | set_bit(DESTROY_IN_PROGRESS, &ar->flag); | 1683 | set_bit(DESTROY_IN_PROGRESS, &ar->flag); |
1752 | 1684 | ||
@@ -1755,13 +1687,16 @@ void ath6kl_stop_txrx(struct ath6kl *ar) | |||
1755 | return; | 1687 | return; |
1756 | } | 1688 | } |
1757 | 1689 | ||
1690 | for (i = 0; i < AP_MAX_NUM_STA; i++) | ||
1691 | aggr_reset_state(ar->sta_list[i].aggr_conn); | ||
1692 | |||
1758 | spin_lock_bh(&ar->list_lock); | 1693 | spin_lock_bh(&ar->list_lock); |
1759 | list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) { | 1694 | list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) { |
1760 | list_del(&vif->list); | 1695 | list_del(&vif->list); |
1761 | spin_unlock_bh(&ar->list_lock); | 1696 | spin_unlock_bh(&ar->list_lock); |
1762 | ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); | 1697 | ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); |
1763 | rtnl_lock(); | 1698 | rtnl_lock(); |
1764 | ath6kl_deinit_if_data(vif); | 1699 | ath6kl_cfg80211_vif_cleanup(vif); |
1765 | rtnl_unlock(); | 1700 | rtnl_unlock(); |
1766 | spin_lock_bh(&ar->list_lock); | 1701 | spin_lock_bh(&ar->list_lock); |
1767 | } | 1702 | } |
@@ -1796,3 +1731,4 @@ void ath6kl_stop_txrx(struct ath6kl *ar) | |||
1796 | 1731 | ||
1797 | clear_bit(WLAN_ENABLED, &ar->flag); | 1732 | clear_bit(WLAN_ENABLED, &ar->flag); |
1798 | } | 1733 | } |
1734 | EXPORT_SYMBOL(ath6kl_stop_txrx); | ||
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index eea3c747653e..b96d01a7919b 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c | |||
@@ -52,9 +52,11 @@ struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid) | |||
52 | return conn; | 52 | return conn; |
53 | } | 53 | } |
54 | 54 | ||
55 | static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie, | 55 | static void ath6kl_add_new_sta(struct ath6kl_vif *vif, u8 *mac, u16 aid, |
56 | u8 ielen, u8 keymgmt, u8 ucipher, u8 auth) | 56 | u8 *wpaie, size_t ielen, u8 keymgmt, |
57 | u8 ucipher, u8 auth, u8 apsd_info) | ||
57 | { | 58 | { |
59 | struct ath6kl *ar = vif->ar; | ||
58 | struct ath6kl_sta *sta; | 60 | struct ath6kl_sta *sta; |
59 | u8 free_slot; | 61 | u8 free_slot; |
60 | 62 | ||
@@ -68,9 +70,11 @@ static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie, | |||
68 | sta->keymgmt = keymgmt; | 70 | sta->keymgmt = keymgmt; |
69 | sta->ucipher = ucipher; | 71 | sta->ucipher = ucipher; |
70 | sta->auth = auth; | 72 | sta->auth = auth; |
73 | sta->apsd_info = apsd_info; | ||
71 | 74 | ||
72 | ar->sta_list_index = ar->sta_list_index | (1 << free_slot); | 75 | ar->sta_list_index = ar->sta_list_index | (1 << free_slot); |
73 | ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid); | 76 | ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid); |
77 | aggr_conn_init(vif, vif->aggr_cntxt, sta->aggr_conn); | ||
74 | } | 78 | } |
75 | 79 | ||
76 | static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) | 80 | static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) |
@@ -80,6 +84,7 @@ static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) | |||
80 | /* empty the queued pkts in the PS queue if any */ | 84 | /* empty the queued pkts in the PS queue if any */ |
81 | spin_lock_bh(&sta->psq_lock); | 85 | spin_lock_bh(&sta->psq_lock); |
82 | skb_queue_purge(&sta->psq); | 86 | skb_queue_purge(&sta->psq); |
87 | skb_queue_purge(&sta->apsdq); | ||
83 | spin_unlock_bh(&sta->psq_lock); | 88 | spin_unlock_bh(&sta->psq_lock); |
84 | 89 | ||
85 | memset(&ar->ap_stats.sta[sta->aid - 1], 0, | 90 | memset(&ar->ap_stats.sta[sta->aid - 1], 0, |
@@ -90,7 +95,7 @@ static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) | |||
90 | sta->sta_flags = 0; | 95 | sta->sta_flags = 0; |
91 | 96 | ||
92 | ar->sta_list_index = ar->sta_list_index & ~(1 << i); | 97 | ar->sta_list_index = ar->sta_list_index & ~(1 << i); |
93 | 98 | aggr_reset_state(sta->aggr_conn); | |
94 | } | 99 | } |
95 | 100 | ||
96 | static u8 ath6kl_remove_sta(struct ath6kl *ar, u8 *mac, u16 reason) | 101 | static u8 ath6kl_remove_sta(struct ath6kl *ar, u8 *mac, u16 reason) |
@@ -252,7 +257,7 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) | |||
252 | struct ath6kl_dbglog_hdr debug_hdr; | 257 | struct ath6kl_dbglog_hdr debug_hdr; |
253 | struct ath6kl_dbglog_buf debug_buf; | 258 | struct ath6kl_dbglog_buf debug_buf; |
254 | u32 address, length, dropped, firstbuf, debug_hdr_addr; | 259 | u32 address, length, dropped, firstbuf, debug_hdr_addr; |
255 | int ret = 0, loop; | 260 | int ret, loop; |
256 | u8 *buf; | 261 | u8 *buf; |
257 | 262 | ||
258 | buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL); | 263 | buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL); |
@@ -347,9 +352,6 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, | |||
347 | case TARGET_TYPE_AR6004: | 352 | case TARGET_TYPE_AR6004: |
348 | address = AR6004_RESET_CONTROL_ADDRESS; | 353 | address = AR6004_RESET_CONTROL_ADDRESS; |
349 | break; | 354 | break; |
350 | default: | ||
351 | address = AR6003_RESET_CONTROL_ADDRESS; | ||
352 | break; | ||
353 | } | 355 | } |
354 | 356 | ||
355 | status = ath6kl_diag_write32(ar, address, data); | 357 | status = ath6kl_diag_write32(ar, address, data); |
@@ -363,7 +365,7 @@ static void ath6kl_install_static_wep_keys(struct ath6kl_vif *vif) | |||
363 | u8 index; | 365 | u8 index; |
364 | u8 keyusage; | 366 | u8 keyusage; |
365 | 367 | ||
366 | for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) { | 368 | for (index = 0; index <= WMI_MAX_KEY_INDEX; index++) { |
367 | if (vif->wep_key_list[index].key_len) { | 369 | if (vif->wep_key_list[index].key_len) { |
368 | keyusage = GROUP_USAGE; | 370 | keyusage = GROUP_USAGE; |
369 | if (index == vif->def_txkey_index) | 371 | if (index == vif->def_txkey_index) |
@@ -428,9 +430,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) | |||
428 | 430 | ||
429 | void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, | 431 | void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, |
430 | u8 keymgmt, u8 ucipher, u8 auth, | 432 | u8 keymgmt, u8 ucipher, u8 auth, |
431 | u8 assoc_req_len, u8 *assoc_info) | 433 | u8 assoc_req_len, u8 *assoc_info, u8 apsd_info) |
432 | { | 434 | { |
433 | struct ath6kl *ar = vif->ar; | ||
434 | u8 *ies = NULL, *wpa_ie = NULL, *pos; | 435 | u8 *ies = NULL, *wpa_ie = NULL, *pos; |
435 | size_t ies_len = 0; | 436 | size_t ies_len = 0; |
436 | struct station_info sinfo; | 437 | struct station_info sinfo; |
@@ -484,9 +485,9 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, | |||
484 | pos += 2 + pos[1]; | 485 | pos += 2 + pos[1]; |
485 | } | 486 | } |
486 | 487 | ||
487 | ath6kl_add_new_sta(ar, mac_addr, aid, wpa_ie, | 488 | ath6kl_add_new_sta(vif, mac_addr, aid, wpa_ie, |
488 | wpa_ie ? 2 + wpa_ie[1] : 0, | 489 | wpa_ie ? 2 + wpa_ie[1] : 0, |
489 | keymgmt, ucipher, auth); | 490 | keymgmt, ucipher, auth, apsd_info); |
490 | 491 | ||
491 | /* send event to application */ | 492 | /* send event to application */ |
492 | memset(&sinfo, 0, sizeof(sinfo)); | 493 | memset(&sinfo, 0, sizeof(sinfo)); |
@@ -587,10 +588,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, | |||
587 | memcpy(vif->bssid, bssid, sizeof(vif->bssid)); | 588 | memcpy(vif->bssid, bssid, sizeof(vif->bssid)); |
588 | vif->bss_ch = channel; | 589 | vif->bss_ch = channel; |
589 | 590 | ||
590 | if ((vif->nw_type == INFRA_NETWORK)) | 591 | if ((vif->nw_type == INFRA_NETWORK)) { |
592 | ar->listen_intvl_b = listen_int; | ||
591 | ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, | 593 | ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, |
592 | ar->listen_intvl_t, | 594 | 0, ar->listen_intvl_b); |
593 | ar->listen_intvl_b); | 595 | } |
594 | 596 | ||
595 | netif_wake_queue(vif->ndev); | 597 | netif_wake_queue(vif->ndev); |
596 | 598 | ||
@@ -601,7 +603,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, | |||
601 | netif_carrier_on(vif->ndev); | 603 | netif_carrier_on(vif->ndev); |
602 | spin_unlock_bh(&vif->if_lock); | 604 | spin_unlock_bh(&vif->if_lock); |
603 | 605 | ||
604 | aggr_reset_state(vif->aggr_cntxt); | 606 | aggr_reset_state(vif->aggr_cntxt->aggr_conn); |
605 | vif->reconnect_flag = 0; | 607 | vif->reconnect_flag = 0; |
606 | 608 | ||
607 | if ((vif->nw_type == ADHOC_NETWORK) && ar->ibss_ps_enable) { | 609 | if ((vif->nw_type == ADHOC_NETWORK) && ar->ibss_ps_enable) { |
@@ -923,7 +925,7 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, | |||
923 | assoc_resp_len, assoc_info, | 925 | assoc_resp_len, assoc_info, |
924 | prot_reason_status); | 926 | prot_reason_status); |
925 | 927 | ||
926 | aggr_reset_state(vif->aggr_cntxt); | 928 | aggr_reset_state(vif->aggr_cntxt->aggr_conn); |
927 | 929 | ||
928 | del_timer(&vif->disconnect_timer); | 930 | del_timer(&vif->disconnect_timer); |
929 | 931 | ||
@@ -1020,11 +1022,155 @@ static struct net_device_stats *ath6kl_get_stats(struct net_device *dev) | |||
1020 | return &vif->net_stats; | 1022 | return &vif->net_stats; |
1021 | } | 1023 | } |
1022 | 1024 | ||
1023 | static struct net_device_ops ath6kl_netdev_ops = { | 1025 | static int ath6kl_set_features(struct net_device *dev, |
1026 | netdev_features_t features) | ||
1027 | { | ||
1028 | struct ath6kl_vif *vif = netdev_priv(dev); | ||
1029 | struct ath6kl *ar = vif->ar; | ||
1030 | int err = 0; | ||
1031 | |||
1032 | if ((features & NETIF_F_RXCSUM) && | ||
1033 | (ar->rx_meta_ver != WMI_META_VERSION_2)) { | ||
1034 | ar->rx_meta_ver = WMI_META_VERSION_2; | ||
1035 | err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, | ||
1036 | vif->fw_vif_idx, | ||
1037 | ar->rx_meta_ver, 0, 0); | ||
1038 | if (err) { | ||
1039 | dev->features = features & ~NETIF_F_RXCSUM; | ||
1040 | return err; | ||
1041 | } | ||
1042 | } else if (!(features & NETIF_F_RXCSUM) && | ||
1043 | (ar->rx_meta_ver == WMI_META_VERSION_2)) { | ||
1044 | ar->rx_meta_ver = 0; | ||
1045 | err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, | ||
1046 | vif->fw_vif_idx, | ||
1047 | ar->rx_meta_ver, 0, 0); | ||
1048 | if (err) { | ||
1049 | dev->features = features | NETIF_F_RXCSUM; | ||
1050 | return err; | ||
1051 | } | ||
1052 | |||
1053 | } | ||
1054 | |||
1055 | return err; | ||
1056 | } | ||
1057 | |||
1058 | static void ath6kl_set_multicast_list(struct net_device *ndev) | ||
1059 | { | ||
1060 | struct ath6kl_vif *vif = netdev_priv(ndev); | ||
1061 | bool mc_all_on = false, mc_all_off = false; | ||
1062 | int mc_count = netdev_mc_count(ndev); | ||
1063 | struct netdev_hw_addr *ha; | ||
1064 | bool found; | ||
1065 | struct ath6kl_mc_filter *mc_filter, *tmp; | ||
1066 | struct list_head mc_filter_new; | ||
1067 | int ret; | ||
1068 | |||
1069 | if (!test_bit(WMI_READY, &vif->ar->flag) || | ||
1070 | !test_bit(WLAN_ENABLED, &vif->flags)) | ||
1071 | return; | ||
1072 | |||
1073 | mc_all_on = !!(ndev->flags & IFF_PROMISC) || | ||
1074 | !!(ndev->flags & IFF_ALLMULTI) || | ||
1075 | !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST); | ||
1076 | |||
1077 | mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0; | ||
1078 | |||
1079 | if (mc_all_on || mc_all_off) { | ||
1080 | /* Enable/disable all multicast */ | ||
1081 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", | ||
1082 | mc_all_on ? "enabling" : "disabling"); | ||
1083 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, | ||
1084 | mc_all_on); | ||
1085 | if (ret) | ||
1086 | ath6kl_warn("Failed to %s multicast receive\n", | ||
1087 | mc_all_on ? "enable" : "disable"); | ||
1088 | return; | ||
1089 | } | ||
1090 | |||
1091 | list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { | ||
1092 | found = false; | ||
1093 | netdev_for_each_mc_addr(ha, ndev) { | ||
1094 | if (memcmp(ha->addr, mc_filter->hw_addr, | ||
1095 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { | ||
1096 | found = true; | ||
1097 | break; | ||
1098 | } | ||
1099 | } | ||
1100 | |||
1101 | if (!found) { | ||
1102 | /* | ||
1103 | * Delete the filter which was previously set | ||
1104 | * but not in the new request. | ||
1105 | */ | ||
1106 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
1107 | "Removing %pM from multicast filter\n", | ||
1108 | mc_filter->hw_addr); | ||
1109 | ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi, | ||
1110 | vif->fw_vif_idx, mc_filter->hw_addr, | ||
1111 | false); | ||
1112 | if (ret) { | ||
1113 | ath6kl_warn("Failed to remove multicast filter:%pM\n", | ||
1114 | mc_filter->hw_addr); | ||
1115 | return; | ||
1116 | } | ||
1117 | |||
1118 | list_del(&mc_filter->list); | ||
1119 | kfree(mc_filter); | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | INIT_LIST_HEAD(&mc_filter_new); | ||
1124 | |||
1125 | netdev_for_each_mc_addr(ha, ndev) { | ||
1126 | found = false; | ||
1127 | list_for_each_entry(mc_filter, &vif->mc_filter, list) { | ||
1128 | if (memcmp(ha->addr, mc_filter->hw_addr, | ||
1129 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { | ||
1130 | found = true; | ||
1131 | break; | ||
1132 | } | ||
1133 | } | ||
1134 | |||
1135 | if (!found) { | ||
1136 | mc_filter = kzalloc(sizeof(struct ath6kl_mc_filter), | ||
1137 | GFP_ATOMIC); | ||
1138 | if (!mc_filter) { | ||
1139 | WARN_ON(1); | ||
1140 | goto out; | ||
1141 | } | ||
1142 | |||
1143 | memcpy(mc_filter->hw_addr, ha->addr, | ||
1144 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE); | ||
1145 | /* Set the multicast filter */ | ||
1146 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
1147 | "Adding %pM to multicast filter list\n", | ||
1148 | mc_filter->hw_addr); | ||
1149 | ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi, | ||
1150 | vif->fw_vif_idx, mc_filter->hw_addr, | ||
1151 | true); | ||
1152 | if (ret) { | ||
1153 | ath6kl_warn("Failed to add multicast filter :%pM\n", | ||
1154 | mc_filter->hw_addr); | ||
1155 | kfree(mc_filter); | ||
1156 | goto out; | ||
1157 | } | ||
1158 | |||
1159 | list_add_tail(&mc_filter->list, &mc_filter_new); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | out: | ||
1164 | list_splice_tail(&mc_filter_new, &vif->mc_filter); | ||
1165 | } | ||
1166 | |||
1167 | static const struct net_device_ops ath6kl_netdev_ops = { | ||
1024 | .ndo_open = ath6kl_open, | 1168 | .ndo_open = ath6kl_open, |
1025 | .ndo_stop = ath6kl_close, | 1169 | .ndo_stop = ath6kl_close, |
1026 | .ndo_start_xmit = ath6kl_data_tx, | 1170 | .ndo_start_xmit = ath6kl_data_tx, |
1027 | .ndo_get_stats = ath6kl_get_stats, | 1171 | .ndo_get_stats = ath6kl_get_stats, |
1172 | .ndo_set_features = ath6kl_set_features, | ||
1173 | .ndo_set_rx_mode = ath6kl_set_multicast_list, | ||
1028 | }; | 1174 | }; |
1029 | 1175 | ||
1030 | void init_netdev(struct net_device *dev) | 1176 | void init_netdev(struct net_device *dev) |
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 9475e2d0d0b7..4febee723495 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c | |||
@@ -49,11 +49,13 @@ struct ath6kl_sdio { | |||
49 | /* scatter request list head */ | 49 | /* scatter request list head */ |
50 | struct list_head scat_req; | 50 | struct list_head scat_req; |
51 | 51 | ||
52 | /* Avoids disabling irq while the interrupts being handled */ | ||
53 | struct mutex mtx_irq; | ||
54 | |||
52 | spinlock_t scat_lock; | 55 | spinlock_t scat_lock; |
53 | bool scatter_enabled; | 56 | bool scatter_enabled; |
54 | 57 | ||
55 | bool is_disabled; | 58 | bool is_disabled; |
56 | atomic_t irq_handling; | ||
57 | const struct sdio_device_id *id; | 59 | const struct sdio_device_id *id; |
58 | struct work_struct wr_async_work; | 60 | struct work_struct wr_async_work; |
59 | struct list_head wr_asyncq; | 61 | struct list_head wr_asyncq; |
@@ -460,8 +462,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) | |||
460 | ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); | 462 | ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); |
461 | 463 | ||
462 | ar_sdio = sdio_get_drvdata(func); | 464 | ar_sdio = sdio_get_drvdata(func); |
463 | atomic_set(&ar_sdio->irq_handling, 1); | 465 | mutex_lock(&ar_sdio->mtx_irq); |
464 | |||
465 | /* | 466 | /* |
466 | * Release the host during interrups so we can pick it back up when | 467 | * Release the host during interrups so we can pick it back up when |
467 | * we process commands. | 468 | * we process commands. |
@@ -470,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) | |||
470 | 471 | ||
471 | status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); | 472 | status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); |
472 | sdio_claim_host(ar_sdio->func); | 473 | sdio_claim_host(ar_sdio->func); |
473 | atomic_set(&ar_sdio->irq_handling, 0); | 474 | mutex_unlock(&ar_sdio->mtx_irq); |
474 | WARN_ON(status && status != -ECANCELED); | 475 | WARN_ON(status && status != -ECANCELED); |
475 | } | 476 | } |
476 | 477 | ||
@@ -578,17 +579,14 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar) | |||
578 | 579 | ||
579 | sdio_claim_host(ar_sdio->func); | 580 | sdio_claim_host(ar_sdio->func); |
580 | 581 | ||
581 | /* Mask our function IRQ */ | 582 | mutex_lock(&ar_sdio->mtx_irq); |
582 | while (atomic_read(&ar_sdio->irq_handling)) { | ||
583 | sdio_release_host(ar_sdio->func); | ||
584 | schedule_timeout(HZ / 10); | ||
585 | sdio_claim_host(ar_sdio->func); | ||
586 | } | ||
587 | 583 | ||
588 | ret = sdio_release_irq(ar_sdio->func); | 584 | ret = sdio_release_irq(ar_sdio->func); |
589 | if (ret) | 585 | if (ret) |
590 | ath6kl_err("Failed to release sdio irq: %d\n", ret); | 586 | ath6kl_err("Failed to release sdio irq: %d\n", ret); |
591 | 587 | ||
588 | mutex_unlock(&ar_sdio->mtx_irq); | ||
589 | |||
592 | sdio_release_host(ar_sdio->func); | 590 | sdio_release_host(ar_sdio->func); |
593 | } | 591 | } |
594 | 592 | ||
@@ -772,7 +770,6 @@ static int ath6kl_sdio_config(struct ath6kl *ar) | |||
772 | if (ret) { | 770 | if (ret) { |
773 | ath6kl_err("Set sdio block size %d failed: %d)\n", | 771 | ath6kl_err("Set sdio block size %d failed: %d)\n", |
774 | HIF_MBOX_BLOCK_SIZE, ret); | 772 | HIF_MBOX_BLOCK_SIZE, ret); |
775 | sdio_release_host(func); | ||
776 | goto out; | 773 | goto out; |
777 | } | 774 | } |
778 | 775 | ||
@@ -782,7 +779,7 @@ out: | |||
782 | return ret; | 779 | return ret; |
783 | } | 780 | } |
784 | 781 | ||
785 | static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | 782 | static int ath6kl_set_sdio_pm_caps(struct ath6kl *ar) |
786 | { | 783 | { |
787 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | 784 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); |
788 | struct sdio_func *func = ar_sdio->func; | 785 | struct sdio_func *func = ar_sdio->func; |
@@ -793,60 +790,95 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
793 | 790 | ||
794 | ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags); | 791 | ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags); |
795 | 792 | ||
796 | if (!(flags & MMC_PM_KEEP_POWER) || | 793 | if (!(flags & MMC_PM_WAKE_SDIO_IRQ) || |
797 | (ar->conf_flags & ATH6KL_CONF_SUSPEND_CUTPOWER)) { | 794 | !(flags & MMC_PM_KEEP_POWER)) |
798 | /* as host doesn't support keep power we need to cut power */ | 795 | return -EINVAL; |
799 | return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, | ||
800 | NULL); | ||
801 | } | ||
802 | 796 | ||
803 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); | 797 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); |
804 | if (ret) { | 798 | if (ret) { |
805 | printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n", | 799 | ath6kl_err("set sdio keep pwr flag failed: %d\n", ret); |
806 | ret); | ||
807 | return ret; | 800 | return ret; |
808 | } | 801 | } |
809 | 802 | ||
810 | if (!(flags & MMC_PM_WAKE_SDIO_IRQ)) | ||
811 | goto deepsleep; | ||
812 | |||
813 | /* sdio irq wakes up host */ | 803 | /* sdio irq wakes up host */ |
804 | ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); | ||
805 | if (ret) | ||
806 | ath6kl_err("set sdio wake irq flag failed: %d\n", ret); | ||
807 | |||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | ||
812 | { | ||
813 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
814 | struct sdio_func *func = ar_sdio->func; | ||
815 | mmc_pm_flag_t flags; | ||
816 | int ret; | ||
814 | 817 | ||
815 | if (ar->state == ATH6KL_STATE_SCHED_SCAN) { | 818 | if (ar->state == ATH6KL_STATE_SCHED_SCAN) { |
819 | ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n"); | ||
820 | |||
821 | ret = ath6kl_set_sdio_pm_caps(ar); | ||
822 | if (ret) | ||
823 | goto cut_pwr; | ||
824 | |||
816 | ret = ath6kl_cfg80211_suspend(ar, | 825 | ret = ath6kl_cfg80211_suspend(ar, |
817 | ATH6KL_CFG_SUSPEND_SCHED_SCAN, | 826 | ATH6KL_CFG_SUSPEND_SCHED_SCAN, |
818 | NULL); | 827 | NULL); |
819 | if (ret) { | 828 | if (ret) |
820 | ath6kl_warn("Schedule scan suspend failed: %d", ret); | 829 | goto cut_pwr; |
821 | return ret; | 830 | |
822 | } | 831 | return 0; |
832 | } | ||
833 | |||
834 | if (ar->suspend_mode == WLAN_POWER_STATE_WOW || | ||
835 | (!ar->suspend_mode && wow)) { | ||
823 | 836 | ||
824 | ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); | 837 | ret = ath6kl_set_sdio_pm_caps(ar); |
825 | if (ret) | 838 | if (ret) |
826 | ath6kl_warn("set sdio wake irq flag failed: %d\n", ret); | 839 | goto cut_pwr; |
827 | 840 | ||
828 | return ret; | 841 | ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); |
842 | if (ret) | ||
843 | goto cut_pwr; | ||
844 | |||
845 | return 0; | ||
829 | } | 846 | } |
830 | 847 | ||
831 | if (wow) { | 848 | if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP || |
849 | !ar->suspend_mode) { | ||
850 | |||
851 | flags = sdio_get_host_pm_caps(func); | ||
852 | if (!(flags & MMC_PM_KEEP_POWER)) | ||
853 | goto cut_pwr; | ||
854 | |||
855 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); | ||
856 | if (ret) | ||
857 | goto cut_pwr; | ||
858 | |||
832 | /* | 859 | /* |
833 | * The host sdio controller is capable of keep power and | 860 | * Workaround to support Deep Sleep with MSM, set the host pm |
834 | * sdio irq wake up at this point. It's fine to continue | 861 | * flag as MMC_PM_WAKE_SDIO_IRQ to allow SDCC deiver to disable |
835 | * wow suspend operation. | 862 | * the sdc2_clock and internally allows MSM to enter |
863 | * TCXO shutdown properly. | ||
836 | */ | 864 | */ |
837 | ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); | 865 | if ((flags & MMC_PM_WAKE_SDIO_IRQ)) { |
838 | if (ret) | 866 | ret = sdio_set_host_pm_flags(func, |
839 | return ret; | 867 | MMC_PM_WAKE_SDIO_IRQ); |
868 | if (ret) | ||
869 | goto cut_pwr; | ||
870 | } | ||
840 | 871 | ||
841 | ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); | 872 | ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, |
873 | NULL); | ||
842 | if (ret) | 874 | if (ret) |
843 | ath6kl_err("set sdio wake irq flag failed: %d\n", ret); | 875 | goto cut_pwr; |
844 | 876 | ||
845 | return ret; | 877 | return 0; |
846 | } | 878 | } |
847 | 879 | ||
848 | deepsleep: | 880 | cut_pwr: |
849 | return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL); | 881 | return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL); |
850 | } | 882 | } |
851 | 883 | ||
852 | static int ath6kl_sdio_resume(struct ath6kl *ar) | 884 | static int ath6kl_sdio_resume(struct ath6kl *ar) |
@@ -1253,6 +1285,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func, | |||
1253 | spin_lock_init(&ar_sdio->scat_lock); | 1285 | spin_lock_init(&ar_sdio->scat_lock); |
1254 | spin_lock_init(&ar_sdio->wr_async_lock); | 1286 | spin_lock_init(&ar_sdio->wr_async_lock); |
1255 | mutex_init(&ar_sdio->dma_buffer_mutex); | 1287 | mutex_init(&ar_sdio->dma_buffer_mutex); |
1288 | mutex_init(&ar_sdio->mtx_irq); | ||
1256 | 1289 | ||
1257 | INIT_LIST_HEAD(&ar_sdio->scat_req); | 1290 | INIT_LIST_HEAD(&ar_sdio->scat_req); |
1258 | INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); | 1291 | INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); |
@@ -1263,7 +1296,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func, | |||
1263 | for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) | 1296 | for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) |
1264 | ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); | 1297 | ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); |
1265 | 1298 | ||
1266 | ar = ath6kl_core_alloc(&ar_sdio->func->dev); | 1299 | ar = ath6kl_core_create(&ar_sdio->func->dev); |
1267 | if (!ar) { | 1300 | if (!ar) { |
1268 | ath6kl_err("Failed to alloc ath6kl core\n"); | 1301 | ath6kl_err("Failed to alloc ath6kl core\n"); |
1269 | ret = -ENOMEM; | 1302 | ret = -ENOMEM; |
@@ -1293,7 +1326,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func, | |||
1293 | return ret; | 1326 | return ret; |
1294 | 1327 | ||
1295 | err_core_alloc: | 1328 | err_core_alloc: |
1296 | ath6kl_core_free(ar_sdio->ar); | 1329 | ath6kl_core_destroy(ar_sdio->ar); |
1297 | err_dma: | 1330 | err_dma: |
1298 | kfree(ar_sdio->dma_buffer); | 1331 | kfree(ar_sdio->dma_buffer); |
1299 | err_hif: | 1332 | err_hif: |
@@ -1316,6 +1349,7 @@ static void ath6kl_sdio_remove(struct sdio_func *func) | |||
1316 | cancel_work_sync(&ar_sdio->wr_async_work); | 1349 | cancel_work_sync(&ar_sdio->wr_async_work); |
1317 | 1350 | ||
1318 | ath6kl_core_cleanup(ar_sdio->ar); | 1351 | ath6kl_core_cleanup(ar_sdio->ar); |
1352 | ath6kl_core_destroy(ar_sdio->ar); | ||
1319 | 1353 | ||
1320 | kfree(ar_sdio->dma_buffer); | 1354 | kfree(ar_sdio->dma_buffer); |
1321 | kfree(ar_sdio); | 1355 | kfree(ar_sdio); |
@@ -1332,7 +1366,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = { | |||
1332 | MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices); | 1366 | MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices); |
1333 | 1367 | ||
1334 | static struct sdio_driver ath6kl_sdio_driver = { | 1368 | static struct sdio_driver ath6kl_sdio_driver = { |
1335 | .name = "ath6kl", | 1369 | .name = "ath6kl_sdio", |
1336 | .id_table = ath6kl_sdio_devices, | 1370 | .id_table = ath6kl_sdio_devices, |
1337 | .probe = ath6kl_sdio_probe, | 1371 | .probe = ath6kl_sdio_probe, |
1338 | .remove = ath6kl_sdio_remove, | 1372 | .remove = ath6kl_sdio_remove, |
@@ -1362,19 +1396,19 @@ MODULE_AUTHOR("Atheros Communications, Inc."); | |||
1362 | MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices"); | 1396 | MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices"); |
1363 | MODULE_LICENSE("Dual BSD/GPL"); | 1397 | MODULE_LICENSE("Dual BSD/GPL"); |
1364 | 1398 | ||
1365 | MODULE_FIRMWARE(AR6003_HW_2_0_OTP_FILE); | 1399 | MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_OTP_FILE); |
1366 | MODULE_FIRMWARE(AR6003_HW_2_0_FIRMWARE_FILE); | 1400 | MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_FIRMWARE_FILE); |
1367 | MODULE_FIRMWARE(AR6003_HW_2_0_PATCH_FILE); | 1401 | MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_PATCH_FILE); |
1368 | MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE); | 1402 | MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE); |
1369 | MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE); | 1403 | MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE); |
1370 | MODULE_FIRMWARE(AR6003_HW_2_1_1_OTP_FILE); | 1404 | MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_OTP_FILE); |
1371 | MODULE_FIRMWARE(AR6003_HW_2_1_1_FIRMWARE_FILE); | 1405 | MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_FIRMWARE_FILE); |
1372 | MODULE_FIRMWARE(AR6003_HW_2_1_1_PATCH_FILE); | 1406 | MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_PATCH_FILE); |
1373 | MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE); | 1407 | MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE); |
1374 | MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE); | 1408 | MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE); |
1375 | MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE); | 1409 | MODULE_FIRMWARE(AR6004_HW_1_0_FW_DIR "/" AR6004_HW_1_0_FIRMWARE_FILE); |
1376 | MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE); | 1410 | MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE); |
1377 | MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); | 1411 | MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); |
1378 | MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE); | 1412 | MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE); |
1379 | MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); | 1413 | MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); |
1380 | MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); | 1414 | MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); |
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c index 381eb66a605f..f0cd61d6188a 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.c +++ b/drivers/net/wireless/ath/ath6kl/testmode.c | |||
@@ -15,6 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "testmode.h" | 17 | #include "testmode.h" |
18 | #include "debug.h" | ||
18 | 19 | ||
19 | #include <net/netlink.h> | 20 | #include <net/netlink.h> |
20 | 21 | ||
@@ -30,7 +31,7 @@ enum ath6kl_tm_attr { | |||
30 | 31 | ||
31 | enum ath6kl_tm_cmd { | 32 | enum ath6kl_tm_cmd { |
32 | ATH6KL_TM_CMD_TCMD = 0, | 33 | ATH6KL_TM_CMD_TCMD = 0, |
33 | ATH6KL_TM_CMD_RX_REPORT = 1, | 34 | ATH6KL_TM_CMD_RX_REPORT = 1, /* not used anymore */ |
34 | }; | 35 | }; |
35 | 36 | ||
36 | #define ATH6KL_TM_DATA_MAX_LEN 5000 | 37 | #define ATH6KL_TM_DATA_MAX_LEN 5000 |
@@ -41,84 +42,33 @@ static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = { | |||
41 | .len = ATH6KL_TM_DATA_MAX_LEN }, | 42 | .len = ATH6KL_TM_DATA_MAX_LEN }, |
42 | }; | 43 | }; |
43 | 44 | ||
44 | void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len) | 45 | void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len) |
45 | { | 46 | { |
46 | if (down_interruptible(&ar->sem)) | 47 | struct sk_buff *skb; |
47 | return; | ||
48 | |||
49 | kfree(ar->tm.rx_report); | ||
50 | |||
51 | ar->tm.rx_report = kmemdup(buf, buf_len, GFP_KERNEL); | ||
52 | ar->tm.rx_report_len = buf_len; | ||
53 | |||
54 | up(&ar->sem); | ||
55 | |||
56 | wake_up(&ar->event_wq); | ||
57 | } | ||
58 | |||
59 | static int ath6kl_tm_rx_report(struct ath6kl *ar, void *buf, size_t buf_len, | ||
60 | struct sk_buff *skb) | ||
61 | { | ||
62 | int ret = 0; | ||
63 | long left; | ||
64 | |||
65 | if (down_interruptible(&ar->sem)) | ||
66 | return -ERESTARTSYS; | ||
67 | |||
68 | if (!test_bit(WMI_READY, &ar->flag)) { | ||
69 | ret = -EIO; | ||
70 | goto out; | ||
71 | } | ||
72 | |||
73 | if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { | ||
74 | ret = -EBUSY; | ||
75 | goto out; | ||
76 | } | ||
77 | |||
78 | if (ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len) < 0) { | ||
79 | up(&ar->sem); | ||
80 | return -EIO; | ||
81 | } | ||
82 | |||
83 | left = wait_event_interruptible_timeout(ar->event_wq, | ||
84 | ar->tm.rx_report != NULL, | ||
85 | WMI_TIMEOUT); | ||
86 | 48 | ||
87 | if (left == 0) { | 49 | if (!buf || buf_len == 0) |
88 | ret = -ETIMEDOUT; | 50 | return; |
89 | goto out; | ||
90 | } else if (left < 0) { | ||
91 | ret = left; | ||
92 | goto out; | ||
93 | } | ||
94 | 51 | ||
95 | if (ar->tm.rx_report == NULL || ar->tm.rx_report_len == 0) { | 52 | skb = cfg80211_testmode_alloc_event_skb(ar->wiphy, buf_len, GFP_KERNEL); |
96 | ret = -EINVAL; | 53 | if (!skb) { |
97 | goto out; | 54 | ath6kl_warn("failed to allocate testmode rx skb!\n"); |
55 | return; | ||
98 | } | 56 | } |
99 | 57 | NLA_PUT_U32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_TCMD); | |
100 | NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, ar->tm.rx_report_len, | 58 | NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf); |
101 | ar->tm.rx_report); | 59 | cfg80211_testmode_event(skb, GFP_KERNEL); |
102 | 60 | return; | |
103 | kfree(ar->tm.rx_report); | ||
104 | ar->tm.rx_report = NULL; | ||
105 | |||
106 | out: | ||
107 | up(&ar->sem); | ||
108 | |||
109 | return ret; | ||
110 | 61 | ||
111 | nla_put_failure: | 62 | nla_put_failure: |
112 | ret = -ENOBUFS; | 63 | kfree_skb(skb); |
113 | goto out; | 64 | ath6kl_warn("nla_put failed on testmode rx skb!\n"); |
114 | } | 65 | } |
115 | 66 | ||
116 | int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) | 67 | int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) |
117 | { | 68 | { |
118 | struct ath6kl *ar = wiphy_priv(wiphy); | 69 | struct ath6kl *ar = wiphy_priv(wiphy); |
119 | struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; | 70 | struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; |
120 | int err, buf_len, reply_len; | 71 | int err, buf_len; |
121 | struct sk_buff *skb; | ||
122 | void *buf; | 72 | void *buf; |
123 | 73 | ||
124 | err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, | 74 | err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, |
@@ -143,24 +93,6 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) | |||
143 | 93 | ||
144 | break; | 94 | break; |
145 | case ATH6KL_TM_CMD_RX_REPORT: | 95 | case ATH6KL_TM_CMD_RX_REPORT: |
146 | if (!tb[ATH6KL_TM_ATTR_DATA]) | ||
147 | return -EINVAL; | ||
148 | |||
149 | buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); | ||
150 | buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); | ||
151 | |||
152 | reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN); | ||
153 | skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len); | ||
154 | if (!skb) | ||
155 | return -ENOMEM; | ||
156 | |||
157 | err = ath6kl_tm_rx_report(ar, buf, buf_len, skb); | ||
158 | if (err < 0) { | ||
159 | kfree_skb(skb); | ||
160 | return err; | ||
161 | } | ||
162 | |||
163 | return cfg80211_testmode_reply(skb); | ||
164 | default: | 96 | default: |
165 | return -EOPNOTSUPP; | 97 | return -EOPNOTSUPP; |
166 | } | 98 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.h b/drivers/net/wireless/ath/ath6kl/testmode.h index 43dffcc11fb1..7fd47a62d078 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.h +++ b/drivers/net/wireless/ath/ath6kl/testmode.h | |||
@@ -18,13 +18,13 @@ | |||
18 | 18 | ||
19 | #ifdef CONFIG_NL80211_TESTMODE | 19 | #ifdef CONFIG_NL80211_TESTMODE |
20 | 20 | ||
21 | void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len); | 21 | void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len); |
22 | int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len); | 22 | int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len); |
23 | 23 | ||
24 | #else | 24 | #else |
25 | 25 | ||
26 | static inline void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, | 26 | static inline void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, |
27 | size_t buf_len) | 27 | size_t buf_len) |
28 | { | 28 | { |
29 | } | 29 | } |
30 | 30 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 506a3031a885..a3dc6943c7f7 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c | |||
@@ -17,6 +17,23 @@ | |||
17 | #include "core.h" | 17 | #include "core.h" |
18 | #include "debug.h" | 18 | #include "debug.h" |
19 | 19 | ||
20 | /* | ||
21 | * tid - tid_mux0..tid_mux3 | ||
22 | * aid - tid_mux4..tid_mux7 | ||
23 | */ | ||
24 | #define ATH6KL_TID_MASK 0xf | ||
25 | #define ATH6KL_AID_SHIFT 4 | ||
26 | |||
27 | static inline u8 ath6kl_get_tid(u8 tid_mux) | ||
28 | { | ||
29 | return tid_mux & ATH6KL_TID_MASK; | ||
30 | } | ||
31 | |||
32 | static inline u8 ath6kl_get_aid(u8 tid_mux) | ||
33 | { | ||
34 | return tid_mux >> ATH6KL_AID_SHIFT; | ||
35 | } | ||
36 | |||
20 | static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev, | 37 | static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev, |
21 | u32 *map_no) | 38 | u32 *map_no) |
22 | { | 39 | { |
@@ -77,12 +94,118 @@ static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev, | |||
77 | return ar->node_map[ep_map].ep_id; | 94 | return ar->node_map[ep_map].ep_id; |
78 | } | 95 | } |
79 | 96 | ||
97 | static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn, | ||
98 | struct ath6kl_vif *vif, | ||
99 | struct sk_buff *skb, | ||
100 | u32 *flags) | ||
101 | { | ||
102 | struct ath6kl *ar = vif->ar; | ||
103 | bool is_apsdq_empty = false; | ||
104 | struct ethhdr *datap = (struct ethhdr *) skb->data; | ||
105 | u8 up = 0, traffic_class, *ip_hdr; | ||
106 | u16 ether_type; | ||
107 | struct ath6kl_llc_snap_hdr *llc_hdr; | ||
108 | |||
109 | if (conn->sta_flags & STA_PS_APSD_TRIGGER) { | ||
110 | /* | ||
111 | * This tx is because of a uAPSD trigger, determine | ||
112 | * more and EOSP bit. Set EOSP if queue is empty | ||
113 | * or sufficient frames are delivered for this trigger. | ||
114 | */ | ||
115 | spin_lock_bh(&conn->psq_lock); | ||
116 | if (!skb_queue_empty(&conn->apsdq)) | ||
117 | *flags |= WMI_DATA_HDR_FLAGS_MORE; | ||
118 | else if (conn->sta_flags & STA_PS_APSD_EOSP) | ||
119 | *flags |= WMI_DATA_HDR_FLAGS_EOSP; | ||
120 | *flags |= WMI_DATA_HDR_FLAGS_UAPSD; | ||
121 | spin_unlock_bh(&conn->psq_lock); | ||
122 | return false; | ||
123 | } else if (!conn->apsd_info) | ||
124 | return false; | ||
125 | |||
126 | if (test_bit(WMM_ENABLED, &vif->flags)) { | ||
127 | ether_type = be16_to_cpu(datap->h_proto); | ||
128 | if (is_ethertype(ether_type)) { | ||
129 | /* packet is in DIX format */ | ||
130 | ip_hdr = (u8 *)(datap + 1); | ||
131 | } else { | ||
132 | /* packet is in 802.3 format */ | ||
133 | llc_hdr = (struct ath6kl_llc_snap_hdr *) | ||
134 | (datap + 1); | ||
135 | ether_type = be16_to_cpu(llc_hdr->eth_type); | ||
136 | ip_hdr = (u8 *)(llc_hdr + 1); | ||
137 | } | ||
138 | |||
139 | if (ether_type == IP_ETHERTYPE) | ||
140 | up = ath6kl_wmi_determine_user_priority( | ||
141 | ip_hdr, 0); | ||
142 | } | ||
143 | |||
144 | traffic_class = ath6kl_wmi_get_traffic_class(up); | ||
145 | |||
146 | if ((conn->apsd_info & (1 << traffic_class)) == 0) | ||
147 | return false; | ||
148 | |||
149 | /* Queue the frames if the STA is sleeping */ | ||
150 | spin_lock_bh(&conn->psq_lock); | ||
151 | is_apsdq_empty = skb_queue_empty(&conn->apsdq); | ||
152 | skb_queue_tail(&conn->apsdq, skb); | ||
153 | spin_unlock_bh(&conn->psq_lock); | ||
154 | |||
155 | /* | ||
156 | * If this is the first pkt getting queued | ||
157 | * for this STA, update the PVB for this STA | ||
158 | */ | ||
159 | if (is_apsdq_empty) { | ||
160 | ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, | ||
161 | vif->fw_vif_idx, | ||
162 | conn->aid, 1, 0); | ||
163 | } | ||
164 | *flags |= WMI_DATA_HDR_FLAGS_UAPSD; | ||
165 | |||
166 | return true; | ||
167 | } | ||
168 | |||
169 | static bool ath6kl_process_psq(struct ath6kl_sta *conn, | ||
170 | struct ath6kl_vif *vif, | ||
171 | struct sk_buff *skb, | ||
172 | u32 *flags) | ||
173 | { | ||
174 | bool is_psq_empty = false; | ||
175 | struct ath6kl *ar = vif->ar; | ||
176 | |||
177 | if (conn->sta_flags & STA_PS_POLLED) { | ||
178 | spin_lock_bh(&conn->psq_lock); | ||
179 | if (!skb_queue_empty(&conn->psq)) | ||
180 | *flags |= WMI_DATA_HDR_FLAGS_MORE; | ||
181 | spin_unlock_bh(&conn->psq_lock); | ||
182 | return false; | ||
183 | } | ||
184 | |||
185 | /* Queue the frames if the STA is sleeping */ | ||
186 | spin_lock_bh(&conn->psq_lock); | ||
187 | is_psq_empty = skb_queue_empty(&conn->psq); | ||
188 | skb_queue_tail(&conn->psq, skb); | ||
189 | spin_unlock_bh(&conn->psq_lock); | ||
190 | |||
191 | /* | ||
192 | * If this is the first pkt getting queued | ||
193 | * for this STA, update the PVB for this | ||
194 | * STA. | ||
195 | */ | ||
196 | if (is_psq_empty) | ||
197 | ath6kl_wmi_set_pvb_cmd(ar->wmi, | ||
198 | vif->fw_vif_idx, | ||
199 | conn->aid, 1); | ||
200 | return true; | ||
201 | } | ||
202 | |||
80 | static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb, | 203 | static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb, |
81 | bool *more_data) | 204 | u32 *flags) |
82 | { | 205 | { |
83 | struct ethhdr *datap = (struct ethhdr *) skb->data; | 206 | struct ethhdr *datap = (struct ethhdr *) skb->data; |
84 | struct ath6kl_sta *conn = NULL; | 207 | struct ath6kl_sta *conn = NULL; |
85 | bool ps_queued = false, is_psq_empty = false; | 208 | bool ps_queued = false; |
86 | struct ath6kl *ar = vif->ar; | 209 | struct ath6kl *ar = vif->ar; |
87 | 210 | ||
88 | if (is_multicast_ether_addr(datap->h_dest)) { | 211 | if (is_multicast_ether_addr(datap->h_dest)) { |
@@ -128,7 +251,7 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb, | |||
128 | */ | 251 | */ |
129 | spin_lock_bh(&ar->mcastpsq_lock); | 252 | spin_lock_bh(&ar->mcastpsq_lock); |
130 | if (!skb_queue_empty(&ar->mcastpsq)) | 253 | if (!skb_queue_empty(&ar->mcastpsq)) |
131 | *more_data = true; | 254 | *flags |= WMI_DATA_HDR_FLAGS_MORE; |
132 | spin_unlock_bh(&ar->mcastpsq_lock); | 255 | spin_unlock_bh(&ar->mcastpsq_lock); |
133 | } | 256 | } |
134 | } | 257 | } |
@@ -142,37 +265,13 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb, | |||
142 | } | 265 | } |
143 | 266 | ||
144 | if (conn->sta_flags & STA_PS_SLEEP) { | 267 | if (conn->sta_flags & STA_PS_SLEEP) { |
145 | if (!(conn->sta_flags & STA_PS_POLLED)) { | 268 | ps_queued = ath6kl_process_uapsdq(conn, |
146 | /* Queue the frames if the STA is sleeping */ | 269 | vif, skb, flags); |
147 | spin_lock_bh(&conn->psq_lock); | 270 | if (!(*flags & WMI_DATA_HDR_FLAGS_UAPSD)) |
148 | is_psq_empty = skb_queue_empty(&conn->psq); | 271 | ps_queued = ath6kl_process_psq(conn, |
149 | skb_queue_tail(&conn->psq, skb); | 272 | vif, skb, flags); |
150 | spin_unlock_bh(&conn->psq_lock); | ||
151 | |||
152 | /* | ||
153 | * If this is the first pkt getting queued | ||
154 | * for this STA, update the PVB for this | ||
155 | * STA. | ||
156 | */ | ||
157 | if (is_psq_empty) | ||
158 | ath6kl_wmi_set_pvb_cmd(ar->wmi, | ||
159 | vif->fw_vif_idx, | ||
160 | conn->aid, 1); | ||
161 | |||
162 | ps_queued = true; | ||
163 | } else { | ||
164 | /* | ||
165 | * This tx is because of a PsPoll. | ||
166 | * Determine if MoreData bit has to be set. | ||
167 | */ | ||
168 | spin_lock_bh(&conn->psq_lock); | ||
169 | if (!skb_queue_empty(&conn->psq)) | ||
170 | *more_data = true; | ||
171 | spin_unlock_bh(&conn->psq_lock); | ||
172 | } | ||
173 | } | 273 | } |
174 | } | 274 | } |
175 | |||
176 | return ps_queued; | 275 | return ps_queued; |
177 | } | 276 | } |
178 | 277 | ||
@@ -242,8 +341,13 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
242 | u32 map_no = 0; | 341 | u32 map_no = 0; |
243 | u16 htc_tag = ATH6KL_DATA_PKT_TAG; | 342 | u16 htc_tag = ATH6KL_DATA_PKT_TAG; |
244 | u8 ac = 99 ; /* initialize to unmapped ac */ | 343 | u8 ac = 99 ; /* initialize to unmapped ac */ |
245 | bool chk_adhoc_ps_mapping = false, more_data = false; | 344 | bool chk_adhoc_ps_mapping = false; |
246 | int ret; | 345 | int ret; |
346 | struct wmi_tx_meta_v2 meta_v2; | ||
347 | void *meta; | ||
348 | u8 csum_start = 0, csum_dest = 0, csum = skb->ip_summed; | ||
349 | u8 meta_ver = 0; | ||
350 | u32 flags = 0; | ||
247 | 351 | ||
248 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, | 352 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, |
249 | "%s: skb=0x%p, data=0x%p, len=0x%x\n", __func__, | 353 | "%s: skb=0x%p, data=0x%p, len=0x%x\n", __func__, |
@@ -260,11 +364,19 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
260 | 364 | ||
261 | /* AP mode Power saving processing */ | 365 | /* AP mode Power saving processing */ |
262 | if (vif->nw_type == AP_NETWORK) { | 366 | if (vif->nw_type == AP_NETWORK) { |
263 | if (ath6kl_powersave_ap(vif, skb, &more_data)) | 367 | if (ath6kl_powersave_ap(vif, skb, &flags)) |
264 | return 0; | 368 | return 0; |
265 | } | 369 | } |
266 | 370 | ||
267 | if (test_bit(WMI_ENABLED, &ar->flag)) { | 371 | if (test_bit(WMI_ENABLED, &ar->flag)) { |
372 | if ((dev->features & NETIF_F_IP_CSUM) && | ||
373 | (csum == CHECKSUM_PARTIAL)) { | ||
374 | csum_start = skb->csum_start - | ||
375 | (skb_network_header(skb) - skb->head) + | ||
376 | sizeof(struct ath6kl_llc_snap_hdr); | ||
377 | csum_dest = skb->csum_offset + csum_start; | ||
378 | } | ||
379 | |||
268 | if (skb_headroom(skb) < dev->needed_headroom) { | 380 | if (skb_headroom(skb) < dev->needed_headroom) { |
269 | struct sk_buff *tmp_skb = skb; | 381 | struct sk_buff *tmp_skb = skb; |
270 | 382 | ||
@@ -281,10 +393,28 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
281 | goto fail_tx; | 393 | goto fail_tx; |
282 | } | 394 | } |
283 | 395 | ||
284 | if (ath6kl_wmi_data_hdr_add(ar->wmi, skb, DATA_MSGTYPE, | 396 | if ((dev->features & NETIF_F_IP_CSUM) && |
285 | more_data, 0, 0, NULL, | 397 | (csum == CHECKSUM_PARTIAL)) { |
286 | vif->fw_vif_idx)) { | 398 | meta_v2.csum_start = csum_start; |
287 | ath6kl_err("wmi_data_hdr_add failed\n"); | 399 | meta_v2.csum_dest = csum_dest; |
400 | |||
401 | /* instruct target to calculate checksum */ | ||
402 | meta_v2.csum_flags = WMI_META_V2_FLAG_CSUM_OFFLOAD; | ||
403 | meta_ver = WMI_META_VERSION_2; | ||
404 | meta = &meta_v2; | ||
405 | } else { | ||
406 | meta_ver = 0; | ||
407 | meta = NULL; | ||
408 | } | ||
409 | |||
410 | ret = ath6kl_wmi_data_hdr_add(ar->wmi, skb, | ||
411 | DATA_MSGTYPE, flags, 0, | ||
412 | meta_ver, | ||
413 | meta, vif->fw_vif_idx); | ||
414 | |||
415 | if (ret) { | ||
416 | ath6kl_warn("failed to add wmi data header:%d\n" | ||
417 | , ret); | ||
288 | goto fail_tx; | 418 | goto fail_tx; |
289 | } | 419 | } |
290 | 420 | ||
@@ -449,9 +579,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, | |||
449 | * WMI queue with too many commands the only exception to | 579 | * WMI queue with too many commands the only exception to |
450 | * this is during testing using endpointping. | 580 | * this is during testing using endpointping. |
451 | */ | 581 | */ |
452 | spin_lock_bh(&ar->lock); | ||
453 | set_bit(WMI_CTRL_EP_FULL, &ar->flag); | 582 | set_bit(WMI_CTRL_EP_FULL, &ar->flag); |
454 | spin_unlock_bh(&ar->lock); | ||
455 | ath6kl_err("wmi ctrl ep is full\n"); | 583 | ath6kl_err("wmi ctrl ep is full\n"); |
456 | return action; | 584 | return action; |
457 | } | 585 | } |
@@ -479,9 +607,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, | |||
479 | action != HTC_SEND_FULL_DROP) { | 607 | action != HTC_SEND_FULL_DROP) { |
480 | spin_unlock_bh(&ar->list_lock); | 608 | spin_unlock_bh(&ar->list_lock); |
481 | 609 | ||
482 | spin_lock_bh(&vif->if_lock); | ||
483 | set_bit(NETQ_STOPPED, &vif->flags); | 610 | set_bit(NETQ_STOPPED, &vif->flags); |
484 | spin_unlock_bh(&vif->if_lock); | ||
485 | netif_stop_queue(vif->ndev); | 611 | netif_stop_queue(vif->ndev); |
486 | 612 | ||
487 | return action; | 613 | return action; |
@@ -710,10 +836,12 @@ static struct sk_buff *aggr_get_free_skb(struct aggr_info *p_aggr) | |||
710 | { | 836 | { |
711 | struct sk_buff *skb = NULL; | 837 | struct sk_buff *skb = NULL; |
712 | 838 | ||
713 | if (skb_queue_len(&p_aggr->free_q) < (AGGR_NUM_OF_FREE_NETBUFS >> 2)) | 839 | if (skb_queue_len(&p_aggr->rx_amsdu_freeq) < |
714 | ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS); | 840 | (AGGR_NUM_OF_FREE_NETBUFS >> 2)) |
841 | ath6kl_alloc_netbufs(&p_aggr->rx_amsdu_freeq, | ||
842 | AGGR_NUM_OF_FREE_NETBUFS); | ||
715 | 843 | ||
716 | skb = skb_dequeue(&p_aggr->free_q); | 844 | skb = skb_dequeue(&p_aggr->rx_amsdu_freeq); |
717 | 845 | ||
718 | return skb; | 846 | return skb; |
719 | } | 847 | } |
@@ -881,7 +1009,7 @@ static void aggr_slice_amsdu(struct aggr_info *p_aggr, | |||
881 | dev_kfree_skb(skb); | 1009 | dev_kfree_skb(skb); |
882 | } | 1010 | } |
883 | 1011 | ||
884 | static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, | 1012 | static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid, |
885 | u16 seq_no, u8 order) | 1013 | u16 seq_no, u8 order) |
886 | { | 1014 | { |
887 | struct sk_buff *skb; | 1015 | struct sk_buff *skb; |
@@ -890,11 +1018,8 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, | |||
890 | u16 idx, idx_end, seq_end; | 1018 | u16 idx, idx_end, seq_end; |
891 | struct rxtid_stats *stats; | 1019 | struct rxtid_stats *stats; |
892 | 1020 | ||
893 | if (!p_aggr) | 1021 | rxtid = &agg_conn->rx_tid[tid]; |
894 | return; | 1022 | stats = &agg_conn->stat[tid]; |
895 | |||
896 | rxtid = &p_aggr->rx_tid[tid]; | ||
897 | stats = &p_aggr->stat[tid]; | ||
898 | 1023 | ||
899 | idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); | 1024 | idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); |
900 | 1025 | ||
@@ -923,7 +1048,8 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, | |||
923 | 1048 | ||
924 | if (node->skb) { | 1049 | if (node->skb) { |
925 | if (node->is_amsdu) | 1050 | if (node->is_amsdu) |
926 | aggr_slice_amsdu(p_aggr, rxtid, node->skb); | 1051 | aggr_slice_amsdu(agg_conn->aggr_info, rxtid, |
1052 | node->skb); | ||
927 | else | 1053 | else |
928 | skb_queue_tail(&rxtid->q, node->skb); | 1054 | skb_queue_tail(&rxtid->q, node->skb); |
929 | node->skb = NULL; | 1055 | node->skb = NULL; |
@@ -939,10 +1065,10 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, | |||
939 | stats->num_delivered += skb_queue_len(&rxtid->q); | 1065 | stats->num_delivered += skb_queue_len(&rxtid->q); |
940 | 1066 | ||
941 | while ((skb = skb_dequeue(&rxtid->q))) | 1067 | while ((skb = skb_dequeue(&rxtid->q))) |
942 | ath6kl_deliver_frames_to_nw_stack(p_aggr->dev, skb); | 1068 | ath6kl_deliver_frames_to_nw_stack(agg_conn->dev, skb); |
943 | } | 1069 | } |
944 | 1070 | ||
945 | static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, | 1071 | static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid, |
946 | u16 seq_no, | 1072 | u16 seq_no, |
947 | bool is_amsdu, struct sk_buff *frame) | 1073 | bool is_amsdu, struct sk_buff *frame) |
948 | { | 1074 | { |
@@ -954,18 +1080,18 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, | |||
954 | bool is_queued = false; | 1080 | bool is_queued = false; |
955 | u16 extended_end; | 1081 | u16 extended_end; |
956 | 1082 | ||
957 | rxtid = &agg_info->rx_tid[tid]; | 1083 | rxtid = &agg_conn->rx_tid[tid]; |
958 | stats = &agg_info->stat[tid]; | 1084 | stats = &agg_conn->stat[tid]; |
959 | 1085 | ||
960 | stats->num_into_aggr++; | 1086 | stats->num_into_aggr++; |
961 | 1087 | ||
962 | if (!rxtid->aggr) { | 1088 | if (!rxtid->aggr) { |
963 | if (is_amsdu) { | 1089 | if (is_amsdu) { |
964 | aggr_slice_amsdu(agg_info, rxtid, frame); | 1090 | aggr_slice_amsdu(agg_conn->aggr_info, rxtid, frame); |
965 | is_queued = true; | 1091 | is_queued = true; |
966 | stats->num_amsdu++; | 1092 | stats->num_amsdu++; |
967 | while ((skb = skb_dequeue(&rxtid->q))) | 1093 | while ((skb = skb_dequeue(&rxtid->q))) |
968 | ath6kl_deliver_frames_to_nw_stack(agg_info->dev, | 1094 | ath6kl_deliver_frames_to_nw_stack(agg_conn->dev, |
969 | skb); | 1095 | skb); |
970 | } | 1096 | } |
971 | return is_queued; | 1097 | return is_queued; |
@@ -985,7 +1111,7 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, | |||
985 | (cur < end || cur > extended_end)) || | 1111 | (cur < end || cur > extended_end)) || |
986 | ((end > extended_end) && (cur > extended_end) && | 1112 | ((end > extended_end) && (cur > extended_end) && |
987 | (cur < end))) { | 1113 | (cur < end))) { |
988 | aggr_deque_frms(agg_info, tid, 0, 0); | 1114 | aggr_deque_frms(agg_conn, tid, 0, 0); |
989 | if (cur >= rxtid->hold_q_sz - 1) | 1115 | if (cur >= rxtid->hold_q_sz - 1) |
990 | rxtid->seq_next = cur - (rxtid->hold_q_sz - 1); | 1116 | rxtid->seq_next = cur - (rxtid->hold_q_sz - 1); |
991 | else | 1117 | else |
@@ -1002,7 +1128,7 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, | |||
1002 | st = ATH6KL_MAX_SEQ_NO - | 1128 | st = ATH6KL_MAX_SEQ_NO - |
1003 | (rxtid->hold_q_sz - 2 - cur); | 1129 | (rxtid->hold_q_sz - 2 - cur); |
1004 | 1130 | ||
1005 | aggr_deque_frms(agg_info, tid, st, 0); | 1131 | aggr_deque_frms(agg_conn, tid, st, 0); |
1006 | } | 1132 | } |
1007 | 1133 | ||
1008 | stats->num_oow++; | 1134 | stats->num_oow++; |
@@ -1041,9 +1167,9 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, | |||
1041 | 1167 | ||
1042 | spin_unlock_bh(&rxtid->lock); | 1168 | spin_unlock_bh(&rxtid->lock); |
1043 | 1169 | ||
1044 | aggr_deque_frms(agg_info, tid, 0, 1); | 1170 | aggr_deque_frms(agg_conn, tid, 0, 1); |
1045 | 1171 | ||
1046 | if (agg_info->timer_scheduled) | 1172 | if (agg_conn->timer_scheduled) |
1047 | rxtid->progress = true; | 1173 | rxtid->progress = true; |
1048 | else | 1174 | else |
1049 | for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { | 1175 | for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { |
@@ -1054,8 +1180,8 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, | |||
1054 | * the frame doesn't remain stuck | 1180 | * the frame doesn't remain stuck |
1055 | * forever. | 1181 | * forever. |
1056 | */ | 1182 | */ |
1057 | agg_info->timer_scheduled = true; | 1183 | agg_conn->timer_scheduled = true; |
1058 | mod_timer(&agg_info->timer, | 1184 | mod_timer(&agg_conn->timer, |
1059 | (jiffies + | 1185 | (jiffies + |
1060 | HZ * (AGGR_RX_TIMEOUT) / 1000)); | 1186 | HZ * (AGGR_RX_TIMEOUT) / 1000)); |
1061 | rxtid->progress = false; | 1187 | rxtid->progress = false; |
@@ -1067,6 +1193,76 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, | |||
1067 | return is_queued; | 1193 | return is_queued; |
1068 | } | 1194 | } |
1069 | 1195 | ||
1196 | static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif, | ||
1197 | struct ath6kl_sta *conn) | ||
1198 | { | ||
1199 | struct ath6kl *ar = vif->ar; | ||
1200 | bool is_apsdq_empty, is_apsdq_empty_at_start; | ||
1201 | u32 num_frames_to_deliver, flags; | ||
1202 | struct sk_buff *skb = NULL; | ||
1203 | |||
1204 | /* | ||
1205 | * If the APSD q for this STA is not empty, dequeue and | ||
1206 | * send a pkt from the head of the q. Also update the | ||
1207 | * More data bit in the WMI_DATA_HDR if there are | ||
1208 | * more pkts for this STA in the APSD q. | ||
1209 | * If there are no more pkts for this STA, | ||
1210 | * update the APSD bitmap for this STA. | ||
1211 | */ | ||
1212 | |||
1213 | num_frames_to_deliver = (conn->apsd_info >> ATH6KL_APSD_NUM_OF_AC) & | ||
1214 | ATH6KL_APSD_FRAME_MASK; | ||
1215 | /* | ||
1216 | * Number of frames to send in a service period is | ||
1217 | * indicated by the station | ||
1218 | * in the QOS_INFO of the association request | ||
1219 | * If it is zero, send all frames | ||
1220 | */ | ||
1221 | if (!num_frames_to_deliver) | ||
1222 | num_frames_to_deliver = ATH6KL_APSD_ALL_FRAME; | ||
1223 | |||
1224 | spin_lock_bh(&conn->psq_lock); | ||
1225 | is_apsdq_empty = skb_queue_empty(&conn->apsdq); | ||
1226 | spin_unlock_bh(&conn->psq_lock); | ||
1227 | is_apsdq_empty_at_start = is_apsdq_empty; | ||
1228 | |||
1229 | while ((!is_apsdq_empty) && (num_frames_to_deliver)) { | ||
1230 | |||
1231 | spin_lock_bh(&conn->psq_lock); | ||
1232 | skb = skb_dequeue(&conn->apsdq); | ||
1233 | is_apsdq_empty = skb_queue_empty(&conn->apsdq); | ||
1234 | spin_unlock_bh(&conn->psq_lock); | ||
1235 | |||
1236 | /* | ||
1237 | * Set the STA flag to Trigger delivery, | ||
1238 | * so that the frame will go out | ||
1239 | */ | ||
1240 | conn->sta_flags |= STA_PS_APSD_TRIGGER; | ||
1241 | num_frames_to_deliver--; | ||
1242 | |||
1243 | /* Last frame in the service period, set EOSP or queue empty */ | ||
1244 | if ((is_apsdq_empty) || (!num_frames_to_deliver)) | ||
1245 | conn->sta_flags |= STA_PS_APSD_EOSP; | ||
1246 | |||
1247 | ath6kl_data_tx(skb, vif->ndev); | ||
1248 | conn->sta_flags &= ~(STA_PS_APSD_TRIGGER); | ||
1249 | conn->sta_flags &= ~(STA_PS_APSD_EOSP); | ||
1250 | } | ||
1251 | |||
1252 | if (is_apsdq_empty) { | ||
1253 | if (is_apsdq_empty_at_start) | ||
1254 | flags = WMI_AP_APSD_NO_DELIVERY_FRAMES; | ||
1255 | else | ||
1256 | flags = 0; | ||
1257 | |||
1258 | ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, | ||
1259 | vif->fw_vif_idx, | ||
1260 | conn->aid, 0, flags); | ||
1261 | } | ||
1262 | |||
1263 | return; | ||
1264 | } | ||
1265 | |||
1070 | void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | 1266 | void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) |
1071 | { | 1267 | { |
1072 | struct ath6kl *ar = target->dev->ar; | 1268 | struct ath6kl *ar = target->dev->ar; |
@@ -1078,10 +1274,12 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1078 | int status = packet->status; | 1274 | int status = packet->status; |
1079 | enum htc_endpoint_id ept = packet->endpoint; | 1275 | enum htc_endpoint_id ept = packet->endpoint; |
1080 | bool is_amsdu, prev_ps, ps_state = false; | 1276 | bool is_amsdu, prev_ps, ps_state = false; |
1277 | bool trig_state = false; | ||
1081 | struct ath6kl_sta *conn = NULL; | 1278 | struct ath6kl_sta *conn = NULL; |
1082 | struct sk_buff *skb1 = NULL; | 1279 | struct sk_buff *skb1 = NULL; |
1083 | struct ethhdr *datap = NULL; | 1280 | struct ethhdr *datap = NULL; |
1084 | struct ath6kl_vif *vif; | 1281 | struct ath6kl_vif *vif; |
1282 | struct aggr_info_conn *aggr_conn; | ||
1085 | u16 seq_no, offset; | 1283 | u16 seq_no, offset; |
1086 | u8 tid, if_idx; | 1284 | u8 tid, if_idx; |
1087 | 1285 | ||
@@ -1171,6 +1369,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1171 | WMI_DATA_HDR_PS_MASK); | 1369 | WMI_DATA_HDR_PS_MASK); |
1172 | 1370 | ||
1173 | offset = sizeof(struct wmi_data_hdr); | 1371 | offset = sizeof(struct wmi_data_hdr); |
1372 | trig_state = !!(le16_to_cpu(dhdr->info3) & WMI_DATA_HDR_TRIG); | ||
1174 | 1373 | ||
1175 | switch (meta_type) { | 1374 | switch (meta_type) { |
1176 | case 0: | 1375 | case 0: |
@@ -1209,18 +1408,36 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1209 | else | 1408 | else |
1210 | conn->sta_flags &= ~STA_PS_SLEEP; | 1409 | conn->sta_flags &= ~STA_PS_SLEEP; |
1211 | 1410 | ||
1411 | /* Accept trigger only when the station is in sleep */ | ||
1412 | if ((conn->sta_flags & STA_PS_SLEEP) && trig_state) | ||
1413 | ath6kl_uapsd_trigger_frame_rx(vif, conn); | ||
1414 | |||
1212 | if (prev_ps ^ !!(conn->sta_flags & STA_PS_SLEEP)) { | 1415 | if (prev_ps ^ !!(conn->sta_flags & STA_PS_SLEEP)) { |
1213 | if (!(conn->sta_flags & STA_PS_SLEEP)) { | 1416 | if (!(conn->sta_flags & STA_PS_SLEEP)) { |
1214 | struct sk_buff *skbuff = NULL; | 1417 | struct sk_buff *skbuff = NULL; |
1418 | bool is_apsdq_empty; | ||
1215 | 1419 | ||
1216 | spin_lock_bh(&conn->psq_lock); | 1420 | spin_lock_bh(&conn->psq_lock); |
1217 | while ((skbuff = skb_dequeue(&conn->psq)) | 1421 | while ((skbuff = skb_dequeue(&conn->psq))) { |
1218 | != NULL) { | 1422 | spin_unlock_bh(&conn->psq_lock); |
1423 | ath6kl_data_tx(skbuff, vif->ndev); | ||
1424 | spin_lock_bh(&conn->psq_lock); | ||
1425 | } | ||
1426 | |||
1427 | is_apsdq_empty = skb_queue_empty(&conn->apsdq); | ||
1428 | while ((skbuff = skb_dequeue(&conn->apsdq))) { | ||
1219 | spin_unlock_bh(&conn->psq_lock); | 1429 | spin_unlock_bh(&conn->psq_lock); |
1220 | ath6kl_data_tx(skbuff, vif->ndev); | 1430 | ath6kl_data_tx(skbuff, vif->ndev); |
1221 | spin_lock_bh(&conn->psq_lock); | 1431 | spin_lock_bh(&conn->psq_lock); |
1222 | } | 1432 | } |
1223 | spin_unlock_bh(&conn->psq_lock); | 1433 | spin_unlock_bh(&conn->psq_lock); |
1434 | |||
1435 | if (!is_apsdq_empty) | ||
1436 | ath6kl_wmi_set_apsd_bfrd_traf( | ||
1437 | ar->wmi, | ||
1438 | vif->fw_vif_idx, | ||
1439 | conn->aid, 0, 0); | ||
1440 | |||
1224 | /* Clear the PVB for this STA */ | 1441 | /* Clear the PVB for this STA */ |
1225 | ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, | 1442 | ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, |
1226 | conn->aid, 0); | 1443 | conn->aid, 0); |
@@ -1314,11 +1531,21 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1314 | 1531 | ||
1315 | datap = (struct ethhdr *) skb->data; | 1532 | datap = (struct ethhdr *) skb->data; |
1316 | 1533 | ||
1317 | if (is_unicast_ether_addr(datap->h_dest) && | 1534 | if (is_unicast_ether_addr(datap->h_dest)) { |
1318 | aggr_process_recv_frm(vif->aggr_cntxt, tid, seq_no, | 1535 | if (vif->nw_type == AP_NETWORK) { |
1319 | is_amsdu, skb)) | 1536 | conn = ath6kl_find_sta(vif, datap->h_source); |
1320 | /* aggregation code will handle the skb */ | 1537 | if (!conn) |
1321 | return; | 1538 | return; |
1539 | aggr_conn = conn->aggr_conn; | ||
1540 | } else | ||
1541 | aggr_conn = vif->aggr_cntxt->aggr_conn; | ||
1542 | |||
1543 | if (aggr_process_recv_frm(aggr_conn, tid, seq_no, | ||
1544 | is_amsdu, skb)) { | ||
1545 | /* aggregation code will handle the skb */ | ||
1546 | return; | ||
1547 | } | ||
1548 | } | ||
1322 | 1549 | ||
1323 | ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb); | 1550 | ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb); |
1324 | } | 1551 | } |
@@ -1326,13 +1553,13 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1326 | static void aggr_timeout(unsigned long arg) | 1553 | static void aggr_timeout(unsigned long arg) |
1327 | { | 1554 | { |
1328 | u8 i, j; | 1555 | u8 i, j; |
1329 | struct aggr_info *p_aggr = (struct aggr_info *) arg; | 1556 | struct aggr_info_conn *aggr_conn = (struct aggr_info_conn *) arg; |
1330 | struct rxtid *rxtid; | 1557 | struct rxtid *rxtid; |
1331 | struct rxtid_stats *stats; | 1558 | struct rxtid_stats *stats; |
1332 | 1559 | ||
1333 | for (i = 0; i < NUM_OF_TIDS; i++) { | 1560 | for (i = 0; i < NUM_OF_TIDS; i++) { |
1334 | rxtid = &p_aggr->rx_tid[i]; | 1561 | rxtid = &aggr_conn->rx_tid[i]; |
1335 | stats = &p_aggr->stat[i]; | 1562 | stats = &aggr_conn->stat[i]; |
1336 | 1563 | ||
1337 | if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress) | 1564 | if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress) |
1338 | continue; | 1565 | continue; |
@@ -1343,18 +1570,18 @@ static void aggr_timeout(unsigned long arg) | |||
1343 | rxtid->seq_next, | 1570 | rxtid->seq_next, |
1344 | ((rxtid->seq_next + rxtid->hold_q_sz-1) & | 1571 | ((rxtid->seq_next + rxtid->hold_q_sz-1) & |
1345 | ATH6KL_MAX_SEQ_NO)); | 1572 | ATH6KL_MAX_SEQ_NO)); |
1346 | aggr_deque_frms(p_aggr, i, 0, 0); | 1573 | aggr_deque_frms(aggr_conn, i, 0, 0); |
1347 | } | 1574 | } |
1348 | 1575 | ||
1349 | p_aggr->timer_scheduled = false; | 1576 | aggr_conn->timer_scheduled = false; |
1350 | 1577 | ||
1351 | for (i = 0; i < NUM_OF_TIDS; i++) { | 1578 | for (i = 0; i < NUM_OF_TIDS; i++) { |
1352 | rxtid = &p_aggr->rx_tid[i]; | 1579 | rxtid = &aggr_conn->rx_tid[i]; |
1353 | 1580 | ||
1354 | if (rxtid->aggr && rxtid->hold_q) { | 1581 | if (rxtid->aggr && rxtid->hold_q) { |
1355 | for (j = 0; j < rxtid->hold_q_sz; j++) { | 1582 | for (j = 0; j < rxtid->hold_q_sz; j++) { |
1356 | if (rxtid->hold_q[j].skb) { | 1583 | if (rxtid->hold_q[j].skb) { |
1357 | p_aggr->timer_scheduled = true; | 1584 | aggr_conn->timer_scheduled = true; |
1358 | rxtid->timer_mon = true; | 1585 | rxtid->timer_mon = true; |
1359 | rxtid->progress = false; | 1586 | rxtid->progress = false; |
1360 | break; | 1587 | break; |
@@ -1366,24 +1593,24 @@ static void aggr_timeout(unsigned long arg) | |||
1366 | } | 1593 | } |
1367 | } | 1594 | } |
1368 | 1595 | ||
1369 | if (p_aggr->timer_scheduled) | 1596 | if (aggr_conn->timer_scheduled) |
1370 | mod_timer(&p_aggr->timer, | 1597 | mod_timer(&aggr_conn->timer, |
1371 | jiffies + msecs_to_jiffies(AGGR_RX_TIMEOUT)); | 1598 | jiffies + msecs_to_jiffies(AGGR_RX_TIMEOUT)); |
1372 | } | 1599 | } |
1373 | 1600 | ||
1374 | static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid) | 1601 | static void aggr_delete_tid_state(struct aggr_info_conn *aggr_conn, u8 tid) |
1375 | { | 1602 | { |
1376 | struct rxtid *rxtid; | 1603 | struct rxtid *rxtid; |
1377 | struct rxtid_stats *stats; | 1604 | struct rxtid_stats *stats; |
1378 | 1605 | ||
1379 | if (!p_aggr || tid >= NUM_OF_TIDS) | 1606 | if (!aggr_conn || tid >= NUM_OF_TIDS) |
1380 | return; | 1607 | return; |
1381 | 1608 | ||
1382 | rxtid = &p_aggr->rx_tid[tid]; | 1609 | rxtid = &aggr_conn->rx_tid[tid]; |
1383 | stats = &p_aggr->stat[tid]; | 1610 | stats = &aggr_conn->stat[tid]; |
1384 | 1611 | ||
1385 | if (rxtid->aggr) | 1612 | if (rxtid->aggr) |
1386 | aggr_deque_frms(p_aggr, tid, 0, 0); | 1613 | aggr_deque_frms(aggr_conn, tid, 0, 0); |
1387 | 1614 | ||
1388 | rxtid->aggr = false; | 1615 | rxtid->aggr = false; |
1389 | rxtid->progress = false; | 1616 | rxtid->progress = false; |
@@ -1398,26 +1625,40 @@ static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid) | |||
1398 | memset(stats, 0, sizeof(struct rxtid_stats)); | 1625 | memset(stats, 0, sizeof(struct rxtid_stats)); |
1399 | } | 1626 | } |
1400 | 1627 | ||
1401 | void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid, u16 seq_no, | 1628 | void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no, |
1402 | u8 win_sz) | 1629 | u8 win_sz) |
1403 | { | 1630 | { |
1404 | struct aggr_info *p_aggr = vif->aggr_cntxt; | 1631 | struct ath6kl_sta *sta; |
1632 | struct aggr_info_conn *aggr_conn = NULL; | ||
1405 | struct rxtid *rxtid; | 1633 | struct rxtid *rxtid; |
1406 | struct rxtid_stats *stats; | 1634 | struct rxtid_stats *stats; |
1407 | u16 hold_q_size; | 1635 | u16 hold_q_size; |
1636 | u8 tid, aid; | ||
1408 | 1637 | ||
1409 | if (!p_aggr) | 1638 | if (vif->nw_type == AP_NETWORK) { |
1639 | aid = ath6kl_get_aid(tid_mux); | ||
1640 | sta = ath6kl_find_sta_by_aid(vif->ar, aid); | ||
1641 | if (sta) | ||
1642 | aggr_conn = sta->aggr_conn; | ||
1643 | } else | ||
1644 | aggr_conn = vif->aggr_cntxt->aggr_conn; | ||
1645 | |||
1646 | if (!aggr_conn) | ||
1647 | return; | ||
1648 | |||
1649 | tid = ath6kl_get_tid(tid_mux); | ||
1650 | if (tid >= NUM_OF_TIDS) | ||
1410 | return; | 1651 | return; |
1411 | 1652 | ||
1412 | rxtid = &p_aggr->rx_tid[tid]; | 1653 | rxtid = &aggr_conn->rx_tid[tid]; |
1413 | stats = &p_aggr->stat[tid]; | 1654 | stats = &aggr_conn->stat[tid]; |
1414 | 1655 | ||
1415 | if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) | 1656 | if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) |
1416 | ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n", | 1657 | ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n", |
1417 | __func__, win_sz, tid); | 1658 | __func__, win_sz, tid); |
1418 | 1659 | ||
1419 | if (rxtid->aggr) | 1660 | if (rxtid->aggr) |
1420 | aggr_delete_tid_state(p_aggr, tid); | 1661 | aggr_delete_tid_state(aggr_conn, tid); |
1421 | 1662 | ||
1422 | rxtid->seq_next = seq_no; | 1663 | rxtid->seq_next = seq_no; |
1423 | hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q); | 1664 | hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q); |
@@ -1433,31 +1674,23 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid, u16 seq_no, | |||
1433 | rxtid->aggr = true; | 1674 | rxtid->aggr = true; |
1434 | } | 1675 | } |
1435 | 1676 | ||
1436 | struct aggr_info *aggr_init(struct net_device *dev) | 1677 | void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info, |
1678 | struct aggr_info_conn *aggr_conn) | ||
1437 | { | 1679 | { |
1438 | struct aggr_info *p_aggr = NULL; | ||
1439 | struct rxtid *rxtid; | 1680 | struct rxtid *rxtid; |
1440 | u8 i; | 1681 | u8 i; |
1441 | 1682 | ||
1442 | p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL); | 1683 | aggr_conn->aggr_sz = AGGR_SZ_DEFAULT; |
1443 | if (!p_aggr) { | 1684 | aggr_conn->dev = vif->ndev; |
1444 | ath6kl_err("failed to alloc memory for aggr_node\n"); | 1685 | init_timer(&aggr_conn->timer); |
1445 | return NULL; | 1686 | aggr_conn->timer.function = aggr_timeout; |
1446 | } | 1687 | aggr_conn->timer.data = (unsigned long) aggr_conn; |
1447 | 1688 | aggr_conn->aggr_info = aggr_info; | |
1448 | p_aggr->aggr_sz = AGGR_SZ_DEFAULT; | ||
1449 | p_aggr->dev = dev; | ||
1450 | init_timer(&p_aggr->timer); | ||
1451 | p_aggr->timer.function = aggr_timeout; | ||
1452 | p_aggr->timer.data = (unsigned long) p_aggr; | ||
1453 | 1689 | ||
1454 | p_aggr->timer_scheduled = false; | 1690 | aggr_conn->timer_scheduled = false; |
1455 | skb_queue_head_init(&p_aggr->free_q); | ||
1456 | |||
1457 | ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS); | ||
1458 | 1691 | ||
1459 | for (i = 0; i < NUM_OF_TIDS; i++) { | 1692 | for (i = 0; i < NUM_OF_TIDS; i++) { |
1460 | rxtid = &p_aggr->rx_tid[i]; | 1693 | rxtid = &aggr_conn->rx_tid[i]; |
1461 | rxtid->aggr = false; | 1694 | rxtid->aggr = false; |
1462 | rxtid->progress = false; | 1695 | rxtid->progress = false; |
1463 | rxtid->timer_mon = false; | 1696 | rxtid->timer_mon = false; |
@@ -1465,29 +1698,75 @@ struct aggr_info *aggr_init(struct net_device *dev) | |||
1465 | spin_lock_init(&rxtid->lock); | 1698 | spin_lock_init(&rxtid->lock); |
1466 | } | 1699 | } |
1467 | 1700 | ||
1701 | } | ||
1702 | |||
1703 | struct aggr_info *aggr_init(struct ath6kl_vif *vif) | ||
1704 | { | ||
1705 | struct aggr_info *p_aggr = NULL; | ||
1706 | |||
1707 | p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL); | ||
1708 | if (!p_aggr) { | ||
1709 | ath6kl_err("failed to alloc memory for aggr_node\n"); | ||
1710 | return NULL; | ||
1711 | } | ||
1712 | |||
1713 | p_aggr->aggr_conn = kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); | ||
1714 | if (!p_aggr->aggr_conn) { | ||
1715 | ath6kl_err("failed to alloc memory for connection specific aggr info\n"); | ||
1716 | kfree(p_aggr); | ||
1717 | return NULL; | ||
1718 | } | ||
1719 | |||
1720 | aggr_conn_init(vif, p_aggr, p_aggr->aggr_conn); | ||
1721 | |||
1722 | skb_queue_head_init(&p_aggr->rx_amsdu_freeq); | ||
1723 | ath6kl_alloc_netbufs(&p_aggr->rx_amsdu_freeq, AGGR_NUM_OF_FREE_NETBUFS); | ||
1724 | |||
1468 | return p_aggr; | 1725 | return p_aggr; |
1469 | } | 1726 | } |
1470 | 1727 | ||
1471 | void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid) | 1728 | void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid_mux) |
1472 | { | 1729 | { |
1473 | struct aggr_info *p_aggr = vif->aggr_cntxt; | 1730 | struct ath6kl_sta *sta; |
1474 | struct rxtid *rxtid; | 1731 | struct rxtid *rxtid; |
1732 | struct aggr_info_conn *aggr_conn = NULL; | ||
1733 | u8 tid, aid; | ||
1734 | |||
1735 | if (vif->nw_type == AP_NETWORK) { | ||
1736 | aid = ath6kl_get_aid(tid_mux); | ||
1737 | sta = ath6kl_find_sta_by_aid(vif->ar, aid); | ||
1738 | if (sta) | ||
1739 | aggr_conn = sta->aggr_conn; | ||
1740 | } else | ||
1741 | aggr_conn = vif->aggr_cntxt->aggr_conn; | ||
1742 | |||
1743 | if (!aggr_conn) | ||
1744 | return; | ||
1475 | 1745 | ||
1476 | if (!p_aggr) | 1746 | tid = ath6kl_get_tid(tid_mux); |
1747 | if (tid >= NUM_OF_TIDS) | ||
1477 | return; | 1748 | return; |
1478 | 1749 | ||
1479 | rxtid = &p_aggr->rx_tid[tid]; | 1750 | rxtid = &aggr_conn->rx_tid[tid]; |
1480 | 1751 | ||
1481 | if (rxtid->aggr) | 1752 | if (rxtid->aggr) |
1482 | aggr_delete_tid_state(p_aggr, tid); | 1753 | aggr_delete_tid_state(aggr_conn, tid); |
1483 | } | 1754 | } |
1484 | 1755 | ||
1485 | void aggr_reset_state(struct aggr_info *aggr_info) | 1756 | void aggr_reset_state(struct aggr_info_conn *aggr_conn) |
1486 | { | 1757 | { |
1487 | u8 tid; | 1758 | u8 tid; |
1488 | 1759 | ||
1760 | if (!aggr_conn) | ||
1761 | return; | ||
1762 | |||
1763 | if (aggr_conn->timer_scheduled) { | ||
1764 | del_timer(&aggr_conn->timer); | ||
1765 | aggr_conn->timer_scheduled = false; | ||
1766 | } | ||
1767 | |||
1489 | for (tid = 0; tid < NUM_OF_TIDS; tid++) | 1768 | for (tid = 0; tid < NUM_OF_TIDS; tid++) |
1490 | aggr_delete_tid_state(aggr_info, tid); | 1769 | aggr_delete_tid_state(aggr_conn, tid); |
1491 | } | 1770 | } |
1492 | 1771 | ||
1493 | /* clean up our amsdu buffer list */ | 1772 | /* clean up our amsdu buffer list */ |
@@ -1514,28 +1793,11 @@ void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar) | |||
1514 | 1793 | ||
1515 | void aggr_module_destroy(struct aggr_info *aggr_info) | 1794 | void aggr_module_destroy(struct aggr_info *aggr_info) |
1516 | { | 1795 | { |
1517 | struct rxtid *rxtid; | ||
1518 | u8 i, k; | ||
1519 | |||
1520 | if (!aggr_info) | 1796 | if (!aggr_info) |
1521 | return; | 1797 | return; |
1522 | 1798 | ||
1523 | if (aggr_info->timer_scheduled) { | 1799 | aggr_reset_state(aggr_info->aggr_conn); |
1524 | del_timer(&aggr_info->timer); | 1800 | skb_queue_purge(&aggr_info->rx_amsdu_freeq); |
1525 | aggr_info->timer_scheduled = false; | 1801 | kfree(aggr_info->aggr_conn); |
1526 | } | ||
1527 | |||
1528 | for (i = 0; i < NUM_OF_TIDS; i++) { | ||
1529 | rxtid = &aggr_info->rx_tid[i]; | ||
1530 | if (rxtid->hold_q) { | ||
1531 | for (k = 0; k < rxtid->hold_q_sz; k++) | ||
1532 | dev_kfree_skb(rxtid->hold_q[k].skb); | ||
1533 | kfree(rxtid->hold_q); | ||
1534 | } | ||
1535 | |||
1536 | skb_queue_purge(&rxtid->q); | ||
1537 | } | ||
1538 | |||
1539 | skb_queue_purge(&aggr_info->free_q); | ||
1540 | kfree(aggr_info); | 1802 | kfree(aggr_info); |
1541 | } | 1803 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c new file mode 100644 index 000000000000..c72567c6d338 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/usb.c | |||
@@ -0,0 +1,431 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007-2011 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/usb.h> | ||
19 | |||
20 | #include "debug.h" | ||
21 | #include "core.h" | ||
22 | |||
23 | /* usb device object */ | ||
24 | struct ath6kl_usb { | ||
25 | struct usb_device *udev; | ||
26 | struct usb_interface *interface; | ||
27 | u8 *diag_cmd_buffer; | ||
28 | u8 *diag_resp_buffer; | ||
29 | struct ath6kl *ar; | ||
30 | }; | ||
31 | |||
32 | /* diagnostic command defnitions */ | ||
33 | #define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1 | ||
34 | #define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2 | ||
35 | #define ATH6KL_USB_CONTROL_REQ_DIAG_CMD 3 | ||
36 | #define ATH6KL_USB_CONTROL_REQ_DIAG_RESP 4 | ||
37 | |||
38 | #define ATH6KL_USB_CTRL_DIAG_CC_READ 0 | ||
39 | #define ATH6KL_USB_CTRL_DIAG_CC_WRITE 1 | ||
40 | |||
41 | struct ath6kl_usb_ctrl_diag_cmd_write { | ||
42 | __le32 cmd; | ||
43 | __le32 address; | ||
44 | __le32 value; | ||
45 | __le32 _pad[1]; | ||
46 | } __packed; | ||
47 | |||
48 | struct ath6kl_usb_ctrl_diag_cmd_read { | ||
49 | __le32 cmd; | ||
50 | __le32 address; | ||
51 | } __packed; | ||
52 | |||
53 | struct ath6kl_usb_ctrl_diag_resp_read { | ||
54 | __le32 value; | ||
55 | } __packed; | ||
56 | |||
57 | #define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write)) | ||
58 | #define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read)) | ||
59 | |||
60 | static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb) | ||
61 | { | ||
62 | usb_set_intfdata(ar_usb->interface, NULL); | ||
63 | |||
64 | kfree(ar_usb->diag_cmd_buffer); | ||
65 | kfree(ar_usb->diag_resp_buffer); | ||
66 | |||
67 | kfree(ar_usb); | ||
68 | } | ||
69 | |||
70 | static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface) | ||
71 | { | ||
72 | struct ath6kl_usb *ar_usb = NULL; | ||
73 | struct usb_device *dev = interface_to_usbdev(interface); | ||
74 | int status = 0; | ||
75 | |||
76 | ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL); | ||
77 | if (ar_usb == NULL) | ||
78 | goto fail_ath6kl_usb_create; | ||
79 | |||
80 | memset(ar_usb, 0, sizeof(struct ath6kl_usb)); | ||
81 | usb_set_intfdata(interface, ar_usb); | ||
82 | ar_usb->udev = dev; | ||
83 | ar_usb->interface = interface; | ||
84 | |||
85 | ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL); | ||
86 | if (ar_usb->diag_cmd_buffer == NULL) { | ||
87 | status = -ENOMEM; | ||
88 | goto fail_ath6kl_usb_create; | ||
89 | } | ||
90 | |||
91 | ar_usb->diag_resp_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_RESP, | ||
92 | GFP_KERNEL); | ||
93 | if (ar_usb->diag_resp_buffer == NULL) { | ||
94 | status = -ENOMEM; | ||
95 | goto fail_ath6kl_usb_create; | ||
96 | } | ||
97 | |||
98 | fail_ath6kl_usb_create: | ||
99 | if (status != 0) { | ||
100 | ath6kl_usb_destroy(ar_usb); | ||
101 | ar_usb = NULL; | ||
102 | } | ||
103 | return ar_usb; | ||
104 | } | ||
105 | |||
106 | static void ath6kl_usb_device_detached(struct usb_interface *interface) | ||
107 | { | ||
108 | struct ath6kl_usb *ar_usb; | ||
109 | |||
110 | ar_usb = usb_get_intfdata(interface); | ||
111 | if (ar_usb == NULL) | ||
112 | return; | ||
113 | |||
114 | ath6kl_stop_txrx(ar_usb->ar); | ||
115 | |||
116 | ath6kl_core_cleanup(ar_usb->ar); | ||
117 | |||
118 | ath6kl_usb_destroy(ar_usb); | ||
119 | } | ||
120 | |||
121 | static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb, | ||
122 | u8 req, u16 value, u16 index, void *data, | ||
123 | u32 size) | ||
124 | { | ||
125 | u8 *buf = NULL; | ||
126 | int ret; | ||
127 | |||
128 | if (size > 0) { | ||
129 | buf = kmalloc(size, GFP_KERNEL); | ||
130 | if (buf == NULL) | ||
131 | return -ENOMEM; | ||
132 | |||
133 | memcpy(buf, data, size); | ||
134 | } | ||
135 | |||
136 | /* note: if successful returns number of bytes transfered */ | ||
137 | ret = usb_control_msg(ar_usb->udev, | ||
138 | usb_sndctrlpipe(ar_usb->udev, 0), | ||
139 | req, | ||
140 | USB_DIR_OUT | USB_TYPE_VENDOR | | ||
141 | USB_RECIP_DEVICE, value, index, buf, | ||
142 | size, 1000); | ||
143 | |||
144 | if (ret < 0) { | ||
145 | ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n", | ||
146 | __func__, ret); | ||
147 | } | ||
148 | |||
149 | kfree(buf); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb, | ||
155 | u8 req, u16 value, u16 index, void *data, | ||
156 | u32 size) | ||
157 | { | ||
158 | u8 *buf = NULL; | ||
159 | int ret; | ||
160 | |||
161 | if (size > 0) { | ||
162 | buf = kmalloc(size, GFP_KERNEL); | ||
163 | if (buf == NULL) | ||
164 | return -ENOMEM; | ||
165 | } | ||
166 | |||
167 | /* note: if successful returns number of bytes transfered */ | ||
168 | ret = usb_control_msg(ar_usb->udev, | ||
169 | usb_rcvctrlpipe(ar_usb->udev, 0), | ||
170 | req, | ||
171 | USB_DIR_IN | USB_TYPE_VENDOR | | ||
172 | USB_RECIP_DEVICE, value, index, buf, | ||
173 | size, 2 * HZ); | ||
174 | |||
175 | if (ret < 0) { | ||
176 | ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n", | ||
177 | __func__, ret); | ||
178 | } | ||
179 | |||
180 | memcpy((u8 *) data, buf, size); | ||
181 | |||
182 | kfree(buf); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int ath6kl_usb_ctrl_msg_exchange(struct ath6kl_usb *ar_usb, | ||
188 | u8 req_val, u8 *req_buf, u32 req_len, | ||
189 | u8 resp_val, u8 *resp_buf, u32 *resp_len) | ||
190 | { | ||
191 | int ret; | ||
192 | |||
193 | /* send command */ | ||
194 | ret = ath6kl_usb_submit_ctrl_out(ar_usb, req_val, 0, 0, | ||
195 | req_buf, req_len); | ||
196 | |||
197 | if (ret != 0) | ||
198 | return ret; | ||
199 | |||
200 | if (resp_buf == NULL) { | ||
201 | /* no expected response */ | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | /* get response */ | ||
206 | ret = ath6kl_usb_submit_ctrl_in(ar_usb, resp_val, 0, 0, | ||
207 | resp_buf, *resp_len); | ||
208 | |||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | static int ath6kl_usb_diag_read32(struct ath6kl *ar, u32 address, u32 *data) | ||
213 | { | ||
214 | struct ath6kl_usb *ar_usb = ar->hif_priv; | ||
215 | struct ath6kl_usb_ctrl_diag_resp_read *resp; | ||
216 | struct ath6kl_usb_ctrl_diag_cmd_read *cmd; | ||
217 | u32 resp_len; | ||
218 | int ret; | ||
219 | |||
220 | cmd = (struct ath6kl_usb_ctrl_diag_cmd_read *) ar_usb->diag_cmd_buffer; | ||
221 | |||
222 | memset(cmd, 0, sizeof(*cmd)); | ||
223 | cmd->cmd = ATH6KL_USB_CTRL_DIAG_CC_READ; | ||
224 | cmd->address = cpu_to_le32(address); | ||
225 | resp_len = sizeof(*resp); | ||
226 | |||
227 | ret = ath6kl_usb_ctrl_msg_exchange(ar_usb, | ||
228 | ATH6KL_USB_CONTROL_REQ_DIAG_CMD, | ||
229 | (u8 *) cmd, | ||
230 | sizeof(struct ath6kl_usb_ctrl_diag_cmd_write), | ||
231 | ATH6KL_USB_CONTROL_REQ_DIAG_RESP, | ||
232 | ar_usb->diag_resp_buffer, &resp_len); | ||
233 | |||
234 | if (ret) | ||
235 | return ret; | ||
236 | |||
237 | resp = (struct ath6kl_usb_ctrl_diag_resp_read *) | ||
238 | ar_usb->diag_resp_buffer; | ||
239 | |||
240 | *data = le32_to_cpu(resp->value); | ||
241 | |||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data) | ||
246 | { | ||
247 | struct ath6kl_usb *ar_usb = ar->hif_priv; | ||
248 | struct ath6kl_usb_ctrl_diag_cmd_write *cmd; | ||
249 | |||
250 | cmd = (struct ath6kl_usb_ctrl_diag_cmd_write *) ar_usb->diag_cmd_buffer; | ||
251 | |||
252 | memset(cmd, 0, sizeof(struct ath6kl_usb_ctrl_diag_cmd_write)); | ||
253 | cmd->cmd = cpu_to_le32(ATH6KL_USB_CTRL_DIAG_CC_WRITE); | ||
254 | cmd->address = cpu_to_le32(address); | ||
255 | cmd->value = data; | ||
256 | |||
257 | return ath6kl_usb_ctrl_msg_exchange(ar_usb, | ||
258 | ATH6KL_USB_CONTROL_REQ_DIAG_CMD, | ||
259 | (u8 *) cmd, | ||
260 | sizeof(*cmd), | ||
261 | 0, NULL, NULL); | ||
262 | |||
263 | } | ||
264 | |||
265 | static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len) | ||
266 | { | ||
267 | struct ath6kl_usb *ar_usb = ar->hif_priv; | ||
268 | int ret; | ||
269 | |||
270 | /* get response */ | ||
271 | ret = ath6kl_usb_submit_ctrl_in(ar_usb, | ||
272 | ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP, | ||
273 | 0, 0, buf, len); | ||
274 | if (ret != 0) { | ||
275 | ath6kl_err("Unable to read the bmi data from the device: %d\n", | ||
276 | ret); | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len) | ||
284 | { | ||
285 | struct ath6kl_usb *ar_usb = ar->hif_priv; | ||
286 | int ret; | ||
287 | |||
288 | /* send command */ | ||
289 | ret = ath6kl_usb_submit_ctrl_out(ar_usb, | ||
290 | ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD, | ||
291 | 0, 0, buf, len); | ||
292 | if (ret != 0) { | ||
293 | ath6kl_err("unable to send the bmi data to the device: %d\n", | ||
294 | ret); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int ath6kl_usb_power_on(struct ath6kl *ar) | ||
302 | { | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int ath6kl_usb_power_off(struct ath6kl *ar) | ||
307 | { | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static const struct ath6kl_hif_ops ath6kl_usb_ops = { | ||
312 | .diag_read32 = ath6kl_usb_diag_read32, | ||
313 | .diag_write32 = ath6kl_usb_diag_write32, | ||
314 | .bmi_read = ath6kl_usb_bmi_read, | ||
315 | .bmi_write = ath6kl_usb_bmi_write, | ||
316 | .power_on = ath6kl_usb_power_on, | ||
317 | .power_off = ath6kl_usb_power_off, | ||
318 | }; | ||
319 | |||
320 | /* ath6kl usb driver registered functions */ | ||
321 | static int ath6kl_usb_probe(struct usb_interface *interface, | ||
322 | const struct usb_device_id *id) | ||
323 | { | ||
324 | struct usb_device *dev = interface_to_usbdev(interface); | ||
325 | struct ath6kl *ar; | ||
326 | struct ath6kl_usb *ar_usb = NULL; | ||
327 | int vendor_id, product_id; | ||
328 | int ret = 0; | ||
329 | |||
330 | usb_get_dev(dev); | ||
331 | |||
332 | vendor_id = le16_to_cpu(dev->descriptor.idVendor); | ||
333 | product_id = le16_to_cpu(dev->descriptor.idProduct); | ||
334 | |||
335 | ath6kl_dbg(ATH6KL_DBG_USB, "vendor_id = %04x\n", vendor_id); | ||
336 | ath6kl_dbg(ATH6KL_DBG_USB, "product_id = %04x\n", product_id); | ||
337 | |||
338 | if (interface->cur_altsetting) | ||
339 | ath6kl_dbg(ATH6KL_DBG_USB, "USB Interface %d\n", | ||
340 | interface->cur_altsetting->desc.bInterfaceNumber); | ||
341 | |||
342 | |||
343 | if (dev->speed == USB_SPEED_HIGH) | ||
344 | ath6kl_dbg(ATH6KL_DBG_USB, "USB 2.0 Host\n"); | ||
345 | else | ||
346 | ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n"); | ||
347 | |||
348 | ar_usb = ath6kl_usb_create(interface); | ||
349 | |||
350 | if (ar_usb == NULL) { | ||
351 | ret = -ENOMEM; | ||
352 | goto err_usb_put; | ||
353 | } | ||
354 | |||
355 | ar = ath6kl_core_create(&ar_usb->udev->dev); | ||
356 | if (ar == NULL) { | ||
357 | ath6kl_err("Failed to alloc ath6kl core\n"); | ||
358 | ret = -ENOMEM; | ||
359 | goto err_usb_destroy; | ||
360 | } | ||
361 | |||
362 | ar->hif_priv = ar_usb; | ||
363 | ar->hif_type = ATH6KL_HIF_TYPE_USB; | ||
364 | ar->hif_ops = &ath6kl_usb_ops; | ||
365 | ar->mbox_info.block_size = 16; | ||
366 | ar->bmi.max_data_size = 252; | ||
367 | |||
368 | ar_usb->ar = ar; | ||
369 | |||
370 | ret = ath6kl_core_init(ar); | ||
371 | if (ret) { | ||
372 | ath6kl_err("Failed to init ath6kl core: %d\n", ret); | ||
373 | goto err_core_free; | ||
374 | } | ||
375 | |||
376 | return ret; | ||
377 | |||
378 | err_core_free: | ||
379 | ath6kl_core_destroy(ar); | ||
380 | err_usb_destroy: | ||
381 | ath6kl_usb_destroy(ar_usb); | ||
382 | err_usb_put: | ||
383 | usb_put_dev(dev); | ||
384 | |||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | static void ath6kl_usb_remove(struct usb_interface *interface) | ||
389 | { | ||
390 | usb_put_dev(interface_to_usbdev(interface)); | ||
391 | ath6kl_usb_device_detached(interface); | ||
392 | } | ||
393 | |||
394 | /* table of devices that work with this driver */ | ||
395 | static struct usb_device_id ath6kl_usb_ids[] = { | ||
396 | {USB_DEVICE(0x0cf3, 0x9374)}, | ||
397 | { /* Terminating entry */ }, | ||
398 | }; | ||
399 | |||
400 | MODULE_DEVICE_TABLE(usb, ath6kl_usb_ids); | ||
401 | |||
402 | static struct usb_driver ath6kl_usb_driver = { | ||
403 | .name = "ath6kl_usb", | ||
404 | .probe = ath6kl_usb_probe, | ||
405 | .disconnect = ath6kl_usb_remove, | ||
406 | .id_table = ath6kl_usb_ids, | ||
407 | }; | ||
408 | |||
409 | static int ath6kl_usb_init(void) | ||
410 | { | ||
411 | usb_register(&ath6kl_usb_driver); | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static void ath6kl_usb_exit(void) | ||
416 | { | ||
417 | usb_deregister(&ath6kl_usb_driver); | ||
418 | } | ||
419 | |||
420 | module_init(ath6kl_usb_init); | ||
421 | module_exit(ath6kl_usb_exit); | ||
422 | |||
423 | MODULE_AUTHOR("Atheros Communications, Inc."); | ||
424 | MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices"); | ||
425 | MODULE_LICENSE("Dual BSD/GPL"); | ||
426 | MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE); | ||
427 | MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE); | ||
428 | MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); | ||
429 | MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE); | ||
430 | MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); | ||
431 | MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); | ||
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index f6f2aa27fc20..18fa9aa8af92 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -180,7 +180,7 @@ static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb, | |||
180 | } | 180 | } |
181 | 181 | ||
182 | int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, | 182 | int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, |
183 | u8 msg_type, bool more_data, | 183 | u8 msg_type, u32 flags, |
184 | enum wmi_data_hdr_data_type data_type, | 184 | enum wmi_data_hdr_data_type data_type, |
185 | u8 meta_ver, void *tx_meta_info, u8 if_idx) | 185 | u8 meta_ver, void *tx_meta_info, u8 if_idx) |
186 | { | 186 | { |
@@ -204,17 +204,19 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, | |||
204 | data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT; | 204 | data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT; |
205 | data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT; | 205 | data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT; |
206 | 206 | ||
207 | if (more_data) | 207 | if (flags & WMI_DATA_HDR_FLAGS_MORE) |
208 | data_hdr->info |= | 208 | data_hdr->info |= WMI_DATA_HDR_MORE; |
209 | WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT; | ||
210 | 209 | ||
211 | data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT); | 210 | if (flags & WMI_DATA_HDR_FLAGS_EOSP) |
212 | data_hdr->info3 = cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK); | 211 | data_hdr->info3 |= cpu_to_le16(WMI_DATA_HDR_EOSP); |
212 | |||
213 | data_hdr->info2 |= cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT); | ||
214 | data_hdr->info3 |= cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK); | ||
213 | 215 | ||
214 | return 0; | 216 | return 0; |
215 | } | 217 | } |
216 | 218 | ||
217 | static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri) | 219 | u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri) |
218 | { | 220 | { |
219 | struct iphdr *ip_hdr = (struct iphdr *) pkt; | 221 | struct iphdr *ip_hdr = (struct iphdr *) pkt; |
220 | u8 ip_pri; | 222 | u8 ip_pri; |
@@ -236,6 +238,11 @@ static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri) | |||
236 | return ip_pri; | 238 | return ip_pri; |
237 | } | 239 | } |
238 | 240 | ||
241 | u8 ath6kl_wmi_get_traffic_class(u8 user_priority) | ||
242 | { | ||
243 | return up_to_ac[user_priority & 0x7]; | ||
244 | } | ||
245 | |||
239 | int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx, | 246 | int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx, |
240 | struct sk_buff *skb, | 247 | struct sk_buff *skb, |
241 | u32 layer2_priority, bool wmm_enabled, | 248 | u32 layer2_priority, bool wmm_enabled, |
@@ -419,9 +426,6 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) | |||
419 | ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n", | 426 | ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n", |
420 | evt->num_msg, evt->msg_len, evt->msg_type); | 427 | evt->num_msg, evt->msg_len, evt->msg_type); |
421 | 428 | ||
422 | if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_WMI)) | ||
423 | return 0; | ||
424 | |||
425 | for (index = 0; index < evt->num_msg; index++) { | 429 | for (index = 0; index < evt->num_msg; index++) { |
426 | size = sizeof(struct wmi_tx_complete_event) + | 430 | size = sizeof(struct wmi_tx_complete_event) + |
427 | (index * sizeof(struct tx_complete_msg_v1)); | 431 | (index * sizeof(struct tx_complete_msg_v1)); |
@@ -786,12 +790,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, | |||
786 | ev->u.ap_sta.keymgmt, | 790 | ev->u.ap_sta.keymgmt, |
787 | le16_to_cpu(ev->u.ap_sta.cipher), | 791 | le16_to_cpu(ev->u.ap_sta.cipher), |
788 | ev->u.ap_sta.apsd_info); | 792 | ev->u.ap_sta.apsd_info); |
793 | |||
789 | ath6kl_connect_ap_mode_sta( | 794 | ath6kl_connect_ap_mode_sta( |
790 | vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr, | 795 | vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr, |
791 | ev->u.ap_sta.keymgmt, | 796 | ev->u.ap_sta.keymgmt, |
792 | le16_to_cpu(ev->u.ap_sta.cipher), | 797 | le16_to_cpu(ev->u.ap_sta.cipher), |
793 | ev->u.ap_sta.auth, ev->assoc_req_len, | 798 | ev->u.ap_sta.auth, ev->assoc_req_len, |
794 | ev->assoc_info + ev->beacon_ie_len); | 799 | ev->assoc_info + ev->beacon_ie_len, |
800 | ev->u.ap_sta.apsd_info); | ||
795 | } | 801 | } |
796 | return 0; | 802 | return 0; |
797 | } | 803 | } |
@@ -1145,9 +1151,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) | |||
1145 | return 0; | 1151 | return 0; |
1146 | } | 1152 | } |
1147 | 1153 | ||
1148 | static int ath6kl_wmi_tcmd_test_report_rx(struct wmi *wmi, u8 *datap, int len) | 1154 | static int ath6kl_wmi_test_rx(struct wmi *wmi, u8 *datap, int len) |
1149 | { | 1155 | { |
1150 | ath6kl_tm_rx_report_event(wmi->parent_dev, datap, len); | 1156 | ath6kl_tm_rx_event(wmi->parent_dev, datap, len); |
1151 | 1157 | ||
1152 | return 0; | 1158 | return 0; |
1153 | } | 1159 | } |
@@ -2479,15 +2485,16 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class, | |||
2479 | return ret; | 2485 | return ret; |
2480 | } | 2486 | } |
2481 | 2487 | ||
2482 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd) | 2488 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx, |
2489 | __be32 ips0, __be32 ips1) | ||
2483 | { | 2490 | { |
2484 | struct sk_buff *skb; | 2491 | struct sk_buff *skb; |
2485 | struct wmi_set_ip_cmd *cmd; | 2492 | struct wmi_set_ip_cmd *cmd; |
2486 | int ret; | 2493 | int ret; |
2487 | 2494 | ||
2488 | /* Multicast address are not valid */ | 2495 | /* Multicast address are not valid */ |
2489 | if ((*((u8 *) &ip_cmd->ips[0]) >= 0xE0) || | 2496 | if (ipv4_is_multicast(ips0) || |
2490 | (*((u8 *) &ip_cmd->ips[1]) >= 0xE0)) | 2497 | ipv4_is_multicast(ips1)) |
2491 | return -EINVAL; | 2498 | return -EINVAL; |
2492 | 2499 | ||
2493 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd)); | 2500 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd)); |
@@ -2495,9 +2502,10 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd) | |||
2495 | return -ENOMEM; | 2502 | return -ENOMEM; |
2496 | 2503 | ||
2497 | cmd = (struct wmi_set_ip_cmd *) skb->data; | 2504 | cmd = (struct wmi_set_ip_cmd *) skb->data; |
2498 | memcpy(cmd, ip_cmd, sizeof(struct wmi_set_ip_cmd)); | 2505 | cmd->ips[0] = ips0; |
2506 | cmd->ips[1] = ips1; | ||
2499 | 2507 | ||
2500 | ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_IP_CMDID, | 2508 | ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IP_CMDID, |
2501 | NO_SYNC_WMIFLAG); | 2509 | NO_SYNC_WMIFLAG); |
2502 | return ret; | 2510 | return ret; |
2503 | } | 2511 | } |
@@ -2582,6 +2590,18 @@ int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, | |||
2582 | return ret; | 2590 | return ret; |
2583 | } | 2591 | } |
2584 | 2592 | ||
2593 | /* This command has zero length payload */ | ||
2594 | static int ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(struct wmi *wmi, | ||
2595 | struct ath6kl_vif *vif) | ||
2596 | { | ||
2597 | struct ath6kl *ar = wmi->parent_dev; | ||
2598 | |||
2599 | set_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); | ||
2600 | wake_up(&ar->event_wq); | ||
2601 | |||
2602 | return 0; | ||
2603 | } | ||
2604 | |||
2585 | int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, | 2605 | int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, |
2586 | enum ath6kl_wow_mode wow_mode, | 2606 | enum ath6kl_wow_mode wow_mode, |
2587 | u32 filter, u16 host_req_delay) | 2607 | u32 filter, u16 host_req_delay) |
@@ -2612,7 +2632,8 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, | |||
2612 | 2632 | ||
2613 | int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | 2633 | int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, |
2614 | u8 list_id, u8 filter_size, | 2634 | u8 list_id, u8 filter_size, |
2615 | u8 filter_offset, u8 *filter, u8 *mask) | 2635 | u8 filter_offset, const u8 *filter, |
2636 | const u8 *mask) | ||
2616 | { | 2637 | { |
2617 | struct sk_buff *skb; | 2638 | struct sk_buff *skb; |
2618 | struct wmi_add_wow_pattern_cmd *cmd; | 2639 | struct wmi_add_wow_pattern_cmd *cmd; |
@@ -2853,6 +2874,51 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len) | |||
2853 | return ret; | 2874 | return ret; |
2854 | } | 2875 | } |
2855 | 2876 | ||
2877 | int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on) | ||
2878 | { | ||
2879 | struct sk_buff *skb; | ||
2880 | struct wmi_mcast_filter_cmd *cmd; | ||
2881 | int ret; | ||
2882 | |||
2883 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2884 | if (!skb) | ||
2885 | return -ENOMEM; | ||
2886 | |||
2887 | cmd = (struct wmi_mcast_filter_cmd *) skb->data; | ||
2888 | cmd->mcast_all_enable = mc_all_on; | ||
2889 | |||
2890 | ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_MCAST_FILTER_CMDID, | ||
2891 | NO_SYNC_WMIFLAG); | ||
2892 | return ret; | ||
2893 | } | ||
2894 | |||
2895 | int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, | ||
2896 | u8 *filter, bool add_filter) | ||
2897 | { | ||
2898 | struct sk_buff *skb; | ||
2899 | struct wmi_mcast_filter_add_del_cmd *cmd; | ||
2900 | int ret; | ||
2901 | |||
2902 | if ((filter[0] != 0x33 || filter[1] != 0x33) && | ||
2903 | (filter[0] != 0x01 || filter[1] != 0x00 || | ||
2904 | filter[2] != 0x5e || filter[3] > 0x7f)) { | ||
2905 | ath6kl_warn("invalid multicast filter address\n"); | ||
2906 | return -EINVAL; | ||
2907 | } | ||
2908 | |||
2909 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2910 | if (!skb) | ||
2911 | return -ENOMEM; | ||
2912 | |||
2913 | cmd = (struct wmi_mcast_filter_add_del_cmd *) skb->data; | ||
2914 | memcpy(cmd->mcast_mac, filter, ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE); | ||
2915 | ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, | ||
2916 | add_filter ? WMI_SET_MCAST_FILTER_CMDID : | ||
2917 | WMI_DEL_MCAST_FILTER_CMDID, | ||
2918 | NO_SYNC_WMIFLAG); | ||
2919 | |||
2920 | return ret; | ||
2921 | } | ||
2856 | 2922 | ||
2857 | s32 ath6kl_wmi_get_rate(s8 rate_index) | 2923 | s32 ath6kl_wmi_get_rate(s8 rate_index) |
2858 | { | 2924 | { |
@@ -2946,6 +3012,43 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac, | |||
2946 | NO_SYNC_WMIFLAG); | 3012 | NO_SYNC_WMIFLAG); |
2947 | } | 3013 | } |
2948 | 3014 | ||
3015 | /* This command will be used to enable/disable AP uAPSD feature */ | ||
3016 | int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable) | ||
3017 | { | ||
3018 | struct wmi_ap_set_apsd_cmd *cmd; | ||
3019 | struct sk_buff *skb; | ||
3020 | |||
3021 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
3022 | if (!skb) | ||
3023 | return -ENOMEM; | ||
3024 | |||
3025 | cmd = (struct wmi_ap_set_apsd_cmd *)skb->data; | ||
3026 | cmd->enable = enable; | ||
3027 | |||
3028 | return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_APSD_CMDID, | ||
3029 | NO_SYNC_WMIFLAG); | ||
3030 | } | ||
3031 | |||
3032 | int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, u8 if_idx, | ||
3033 | u16 aid, u16 bitmap, u32 flags) | ||
3034 | { | ||
3035 | struct wmi_ap_apsd_buffered_traffic_cmd *cmd; | ||
3036 | struct sk_buff *skb; | ||
3037 | |||
3038 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
3039 | if (!skb) | ||
3040 | return -ENOMEM; | ||
3041 | |||
3042 | cmd = (struct wmi_ap_apsd_buffered_traffic_cmd *)skb->data; | ||
3043 | cmd->aid = cpu_to_le16(aid); | ||
3044 | cmd->bitmap = cpu_to_le16(bitmap); | ||
3045 | cmd->flags = cpu_to_le32(flags); | ||
3046 | |||
3047 | return ath6kl_wmi_cmd_send(wmi, if_idx, skb, | ||
3048 | WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID, | ||
3049 | NO_SYNC_WMIFLAG); | ||
3050 | } | ||
3051 | |||
2949 | static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len, | 3052 | static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len, |
2950 | struct ath6kl_vif *vif) | 3053 | struct ath6kl_vif *vif) |
2951 | { | 3054 | { |
@@ -3400,7 +3503,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
3400 | break; | 3503 | break; |
3401 | case WMI_TEST_EVENTID: | 3504 | case WMI_TEST_EVENTID: |
3402 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n"); | 3505 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n"); |
3403 | ret = ath6kl_wmi_tcmd_test_report_rx(wmi, datap, len); | 3506 | ret = ath6kl_wmi_test_rx(wmi, datap, len); |
3404 | break; | 3507 | break; |
3405 | case WMI_GET_FIXRATES_CMDID: | 3508 | case WMI_GET_FIXRATES_CMDID: |
3406 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n"); | 3509 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n"); |
@@ -3465,6 +3568,11 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
3465 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); | 3568 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); |
3466 | ret = ath6kl_wmi_tx_complete_event_rx(datap, len); | 3569 | ret = ath6kl_wmi_tx_complete_event_rx(datap, len); |
3467 | break; | 3570 | break; |
3571 | case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID: | ||
3572 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
3573 | "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID"); | ||
3574 | ret = ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif); | ||
3575 | break; | ||
3468 | case WMI_REMAIN_ON_CHNL_EVENTID: | 3576 | case WMI_REMAIN_ON_CHNL_EVENTID: |
3469 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); | 3577 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); |
3470 | ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif); | 3578 | ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif); |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 42ac311eda4e..e7919869725e 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
@@ -149,8 +149,7 @@ enum wmi_msg_type { | |||
149 | #define WMI_DATA_HDR_PS_MASK 0x1 | 149 | #define WMI_DATA_HDR_PS_MASK 0x1 |
150 | #define WMI_DATA_HDR_PS_SHIFT 5 | 150 | #define WMI_DATA_HDR_PS_SHIFT 5 |
151 | 151 | ||
152 | #define WMI_DATA_HDR_MORE_MASK 0x1 | 152 | #define WMI_DATA_HDR_MORE 0x20 |
153 | #define WMI_DATA_HDR_MORE_SHIFT 5 | ||
154 | 153 | ||
155 | enum wmi_data_hdr_data_type { | 154 | enum wmi_data_hdr_data_type { |
156 | WMI_DATA_HDR_DATA_TYPE_802_3 = 0, | 155 | WMI_DATA_HDR_DATA_TYPE_802_3 = 0, |
@@ -160,6 +159,13 @@ enum wmi_data_hdr_data_type { | |||
160 | WMI_DATA_HDR_DATA_TYPE_ACL, | 159 | WMI_DATA_HDR_DATA_TYPE_ACL, |
161 | }; | 160 | }; |
162 | 161 | ||
162 | /* Bitmap of data header flags */ | ||
163 | enum wmi_data_hdr_flags { | ||
164 | WMI_DATA_HDR_FLAGS_MORE = 0x1, | ||
165 | WMI_DATA_HDR_FLAGS_EOSP = 0x2, | ||
166 | WMI_DATA_HDR_FLAGS_UAPSD = 0x4, | ||
167 | }; | ||
168 | |||
163 | #define WMI_DATA_HDR_DATA_TYPE_MASK 0x3 | 169 | #define WMI_DATA_HDR_DATA_TYPE_MASK 0x3 |
164 | #define WMI_DATA_HDR_DATA_TYPE_SHIFT 6 | 170 | #define WMI_DATA_HDR_DATA_TYPE_SHIFT 6 |
165 | 171 | ||
@@ -173,8 +179,12 @@ enum wmi_data_hdr_data_type { | |||
173 | #define WMI_DATA_HDR_META_MASK 0x7 | 179 | #define WMI_DATA_HDR_META_MASK 0x7 |
174 | #define WMI_DATA_HDR_META_SHIFT 13 | 180 | #define WMI_DATA_HDR_META_SHIFT 13 |
175 | 181 | ||
182 | /* Macros for operating on WMI_DATA_HDR (info3) field */ | ||
176 | #define WMI_DATA_HDR_IF_IDX_MASK 0xF | 183 | #define WMI_DATA_HDR_IF_IDX_MASK 0xF |
177 | 184 | ||
185 | #define WMI_DATA_HDR_TRIG 0x10 | ||
186 | #define WMI_DATA_HDR_EOSP 0x10 | ||
187 | |||
178 | struct wmi_data_hdr { | 188 | struct wmi_data_hdr { |
179 | s8 rssi; | 189 | s8 rssi; |
180 | 190 | ||
@@ -203,7 +213,8 @@ struct wmi_data_hdr { | |||
203 | /* | 213 | /* |
204 | * usage of info3, 16-bit: | 214 | * usage of info3, 16-bit: |
205 | * b3:b0 - Interface index | 215 | * b3:b0 - Interface index |
206 | * b15:b4 - Reserved | 216 | * b4 - uAPSD trigger in rx & EOSP in tx |
217 | * b15:b5 - Reserved | ||
207 | */ | 218 | */ |
208 | __le16 info3; | 219 | __le16 info3; |
209 | } __packed; | 220 | } __packed; |
@@ -257,6 +268,9 @@ static inline u8 wmi_data_hdr_get_if_idx(struct wmi_data_hdr *dhdr) | |||
257 | #define WMI_META_VERSION_1 0x01 | 268 | #define WMI_META_VERSION_1 0x01 |
258 | #define WMI_META_VERSION_2 0x02 | 269 | #define WMI_META_VERSION_2 0x02 |
259 | 270 | ||
271 | /* Flag to signal to FW to calculate TCP checksum */ | ||
272 | #define WMI_META_V2_FLAG_CSUM_OFFLOAD 0x01 | ||
273 | |||
260 | struct wmi_tx_meta_v1 { | 274 | struct wmi_tx_meta_v1 { |
261 | /* packet ID to identify the tx request */ | 275 | /* packet ID to identify the tx request */ |
262 | u8 pkt_id; | 276 | u8 pkt_id; |
@@ -646,7 +660,6 @@ enum auth_mode { | |||
646 | WPA2_AUTH_CCKM = 0x40, | 660 | WPA2_AUTH_CCKM = 0x40, |
647 | }; | 661 | }; |
648 | 662 | ||
649 | #define WMI_MIN_KEY_INDEX 0 | ||
650 | #define WMI_MAX_KEY_INDEX 3 | 663 | #define WMI_MAX_KEY_INDEX 3 |
651 | 664 | ||
652 | #define WMI_MAX_KEY_LEN 32 | 665 | #define WMI_MAX_KEY_LEN 32 |
@@ -1237,6 +1250,15 @@ enum target_event_report_config { | |||
1237 | NO_DISCONN_EVT_IN_RECONN | 1250 | NO_DISCONN_EVT_IN_RECONN |
1238 | }; | 1251 | }; |
1239 | 1252 | ||
1253 | struct wmi_mcast_filter_cmd { | ||
1254 | u8 mcast_all_enable; | ||
1255 | } __packed; | ||
1256 | |||
1257 | #define ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE 6 | ||
1258 | struct wmi_mcast_filter_add_del_cmd { | ||
1259 | u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; | ||
1260 | } __packed; | ||
1261 | |||
1240 | /* Command Replies */ | 1262 | /* Command Replies */ |
1241 | 1263 | ||
1242 | /* WMI_GET_CHANNEL_LIST_CMDID reply */ | 1264 | /* WMI_GET_CHANNEL_LIST_CMDID reply */ |
@@ -1335,6 +1357,8 @@ enum wmi_event_id { | |||
1335 | WMI_P2P_START_SDPD_EVENTID, | 1357 | WMI_P2P_START_SDPD_EVENTID, |
1336 | WMI_P2P_SDPD_RX_EVENTID, | 1358 | WMI_P2P_SDPD_RX_EVENTID, |
1337 | 1359 | ||
1360 | WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID = 0x1047, | ||
1361 | |||
1338 | WMI_THIN_RESERVED_START_EVENTID = 0x8000, | 1362 | WMI_THIN_RESERVED_START_EVENTID = 0x8000, |
1339 | /* Events in this range are reserved for thinmode */ | 1363 | /* Events in this range are reserved for thinmode */ |
1340 | WMI_THIN_RESERVED_END_EVENTID = 0x8fff, | 1364 | WMI_THIN_RESERVED_END_EVENTID = 0x8fff, |
@@ -1903,7 +1927,7 @@ struct wow_filter { | |||
1903 | 1927 | ||
1904 | struct wmi_set_ip_cmd { | 1928 | struct wmi_set_ip_cmd { |
1905 | /* IP in network byte order */ | 1929 | /* IP in network byte order */ |
1906 | __le32 ips[MAX_IP_ADDRS]; | 1930 | __be32 ips[MAX_IP_ADDRS]; |
1907 | } __packed; | 1931 | } __packed; |
1908 | 1932 | ||
1909 | enum ath6kl_wow_filters { | 1933 | enum ath6kl_wow_filters { |
@@ -2105,6 +2129,19 @@ struct wmi_rx_frame_format_cmd { | |||
2105 | } __packed; | 2129 | } __packed; |
2106 | 2130 | ||
2107 | /* AP mode events */ | 2131 | /* AP mode events */ |
2132 | struct wmi_ap_set_apsd_cmd { | ||
2133 | u8 enable; | ||
2134 | } __packed; | ||
2135 | |||
2136 | enum wmi_ap_apsd_buffered_traffic_flags { | ||
2137 | WMI_AP_APSD_NO_DELIVERY_FRAMES = 0x1, | ||
2138 | }; | ||
2139 | |||
2140 | struct wmi_ap_apsd_buffered_traffic_cmd { | ||
2141 | __le16 aid; | ||
2142 | __le16 bitmap; | ||
2143 | __le32 flags; | ||
2144 | } __packed; | ||
2108 | 2145 | ||
2109 | /* WMI_PS_POLL_EVENT */ | 2146 | /* WMI_PS_POLL_EVENT */ |
2110 | struct wmi_pspoll_event { | 2147 | struct wmi_pspoll_event { |
@@ -2321,7 +2358,7 @@ enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi); | |||
2321 | void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id); | 2358 | void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id); |
2322 | int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb); | 2359 | int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb); |
2323 | int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, | 2360 | int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, |
2324 | u8 msg_type, bool more_data, | 2361 | u8 msg_type, u32 flags, |
2325 | enum wmi_data_hdr_data_type data_type, | 2362 | enum wmi_data_hdr_data_type data_type, |
2326 | u8 meta_ver, void *tx_meta_info, u8 if_idx); | 2363 | u8 meta_ver, void *tx_meta_info, u8 if_idx); |
2327 | 2364 | ||
@@ -2417,7 +2454,8 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); | |||
2417 | 2454 | ||
2418 | s32 ath6kl_wmi_get_rate(s8 rate_index); | 2455 | s32 ath6kl_wmi_get_rate(s8 rate_index); |
2419 | 2456 | ||
2420 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd); | 2457 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx, |
2458 | __be32 ips0, __be32 ips1); | ||
2421 | int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, | 2459 | int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, |
2422 | enum ath6kl_host_mode host_mode); | 2460 | enum ath6kl_host_mode host_mode); |
2423 | int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, | 2461 | int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, |
@@ -2425,13 +2463,26 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, | |||
2425 | u32 filter, u16 host_req_delay); | 2463 | u32 filter, u16 host_req_delay); |
2426 | int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | 2464 | int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, |
2427 | u8 list_id, u8 filter_size, | 2465 | u8 list_id, u8 filter_size, |
2428 | u8 filter_offset, u8 *filter, u8 *mask); | 2466 | u8 filter_offset, const u8 *filter, |
2467 | const u8 *mask); | ||
2429 | int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | 2468 | int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, |
2430 | u16 list_id, u16 filter_id); | 2469 | u16 list_id, u16 filter_id); |
2431 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); | 2470 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); |
2432 | int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); | 2471 | int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); |
2433 | int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); | 2472 | int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); |
2473 | int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); | ||
2474 | int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, | ||
2475 | u8 *filter, bool add_filter); | ||
2476 | /* AP mode uAPSD */ | ||
2477 | int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); | ||
2478 | |||
2479 | int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, | ||
2480 | u8 if_idx, u16 aid, | ||
2481 | u16 bitmap, u32 flags); | ||
2482 | |||
2483 | u8 ath6kl_wmi_get_traffic_class(u8 user_priority); | ||
2434 | 2484 | ||
2485 | u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri); | ||
2435 | /* AP mode */ | 2486 | /* AP mode */ |
2436 | int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx, | 2487 | int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx, |
2437 | struct wmi_connect_cmd *p); | 2488 | struct wmi_connect_cmd *p); |
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index f317515d8bf3..424aabb2c730 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
@@ -981,7 +981,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) | |||
981 | return -ENOMEM; | 981 | return -ENOMEM; |
982 | 982 | ||
983 | while (len) { | 983 | while (len) { |
984 | transfer = min_t(int, len, 4096); | 984 | transfer = min_t(size_t, len, 4096); |
985 | memcpy(buf, data, transfer); | 985 | memcpy(buf, data, transfer); |
986 | 986 | ||
987 | err = usb_control_msg(hif_dev->udev, | 987 | err = usb_control_msg(hif_dev->udev, |
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 635b592ad961..a427a16bb739 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
@@ -1346,7 +1346,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
1346 | fc = hdr->frame_control; | 1346 | fc = hdr->frame_control; |
1347 | for (i = 0; i < sc->hw->max_rates; i++) { | 1347 | for (i = 0; i < sc->hw->max_rates; i++) { |
1348 | struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; | 1348 | struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; |
1349 | if (!rate->count) | 1349 | if (rate->idx < 0 || !rate->count) |
1350 | break; | 1350 | break; |
1351 | 1351 | ||
1352 | final_ts_idx = i; | 1352 | final_ts_idx = i; |