diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-03-13 14:45:40 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-03-13 14:45:40 -0400 |
commit | 843dc6644be05edfcb14f7f7ce5b2ab2bc15b429 (patch) | |
tree | 0e2c580ac949d2619522a64cc5a52585645491f5 /drivers | |
parent | 5d6a1b069b7f72298aff2306a2d02b0188668218 (diff) | |
parent | 9df2a0b7096873e91d1b6b0e842e9f6bdc7ee9fd (diff) |
Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
Diffstat (limited to 'drivers')
25 files changed, 1228 insertions, 667 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 9ba42fa04962..85746c3eb027 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | #------------------------------------------------------------------------------ | 1 | #------------------------------------------------------------------------------ |
2 | # Copyright (c) 2004-2010 Atheros Communications Inc. | 2 | # Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | # Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | # All rights reserved. | 4 | # All rights reserved. |
4 | # | 5 | # |
5 | # | 6 | # |
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c index aef00d5a1438..334dbd834b3a 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.c +++ b/drivers/net/wireless/ath/ath6kl/bmi.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -105,7 +106,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, | |||
105 | } | 106 | } |
106 | 107 | ||
107 | ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n", | 108 | ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n", |
108 | targ_info->version, targ_info->type); | 109 | targ_info->version, targ_info->type); |
109 | 110 | ||
110 | return 0; | 111 | return 0; |
111 | } | 112 | } |
@@ -192,7 +193,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | |||
192 | memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header); | 193 | memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header); |
193 | 194 | ||
194 | ath6kl_dbg(ATH6KL_DBG_BMI, | 195 | ath6kl_dbg(ATH6KL_DBG_BMI, |
195 | "bmi write memory: addr: 0x%x, len: %d\n", addr, len); | 196 | "bmi write memory: addr: 0x%x, len: %d\n", addr, len); |
196 | 197 | ||
197 | len_remain = len; | 198 | len_remain = len; |
198 | while (len_remain) { | 199 | while (len_remain) { |
@@ -434,7 +435,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len) | |||
434 | memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); | 435 | memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); |
435 | offset += sizeof(tx_len); | 436 | offset += sizeof(tx_len); |
436 | memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain], | 437 | memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain], |
437 | tx_len); | 438 | tx_len); |
438 | offset += tx_len; | 439 | offset += tx_len; |
439 | 440 | ||
440 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); | 441 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h index f1ca6812456d..18fdd69e1f71 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.h +++ b/drivers/net/wireless/ath/ath6kl/bmi.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -222,6 +223,29 @@ struct ath6kl_bmi_target_info { | |||
222 | __le32 type; /* target type */ | 223 | __le32 type; /* target type */ |
223 | } __packed; | 224 | } __packed; |
224 | 225 | ||
226 | #define ath6kl_bmi_write_hi32(ar, item, val) \ | ||
227 | ({ \ | ||
228 | u32 addr; \ | ||
229 | __le32 v; \ | ||
230 | \ | ||
231 | addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ | ||
232 | v = cpu_to_le32(val); \ | ||
233 | ath6kl_bmi_write(ar, addr, (u8 *) &v, sizeof(v)); \ | ||
234 | }) | ||
235 | |||
236 | #define ath6kl_bmi_read_hi32(ar, item, val) \ | ||
237 | ({ \ | ||
238 | u32 addr, *check_type = val; \ | ||
239 | __le32 tmp; \ | ||
240 | int ret; \ | ||
241 | \ | ||
242 | (void) (check_type == val); \ | ||
243 | addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ | ||
244 | ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \ | ||
245 | *val = le32_to_cpu(tmp); \ | ||
246 | ret; \ | ||
247 | }) | ||
248 | |||
225 | int ath6kl_bmi_init(struct ath6kl *ar); | 249 | int ath6kl_bmi_init(struct ath6kl *ar); |
226 | void ath6kl_bmi_cleanup(struct ath6kl *ar); | 250 | void ath6kl_bmi_cleanup(struct ath6kl *ar); |
227 | void ath6kl_bmi_reset(struct ath6kl *ar); | 251 | void ath6kl_bmi_reset(struct ath6kl *ar); |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 5370333883e4..00d38952b5fb 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -68,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = { | |||
68 | #define ath6kl_g_rates (ath6kl_rates + 0) | 69 | #define ath6kl_g_rates (ath6kl_rates + 0) |
69 | #define ath6kl_g_rates_size 12 | 70 | #define ath6kl_g_rates_size 12 |
70 | 71 | ||
72 | #define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ | ||
73 | IEEE80211_HT_CAP_SGI_20 | \ | ||
74 | IEEE80211_HT_CAP_SGI_40) | ||
75 | |||
71 | static struct ieee80211_channel ath6kl_2ghz_channels[] = { | 76 | static struct ieee80211_channel ath6kl_2ghz_channels[] = { |
72 | CHAN2G(1, 2412, 0), | 77 | CHAN2G(1, 2412, 0), |
73 | CHAN2G(2, 2417, 0), | 78 | CHAN2G(2, 2417, 0), |
@@ -112,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = { | |||
112 | .channels = ath6kl_2ghz_channels, | 117 | .channels = ath6kl_2ghz_channels, |
113 | .n_bitrates = ath6kl_g_rates_size, | 118 | .n_bitrates = ath6kl_g_rates_size, |
114 | .bitrates = ath6kl_g_rates, | 119 | .bitrates = ath6kl_g_rates, |
120 | .ht_cap.cap = ath6kl_g_htcap, | ||
121 | .ht_cap.ht_supported = true, | ||
115 | }; | 122 | }; |
116 | 123 | ||
117 | static struct ieee80211_supported_band ath6kl_band_5ghz = { | 124 | static struct ieee80211_supported_band ath6kl_band_5ghz = { |
@@ -119,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { | |||
119 | .channels = ath6kl_5ghz_a_channels, | 126 | .channels = ath6kl_5ghz_a_channels, |
120 | .n_bitrates = ath6kl_a_rates_size, | 127 | .n_bitrates = ath6kl_a_rates_size, |
121 | .bitrates = ath6kl_a_rates, | 128 | .bitrates = ath6kl_a_rates, |
129 | .ht_cap.cap = ath6kl_g_htcap, | ||
130 | .ht_cap.ht_supported = true, | ||
122 | }; | 131 | }; |
123 | 132 | ||
124 | #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ | 133 | #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ |
@@ -381,7 +390,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, | |||
381 | return false; | 390 | return false; |
382 | 391 | ||
383 | if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) && | 392 | if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) && |
384 | ar->num_vif)) | 393 | ar->num_vif)) |
385 | return false; | 394 | return false; |
386 | 395 | ||
387 | if (type == NL80211_IFTYPE_STATION || | 396 | if (type == NL80211_IFTYPE_STATION || |
@@ -407,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, | |||
407 | return false; | 416 | return false; |
408 | } | 417 | } |
409 | 418 | ||
419 | static bool ath6kl_is_tx_pending(struct ath6kl *ar) | ||
420 | { | ||
421 | return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; | ||
422 | } | ||
423 | |||
424 | |||
410 | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | 425 | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, |
411 | struct cfg80211_connect_params *sme) | 426 | struct cfg80211_connect_params *sme) |
412 | { | 427 | { |
@@ -414,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
414 | struct ath6kl_vif *vif = netdev_priv(dev); | 429 | struct ath6kl_vif *vif = netdev_priv(dev); |
415 | int status; | 430 | int status; |
416 | u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; | 431 | u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; |
432 | u16 interval; | ||
417 | 433 | ||
418 | ath6kl_cfg80211_sscan_disable(vif); | 434 | ath6kl_cfg80211_sscan_disable(vif); |
419 | 435 | ||
@@ -450,8 +466,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
450 | * sleep until the command queue drains | 466 | * sleep until the command queue drains |
451 | */ | 467 | */ |
452 | wait_event_interruptible_timeout(ar->event_wq, | 468 | wait_event_interruptible_timeout(ar->event_wq, |
453 | ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0, | 469 | ath6kl_is_tx_pending(ar), |
454 | WMI_TIMEOUT); | 470 | WMI_TIMEOUT); |
455 | if (signal_pending(current)) { | 471 | if (signal_pending(current)) { |
456 | ath6kl_err("cmd queue drain timeout\n"); | 472 | ath6kl_err("cmd queue drain timeout\n"); |
457 | up(&ar->sem); | 473 | up(&ar->sem); |
@@ -546,7 +562,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
546 | if (!ar->usr_bss_filter) { | 562 | if (!ar->usr_bss_filter) { |
547 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); | 563 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); |
548 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, | 564 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, |
549 | ALL_BSS_FILTER, 0) != 0) { | 565 | ALL_BSS_FILTER, 0) != 0) { |
550 | ath6kl_err("couldn't set bss filtering\n"); | 566 | ath6kl_err("couldn't set bss filtering\n"); |
551 | up(&ar->sem); | 567 | up(&ar->sem); |
552 | return -EIO; | 568 | return -EIO; |
@@ -568,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
568 | vif->grp_crypto_len, vif->ch_hint); | 584 | vif->grp_crypto_len, vif->ch_hint); |
569 | 585 | ||
570 | vif->reconnect_flag = 0; | 586 | vif->reconnect_flag = 0; |
587 | |||
588 | if (vif->nw_type == INFRA_NETWORK) { | ||
589 | interval = max_t(u16, vif->listen_intvl_t, | ||
590 | ATH6KL_MAX_WOW_LISTEN_INTL); | ||
591 | status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, | ||
592 | interval, | ||
593 | 0); | ||
594 | if (status) { | ||
595 | ath6kl_err("couldn't set listen intervel\n"); | ||
596 | up(&ar->sem); | ||
597 | return status; | ||
598 | } | ||
599 | } | ||
600 | |||
571 | status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, | 601 | status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, |
572 | vif->dot11_auth_mode, vif->auth_mode, | 602 | vif->dot11_auth_mode, vif->auth_mode, |
573 | vif->prwise_crypto, | 603 | vif->prwise_crypto, |
@@ -590,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
590 | } | 620 | } |
591 | 621 | ||
592 | if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && | 622 | if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && |
593 | ((vif->auth_mode == WPA_PSK_AUTH) | 623 | ((vif->auth_mode == WPA_PSK_AUTH) || |
594 | || (vif->auth_mode == WPA2_PSK_AUTH))) { | 624 | (vif->auth_mode == WPA2_PSK_AUTH))) { |
595 | mod_timer(&vif->disconnect_timer, | 625 | mod_timer(&vif->disconnect_timer, |
596 | jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); | 626 | jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); |
597 | } | 627 | } |
@@ -824,13 +854,13 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, | |||
824 | 854 | ||
825 | if (vif->sme_state == SME_CONNECTING) { | 855 | if (vif->sme_state == SME_CONNECTING) { |
826 | cfg80211_connect_result(vif->ndev, | 856 | cfg80211_connect_result(vif->ndev, |
827 | bssid, NULL, 0, | 857 | bssid, NULL, 0, |
828 | NULL, 0, | 858 | NULL, 0, |
829 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 859 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
830 | GFP_KERNEL); | 860 | GFP_KERNEL); |
831 | } else if (vif->sme_state == SME_CONNECTED) { | 861 | } else if (vif->sme_state == SME_CONNECTED) { |
832 | cfg80211_disconnected(vif->ndev, reason, | 862 | cfg80211_disconnected(vif->ndev, reason, |
833 | NULL, 0, GFP_KERNEL); | 863 | NULL, 0, GFP_KERNEL); |
834 | } | 864 | } |
835 | 865 | ||
836 | vif->sme_state = SME_DISCONNECTED; | 866 | vif->sme_state = SME_DISCONNECTED; |
@@ -876,19 +906,14 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | |||
876 | request->ssids[i].ssid); | 906 | request->ssids[i].ssid); |
877 | } | 907 | } |
878 | 908 | ||
879 | /* | 909 | /* this also clears IE in fw if it's not set */ |
880 | * FIXME: we should clear the IE in fw if it's not set so just | 910 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, |
881 | * remove the check altogether | 911 | WMI_FRAME_PROBE_REQ, |
882 | */ | 912 | request->ie, request->ie_len); |
883 | if (request->ie) { | 913 | if (ret) { |
884 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, | 914 | ath6kl_err("failed to set Probe Request appie for " |
885 | WMI_FRAME_PROBE_REQ, | 915 | "scan"); |
886 | request->ie, request->ie_len); | 916 | return ret; |
887 | if (ret) { | ||
888 | ath6kl_err("failed to set Probe Request appie for " | ||
889 | "scan"); | ||
890 | return ret; | ||
891 | } | ||
892 | } | 917 | } |
893 | 918 | ||
894 | /* | 919 | /* |
@@ -917,7 +942,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | |||
917 | force_fg_scan = 1; | 942 | force_fg_scan = 1; |
918 | 943 | ||
919 | if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, | 944 | if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, |
920 | ar->fw_capabilities)) { | 945 | ar->fw_capabilities)) { |
921 | /* | 946 | /* |
922 | * If capable of doing P2P mgmt operations using | 947 | * If capable of doing P2P mgmt operations using |
923 | * station interface, send additional information like | 948 | * station interface, send additional information like |
@@ -926,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | |||
926 | */ | 951 | */ |
927 | ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, | 952 | ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, |
928 | WMI_LONG_SCAN, force_fg_scan, | 953 | WMI_LONG_SCAN, force_fg_scan, |
929 | false, 0, 0, n_channels, | 954 | false, 0, |
930 | channels, request->no_cck, | 955 | ATH6KL_FG_SCAN_INTERVAL, |
956 | n_channels, channels, | ||
957 | request->no_cck, | ||
931 | request->rates); | 958 | request->rates); |
932 | } else { | 959 | } else { |
933 | ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, | 960 | ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, |
934 | WMI_LONG_SCAN, force_fg_scan, | 961 | WMI_LONG_SCAN, force_fg_scan, |
935 | false, 0, 0, n_channels, | 962 | false, 0, |
936 | channels); | 963 | ATH6KL_FG_SCAN_INTERVAL, |
964 | n_channels, channels); | ||
937 | } | 965 | } |
938 | if (ret) | 966 | if (ret) |
939 | ath6kl_err("wmi_startscan_cmd failed\n"); | 967 | ath6kl_err("wmi_startscan_cmd failed\n"); |
@@ -1046,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
1046 | return -ENOTSUPP; | 1074 | return -ENOTSUPP; |
1047 | } | 1075 | } |
1048 | 1076 | ||
1049 | if (((vif->auth_mode == WPA_PSK_AUTH) | 1077 | if (((vif->auth_mode == WPA_PSK_AUTH) || |
1050 | || (vif->auth_mode == WPA2_PSK_AUTH)) | 1078 | (vif->auth_mode == WPA2_PSK_AUTH)) && |
1051 | && (key_usage & GROUP_USAGE)) | 1079 | (key_usage & GROUP_USAGE)) |
1052 | del_timer(&vif->disconnect_timer); | 1080 | del_timer(&vif->disconnect_timer); |
1053 | 1081 | ||
1054 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 1082 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
@@ -1058,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
1058 | 1086 | ||
1059 | if (vif->nw_type == AP_NETWORK && !pairwise && | 1087 | if (vif->nw_type == AP_NETWORK && !pairwise && |
1060 | (key_type == TKIP_CRYPT || key_type == AES_CRYPT || | 1088 | (key_type == TKIP_CRYPT || key_type == AES_CRYPT || |
1061 | key_type == WAPI_CRYPT) && params) { | 1089 | key_type == WAPI_CRYPT)) { |
1062 | ar->ap_mode_bkey.valid = true; | 1090 | ar->ap_mode_bkey.valid = true; |
1063 | ar->ap_mode_bkey.key_index = key_index; | 1091 | ar->ap_mode_bkey.key_index = key_index; |
1064 | ar->ap_mode_bkey.key_type = key_type; | 1092 | ar->ap_mode_bkey.key_type = key_type; |
@@ -1263,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, | |||
1263 | { | 1291 | { |
1264 | struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); | 1292 | struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); |
1265 | struct ath6kl_vif *vif; | 1293 | struct ath6kl_vif *vif; |
1266 | u8 ath6kl_dbm; | ||
1267 | int dbm = MBM_TO_DBM(mbm); | 1294 | int dbm = MBM_TO_DBM(mbm); |
1268 | 1295 | ||
1269 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, | 1296 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, |
@@ -1280,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, | |||
1280 | case NL80211_TX_POWER_AUTOMATIC: | 1307 | case NL80211_TX_POWER_AUTOMATIC: |
1281 | return 0; | 1308 | return 0; |
1282 | case NL80211_TX_POWER_LIMITED: | 1309 | case NL80211_TX_POWER_LIMITED: |
1283 | ar->tx_pwr = ath6kl_dbm = dbm; | 1310 | ar->tx_pwr = dbm; |
1284 | break; | 1311 | break; |
1285 | default: | 1312 | default: |
1286 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", | 1313 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", |
@@ -1288,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, | |||
1288 | return -EOPNOTSUPP; | 1315 | return -EOPNOTSUPP; |
1289 | } | 1316 | } |
1290 | 1317 | ||
1291 | ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm); | 1318 | ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm); |
1292 | 1319 | ||
1293 | return 0; | 1320 | return 0; |
1294 | } | 1321 | } |
@@ -1349,7 +1376,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, | |||
1349 | } | 1376 | } |
1350 | 1377 | ||
1351 | if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx, | 1378 | if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx, |
1352 | mode.pwr_mode) != 0) { | 1379 | mode.pwr_mode) != 0) { |
1353 | ath6kl_err("wmi_powermode_cmd failed\n"); | 1380 | ath6kl_err("wmi_powermode_cmd failed\n"); |
1354 | return -EIO; | 1381 | return -EIO; |
1355 | } | 1382 | } |
@@ -1904,7 +1931,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
1904 | struct ath6kl_vif *vif; | 1931 | struct ath6kl_vif *vif; |
1905 | int ret, left; | 1932 | int ret, left; |
1906 | u32 filter = 0; | 1933 | u32 filter = 0; |
1907 | u16 i; | 1934 | u16 i, bmiss_time; |
1908 | u8 index = 0; | 1935 | u8 index = 0; |
1909 | __be32 ips[MAX_IP_ADDRS]; | 1936 | __be32 ips[MAX_IP_ADDRS]; |
1910 | 1937 | ||
@@ -1941,6 +1968,34 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
1941 | if (ret) | 1968 | if (ret) |
1942 | return ret; | 1969 | return ret; |
1943 | 1970 | ||
1971 | netif_stop_queue(vif->ndev); | ||
1972 | |||
1973 | if (vif->nw_type != AP_NETWORK) { | ||
1974 | ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, | ||
1975 | ATH6KL_MAX_WOW_LISTEN_INTL, | ||
1976 | 0); | ||
1977 | if (ret) | ||
1978 | return ret; | ||
1979 | |||
1980 | /* Set listen interval x 15 times as bmiss time */ | ||
1981 | bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15; | ||
1982 | if (bmiss_time > ATH6KL_MAX_BMISS_TIME) | ||
1983 | bmiss_time = ATH6KL_MAX_BMISS_TIME; | ||
1984 | |||
1985 | ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, | ||
1986 | bmiss_time, 0); | ||
1987 | if (ret) | ||
1988 | return ret; | ||
1989 | |||
1990 | ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, | ||
1991 | 0xFFFF, 0, 0xFFFF, 0, 0, 0, | ||
1992 | 0, 0, 0, 0); | ||
1993 | if (ret) | ||
1994 | return ret; | ||
1995 | } | ||
1996 | |||
1997 | ar->state = ATH6KL_STATE_SUSPENDING; | ||
1998 | |||
1944 | /* Setup own IP addr for ARP agent. */ | 1999 | /* Setup own IP addr for ARP agent. */ |
1945 | in_dev = __in_dev_get_rtnl(vif->ndev); | 2000 | in_dev = __in_dev_get_rtnl(vif->ndev); |
1946 | if (!in_dev) | 2001 | if (!in_dev) |
@@ -2019,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar) | |||
2019 | if (!vif) | 2074 | if (!vif) |
2020 | return -EIO; | 2075 | return -EIO; |
2021 | 2076 | ||
2077 | ar->state = ATH6KL_STATE_RESUMING; | ||
2078 | |||
2022 | ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, | 2079 | ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, |
2023 | ATH6KL_HOST_MODE_AWAKE); | 2080 | ATH6KL_HOST_MODE_AWAKE); |
2024 | return ret; | 2081 | if (ret) { |
2082 | ath6kl_warn("Failed to configure host sleep mode for " | ||
2083 | "wow resume: %d\n", ret); | ||
2084 | ar->state = ATH6KL_STATE_WOW; | ||
2085 | return ret; | ||
2086 | } | ||
2087 | |||
2088 | if (vif->nw_type != AP_NETWORK) { | ||
2089 | ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, | ||
2090 | 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); | ||
2091 | if (ret) | ||
2092 | return ret; | ||
2093 | |||
2094 | ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, | ||
2095 | vif->listen_intvl_t, 0); | ||
2096 | if (ret) | ||
2097 | return ret; | ||
2098 | |||
2099 | ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, | ||
2100 | vif->bmiss_time_t, 0); | ||
2101 | if (ret) | ||
2102 | return ret; | ||
2103 | } | ||
2104 | |||
2105 | ar->state = ATH6KL_STATE_ON; | ||
2106 | |||
2107 | netif_wake_queue(vif->ndev); | ||
2108 | |||
2109 | return 0; | ||
2025 | } | 2110 | } |
2026 | 2111 | ||
2027 | int ath6kl_cfg80211_suspend(struct ath6kl *ar, | 2112 | int ath6kl_cfg80211_suspend(struct ath6kl *ar, |
2028 | enum ath6kl_cfg_suspend_mode mode, | 2113 | enum ath6kl_cfg_suspend_mode mode, |
2029 | struct cfg80211_wowlan *wow) | 2114 | struct cfg80211_wowlan *wow) |
2030 | { | 2115 | { |
2116 | enum ath6kl_state prev_state; | ||
2031 | int ret; | 2117 | int ret; |
2032 | 2118 | ||
2033 | switch (mode) { | 2119 | switch (mode) { |
@@ -2038,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, | |||
2038 | /* Flush all non control pkts in TX path */ | 2124 | /* Flush all non control pkts in TX path */ |
2039 | ath6kl_tx_data_cleanup(ar); | 2125 | ath6kl_tx_data_cleanup(ar); |
2040 | 2126 | ||
2127 | prev_state = ar->state; | ||
2128 | |||
2041 | ret = ath6kl_wow_suspend(ar, wow); | 2129 | ret = ath6kl_wow_suspend(ar, wow); |
2042 | if (ret) { | 2130 | if (ret) { |
2043 | ath6kl_err("wow suspend failed: %d\n", ret); | 2131 | ar->state = prev_state; |
2044 | return ret; | 2132 | return ret; |
2045 | } | 2133 | } |
2134 | |||
2046 | ar->state = ATH6KL_STATE_WOW; | 2135 | ar->state = ATH6KL_STATE_WOW; |
2047 | break; | 2136 | break; |
2048 | 2137 | ||
@@ -2114,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) | |||
2114 | return ret; | 2203 | return ret; |
2115 | } | 2204 | } |
2116 | 2205 | ||
2117 | ar->state = ATH6KL_STATE_ON; | ||
2118 | break; | 2206 | break; |
2119 | 2207 | ||
2120 | case ATH6KL_STATE_DEEPSLEEP: | 2208 | case ATH6KL_STATE_DEEPSLEEP: |
@@ -2188,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) | |||
2188 | */ | 2276 | */ |
2189 | void ath6kl_check_wow_status(struct ath6kl *ar) | 2277 | void ath6kl_check_wow_status(struct ath6kl *ar) |
2190 | { | 2278 | { |
2279 | if (ar->state == ATH6KL_STATE_SUSPENDING) | ||
2280 | return; | ||
2281 | |||
2191 | if (ar->state == ATH6KL_STATE_WOW) | 2282 | if (ar->state == ATH6KL_STATE_WOW) |
2192 | ath6kl_cfg80211_resume(ar); | 2283 | ath6kl_cfg80211_resume(ar); |
2193 | } | 2284 | } |
@@ -2275,30 +2366,27 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, | |||
2275 | struct ath6kl *ar = vif->ar; | 2366 | struct ath6kl *ar = vif->ar; |
2276 | int res; | 2367 | int res; |
2277 | 2368 | ||
2278 | if (info->beacon_ies) { | 2369 | /* this also clears IE in fw if it's not set */ |
2279 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, | 2370 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, |
2280 | WMI_FRAME_BEACON, | 2371 | WMI_FRAME_BEACON, |
2281 | info->beacon_ies, | 2372 | info->beacon_ies, |
2282 | info->beacon_ies_len); | 2373 | info->beacon_ies_len); |
2283 | if (res) | 2374 | if (res) |
2284 | return res; | 2375 | return res; |
2285 | } | ||
2286 | 2376 | ||
2287 | if (info->proberesp_ies) { | 2377 | /* this also clears IE in fw if it's not set */ |
2288 | res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, | 2378 | res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, |
2289 | info->proberesp_ies_len); | 2379 | info->proberesp_ies_len); |
2290 | if (res) | 2380 | if (res) |
2291 | return res; | 2381 | return res; |
2292 | } | ||
2293 | 2382 | ||
2294 | if (info->assocresp_ies) { | 2383 | /* this also clears IE in fw if it's not set */ |
2295 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, | 2384 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, |
2296 | WMI_FRAME_ASSOC_RESP, | 2385 | WMI_FRAME_ASSOC_RESP, |
2297 | info->assocresp_ies, | 2386 | info->assocresp_ies, |
2298 | info->assocresp_ies_len); | 2387 | info->assocresp_ies_len); |
2299 | if (res) | 2388 | if (res) |
2300 | return res; | 2389 | return res; |
2301 | } | ||
2302 | 2390 | ||
2303 | return 0; | 2391 | return 0; |
2304 | } | 2392 | } |
@@ -2309,6 +2397,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2309 | struct ath6kl *ar = ath6kl_priv(dev); | 2397 | struct ath6kl *ar = ath6kl_priv(dev); |
2310 | struct ath6kl_vif *vif = netdev_priv(dev); | 2398 | struct ath6kl_vif *vif = netdev_priv(dev); |
2311 | struct ieee80211_mgmt *mgmt; | 2399 | struct ieee80211_mgmt *mgmt; |
2400 | bool hidden = false; | ||
2312 | u8 *ies; | 2401 | u8 *ies; |
2313 | int ies_len; | 2402 | int ies_len; |
2314 | struct wmi_connect_cmd p; | 2403 | struct wmi_connect_cmd p; |
@@ -2345,7 +2434,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2345 | memcpy(vif->ssid, info->ssid, info->ssid_len); | 2434 | memcpy(vif->ssid, info->ssid, info->ssid_len); |
2346 | vif->ssid_len = info->ssid_len; | 2435 | vif->ssid_len = info->ssid_len; |
2347 | if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) | 2436 | if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) |
2348 | return -EOPNOTSUPP; /* TODO */ | 2437 | hidden = true; |
2438 | |||
2439 | res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden); | ||
2440 | if (res) | ||
2441 | return res; | ||
2349 | 2442 | ||
2350 | ret = ath6kl_set_auth_type(vif, info->auth_type); | 2443 | ret = ath6kl_set_auth_type(vif, info->auth_type); |
2351 | if (ret) | 2444 | if (ret) |
@@ -2584,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif, | |||
2584 | return ret; | 2677 | return ret; |
2585 | } | 2678 | } |
2586 | 2679 | ||
2680 | static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, | ||
2681 | u32 id, | ||
2682 | u32 freq, | ||
2683 | u32 wait, | ||
2684 | const u8 *buf, | ||
2685 | size_t len, | ||
2686 | bool *more_data, | ||
2687 | bool no_cck) | ||
2688 | { | ||
2689 | struct ieee80211_mgmt *mgmt; | ||
2690 | struct ath6kl_sta *conn; | ||
2691 | bool is_psq_empty = false; | ||
2692 | struct ath6kl_mgmt_buff *mgmt_buf; | ||
2693 | size_t mgmt_buf_size; | ||
2694 | struct ath6kl *ar = vif->ar; | ||
2695 | |||
2696 | mgmt = (struct ieee80211_mgmt *) buf; | ||
2697 | if (is_multicast_ether_addr(mgmt->da)) | ||
2698 | return false; | ||
2699 | |||
2700 | conn = ath6kl_find_sta(vif, mgmt->da); | ||
2701 | if (!conn) | ||
2702 | return false; | ||
2703 | |||
2704 | if (conn->sta_flags & STA_PS_SLEEP) { | ||
2705 | if (!(conn->sta_flags & STA_PS_POLLED)) { | ||
2706 | /* Queue the frames if the STA is sleeping */ | ||
2707 | mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff); | ||
2708 | mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL); | ||
2709 | if (!mgmt_buf) | ||
2710 | return false; | ||
2711 | |||
2712 | INIT_LIST_HEAD(&mgmt_buf->list); | ||
2713 | mgmt_buf->id = id; | ||
2714 | mgmt_buf->freq = freq; | ||
2715 | mgmt_buf->wait = wait; | ||
2716 | mgmt_buf->len = len; | ||
2717 | mgmt_buf->no_cck = no_cck; | ||
2718 | memcpy(mgmt_buf->buf, buf, len); | ||
2719 | spin_lock_bh(&conn->psq_lock); | ||
2720 | is_psq_empty = skb_queue_empty(&conn->psq) && | ||
2721 | (conn->mgmt_psq_len == 0); | ||
2722 | list_add_tail(&mgmt_buf->list, &conn->mgmt_psq); | ||
2723 | conn->mgmt_psq_len++; | ||
2724 | spin_unlock_bh(&conn->psq_lock); | ||
2725 | |||
2726 | /* | ||
2727 | * If this is the first pkt getting queued | ||
2728 | * for this STA, update the PVB for this | ||
2729 | * STA. | ||
2730 | */ | ||
2731 | if (is_psq_empty) | ||
2732 | ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, | ||
2733 | conn->aid, 1); | ||
2734 | return true; | ||
2735 | } | ||
2736 | |||
2737 | /* | ||
2738 | * This tx is because of a PsPoll. | ||
2739 | * Determine if MoreData bit has to be set. | ||
2740 | */ | ||
2741 | spin_lock_bh(&conn->psq_lock); | ||
2742 | if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0)) | ||
2743 | *more_data = true; | ||
2744 | spin_unlock_bh(&conn->psq_lock); | ||
2745 | } | ||
2746 | |||
2747 | return false; | ||
2748 | } | ||
2749 | |||
2587 | static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | 2750 | static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, |
2588 | struct ieee80211_channel *chan, bool offchan, | 2751 | struct ieee80211_channel *chan, bool offchan, |
2589 | enum nl80211_channel_type channel_type, | 2752 | enum nl80211_channel_type channel_type, |
@@ -2595,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2595 | struct ath6kl_vif *vif = netdev_priv(dev); | 2758 | struct ath6kl_vif *vif = netdev_priv(dev); |
2596 | u32 id; | 2759 | u32 id; |
2597 | const struct ieee80211_mgmt *mgmt; | 2760 | const struct ieee80211_mgmt *mgmt; |
2761 | bool more_data, queued; | ||
2598 | 2762 | ||
2599 | mgmt = (const struct ieee80211_mgmt *) buf; | 2763 | mgmt = (const struct ieee80211_mgmt *) buf; |
2600 | if (buf + len >= mgmt->u.probe_resp.variable && | 2764 | if (buf + len >= mgmt->u.probe_resp.variable && |
@@ -2620,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2620 | 2784 | ||
2621 | *cookie = id; | 2785 | *cookie = id; |
2622 | 2786 | ||
2623 | if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, | 2787 | /* AP mode Power saving processing */ |
2624 | ar->fw_capabilities)) { | 2788 | if (vif->nw_type == AP_NETWORK) { |
2625 | /* | 2789 | queued = ath6kl_mgmt_powersave_ap(vif, |
2626 | * If capable of doing P2P mgmt operations using | 2790 | id, chan->center_freq, |
2627 | * station interface, send additional information like | 2791 | wait, buf, |
2628 | * supported rates to advertise and xmit rates for | 2792 | len, &more_data, no_cck); |
2629 | * probe requests | 2793 | if (queued) |
2630 | */ | 2794 | return 0; |
2631 | return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, | ||
2632 | chan->center_freq, wait, | ||
2633 | buf, len, no_cck); | ||
2634 | } else { | ||
2635 | return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id, | ||
2636 | chan->center_freq, wait, | ||
2637 | buf, len); | ||
2638 | } | 2795 | } |
2796 | |||
2797 | return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, | ||
2798 | chan->center_freq, wait, | ||
2799 | buf, len, no_cck); | ||
2639 | } | 2800 | } |
2640 | 2801 | ||
2641 | static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, | 2802 | static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, |
@@ -2929,7 +3090,10 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, | |||
2929 | vif->wdev.netdev = ndev; | 3090 | vif->wdev.netdev = ndev; |
2930 | vif->wdev.iftype = type; | 3091 | vif->wdev.iftype = type; |
2931 | vif->fw_vif_idx = fw_vif_idx; | 3092 | vif->fw_vif_idx = fw_vif_idx; |
2932 | vif->nw_type = vif->next_mode = nw_type; | 3093 | vif->nw_type = nw_type; |
3094 | vif->next_mode = nw_type; | ||
3095 | vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; | ||
3096 | vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; | ||
2933 | 3097 | ||
2934 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); | 3098 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); |
2935 | if (fw_vif_idx != 0) | 3099 | if (fw_vif_idx != 0) |
@@ -3009,18 +3173,36 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | |||
3009 | 3173 | ||
3010 | wiphy->max_sched_scan_ssids = 10; | 3174 | wiphy->max_sched_scan_ssids = 10; |
3011 | 3175 | ||
3176 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | | ||
3177 | WIPHY_FLAG_HAVE_AP_SME | | ||
3178 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | | ||
3179 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | ||
3180 | |||
3181 | if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) | ||
3182 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | ||
3183 | |||
3184 | ar->wiphy->probe_resp_offload = | ||
3185 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | ||
3186 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | | ||
3187 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | | ||
3188 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; | ||
3189 | |||
3012 | ret = wiphy_register(wiphy); | 3190 | ret = wiphy_register(wiphy); |
3013 | if (ret < 0) { | 3191 | if (ret < 0) { |
3014 | ath6kl_err("couldn't register wiphy device\n"); | 3192 | ath6kl_err("couldn't register wiphy device\n"); |
3015 | return ret; | 3193 | return ret; |
3016 | } | 3194 | } |
3017 | 3195 | ||
3196 | ar->wiphy_registered = true; | ||
3197 | |||
3018 | return 0; | 3198 | return 0; |
3019 | } | 3199 | } |
3020 | 3200 | ||
3021 | void ath6kl_cfg80211_cleanup(struct ath6kl *ar) | 3201 | void ath6kl_cfg80211_cleanup(struct ath6kl *ar) |
3022 | { | 3202 | { |
3023 | wiphy_unregister(ar->wiphy); | 3203 | wiphy_unregister(ar->wiphy); |
3204 | |||
3205 | ar->wiphy_registered = false; | ||
3024 | } | 3206 | } |
3025 | 3207 | ||
3026 | struct ath6kl *ath6kl_cfg80211_create(void) | 3208 | struct ath6kl *ath6kl_cfg80211_create(void) |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 3c693b7c0efd..c5def436417f 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2011 Atheros Communications Inc. | 2 | * Copyright (c) 2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h index f89f1e180da3..a60e78c0472f 100644 --- a/drivers/net/wireless/ath/ath6kl/common.h +++ b/drivers/net/wireless/ath/ath6kl/common.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 722ca59b88ce..45e641f3a41b 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -26,12 +27,14 @@ | |||
26 | 27 | ||
27 | unsigned int debug_mask; | 28 | unsigned int debug_mask; |
28 | static unsigned int suspend_mode; | 29 | static unsigned int suspend_mode; |
30 | static unsigned int wow_mode; | ||
29 | static unsigned int uart_debug; | 31 | static unsigned int uart_debug; |
30 | static unsigned int ath6kl_p2p; | 32 | static unsigned int ath6kl_p2p; |
31 | static unsigned int testmode; | 33 | static unsigned int testmode; |
32 | 34 | ||
33 | module_param(debug_mask, uint, 0644); | 35 | module_param(debug_mask, uint, 0644); |
34 | module_param(suspend_mode, uint, 0644); | 36 | module_param(suspend_mode, uint, 0644); |
37 | module_param(wow_mode, uint, 0644); | ||
35 | module_param(uart_debug, uint, 0644); | 38 | module_param(uart_debug, uint, 0644); |
36 | module_param(ath6kl_p2p, uint, 0644); | 39 | module_param(ath6kl_p2p, uint, 0644); |
37 | module_param(testmode, uint, 0644); | 40 | module_param(testmode, uint, 0644); |
@@ -97,48 +100,12 @@ int ath6kl_core_init(struct ath6kl *ar) | |||
97 | 100 | ||
98 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); | 101 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); |
99 | 102 | ||
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 */ | 103 | /* setup access class priority mappings */ |
133 | ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ | 104 | ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ |
134 | ar->ac_stream_pri_map[WMM_AC_BE] = 1; | 105 | ar->ac_stream_pri_map[WMM_AC_BE] = 1; |
135 | ar->ac_stream_pri_map[WMM_AC_VI] = 2; | 106 | ar->ac_stream_pri_map[WMM_AC_VI] = 2; |
136 | ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ | 107 | ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ |
137 | 108 | ||
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 */ | 109 | /* allocate some buffers that handle larger AMSDU frames */ |
143 | ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); | 110 | ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); |
144 | 111 | ||
@@ -148,32 +115,25 @@ int ath6kl_core_init(struct ath6kl *ar) | |||
148 | ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; | 115 | ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; |
149 | 116 | ||
150 | if (suspend_mode && | 117 | if (suspend_mode && |
151 | suspend_mode >= WLAN_POWER_STATE_CUT_PWR && | 118 | suspend_mode >= WLAN_POWER_STATE_CUT_PWR && |
152 | suspend_mode <= WLAN_POWER_STATE_WOW) | 119 | suspend_mode <= WLAN_POWER_STATE_WOW) |
153 | ar->suspend_mode = suspend_mode; | 120 | ar->suspend_mode = suspend_mode; |
154 | else | 121 | else |
155 | ar->suspend_mode = 0; | 122 | ar->suspend_mode = 0; |
156 | 123 | ||
124 | if (suspend_mode == WLAN_POWER_STATE_WOW && | ||
125 | (wow_mode == WLAN_POWER_STATE_CUT_PWR || | ||
126 | wow_mode == WLAN_POWER_STATE_DEEP_SLEEP)) | ||
127 | ar->wow_suspend_mode = wow_mode; | ||
128 | else | ||
129 | ar->wow_suspend_mode = 0; | ||
130 | |||
157 | if (uart_debug) | 131 | if (uart_debug) |
158 | ar->conf_flags |= ATH6KL_CONF_UART_DEBUG; | 132 | ar->conf_flags |= ATH6KL_CONF_UART_DEBUG; |
159 | 133 | ||
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); | 134 | set_bit(FIRST_BOOT, &ar->flag); |
175 | 135 | ||
176 | ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; | 136 | ath6kl_debug_init(ar); |
177 | 137 | ||
178 | ret = ath6kl_init_hw_start(ar); | 138 | ret = ath6kl_init_hw_start(ar); |
179 | if (ret) { | 139 | if (ret) { |
@@ -181,24 +141,47 @@ int ath6kl_core_init(struct ath6kl *ar) | |||
181 | goto err_rxbuf_cleanup; | 141 | goto err_rxbuf_cleanup; |
182 | } | 142 | } |
183 | 143 | ||
184 | /* | 144 | /* give our connected endpoints some buffers */ |
185 | * Set mac address which is received in ready event | 145 | ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); |
186 | * FIXME: Move to ath6kl_interface_add() | 146 | ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); |
187 | */ | 147 | |
188 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); | 148 | ret = ath6kl_cfg80211_init(ar); |
149 | if (ret) | ||
150 | goto err_rxbuf_cleanup; | ||
151 | |||
152 | ret = ath6kl_debug_init_fs(ar); | ||
153 | if (ret) { | ||
154 | wiphy_unregister(ar->wiphy); | ||
155 | goto err_rxbuf_cleanup; | ||
156 | } | ||
157 | |||
158 | for (i = 0; i < ar->vif_max; i++) | ||
159 | ar->avail_idx_map |= BIT(i); | ||
160 | |||
161 | rtnl_lock(); | ||
162 | |||
163 | /* Add an initial station interface */ | ||
164 | ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, | ||
165 | INFRA_NETWORK); | ||
166 | |||
167 | rtnl_unlock(); | ||
168 | |||
169 | if (!ndev) { | ||
170 | ath6kl_err("Failed to instantiate a network device\n"); | ||
171 | ret = -ENOMEM; | ||
172 | wiphy_unregister(ar->wiphy); | ||
173 | goto err_rxbuf_cleanup; | ||
174 | } | ||
175 | |||
176 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", | ||
177 | __func__, ndev->name, ndev, ar); | ||
189 | 178 | ||
190 | return ret; | 179 | return ret; |
191 | 180 | ||
192 | err_rxbuf_cleanup: | 181 | err_rxbuf_cleanup: |
182 | ath6kl_debug_cleanup(ar); | ||
193 | ath6kl_htc_flush_rx_buf(ar->htc_target); | 183 | ath6kl_htc_flush_rx_buf(ar->htc_target); |
194 | ath6kl_cleanup_amsdu_rxbufs(ar); | 184 | 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); | 185 | ath6kl_wmi_shutdown(ar->wmi); |
203 | clear_bit(WMI_ENABLED, &ar->flag); | 186 | clear_bit(WMI_ENABLED, &ar->flag); |
204 | ar->wmi = NULL; | 187 | ar->wmi = NULL; |
@@ -245,9 +228,7 @@ struct ath6kl *ath6kl_core_create(struct device *dev) | |||
245 | clear_bit(SKIP_SCAN, &ar->flag); | 228 | clear_bit(SKIP_SCAN, &ar->flag); |
246 | clear_bit(DESTROY_IN_PROGRESS, &ar->flag); | 229 | clear_bit(DESTROY_IN_PROGRESS, &ar->flag); |
247 | 230 | ||
248 | ar->listen_intvl_b = A_DEFAULT_LISTEN_INTERVAL; | ||
249 | ar->tx_pwr = 0; | 231 | ar->tx_pwr = 0; |
250 | |||
251 | ar->intra_bss = 1; | 232 | ar->intra_bss = 1; |
252 | ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; | 233 | ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; |
253 | 234 | ||
@@ -261,6 +242,8 @@ struct ath6kl *ath6kl_core_create(struct device *dev) | |||
261 | spin_lock_init(&ar->sta_list[ctr].psq_lock); | 242 | spin_lock_init(&ar->sta_list[ctr].psq_lock); |
262 | skb_queue_head_init(&ar->sta_list[ctr].psq); | 243 | skb_queue_head_init(&ar->sta_list[ctr].psq); |
263 | skb_queue_head_init(&ar->sta_list[ctr].apsdq); | 244 | skb_queue_head_init(&ar->sta_list[ctr].apsdq); |
245 | ar->sta_list[ctr].mgmt_psq_len = 0; | ||
246 | INIT_LIST_HEAD(&ar->sta_list[ctr].mgmt_psq); | ||
264 | ar->sta_list[ctr].aggr_conn = | 247 | ar->sta_list[ctr].aggr_conn = |
265 | kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); | 248 | kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); |
266 | if (!ar->sta_list[ctr].aggr_conn) { | 249 | if (!ar->sta_list[ctr].aggr_conn) { |
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index c4d66e066dc9..f1dd8906be45 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -59,8 +60,9 @@ | |||
59 | #define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC) | 60 | #define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC) |
60 | 61 | ||
61 | #define DISCON_TIMER_INTVAL 10000 /* in msec */ | 62 | #define DISCON_TIMER_INTVAL 10000 /* in msec */ |
62 | #define A_DEFAULT_LISTEN_INTERVAL 1 /* beacon intervals */ | 63 | |
63 | #define A_MAX_WOW_LISTEN_INTERVAL 1000 | 64 | /* Channel dwell time in fg scan */ |
65 | #define ATH6KL_FG_SCAN_INTERVAL 50 /* in ms */ | ||
64 | 66 | ||
65 | /* includes also the null byte */ | 67 | /* includes also the null byte */ |
66 | #define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL" | 68 | #define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL" |
@@ -183,6 +185,11 @@ struct ath6kl_fw_ie { | |||
183 | 185 | ||
184 | #define MBOX_YIELD_LIMIT 99 | 186 | #define MBOX_YIELD_LIMIT 99 |
185 | 187 | ||
188 | #define ATH6KL_DEFAULT_LISTEN_INTVAL 100 /* in TUs */ | ||
189 | #define ATH6KL_DEFAULT_BMISS_TIME 1500 | ||
190 | #define ATH6KL_MAX_WOW_LISTEN_INTL 300 /* in TUs */ | ||
191 | #define ATH6KL_MAX_BMISS_TIME 5000 | ||
192 | |||
186 | /* configuration lags */ | 193 | /* configuration lags */ |
187 | /* | 194 | /* |
188 | * ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in | 195 | * ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in |
@@ -226,6 +233,12 @@ struct rxtid { | |||
226 | u32 hold_q_sz; | 233 | u32 hold_q_sz; |
227 | struct skb_hold_q *hold_q; | 234 | struct skb_hold_q *hold_q; |
228 | struct sk_buff_head q; | 235 | struct sk_buff_head q; |
236 | |||
237 | /* | ||
238 | * FIXME: No clue what this should protect. Apparently it should | ||
239 | * protect some of the fields above but they are also accessed | ||
240 | * without taking the lock. | ||
241 | */ | ||
229 | spinlock_t lock; | 242 | spinlock_t lock; |
230 | }; | 243 | }; |
231 | 244 | ||
@@ -285,6 +298,16 @@ struct ath6kl_cookie { | |||
285 | struct ath6kl_cookie *arc_list_next; | 298 | struct ath6kl_cookie *arc_list_next; |
286 | }; | 299 | }; |
287 | 300 | ||
301 | struct ath6kl_mgmt_buff { | ||
302 | struct list_head list; | ||
303 | u32 freq; | ||
304 | u32 wait; | ||
305 | u32 id; | ||
306 | bool no_cck; | ||
307 | size_t len; | ||
308 | u8 buf[0]; | ||
309 | }; | ||
310 | |||
288 | struct ath6kl_sta { | 311 | struct ath6kl_sta { |
289 | u16 sta_flags; | 312 | u16 sta_flags; |
290 | u8 mac[ETH_ALEN]; | 313 | u8 mac[ETH_ALEN]; |
@@ -294,7 +317,12 @@ struct ath6kl_sta { | |||
294 | u8 auth; | 317 | u8 auth; |
295 | u8 wpa_ie[ATH6KL_MAX_IE]; | 318 | u8 wpa_ie[ATH6KL_MAX_IE]; |
296 | struct sk_buff_head psq; | 319 | struct sk_buff_head psq; |
320 | |||
321 | /* protects psq, mgmt_psq, apsdq, and mgmt_psq_len fields */ | ||
297 | spinlock_t psq_lock; | 322 | spinlock_t psq_lock; |
323 | |||
324 | struct list_head mgmt_psq; | ||
325 | size_t mgmt_psq_len; | ||
298 | u8 apsd_info; | 326 | u8 apsd_info; |
299 | struct sk_buff_head apsdq; | 327 | struct sk_buff_head apsdq; |
300 | struct aggr_info_conn *aggr_conn; | 328 | struct aggr_info_conn *aggr_conn; |
@@ -494,6 +522,8 @@ struct ath6kl_vif { | |||
494 | bool probe_req_report; | 522 | bool probe_req_report; |
495 | u16 next_chan; | 523 | u16 next_chan; |
496 | u16 assoc_bss_beacon_int; | 524 | u16 assoc_bss_beacon_int; |
525 | u16 listen_intvl_t; | ||
526 | u16 bmiss_time_t; | ||
497 | u8 assoc_bss_dtim_period; | 527 | u8 assoc_bss_dtim_period; |
498 | struct net_device_stats net_stats; | 528 | struct net_device_stats net_stats; |
499 | struct target_stats target_stats; | 529 | struct target_stats target_stats; |
@@ -521,6 +551,8 @@ enum ath6kl_dev_state { | |||
521 | enum ath6kl_state { | 551 | enum ath6kl_state { |
522 | ATH6KL_STATE_OFF, | 552 | ATH6KL_STATE_OFF, |
523 | ATH6KL_STATE_ON, | 553 | ATH6KL_STATE_ON, |
554 | ATH6KL_STATE_SUSPENDING, | ||
555 | ATH6KL_STATE_RESUMING, | ||
524 | ATH6KL_STATE_DEEPSLEEP, | 556 | ATH6KL_STATE_DEEPSLEEP, |
525 | ATH6KL_STATE_CUTPOWER, | 557 | ATH6KL_STATE_CUTPOWER, |
526 | ATH6KL_STATE_WOW, | 558 | ATH6KL_STATE_WOW, |
@@ -549,9 +581,14 @@ struct ath6kl { | |||
549 | unsigned int vif_max; | 581 | unsigned int vif_max; |
550 | u8 max_norm_iface; | 582 | u8 max_norm_iface; |
551 | u8 avail_idx_map; | 583 | u8 avail_idx_map; |
584 | |||
585 | /* | ||
586 | * Protects at least amsdu_rx_buffer_queue, ath6kl_alloc_cookie() | ||
587 | * calls, tx_pending and total_tx_data_pend. | ||
588 | */ | ||
552 | spinlock_t lock; | 589 | spinlock_t lock; |
590 | |||
553 | struct semaphore sem; | 591 | struct semaphore sem; |
554 | u16 listen_intvl_b; | ||
555 | u8 lrssi_roam_threshold; | 592 | u8 lrssi_roam_threshold; |
556 | struct ath6kl_version version; | 593 | struct ath6kl_version version; |
557 | u32 target_type; | 594 | u32 target_type; |
@@ -577,7 +614,13 @@ struct ath6kl { | |||
577 | u8 sta_list_index; | 614 | u8 sta_list_index; |
578 | struct ath6kl_req_key ap_mode_bkey; | 615 | struct ath6kl_req_key ap_mode_bkey; |
579 | struct sk_buff_head mcastpsq; | 616 | struct sk_buff_head mcastpsq; |
617 | |||
618 | /* | ||
619 | * FIXME: protects access to mcastpsq but is actually useless as | ||
620 | * all skbe_queue_*() functions provide serialisation themselves | ||
621 | */ | ||
580 | spinlock_t mcastpsq_lock; | 622 | spinlock_t mcastpsq_lock; |
623 | |||
581 | u8 intra_bss; | 624 | u8 intra_bss; |
582 | struct wmi_ap_mode_stat ap_stats; | 625 | struct wmi_ap_mode_stat ap_stats; |
583 | u8 ap_country_code[3]; | 626 | u8 ap_country_code[3]; |
@@ -620,6 +663,7 @@ struct ath6kl { | |||
620 | 663 | ||
621 | u16 conf_flags; | 664 | u16 conf_flags; |
622 | u16 suspend_mode; | 665 | u16 suspend_mode; |
666 | u16 wow_suspend_mode; | ||
623 | wait_queue_head_t event_wq; | 667 | wait_queue_head_t event_wq; |
624 | struct ath6kl_mbox_info mbox_info; | 668 | struct ath6kl_mbox_info mbox_info; |
625 | 669 | ||
@@ -650,12 +694,16 @@ struct ath6kl { | |||
650 | 694 | ||
651 | bool p2p; | 695 | bool p2p; |
652 | 696 | ||
697 | bool wiphy_registered; | ||
698 | |||
653 | #ifdef CONFIG_ATH6KL_DEBUG | 699 | #ifdef CONFIG_ATH6KL_DEBUG |
654 | struct { | 700 | struct { |
655 | struct circ_buf fwlog_buf; | 701 | struct sk_buff_head fwlog_queue; |
656 | spinlock_t fwlog_lock; | 702 | struct completion fwlog_completion; |
657 | void *fwlog_tmp; | 703 | bool fwlog_open; |
704 | |||
658 | u32 fwlog_mask; | 705 | u32 fwlog_mask; |
706 | |||
659 | unsigned int dbgfs_diag_reg; | 707 | unsigned int dbgfs_diag_reg; |
660 | u32 diag_reg_addr_wr; | 708 | u32 diag_reg_addr_wr; |
661 | u32 diag_reg_val_wr; | 709 | u32 diag_reg_val_wr; |
@@ -727,10 +775,10 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target, | |||
727 | void aggr_module_destroy(struct aggr_info *aggr_info); | 775 | void aggr_module_destroy(struct aggr_info *aggr_info); |
728 | void aggr_reset_state(struct aggr_info_conn *aggr_conn); | 776 | void aggr_reset_state(struct aggr_info_conn *aggr_conn); |
729 | 777 | ||
730 | struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 * node_addr); | 778 | struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr); |
731 | struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); | 779 | struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); |
732 | 780 | ||
733 | void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver); | 781 | void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver); |
734 | int ath6kl_control_tx(void *devt, struct sk_buff *skb, | 782 | int ath6kl_control_tx(void *devt, struct sk_buff *skb, |
735 | enum htc_endpoint_id eid); | 783 | enum htc_endpoint_id eid); |
736 | void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, | 784 | void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, |
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index d832058816fe..552adb3f80d0 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -16,7 +17,7 @@ | |||
16 | 17 | ||
17 | #include "core.h" | 18 | #include "core.h" |
18 | 19 | ||
19 | #include <linux/circ_buf.h> | 20 | #include <linux/skbuff.h> |
20 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
21 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
22 | #include <linux/export.h> | 23 | #include <linux/export.h> |
@@ -32,9 +33,8 @@ struct ath6kl_fwlog_slot { | |||
32 | u8 payload[0]; | 33 | u8 payload[0]; |
33 | }; | 34 | }; |
34 | 35 | ||
35 | #define ATH6KL_FWLOG_SIZE 32768 | 36 | #define ATH6KL_FWLOG_MAX_ENTRIES 20 |
36 | #define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ | 37 | |
37 | ATH6KL_FWLOG_PAYLOAD_SIZE) | ||
38 | #define ATH6KL_FWLOG_VALID_MASK 0x1ffff | 38 | #define ATH6KL_FWLOG_VALID_MASK 0x1ffff |
39 | 39 | ||
40 | int ath6kl_printk(const char *level, const char *fmt, ...) | 40 | int ath6kl_printk(const char *level, const char *fmt, ...) |
@@ -119,29 +119,29 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, | |||
119 | 119 | ||
120 | if (irq_proc_reg != NULL) { | 120 | if (irq_proc_reg != NULL) { |
121 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 121 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
122 | "Host Int status: 0x%x\n", | 122 | "Host Int status: 0x%x\n", |
123 | irq_proc_reg->host_int_status); | 123 | irq_proc_reg->host_int_status); |
124 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 124 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
125 | "CPU Int status: 0x%x\n", | 125 | "CPU Int status: 0x%x\n", |
126 | irq_proc_reg->cpu_int_status); | 126 | irq_proc_reg->cpu_int_status); |
127 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 127 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
128 | "Error Int status: 0x%x\n", | 128 | "Error Int status: 0x%x\n", |
129 | irq_proc_reg->error_int_status); | 129 | irq_proc_reg->error_int_status); |
130 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 130 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
131 | "Counter Int status: 0x%x\n", | 131 | "Counter Int status: 0x%x\n", |
132 | irq_proc_reg->counter_int_status); | 132 | irq_proc_reg->counter_int_status); |
133 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 133 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
134 | "Mbox Frame: 0x%x\n", | 134 | "Mbox Frame: 0x%x\n", |
135 | irq_proc_reg->mbox_frame); | 135 | irq_proc_reg->mbox_frame); |
136 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 136 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
137 | "Rx Lookahead Valid: 0x%x\n", | 137 | "Rx Lookahead Valid: 0x%x\n", |
138 | irq_proc_reg->rx_lkahd_valid); | 138 | irq_proc_reg->rx_lkahd_valid); |
139 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 139 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
140 | "Rx Lookahead 0: 0x%x\n", | 140 | "Rx Lookahead 0: 0x%x\n", |
141 | irq_proc_reg->rx_lkahd[0]); | 141 | irq_proc_reg->rx_lkahd[0]); |
142 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 142 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
143 | "Rx Lookahead 1: 0x%x\n", | 143 | "Rx Lookahead 1: 0x%x\n", |
144 | irq_proc_reg->rx_lkahd[1]); | 144 | irq_proc_reg->rx_lkahd[1]); |
145 | 145 | ||
146 | if (dev->ar->mbox_info.gmbox_addr != 0) { | 146 | if (dev->ar->mbox_info.gmbox_addr != 0) { |
147 | /* | 147 | /* |
@@ -149,27 +149,27 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, | |||
149 | * additional state. | 149 | * additional state. |
150 | */ | 150 | */ |
151 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 151 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
152 | "GMBOX Host Int status 2: 0x%x\n", | 152 | "GMBOX Host Int status 2: 0x%x\n", |
153 | irq_proc_reg->host_int_status2); | 153 | irq_proc_reg->host_int_status2); |
154 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 154 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
155 | "GMBOX RX Avail: 0x%x\n", | 155 | "GMBOX RX Avail: 0x%x\n", |
156 | irq_proc_reg->gmbox_rx_avail); | 156 | irq_proc_reg->gmbox_rx_avail); |
157 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 157 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
158 | "GMBOX lookahead alias 0: 0x%x\n", | 158 | "GMBOX lookahead alias 0: 0x%x\n", |
159 | irq_proc_reg->rx_gmbox_lkahd_alias[0]); | 159 | irq_proc_reg->rx_gmbox_lkahd_alias[0]); |
160 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 160 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
161 | "GMBOX lookahead alias 1: 0x%x\n", | 161 | "GMBOX lookahead alias 1: 0x%x\n", |
162 | irq_proc_reg->rx_gmbox_lkahd_alias[1]); | 162 | irq_proc_reg->rx_gmbox_lkahd_alias[1]); |
163 | } | 163 | } |
164 | 164 | ||
165 | } | 165 | } |
166 | 166 | ||
167 | if (irq_enable_reg != NULL) { | 167 | if (irq_enable_reg != NULL) { |
168 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 168 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
169 | "Int status Enable: 0x%x\n", | 169 | "Int status Enable: 0x%x\n", |
170 | irq_enable_reg->int_status_en); | 170 | irq_enable_reg->int_status_en); |
171 | ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n", | 171 | ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n", |
172 | irq_enable_reg->cntr_int_status_en); | 172 | irq_enable_reg->cntr_int_status_en); |
173 | } | 173 | } |
174 | ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n"); | 174 | ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n"); |
175 | } | 175 | } |
@@ -268,105 +268,103 @@ static const struct file_operations fops_war_stats = { | |||
268 | .llseek = default_llseek, | 268 | .llseek = default_llseek, |
269 | }; | 269 | }; |
270 | 270 | ||
271 | static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, | 271 | void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) |
272 | size_t buf_len) | ||
273 | { | 272 | { |
274 | struct circ_buf *fwlog = &ar->debug.fwlog_buf; | 273 | struct ath6kl_fwlog_slot *slot; |
275 | size_t space; | 274 | struct sk_buff *skb; |
276 | int i; | 275 | size_t slot_len; |
277 | 276 | ||
278 | /* entries must all be equal size */ | 277 | if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) |
279 | if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) | ||
280 | return; | 278 | return; |
281 | 279 | ||
282 | space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); | 280 | slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE; |
283 | if (space < buf_len) | ||
284 | /* discard oldest slot */ | ||
285 | fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & | ||
286 | (ATH6KL_FWLOG_SIZE - 1); | ||
287 | 281 | ||
288 | for (i = 0; i < buf_len; i += space) { | 282 | skb = alloc_skb(slot_len, GFP_KERNEL); |
289 | space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, | 283 | if (!skb) |
290 | ATH6KL_FWLOG_SIZE); | 284 | return; |
291 | 285 | ||
292 | if ((size_t) space > buf_len - i) | 286 | slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len); |
293 | space = buf_len - i; | 287 | slot->timestamp = cpu_to_le32(jiffies); |
288 | slot->length = cpu_to_le32(len); | ||
289 | memcpy(slot->payload, buf, len); | ||
294 | 290 | ||
295 | memcpy(&fwlog->buf[fwlog->head], buf, space); | 291 | /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */ |
296 | fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); | 292 | memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len); |
297 | } | ||
298 | 293 | ||
299 | } | 294 | spin_lock(&ar->debug.fwlog_queue.lock); |
300 | 295 | ||
301 | void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) | 296 | __skb_queue_tail(&ar->debug.fwlog_queue, skb); |
302 | { | 297 | complete(&ar->debug.fwlog_completion); |
303 | struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; | ||
304 | size_t slot_len; | ||
305 | 298 | ||
306 | if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) | 299 | /* drop oldest entries */ |
307 | return; | 300 | while (skb_queue_len(&ar->debug.fwlog_queue) > |
301 | ATH6KL_FWLOG_MAX_ENTRIES) { | ||
302 | skb = __skb_dequeue(&ar->debug.fwlog_queue); | ||
303 | kfree_skb(skb); | ||
304 | } | ||
308 | 305 | ||
309 | spin_lock_bh(&ar->debug.fwlog_lock); | 306 | spin_unlock(&ar->debug.fwlog_queue.lock); |
310 | 307 | ||
311 | slot->timestamp = cpu_to_le32(jiffies); | 308 | return; |
312 | slot->length = cpu_to_le32(len); | 309 | } |
313 | memcpy(slot->payload, buf, len); | ||
314 | 310 | ||
315 | slot_len = sizeof(*slot) + len; | 311 | static int ath6kl_fwlog_open(struct inode *inode, struct file *file) |
312 | { | ||
313 | struct ath6kl *ar = inode->i_private; | ||
316 | 314 | ||
317 | if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) | 315 | if (ar->debug.fwlog_open) |
318 | memset(slot->payload + len, 0, | 316 | return -EBUSY; |
319 | ATH6KL_FWLOG_SLOT_SIZE - slot_len); | ||
320 | 317 | ||
321 | ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); | 318 | ar->debug.fwlog_open = true; |
322 | 319 | ||
323 | spin_unlock_bh(&ar->debug.fwlog_lock); | 320 | file->private_data = inode->i_private; |
321 | return 0; | ||
324 | } | 322 | } |
325 | 323 | ||
326 | static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) | 324 | static int ath6kl_fwlog_release(struct inode *inode, struct file *file) |
327 | { | 325 | { |
328 | return CIRC_CNT(ar->debug.fwlog_buf.head, | 326 | struct ath6kl *ar = inode->i_private; |
329 | ar->debug.fwlog_buf.tail, | 327 | |
330 | ATH6KL_FWLOG_SLOT_SIZE) == 0; | 328 | ar->debug.fwlog_open = false; |
329 | |||
330 | return 0; | ||
331 | } | 331 | } |
332 | 332 | ||
333 | static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, | 333 | static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, |
334 | size_t count, loff_t *ppos) | 334 | size_t count, loff_t *ppos) |
335 | { | 335 | { |
336 | struct ath6kl *ar = file->private_data; | 336 | struct ath6kl *ar = file->private_data; |
337 | struct circ_buf *fwlog = &ar->debug.fwlog_buf; | 337 | struct sk_buff *skb; |
338 | size_t len = 0, buf_len = count; | ||
339 | ssize_t ret_cnt; | 338 | ssize_t ret_cnt; |
339 | size_t len = 0; | ||
340 | char *buf; | 340 | char *buf; |
341 | int ccnt; | ||
342 | 341 | ||
343 | buf = vmalloc(buf_len); | 342 | buf = vmalloc(count); |
344 | if (!buf) | 343 | if (!buf) |
345 | return -ENOMEM; | 344 | return -ENOMEM; |
346 | 345 | ||
347 | /* read undelivered logs from firmware */ | 346 | /* read undelivered logs from firmware */ |
348 | ath6kl_read_fwlogs(ar); | 347 | ath6kl_read_fwlogs(ar); |
349 | 348 | ||
350 | spin_lock_bh(&ar->debug.fwlog_lock); | 349 | spin_lock(&ar->debug.fwlog_queue.lock); |
351 | 350 | ||
352 | while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { | 351 | while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) { |
353 | ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, | 352 | if (skb->len > count - len) { |
354 | ATH6KL_FWLOG_SIZE); | 353 | /* not enough space, put skb back and leave */ |
354 | __skb_queue_head(&ar->debug.fwlog_queue, skb); | ||
355 | break; | ||
356 | } | ||
355 | 357 | ||
356 | if ((size_t) ccnt > buf_len - len) | ||
357 | ccnt = buf_len - len; | ||
358 | 358 | ||
359 | memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); | 359 | memcpy(buf + len, skb->data, skb->len); |
360 | len += ccnt; | 360 | len += skb->len; |
361 | 361 | ||
362 | fwlog->tail = (fwlog->tail + ccnt) & | 362 | kfree_skb(skb); |
363 | (ATH6KL_FWLOG_SIZE - 1); | ||
364 | } | 363 | } |
365 | 364 | ||
366 | spin_unlock_bh(&ar->debug.fwlog_lock); | 365 | spin_unlock(&ar->debug.fwlog_queue.lock); |
367 | 366 | ||
368 | if (WARN_ON(len > buf_len)) | 367 | /* FIXME: what to do if len == 0? */ |
369 | len = buf_len; | ||
370 | 368 | ||
371 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); | 369 | ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); |
372 | 370 | ||
@@ -376,12 +374,87 @@ static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, | |||
376 | } | 374 | } |
377 | 375 | ||
378 | static const struct file_operations fops_fwlog = { | 376 | static const struct file_operations fops_fwlog = { |
379 | .open = ath6kl_debugfs_open, | 377 | .open = ath6kl_fwlog_open, |
378 | .release = ath6kl_fwlog_release, | ||
380 | .read = ath6kl_fwlog_read, | 379 | .read = ath6kl_fwlog_read, |
381 | .owner = THIS_MODULE, | 380 | .owner = THIS_MODULE, |
382 | .llseek = default_llseek, | 381 | .llseek = default_llseek, |
383 | }; | 382 | }; |
384 | 383 | ||
384 | static ssize_t ath6kl_fwlog_block_read(struct file *file, | ||
385 | char __user *user_buf, | ||
386 | size_t count, | ||
387 | loff_t *ppos) | ||
388 | { | ||
389 | struct ath6kl *ar = file->private_data; | ||
390 | struct sk_buff *skb; | ||
391 | ssize_t ret_cnt; | ||
392 | size_t len = 0, not_copied; | ||
393 | char *buf; | ||
394 | int ret; | ||
395 | |||
396 | buf = vmalloc(count); | ||
397 | if (!buf) | ||
398 | return -ENOMEM; | ||
399 | |||
400 | spin_lock(&ar->debug.fwlog_queue.lock); | ||
401 | |||
402 | if (skb_queue_len(&ar->debug.fwlog_queue) == 0) { | ||
403 | /* we must init under queue lock */ | ||
404 | init_completion(&ar->debug.fwlog_completion); | ||
405 | |||
406 | spin_unlock(&ar->debug.fwlog_queue.lock); | ||
407 | |||
408 | ret = wait_for_completion_interruptible( | ||
409 | &ar->debug.fwlog_completion); | ||
410 | if (ret == -ERESTARTSYS) | ||
411 | return ret; | ||
412 | |||
413 | spin_lock(&ar->debug.fwlog_queue.lock); | ||
414 | } | ||
415 | |||
416 | while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) { | ||
417 | if (skb->len > count - len) { | ||
418 | /* not enough space, put skb back and leave */ | ||
419 | __skb_queue_head(&ar->debug.fwlog_queue, skb); | ||
420 | break; | ||
421 | } | ||
422 | |||
423 | |||
424 | memcpy(buf + len, skb->data, skb->len); | ||
425 | len += skb->len; | ||
426 | |||
427 | kfree_skb(skb); | ||
428 | } | ||
429 | |||
430 | spin_unlock(&ar->debug.fwlog_queue.lock); | ||
431 | |||
432 | /* FIXME: what to do if len == 0? */ | ||
433 | |||
434 | not_copied = copy_to_user(user_buf, buf, len); | ||
435 | if (not_copied != 0) { | ||
436 | ret_cnt = -EFAULT; | ||
437 | goto out; | ||
438 | } | ||
439 | |||
440 | *ppos = *ppos + len; | ||
441 | |||
442 | ret_cnt = len; | ||
443 | |||
444 | out: | ||
445 | vfree(buf); | ||
446 | |||
447 | return ret_cnt; | ||
448 | } | ||
449 | |||
450 | static const struct file_operations fops_fwlog_block = { | ||
451 | .open = ath6kl_fwlog_open, | ||
452 | .release = ath6kl_fwlog_release, | ||
453 | .read = ath6kl_fwlog_block_read, | ||
454 | .owner = THIS_MODULE, | ||
455 | .llseek = default_llseek, | ||
456 | }; | ||
457 | |||
385 | static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, | 458 | static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, |
386 | size_t count, loff_t *ppos) | 459 | size_t count, loff_t *ppos) |
387 | { | 460 | { |
@@ -667,9 +740,13 @@ static ssize_t ath6kl_endpoint_stats_read(struct file *file, | |||
667 | return -ENOMEM; | 740 | return -ENOMEM; |
668 | 741 | ||
669 | #define EPSTAT(name) \ | 742 | #define EPSTAT(name) \ |
670 | len = print_endpoint_stat(target, buf, buf_len, len, \ | 743 | do { \ |
671 | offsetof(struct htc_endpoint_stats, name), \ | 744 | len = print_endpoint_stat(target, buf, buf_len, len, \ |
672 | #name) | 745 | offsetof(struct htc_endpoint_stats, \ |
746 | name), \ | ||
747 | #name); \ | ||
748 | } while (0) | ||
749 | |||
673 | EPSTAT(cred_low_indicate); | 750 | EPSTAT(cred_low_indicate); |
674 | EPSTAT(tx_issued); | 751 | EPSTAT(tx_issued); |
675 | EPSTAT(tx_pkt_bundled); | 752 | EPSTAT(tx_pkt_bundled); |
@@ -779,17 +856,9 @@ static ssize_t ath6kl_regread_write(struct file *file, | |||
779 | size_t count, loff_t *ppos) | 856 | size_t count, loff_t *ppos) |
780 | { | 857 | { |
781 | struct ath6kl *ar = file->private_data; | 858 | struct ath6kl *ar = file->private_data; |
782 | u8 buf[50]; | ||
783 | unsigned int len; | ||
784 | unsigned long reg_addr; | 859 | unsigned long reg_addr; |
785 | 860 | ||
786 | len = min(count, sizeof(buf) - 1); | 861 | if (kstrtoul_from_user(user_buf, count, 0, ®_addr)) |
787 | if (copy_from_user(buf, user_buf, len)) | ||
788 | return -EFAULT; | ||
789 | |||
790 | buf[len] = '\0'; | ||
791 | |||
792 | if (strict_strtoul(buf, 0, ®_addr)) | ||
793 | return -EINVAL; | 862 | return -EINVAL; |
794 | 863 | ||
795 | if ((reg_addr % 4) != 0) | 864 | if ((reg_addr % 4) != 0) |
@@ -903,15 +972,8 @@ static ssize_t ath6kl_lrssi_roam_write(struct file *file, | |||
903 | { | 972 | { |
904 | struct ath6kl *ar = file->private_data; | 973 | struct ath6kl *ar = file->private_data; |
905 | unsigned long lrssi_roam_threshold; | 974 | unsigned long lrssi_roam_threshold; |
906 | char buf[32]; | ||
907 | ssize_t len; | ||
908 | 975 | ||
909 | len = min(count, sizeof(buf) - 1); | 976 | if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold)) |
910 | if (copy_from_user(buf, user_buf, len)) | ||
911 | return -EFAULT; | ||
912 | |||
913 | buf[len] = '\0'; | ||
914 | if (strict_strtoul(buf, 0, &lrssi_roam_threshold)) | ||
915 | return -EINVAL; | 977 | return -EINVAL; |
916 | 978 | ||
917 | ar->lrssi_roam_threshold = lrssi_roam_threshold; | 979 | ar->lrssi_roam_threshold = lrssi_roam_threshold; |
@@ -1558,12 +1620,12 @@ static ssize_t ath6kl_listen_int_write(struct file *file, | |||
1558 | if (kstrtou16(buf, 0, &listen_interval)) | 1620 | if (kstrtou16(buf, 0, &listen_interval)) |
1559 | return -EINVAL; | 1621 | return -EINVAL; |
1560 | 1622 | ||
1561 | if ((listen_interval < 1) || (listen_interval > 50)) | 1623 | if ((listen_interval < 15) || (listen_interval > 3000)) |
1562 | return -EINVAL; | 1624 | return -EINVAL; |
1563 | 1625 | ||
1564 | ar->listen_intvl_b = listen_interval; | 1626 | vif->listen_intvl_t = listen_interval; |
1565 | ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, 0, | 1627 | ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, |
1566 | ar->listen_intvl_b); | 1628 | vif->listen_intvl_t, 0); |
1567 | 1629 | ||
1568 | return count; | 1630 | return count; |
1569 | } | 1631 | } |
@@ -1573,10 +1635,15 @@ static ssize_t ath6kl_listen_int_read(struct file *file, | |||
1573 | size_t count, loff_t *ppos) | 1635 | size_t count, loff_t *ppos) |
1574 | { | 1636 | { |
1575 | struct ath6kl *ar = file->private_data; | 1637 | struct ath6kl *ar = file->private_data; |
1638 | struct ath6kl_vif *vif; | ||
1576 | char buf[32]; | 1639 | char buf[32]; |
1577 | int len; | 1640 | int len; |
1578 | 1641 | ||
1579 | len = scnprintf(buf, sizeof(buf), "%u\n", ar->listen_intvl_b); | 1642 | vif = ath6kl_vif_first(ar); |
1643 | if (!vif) | ||
1644 | return -EIO; | ||
1645 | |||
1646 | len = scnprintf(buf, sizeof(buf), "%u\n", vif->listen_intvl_t); | ||
1580 | 1647 | ||
1581 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 1648 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); |
1582 | } | 1649 | } |
@@ -1649,33 +1716,29 @@ static const struct file_operations fops_power_params = { | |||
1649 | .llseek = default_llseek, | 1716 | .llseek = default_llseek, |
1650 | }; | 1717 | }; |
1651 | 1718 | ||
1652 | int ath6kl_debug_init(struct ath6kl *ar) | 1719 | void ath6kl_debug_init(struct ath6kl *ar) |
1653 | { | 1720 | { |
1654 | ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); | 1721 | skb_queue_head_init(&ar->debug.fwlog_queue); |
1655 | if (ar->debug.fwlog_buf.buf == NULL) | 1722 | init_completion(&ar->debug.fwlog_completion); |
1656 | return -ENOMEM; | ||
1657 | |||
1658 | ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); | ||
1659 | if (ar->debug.fwlog_tmp == NULL) { | ||
1660 | vfree(ar->debug.fwlog_buf.buf); | ||
1661 | return -ENOMEM; | ||
1662 | } | ||
1663 | |||
1664 | spin_lock_init(&ar->debug.fwlog_lock); | ||
1665 | 1723 | ||
1666 | /* | 1724 | /* |
1667 | * Actually we are lying here but don't know how to read the mask | 1725 | * Actually we are lying here but don't know how to read the mask |
1668 | * value from the firmware. | 1726 | * value from the firmware. |
1669 | */ | 1727 | */ |
1670 | ar->debug.fwlog_mask = 0; | 1728 | ar->debug.fwlog_mask = 0; |
1729 | } | ||
1671 | 1730 | ||
1731 | /* | ||
1732 | * Initialisation needs to happen in two stages as fwlog events can come | ||
1733 | * before cfg80211 is initialised, and debugfs depends on cfg80211 | ||
1734 | * initialisation. | ||
1735 | */ | ||
1736 | int ath6kl_debug_init_fs(struct ath6kl *ar) | ||
1737 | { | ||
1672 | ar->debugfs_phy = debugfs_create_dir("ath6kl", | 1738 | ar->debugfs_phy = debugfs_create_dir("ath6kl", |
1673 | ar->wiphy->debugfsdir); | 1739 | ar->wiphy->debugfsdir); |
1674 | if (!ar->debugfs_phy) { | 1740 | if (!ar->debugfs_phy) |
1675 | vfree(ar->debug.fwlog_buf.buf); | ||
1676 | kfree(ar->debug.fwlog_tmp); | ||
1677 | return -ENOMEM; | 1741 | return -ENOMEM; |
1678 | } | ||
1679 | 1742 | ||
1680 | debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, | 1743 | debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, |
1681 | &fops_tgt_stats); | 1744 | &fops_tgt_stats); |
@@ -1689,6 +1752,9 @@ int ath6kl_debug_init(struct ath6kl *ar) | |||
1689 | debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, | 1752 | debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, |
1690 | &fops_fwlog); | 1753 | &fops_fwlog); |
1691 | 1754 | ||
1755 | debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar, | ||
1756 | &fops_fwlog_block); | ||
1757 | |||
1692 | debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, | 1758 | debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, |
1693 | ar, &fops_fwlog_mask); | 1759 | ar, &fops_fwlog_mask); |
1694 | 1760 | ||
@@ -1723,27 +1789,26 @@ int ath6kl_debug_init(struct ath6kl *ar) | |||
1723 | ar->debugfs_phy, ar, &fops_disconnect_timeout); | 1789 | ar->debugfs_phy, ar, &fops_disconnect_timeout); |
1724 | 1790 | ||
1725 | debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar, | 1791 | debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar, |
1726 | &fops_create_qos); | 1792 | &fops_create_qos); |
1727 | 1793 | ||
1728 | debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar, | 1794 | debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar, |
1729 | &fops_delete_qos); | 1795 | &fops_delete_qos); |
1730 | 1796 | ||
1731 | debugfs_create_file("bgscan_interval", S_IWUSR, | 1797 | debugfs_create_file("bgscan_interval", S_IWUSR, |
1732 | ar->debugfs_phy, ar, &fops_bgscan_int); | 1798 | ar->debugfs_phy, ar, &fops_bgscan_int); |
1733 | 1799 | ||
1734 | debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR, | 1800 | debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR, |
1735 | ar->debugfs_phy, ar, &fops_listen_int); | 1801 | ar->debugfs_phy, ar, &fops_listen_int); |
1736 | 1802 | ||
1737 | debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar, | 1803 | debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar, |
1738 | &fops_power_params); | 1804 | &fops_power_params); |
1739 | 1805 | ||
1740 | return 0; | 1806 | return 0; |
1741 | } | 1807 | } |
1742 | 1808 | ||
1743 | void ath6kl_debug_cleanup(struct ath6kl *ar) | 1809 | void ath6kl_debug_cleanup(struct ath6kl *ar) |
1744 | { | 1810 | { |
1745 | vfree(ar->debug.fwlog_buf.buf); | 1811 | skb_queue_purge(&ar->debug.fwlog_queue); |
1746 | kfree(ar->debug.fwlog_tmp); | ||
1747 | kfree(ar->debug.roam_tbl); | 1812 | kfree(ar->debug.roam_tbl); |
1748 | } | 1813 | } |
1749 | 1814 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index c4be6e50996b..1803a0baae82 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2011 Atheros Communications Inc. | 2 | * Copyright (c) 2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -77,7 +78,8 @@ int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf, | |||
77 | size_t len); | 78 | size_t len); |
78 | void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive); | 79 | void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive); |
79 | void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout); | 80 | void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout); |
80 | int ath6kl_debug_init(struct ath6kl *ar); | 81 | void ath6kl_debug_init(struct ath6kl *ar); |
82 | int ath6kl_debug_init_fs(struct ath6kl *ar); | ||
81 | void ath6kl_debug_cleanup(struct ath6kl *ar); | 83 | void ath6kl_debug_cleanup(struct ath6kl *ar); |
82 | 84 | ||
83 | #else | 85 | #else |
@@ -127,7 +129,11 @@ static inline void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, | |||
127 | { | 129 | { |
128 | } | 130 | } |
129 | 131 | ||
130 | static inline int ath6kl_debug_init(struct ath6kl *ar) | 132 | static inline void ath6kl_debug_init(struct ath6kl *ar) |
133 | { | ||
134 | } | ||
135 | |||
136 | static inline int ath6kl_debug_init_fs(struct ath6kl *ar) | ||
131 | { | 137 | { |
132 | return 0; | 138 | return 0; |
133 | } | 139 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h index 2fe1dadfc77a..fd84086638e3 100644 --- a/drivers/net/wireless/ath/ath6kl/hif-ops.h +++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index e911737ab345..68ed6c2665b7 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2007-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2007-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -89,7 +90,7 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) | |||
89 | } | 90 | } |
90 | 91 | ||
91 | ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n", | 92 | ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n", |
92 | regdump_addr); | 93 | regdump_addr); |
93 | regdump_addr = TARG_VTOP(ar->target_type, regdump_addr); | 94 | regdump_addr = TARG_VTOP(ar->target_type, regdump_addr); |
94 | 95 | ||
95 | /* fetch register dump data */ | 96 | /* fetch register dump data */ |
@@ -106,9 +107,9 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) | |||
106 | 107 | ||
107 | BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4); | 108 | BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4); |
108 | 109 | ||
109 | for (i = 0; i < REG_DUMP_COUNT_AR6003 / 4; i++) { | 110 | for (i = 0; i < REG_DUMP_COUNT_AR6003; i += 4) { |
110 | ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", | 111 | ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", |
111 | 4 * i, | 112 | i, |
112 | le32_to_cpu(regdump_val[i]), | 113 | le32_to_cpu(regdump_val[i]), |
113 | le32_to_cpu(regdump_val[i + 1]), | 114 | le32_to_cpu(regdump_val[i + 1]), |
114 | le32_to_cpu(regdump_val[i + 2]), | 115 | le32_to_cpu(regdump_val[i + 2]), |
@@ -134,6 +135,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) | |||
134 | ath6kl_warn("Failed to clear debug interrupt: %d\n", ret); | 135 | ath6kl_warn("Failed to clear debug interrupt: %d\n", ret); |
135 | 136 | ||
136 | ath6kl_hif_dump_fw_crash(dev->ar); | 137 | ath6kl_hif_dump_fw_crash(dev->ar); |
138 | ath6kl_read_fwlogs(dev->ar); | ||
137 | 139 | ||
138 | return ret; | 140 | return ret; |
139 | } | 141 | } |
@@ -283,7 +285,7 @@ static int ath6kl_hif_proc_counter_intr(struct ath6kl_device *dev) | |||
283 | dev->irq_en_reg.cntr_int_status_en; | 285 | dev->irq_en_reg.cntr_int_status_en; |
284 | 286 | ||
285 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 287 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
286 | "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", | 288 | "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", |
287 | counter_int_status); | 289 | counter_int_status); |
288 | 290 | ||
289 | /* | 291 | /* |
@@ -358,7 +360,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev) | |||
358 | } | 360 | } |
359 | 361 | ||
360 | ath6kl_dbg(ATH6KL_DBG_IRQ, | 362 | ath6kl_dbg(ATH6KL_DBG_IRQ, |
361 | "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", | 363 | "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", |
362 | cpu_int_status); | 364 | cpu_int_status); |
363 | 365 | ||
364 | /* Clear the interrupt */ | 366 | /* Clear the interrupt */ |
diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index 699a036f3a44..20ed6b73517b 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -197,6 +198,8 @@ struct hif_scatter_req { | |||
197 | u8 *virt_dma_buf; | 198 | u8 *virt_dma_buf; |
198 | 199 | ||
199 | struct hif_scatter_item scat_list[1]; | 200 | struct hif_scatter_item scat_list[1]; |
201 | |||
202 | u32 scat_q_depth; | ||
200 | }; | 203 | }; |
201 | 204 | ||
202 | struct ath6kl_irq_proc_registers { | 205 | struct ath6kl_irq_proc_registers { |
@@ -220,6 +223,7 @@ struct ath6kl_irq_enable_reg { | |||
220 | } __packed; | 223 | } __packed; |
221 | 224 | ||
222 | struct ath6kl_device { | 225 | struct ath6kl_device { |
226 | /* protects irq_proc_reg and irq_en_reg below */ | ||
223 | spinlock_t lock; | 227 | spinlock_t lock; |
224 | struct ath6kl_irq_proc_registers irq_proc_reg; | 228 | struct ath6kl_irq_proc_registers irq_proc_reg; |
225 | struct ath6kl_irq_enable_reg irq_en_reg; | 229 | struct ath6kl_irq_enable_reg irq_en_reg; |
diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index 2d721903640b..4849d99cce77 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2007-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2007-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -22,6 +23,9 @@ | |||
22 | 23 | ||
23 | #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) | 24 | #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) |
24 | 25 | ||
26 | /* threshold to re-enable Tx bundling for an AC*/ | ||
27 | #define TX_RESUME_BUNDLE_THRESHOLD 1500 | ||
28 | |||
25 | /* Functions for Tx credit handling */ | 29 | /* Functions for Tx credit handling */ |
26 | static void ath6kl_credit_deposit(struct ath6kl_htc_credit_info *cred_info, | 30 | static void ath6kl_credit_deposit(struct ath6kl_htc_credit_info *cred_info, |
27 | struct htc_endpoint_credit_dist *ep_dist, | 31 | struct htc_endpoint_credit_dist *ep_dist, |
@@ -168,31 +172,29 @@ static void ath6kl_credit_reduce(struct ath6kl_htc_credit_info *cred_info, | |||
168 | static void ath6kl_credit_update(struct ath6kl_htc_credit_info *cred_info, | 172 | static void ath6kl_credit_update(struct ath6kl_htc_credit_info *cred_info, |
169 | struct list_head *epdist_list) | 173 | struct list_head *epdist_list) |
170 | { | 174 | { |
171 | struct htc_endpoint_credit_dist *cur_dist_list; | 175 | struct htc_endpoint_credit_dist *cur_list; |
172 | 176 | ||
173 | list_for_each_entry(cur_dist_list, epdist_list, list) { | 177 | list_for_each_entry(cur_list, epdist_list, list) { |
174 | if (cur_dist_list->endpoint == ENDPOINT_0) | 178 | if (cur_list->endpoint == ENDPOINT_0) |
175 | continue; | 179 | continue; |
176 | 180 | ||
177 | if (cur_dist_list->cred_to_dist > 0) { | 181 | if (cur_list->cred_to_dist > 0) { |
178 | cur_dist_list->credits += | 182 | cur_list->credits += cur_list->cred_to_dist; |
179 | cur_dist_list->cred_to_dist; | 183 | cur_list->cred_to_dist = 0; |
180 | cur_dist_list->cred_to_dist = 0; | 184 | |
181 | if (cur_dist_list->credits > | 185 | if (cur_list->credits > cur_list->cred_assngd) |
182 | cur_dist_list->cred_assngd) | ||
183 | ath6kl_credit_reduce(cred_info, | 186 | ath6kl_credit_reduce(cred_info, |
184 | cur_dist_list, | 187 | cur_list, |
185 | cur_dist_list->cred_assngd); | 188 | cur_list->cred_assngd); |
186 | 189 | ||
187 | if (cur_dist_list->credits > | 190 | if (cur_list->credits > cur_list->cred_norm) |
188 | cur_dist_list->cred_norm) | 191 | ath6kl_credit_reduce(cred_info, cur_list, |
189 | ath6kl_credit_reduce(cred_info, cur_dist_list, | 192 | cur_list->cred_norm); |
190 | cur_dist_list->cred_norm); | ||
191 | 193 | ||
192 | if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) { | 194 | if (!(cur_list->dist_flags & HTC_EP_ACTIVE)) { |
193 | if (cur_dist_list->txq_depth == 0) | 195 | if (cur_list->txq_depth == 0) |
194 | ath6kl_credit_reduce(cred_info, | 196 | ath6kl_credit_reduce(cred_info, |
195 | cur_dist_list, 0); | 197 | cur_list, 0); |
196 | } | 198 | } |
197 | } | 199 | } |
198 | } | 200 | } |
@@ -460,8 +462,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target, | |||
460 | INIT_LIST_HEAD(&tx_compq); | 462 | INIT_LIST_HEAD(&tx_compq); |
461 | 463 | ||
462 | ath6kl_dbg(ATH6KL_DBG_HTC, | 464 | ath6kl_dbg(ATH6KL_DBG_HTC, |
463 | "htc tx scat complete len %d entries %d\n", | 465 | "htc tx scat complete len %d entries %d\n", |
464 | scat_req->len, scat_req->scat_entries); | 466 | scat_req->len, scat_req->scat_entries); |
465 | 467 | ||
466 | if (scat_req->status) | 468 | if (scat_req->status) |
467 | ath6kl_err("send scatter req failed: %d\n", scat_req->status); | 469 | ath6kl_err("send scatter req failed: %d\n", scat_req->status); |
@@ -599,8 +601,8 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target, | |||
599 | list); | 601 | list); |
600 | 602 | ||
601 | ath6kl_dbg(ATH6KL_DBG_HTC, | 603 | ath6kl_dbg(ATH6KL_DBG_HTC, |
602 | "htc tx got packet 0x%p queue depth %d\n", | 604 | "htc tx got packet 0x%p queue depth %d\n", |
603 | packet, get_queue_depth(&endpoint->txq)); | 605 | packet, get_queue_depth(&endpoint->txq)); |
604 | 606 | ||
605 | len = CALC_TXRX_PADDED_LEN(target, | 607 | len = CALC_TXRX_PADDED_LEN(target, |
606 | packet->act_len + HTC_HDR_LENGTH); | 608 | packet->act_len + HTC_HDR_LENGTH); |
@@ -670,6 +672,7 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, | |||
670 | struct htc_packet *packet; | 672 | struct htc_packet *packet; |
671 | int i, len, rem_scat, cred_pad; | 673 | int i, len, rem_scat, cred_pad; |
672 | int status = 0; | 674 | int status = 0; |
675 | u8 flags; | ||
673 | 676 | ||
674 | rem_scat = target->max_tx_bndl_sz; | 677 | rem_scat = target->max_tx_bndl_sz; |
675 | 678 | ||
@@ -696,9 +699,9 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, | |||
696 | 699 | ||
697 | scat_req->scat_list[i].packet = packet; | 700 | scat_req->scat_list[i].packet = packet; |
698 | /* prepare packet and flag message as part of a send bundle */ | 701 | /* prepare packet and flag message as part of a send bundle */ |
699 | ath6kl_htc_tx_prep_pkt(packet, | 702 | flags = packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE; |
700 | packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE, | 703 | ath6kl_htc_tx_prep_pkt(packet, flags, |
701 | cred_pad, packet->info.tx.seqno); | 704 | cred_pad, packet->info.tx.seqno); |
702 | /* Make sure the buffer is 4-byte aligned */ | 705 | /* Make sure the buffer is 4-byte aligned */ |
703 | ath6kl_htc_tx_buf_align(&packet->buf, | 706 | ath6kl_htc_tx_buf_align(&packet->buf, |
704 | packet->act_len + HTC_HDR_LENGTH); | 707 | packet->act_len + HTC_HDR_LENGTH); |
@@ -744,6 +747,12 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, | |||
744 | struct hif_scatter_req *scat_req = NULL; | 747 | struct hif_scatter_req *scat_req = NULL; |
745 | int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; | 748 | int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; |
746 | int status; | 749 | int status; |
750 | u32 txb_mask; | ||
751 | u8 ac = WMM_NUM_AC; | ||
752 | |||
753 | if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || | ||
754 | (WMI_CONTROL_SVC != endpoint->svc_id)) | ||
755 | ac = target->dev->ar->ep2ac_map[endpoint->eid]; | ||
747 | 756 | ||
748 | while (true) { | 757 | while (true) { |
749 | status = 0; | 758 | status = 0; |
@@ -759,10 +768,35 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, | |||
759 | if (!scat_req) { | 768 | if (!scat_req) { |
760 | /* no scatter resources */ | 769 | /* no scatter resources */ |
761 | ath6kl_dbg(ATH6KL_DBG_HTC, | 770 | ath6kl_dbg(ATH6KL_DBG_HTC, |
762 | "htc tx no more scatter resources\n"); | 771 | "htc tx no more scatter resources\n"); |
763 | break; | 772 | break; |
764 | } | 773 | } |
765 | 774 | ||
775 | if ((ac < WMM_NUM_AC) && (ac != WMM_AC_BK)) { | ||
776 | if (WMM_AC_BE == ac) | ||
777 | /* | ||
778 | * BE, BK have priorities and bit | ||
779 | * positions reversed | ||
780 | */ | ||
781 | txb_mask = (1 << WMM_AC_BK); | ||
782 | else | ||
783 | /* | ||
784 | * any AC with priority lower than | ||
785 | * itself | ||
786 | */ | ||
787 | txb_mask = ((1 << ac) - 1); | ||
788 | /* | ||
789 | * when the scatter request resources drop below a | ||
790 | * certain threshold, disable Tx bundling for all | ||
791 | * AC's with priority lower than the current requesting | ||
792 | * AC. Otherwise re-enable Tx bundling for them | ||
793 | */ | ||
794 | if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS) | ||
795 | target->tx_bndl_mask &= ~txb_mask; | ||
796 | else | ||
797 | target->tx_bndl_mask |= txb_mask; | ||
798 | } | ||
799 | |||
766 | ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n", | 800 | ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n", |
767 | n_scat); | 801 | n_scat); |
768 | 802 | ||
@@ -806,6 +840,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, | |||
806 | struct htc_packet *packet; | 840 | struct htc_packet *packet; |
807 | int bundle_sent; | 841 | int bundle_sent; |
808 | int n_pkts_bundle; | 842 | int n_pkts_bundle; |
843 | u8 ac = WMM_NUM_AC; | ||
809 | 844 | ||
810 | spin_lock_bh(&target->tx_lock); | 845 | spin_lock_bh(&target->tx_lock); |
811 | 846 | ||
@@ -823,6 +858,10 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, | |||
823 | */ | 858 | */ |
824 | INIT_LIST_HEAD(&txq); | 859 | INIT_LIST_HEAD(&txq); |
825 | 860 | ||
861 | if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || | ||
862 | (WMI_CONTROL_SVC != endpoint->svc_id)) | ||
863 | ac = target->dev->ar->ep2ac_map[endpoint->eid]; | ||
864 | |||
826 | while (true) { | 865 | while (true) { |
827 | 866 | ||
828 | if (list_empty(&endpoint->txq)) | 867 | if (list_empty(&endpoint->txq)) |
@@ -840,15 +879,18 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, | |||
840 | 879 | ||
841 | while (true) { | 880 | while (true) { |
842 | /* try to send a bundle on each pass */ | 881 | /* try to send a bundle on each pass */ |
843 | if ((target->tx_bndl_enable) && | 882 | if ((target->tx_bndl_mask) && |
844 | (get_queue_depth(&txq) >= | 883 | (get_queue_depth(&txq) >= |
845 | HTC_MIN_HTC_MSGS_TO_BUNDLE)) { | 884 | HTC_MIN_HTC_MSGS_TO_BUNDLE)) { |
846 | int temp1 = 0, temp2 = 0; | 885 | int temp1 = 0, temp2 = 0; |
847 | 886 | ||
848 | ath6kl_htc_tx_bundle(endpoint, &txq, | 887 | /* check if bundling is enabled for an AC */ |
849 | &temp1, &temp2); | 888 | if (target->tx_bndl_mask & (1 << ac)) { |
850 | bundle_sent += temp1; | 889 | ath6kl_htc_tx_bundle(endpoint, &txq, |
851 | n_pkts_bundle += temp2; | 890 | &temp1, &temp2); |
891 | bundle_sent += temp1; | ||
892 | n_pkts_bundle += temp2; | ||
893 | } | ||
852 | } | 894 | } |
853 | 895 | ||
854 | if (list_empty(&txq)) | 896 | if (list_empty(&txq)) |
@@ -867,6 +909,26 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, | |||
867 | 909 | ||
868 | endpoint->ep_st.tx_bundles += bundle_sent; | 910 | endpoint->ep_st.tx_bundles += bundle_sent; |
869 | endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle; | 911 | endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle; |
912 | |||
913 | /* | ||
914 | * if an AC has bundling disabled and no tx bundling | ||
915 | * has occured continously for a certain number of TX, | ||
916 | * enable tx bundling for this AC | ||
917 | */ | ||
918 | if (!bundle_sent) { | ||
919 | if (!(target->tx_bndl_mask & (1 << ac)) && | ||
920 | (ac < WMM_NUM_AC)) { | ||
921 | if (++target->ac_tx_count[ac] >= | ||
922 | TX_RESUME_BUNDLE_THRESHOLD) { | ||
923 | target->ac_tx_count[ac] = 0; | ||
924 | target->tx_bndl_mask |= (1 << ac); | ||
925 | } | ||
926 | } | ||
927 | } else { | ||
928 | /* tx bundling will reset the counter */ | ||
929 | if (ac < WMM_NUM_AC) | ||
930 | target->ac_tx_count[ac] = 0; | ||
931 | } | ||
870 | } | 932 | } |
871 | 933 | ||
872 | endpoint->tx_proc_cnt = 0; | 934 | endpoint->tx_proc_cnt = 0; |
@@ -979,8 +1041,8 @@ static int htc_setup_tx_complete(struct htc_target *target) | |||
979 | memcpy(&setup_comp_ext->flags, &flags, | 1041 | memcpy(&setup_comp_ext->flags, &flags, |
980 | sizeof(setup_comp_ext->flags)); | 1042 | sizeof(setup_comp_ext->flags)); |
981 | set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext, | 1043 | set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext, |
982 | sizeof(struct htc_setup_comp_ext_msg), | 1044 | sizeof(struct htc_setup_comp_ext_msg), |
983 | ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); | 1045 | ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); |
984 | 1046 | ||
985 | } else { | 1047 | } else { |
986 | struct htc_setup_comp_msg *setup_comp; | 1048 | struct htc_setup_comp_msg *setup_comp; |
@@ -988,8 +1050,8 @@ static int htc_setup_tx_complete(struct htc_target *target) | |||
988 | memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg)); | 1050 | memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg)); |
989 | setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID); | 1051 | setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID); |
990 | set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp, | 1052 | set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp, |
991 | sizeof(struct htc_setup_comp_msg), | 1053 | sizeof(struct htc_setup_comp_msg), |
992 | ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); | 1054 | ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); |
993 | } | 1055 | } |
994 | 1056 | ||
995 | /* we want synchronous operation */ | 1057 | /* we want synchronous operation */ |
@@ -1088,9 +1150,9 @@ void ath6kl_htc_flush_txep(struct htc_target *target, | |||
1088 | packet->status = -ECANCELED; | 1150 | packet->status = -ECANCELED; |
1089 | list_del(&packet->list); | 1151 | list_del(&packet->list); |
1090 | ath6kl_dbg(ATH6KL_DBG_HTC, | 1152 | ath6kl_dbg(ATH6KL_DBG_HTC, |
1091 | "htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n", | 1153 | "htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n", |
1092 | packet, packet->act_len, | 1154 | packet, packet->act_len, |
1093 | packet->endpoint, packet->info.tx.tag); | 1155 | packet->endpoint, packet->info.tx.tag); |
1094 | 1156 | ||
1095 | INIT_LIST_HEAD(&container); | 1157 | INIT_LIST_HEAD(&container); |
1096 | list_add_tail(&packet->list, &container); | 1158 | list_add_tail(&packet->list, &container); |
@@ -1490,7 +1552,7 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) | |||
1490 | 1552 | ||
1491 | if (packets->act_len > 0) { | 1553 | if (packets->act_len > 0) { |
1492 | ath6kl_err("htc_ctrl_rx, got message with len:%zu\n", | 1554 | ath6kl_err("htc_ctrl_rx, got message with len:%zu\n", |
1493 | packets->act_len + HTC_HDR_LENGTH); | 1555 | packets->act_len + HTC_HDR_LENGTH); |
1494 | 1556 | ||
1495 | ath6kl_dbg_dump(ATH6KL_DBG_HTC, | 1557 | ath6kl_dbg_dump(ATH6KL_DBG_HTC, |
1496 | "htc rx unexpected endpoint 0 message", "", | 1558 | "htc rx unexpected endpoint 0 message", "", |
@@ -1609,8 +1671,8 @@ static int htc_parse_trailer(struct htc_target *target, | |||
1609 | } | 1671 | } |
1610 | 1672 | ||
1611 | lk_ahd = (struct htc_lookahead_report *) record_buf; | 1673 | lk_ahd = (struct htc_lookahead_report *) record_buf; |
1612 | if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) | 1674 | if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) && |
1613 | && next_lk_ahds) { | 1675 | next_lk_ahds) { |
1614 | 1676 | ||
1615 | ath6kl_dbg(ATH6KL_DBG_HTC, | 1677 | ath6kl_dbg(ATH6KL_DBG_HTC, |
1616 | "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n", | 1678 | "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n", |
@@ -2038,13 +2100,13 @@ fail_rx: | |||
2038 | list_for_each_entry_safe(packet, tmp_pkt, rx_pktq, list) { | 2100 | list_for_each_entry_safe(packet, tmp_pkt, rx_pktq, list) { |
2039 | list_del(&packet->list); | 2101 | list_del(&packet->list); |
2040 | htc_reclaim_rxbuf(target, packet, | 2102 | htc_reclaim_rxbuf(target, packet, |
2041 | &target->endpoint[packet->endpoint]); | 2103 | &target->endpoint[packet->endpoint]); |
2042 | } | 2104 | } |
2043 | 2105 | ||
2044 | list_for_each_entry_safe(packet, tmp_pkt, &tmp_rxq, list) { | 2106 | list_for_each_entry_safe(packet, tmp_pkt, &tmp_rxq, list) { |
2045 | list_del(&packet->list); | 2107 | list_del(&packet->list); |
2046 | htc_reclaim_rxbuf(target, packet, | 2108 | htc_reclaim_rxbuf(target, packet, |
2047 | &target->endpoint[packet->endpoint]); | 2109 | &target->endpoint[packet->endpoint]); |
2048 | } | 2110 | } |
2049 | 2111 | ||
2050 | return status; | 2112 | return status; |
@@ -2176,11 +2238,11 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) | |||
2176 | u32 look_ahead; | 2238 | u32 look_ahead; |
2177 | 2239 | ||
2178 | if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead, | 2240 | if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead, |
2179 | HTC_TARGET_RESPONSE_TIMEOUT)) | 2241 | HTC_TARGET_RESPONSE_TIMEOUT)) |
2180 | return NULL; | 2242 | return NULL; |
2181 | 2243 | ||
2182 | ath6kl_dbg(ATH6KL_DBG_HTC, | 2244 | ath6kl_dbg(ATH6KL_DBG_HTC, |
2183 | "htc rx wait ctrl look_ahead 0x%X\n", look_ahead); | 2245 | "htc rx wait ctrl look_ahead 0x%X\n", look_ahead); |
2184 | 2246 | ||
2185 | htc_hdr = (struct htc_frame_hdr *)&look_ahead; | 2247 | htc_hdr = (struct htc_frame_hdr *)&look_ahead; |
2186 | 2248 | ||
@@ -2245,7 +2307,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, | |||
2245 | depth = get_queue_depth(pkt_queue); | 2307 | depth = get_queue_depth(pkt_queue); |
2246 | 2308 | ||
2247 | ath6kl_dbg(ATH6KL_DBG_HTC, | 2309 | ath6kl_dbg(ATH6KL_DBG_HTC, |
2248 | "htc rx add multiple ep id %d cnt %d len %d\n", | 2310 | "htc rx add multiple ep id %d cnt %d len %d\n", |
2249 | first_pkt->endpoint, depth, first_pkt->buf_len); | 2311 | first_pkt->endpoint, depth, first_pkt->buf_len); |
2250 | 2312 | ||
2251 | endpoint = &target->endpoint[first_pkt->endpoint]; | 2313 | endpoint = &target->endpoint[first_pkt->endpoint]; |
@@ -2271,8 +2333,8 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, | |||
2271 | if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { | 2333 | if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { |
2272 | if (target->ep_waiting == first_pkt->endpoint) { | 2334 | if (target->ep_waiting == first_pkt->endpoint) { |
2273 | ath6kl_dbg(ATH6KL_DBG_HTC, | 2335 | ath6kl_dbg(ATH6KL_DBG_HTC, |
2274 | "htc rx blocked on ep %d, unblocking\n", | 2336 | "htc rx blocked on ep %d, unblocking\n", |
2275 | target->ep_waiting); | 2337 | target->ep_waiting); |
2276 | target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS; | 2338 | target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS; |
2277 | target->ep_waiting = ENDPOINT_MAX; | 2339 | target->ep_waiting = ENDPOINT_MAX; |
2278 | rx_unblock = true; | 2340 | rx_unblock = true; |
@@ -2309,7 +2371,21 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target) | |||
2309 | "htc rx flush pkt 0x%p len %d ep %d\n", | 2371 | "htc rx flush pkt 0x%p len %d ep %d\n", |
2310 | packet, packet->buf_len, | 2372 | packet, packet->buf_len, |
2311 | packet->endpoint); | 2373 | packet->endpoint); |
2312 | dev_kfree_skb(packet->pkt_cntxt); | 2374 | /* |
2375 | * packets in rx_bufq of endpoint 0 have originally | ||
2376 | * been queued from target->free_ctrl_rxbuf where | ||
2377 | * packet and packet->buf_start are allocated | ||
2378 | * separately using kmalloc(). For other endpoint | ||
2379 | * rx_bufq, it is allocated as skb where packet is | ||
2380 | * skb->head. Take care of this difference while freeing | ||
2381 | * the memory. | ||
2382 | */ | ||
2383 | if (packet->endpoint == ENDPOINT_0) { | ||
2384 | kfree(packet->buf_start); | ||
2385 | kfree(packet); | ||
2386 | } else { | ||
2387 | dev_kfree_skb(packet->pkt_cntxt); | ||
2388 | } | ||
2313 | spin_lock_bh(&target->rx_lock); | 2389 | spin_lock_bh(&target->rx_lock); |
2314 | } | 2390 | } |
2315 | spin_unlock_bh(&target->rx_lock); | 2391 | spin_unlock_bh(&target->rx_lock); |
@@ -2328,6 +2404,7 @@ int ath6kl_htc_conn_service(struct htc_target *target, | |||
2328 | enum htc_endpoint_id assigned_ep = ENDPOINT_MAX; | 2404 | enum htc_endpoint_id assigned_ep = ENDPOINT_MAX; |
2329 | unsigned int max_msg_sz = 0; | 2405 | unsigned int max_msg_sz = 0; |
2330 | int status = 0; | 2406 | int status = 0; |
2407 | u16 msg_id; | ||
2331 | 2408 | ||
2332 | ath6kl_dbg(ATH6KL_DBG_HTC, | 2409 | ath6kl_dbg(ATH6KL_DBG_HTC, |
2333 | "htc connect service target 0x%p service id 0x%x\n", | 2410 | "htc connect service target 0x%p service id 0x%x\n", |
@@ -2371,9 +2448,10 @@ int ath6kl_htc_conn_service(struct htc_target *target, | |||
2371 | } | 2448 | } |
2372 | 2449 | ||
2373 | resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf; | 2450 | resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf; |
2451 | msg_id = le16_to_cpu(resp_msg->msg_id); | ||
2374 | 2452 | ||
2375 | if ((le16_to_cpu(resp_msg->msg_id) != HTC_MSG_CONN_SVC_RESP_ID) | 2453 | if ((msg_id != HTC_MSG_CONN_SVC_RESP_ID) || |
2376 | || (rx_pkt->act_len < sizeof(*resp_msg))) { | 2454 | (rx_pkt->act_len < sizeof(*resp_msg))) { |
2377 | status = -ENOMEM; | 2455 | status = -ENOMEM; |
2378 | goto fail_tx; | 2456 | goto fail_tx; |
2379 | } | 2457 | } |
@@ -2420,6 +2498,15 @@ int ath6kl_htc_conn_service(struct htc_target *target, | |||
2420 | endpoint->cred_dist.endpoint = assigned_ep; | 2498 | endpoint->cred_dist.endpoint = assigned_ep; |
2421 | endpoint->cred_dist.cred_sz = target->tgt_cred_sz; | 2499 | endpoint->cred_dist.cred_sz = target->tgt_cred_sz; |
2422 | 2500 | ||
2501 | switch (endpoint->svc_id) { | ||
2502 | case WMI_DATA_BK_SVC: | ||
2503 | endpoint->tx_drop_packet_threshold = MAX_DEF_COOKIE_NUM / 3; | ||
2504 | break; | ||
2505 | default: | ||
2506 | endpoint->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM; | ||
2507 | break; | ||
2508 | } | ||
2509 | |||
2423 | if (conn_req->max_rxmsg_sz) { | 2510 | if (conn_req->max_rxmsg_sz) { |
2424 | /* | 2511 | /* |
2425 | * Override cred_per_msg calculation, this optimizes | 2512 | * Override cred_per_msg calculation, this optimizes |
@@ -2517,7 +2604,8 @@ static void htc_setup_msg_bndl(struct htc_target *target) | |||
2517 | target->max_rx_bndl_sz, target->max_tx_bndl_sz); | 2604 | target->max_rx_bndl_sz, target->max_tx_bndl_sz); |
2518 | 2605 | ||
2519 | if (target->max_tx_bndl_sz) | 2606 | if (target->max_tx_bndl_sz) |
2520 | target->tx_bndl_enable = true; | 2607 | /* tx_bndl_mask is enabled per AC, each has 1 bit */ |
2608 | target->tx_bndl_mask = (1 << WMM_NUM_AC) - 1; | ||
2521 | 2609 | ||
2522 | if (target->max_rx_bndl_sz) | 2610 | if (target->max_rx_bndl_sz) |
2523 | target->rx_bndl_enable = true; | 2611 | target->rx_bndl_enable = true; |
@@ -2532,7 +2620,7 @@ static void htc_setup_msg_bndl(struct htc_target *target) | |||
2532 | * padding will spill into the next credit buffer | 2620 | * padding will spill into the next credit buffer |
2533 | * which is fatal. | 2621 | * which is fatal. |
2534 | */ | 2622 | */ |
2535 | target->tx_bndl_enable = false; | 2623 | target->tx_bndl_mask = 0; |
2536 | } | 2624 | } |
2537 | } | 2625 | } |
2538 | 2626 | ||
@@ -2589,8 +2677,8 @@ int ath6kl_htc_wait_target(struct htc_target *target) | |||
2589 | } | 2677 | } |
2590 | 2678 | ||
2591 | ath6kl_dbg(ATH6KL_DBG_BOOT, "htc using protocol %s (%d)\n", | 2679 | ath6kl_dbg(ATH6KL_DBG_BOOT, "htc using protocol %s (%d)\n", |
2592 | (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", | 2680 | (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", |
2593 | target->htc_tgt_ver); | 2681 | target->htc_tgt_ver); |
2594 | 2682 | ||
2595 | if (target->msg_per_bndl_max > 0) | 2683 | if (target->msg_per_bndl_max > 0) |
2596 | htc_setup_msg_bndl(target); | 2684 | htc_setup_msg_bndl(target); |
@@ -2784,14 +2872,14 @@ void ath6kl_htc_cleanup(struct htc_target *target) | |||
2784 | ath6kl_hif_cleanup_scatter(target->dev->ar); | 2872 | ath6kl_hif_cleanup_scatter(target->dev->ar); |
2785 | 2873 | ||
2786 | list_for_each_entry_safe(packet, tmp_packet, | 2874 | list_for_each_entry_safe(packet, tmp_packet, |
2787 | &target->free_ctrl_txbuf, list) { | 2875 | &target->free_ctrl_txbuf, list) { |
2788 | list_del(&packet->list); | 2876 | list_del(&packet->list); |
2789 | kfree(packet->buf_start); | 2877 | kfree(packet->buf_start); |
2790 | kfree(packet); | 2878 | kfree(packet); |
2791 | } | 2879 | } |
2792 | 2880 | ||
2793 | list_for_each_entry_safe(packet, tmp_packet, | 2881 | list_for_each_entry_safe(packet, tmp_packet, |
2794 | &target->free_ctrl_rxbuf, list) { | 2882 | &target->free_ctrl_rxbuf, list) { |
2795 | list_del(&packet->list); | 2883 | list_del(&packet->list); |
2796 | kfree(packet->buf_start); | 2884 | kfree(packet->buf_start); |
2797 | kfree(packet); | 2885 | kfree(packet); |
diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 57672e1ed1a6..5027ccc36b62 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -87,6 +88,8 @@ | |||
87 | #define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4) | 88 | #define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4) |
88 | #define WMI_MAX_SERVICES 5 | 89 | #define WMI_MAX_SERVICES 5 |
89 | 90 | ||
91 | #define WMM_NUM_AC 4 | ||
92 | |||
90 | /* reserved and used to flush ALL packets */ | 93 | /* reserved and used to flush ALL packets */ |
91 | #define HTC_TX_PACKET_TAG_ALL 0 | 94 | #define HTC_TX_PACKET_TAG_ALL 0 |
92 | #define HTC_SERVICE_TX_PACKET_TAG 1 | 95 | #define HTC_SERVICE_TX_PACKET_TAG 1 |
@@ -498,6 +501,7 @@ struct htc_endpoint { | |||
498 | u8 seqno; | 501 | u8 seqno; |
499 | u32 conn_flags; | 502 | u32 conn_flags; |
500 | struct htc_endpoint_stats ep_st; | 503 | struct htc_endpoint_stats ep_st; |
504 | u16 tx_drop_packet_threshold; | ||
501 | }; | 505 | }; |
502 | 506 | ||
503 | struct htc_control_buffer { | 507 | struct htc_control_buffer { |
@@ -519,9 +523,16 @@ struct htc_target { | |||
519 | struct ath6kl_htc_credit_info *credit_info; | 523 | struct ath6kl_htc_credit_info *credit_info; |
520 | int tgt_creds; | 524 | int tgt_creds; |
521 | unsigned int tgt_cred_sz; | 525 | unsigned int tgt_cred_sz; |
526 | |||
527 | /* protects free_ctrl_txbuf and free_ctrl_rxbuf */ | ||
522 | spinlock_t htc_lock; | 528 | spinlock_t htc_lock; |
529 | |||
530 | /* FIXME: does this protext rx_bufq and endpoint structures or what? */ | ||
523 | spinlock_t rx_lock; | 531 | spinlock_t rx_lock; |
532 | |||
533 | /* protects endpoint->txq */ | ||
524 | spinlock_t tx_lock; | 534 | spinlock_t tx_lock; |
535 | |||
525 | struct ath6kl_device *dev; | 536 | struct ath6kl_device *dev; |
526 | u32 htc_flags; | 537 | u32 htc_flags; |
527 | u32 rx_st_flags; | 538 | u32 rx_st_flags; |
@@ -531,7 +542,7 @@ struct htc_target { | |||
531 | /* max messages per bundle for HTC */ | 542 | /* max messages per bundle for HTC */ |
532 | int msg_per_bndl_max; | 543 | int msg_per_bndl_max; |
533 | 544 | ||
534 | bool tx_bndl_enable; | 545 | u32 tx_bndl_mask; |
535 | int rx_bndl_enable; | 546 | int rx_bndl_enable; |
536 | int max_rx_bndl_sz; | 547 | int max_rx_bndl_sz; |
537 | int max_tx_bndl_sz; | 548 | int max_tx_bndl_sz; |
@@ -543,6 +554,9 @@ struct htc_target { | |||
543 | int max_xfer_szper_scatreq; | 554 | int max_xfer_szper_scatreq; |
544 | 555 | ||
545 | int chk_irq_status_cnt; | 556 | int chk_irq_status_cnt; |
557 | |||
558 | /* counts the number of Tx without bundling continously per AC */ | ||
559 | u32 ac_tx_count[WMM_NUM_AC]; | ||
546 | }; | 560 | }; |
547 | 561 | ||
548 | void *ath6kl_htc_create(struct ath6kl *ar); | 562 | void *ath6kl_htc_create(struct ath6kl *ar); |
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 0d76c3778106..03cae142f178 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c | |||
@@ -1,6 +1,7 @@ | |||
1 | 1 | ||
2 | /* | 2 | /* |
3 | * Copyright (c) 2011 Atheros Communications Inc. | 3 | * Copyright (c) 2011 Atheros Communications Inc. |
4 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
4 | * | 5 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any | 6 | * Permission to use, copy, modify, and/or distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
@@ -74,7 +75,7 @@ static const struct ath6kl_hw hw_list[] = { | |||
74 | }, | 75 | }, |
75 | 76 | ||
76 | .fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE, | 77 | .fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE, |
77 | .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, | 78 | .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, |
78 | }, | 79 | }, |
79 | { | 80 | { |
80 | .id = AR6004_HW_1_0_VERSION, | 81 | .id = AR6004_HW_1_0_VERSION, |
@@ -351,11 +352,7 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, | |||
351 | blk_size |= ((u32)htc_ctrl_buf) << 16; | 352 | blk_size |= ((u32)htc_ctrl_buf) << 16; |
352 | 353 | ||
353 | /* set the host interest area for the block size */ | 354 | /* set the host interest area for the block size */ |
354 | status = ath6kl_bmi_write(ar, | 355 | status = ath6kl_bmi_write_hi32(ar, hi_mbox_io_block_sz, blk_size); |
355 | ath6kl_get_hi_item_addr(ar, | ||
356 | HI_ITEM(hi_mbox_io_block_sz)), | ||
357 | (u8 *)&blk_size, | ||
358 | 4); | ||
359 | if (status) { | 356 | if (status) { |
360 | ath6kl_err("bmi_write_memory for IO block size failed\n"); | 357 | ath6kl_err("bmi_write_memory for IO block size failed\n"); |
361 | goto out; | 358 | goto out; |
@@ -367,11 +364,8 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, | |||
367 | 364 | ||
368 | if (mbox_isr_yield_val) { | 365 | if (mbox_isr_yield_val) { |
369 | /* set the host interest area for the mbox ISR yield limit */ | 366 | /* set the host interest area for the mbox ISR yield limit */ |
370 | status = ath6kl_bmi_write(ar, | 367 | status = ath6kl_bmi_write_hi32(ar, hi_mbox_isr_yield_limit, |
371 | ath6kl_get_hi_item_addr(ar, | 368 | mbox_isr_yield_val); |
372 | HI_ITEM(hi_mbox_isr_yield_limit)), | ||
373 | (u8 *)&mbox_isr_yield_val, | ||
374 | 4); | ||
375 | if (status) { | 369 | if (status) { |
376 | ath6kl_err("bmi_write_memory for yield limit failed\n"); | 370 | ath6kl_err("bmi_write_memory for yield limit failed\n"); |
377 | goto out; | 371 | goto out; |
@@ -384,7 +378,6 @@ out: | |||
384 | 378 | ||
385 | static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) | 379 | static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) |
386 | { | 380 | { |
387 | int status = 0; | ||
388 | int ret; | 381 | int ret; |
389 | 382 | ||
390 | /* | 383 | /* |
@@ -392,43 +385,54 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) | |||
392 | * default values. Required if checksum offload is needed. Set | 385 | * default values. Required if checksum offload is needed. Set |
393 | * RxMetaVersion to 2. | 386 | * RxMetaVersion to 2. |
394 | */ | 387 | */ |
395 | if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx, | 388 | ret = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx, |
396 | ar->rx_meta_ver, 0, 0)) { | 389 | ar->rx_meta_ver, 0, 0); |
397 | ath6kl_err("unable to set the rx frame format\n"); | 390 | if (ret) { |
398 | status = -EIO; | 391 | ath6kl_err("unable to set the rx frame format: %d\n", ret); |
392 | return ret; | ||
399 | } | 393 | } |
400 | 394 | ||
401 | if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) | 395 | if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) { |
402 | if ((ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1, | 396 | ret = ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1, |
403 | IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) { | 397 | IGNORE_PS_FAIL_DURING_SCAN); |
404 | ath6kl_err("unable to set power save fail event policy\n"); | 398 | if (ret) { |
405 | status = -EIO; | 399 | ath6kl_err("unable to set power save fail event policy: %d\n", |
400 | ret); | ||
401 | return ret; | ||
406 | } | 402 | } |
403 | } | ||
407 | 404 | ||
408 | if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) | 405 | if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) { |
409 | if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0, | 406 | ret = ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0, |
410 | WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) { | 407 | WMI_FOLLOW_BARKER_IN_ERP); |
411 | ath6kl_err("unable to set barker preamble policy\n"); | 408 | if (ret) { |
412 | status = -EIO; | 409 | ath6kl_err("unable to set barker preamble policy: %d\n", |
410 | ret); | ||
411 | return ret; | ||
413 | } | 412 | } |
413 | } | ||
414 | 414 | ||
415 | if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx, | 415 | ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx, |
416 | WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) { | 416 | WLAN_CONFIG_KEEP_ALIVE_INTERVAL); |
417 | ath6kl_err("unable to set keep alive interval\n"); | 417 | if (ret) { |
418 | status = -EIO; | 418 | ath6kl_err("unable to set keep alive interval: %d\n", ret); |
419 | return ret; | ||
419 | } | 420 | } |
420 | 421 | ||
421 | if (ath6kl_wmi_disctimeout_cmd(ar->wmi, idx, | 422 | ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, idx, |
422 | WLAN_CONFIG_DISCONNECT_TIMEOUT)) { | 423 | WLAN_CONFIG_DISCONNECT_TIMEOUT); |
423 | ath6kl_err("unable to set disconnect timeout\n"); | 424 | if (ret) { |
424 | status = -EIO; | 425 | ath6kl_err("unable to set disconnect timeout: %d\n", ret); |
426 | return ret; | ||
425 | } | 427 | } |
426 | 428 | ||
427 | if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) | 429 | if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) { |
428 | if (ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED)) { | 430 | ret = ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED); |
429 | ath6kl_err("unable to set txop bursting\n"); | 431 | if (ret) { |
430 | status = -EIO; | 432 | ath6kl_err("unable to set txop bursting: %d\n", ret); |
433 | return ret; | ||
431 | } | 434 | } |
435 | } | ||
432 | 436 | ||
433 | if (ar->p2p && (ar->vif_max == 1 || idx)) { | 437 | if (ar->p2p && (ar->vif_max == 1 || idx)) { |
434 | ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx, | 438 | ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx, |
@@ -452,7 +456,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) | |||
452 | } | 456 | } |
453 | } | 457 | } |
454 | 458 | ||
455 | return status; | 459 | return ret; |
456 | } | 460 | } |
457 | 461 | ||
458 | int ath6kl_configure_target(struct ath6kl *ar) | 462 | int ath6kl_configure_target(struct ath6kl *ar) |
@@ -462,8 +466,7 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
462 | int i, status; | 466 | int i, status; |
463 | 467 | ||
464 | param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG); | 468 | param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG); |
465 | if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, | 469 | if (ath6kl_bmi_write_hi32(ar, hi_serial_enable, param)) { |
466 | HI_ITEM(hi_serial_enable)), (u8 *)¶m, 4)) { | ||
467 | ath6kl_err("bmi_write_memory for uart debug failed\n"); | 470 | ath6kl_err("bmi_write_memory for uart debug failed\n"); |
468 | return -EIO; | 471 | return -EIO; |
469 | } | 472 | } |
@@ -499,11 +502,8 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
499 | if (ar->p2p && ar->vif_max == 1) | 502 | if (ar->p2p && ar->vif_max == 1) |
500 | fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; | 503 | fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; |
501 | 504 | ||
502 | param = HTC_PROTOCOL_VERSION; | 505 | if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest, |
503 | if (ath6kl_bmi_write(ar, | 506 | HTC_PROTOCOL_VERSION) != 0) { |
504 | ath6kl_get_hi_item_addr(ar, | ||
505 | HI_ITEM(hi_app_host_interest)), | ||
506 | (u8 *)¶m, 4) != 0) { | ||
507 | ath6kl_err("bmi_write_memory for htc version failed\n"); | 507 | ath6kl_err("bmi_write_memory for htc version failed\n"); |
508 | return -EIO; | 508 | return -EIO; |
509 | } | 509 | } |
@@ -511,10 +511,7 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
511 | /* set the firmware mode to STA/IBSS/AP */ | 511 | /* set the firmware mode to STA/IBSS/AP */ |
512 | param = 0; | 512 | param = 0; |
513 | 513 | ||
514 | if (ath6kl_bmi_read(ar, | 514 | if (ath6kl_bmi_read_hi32(ar, hi_option_flag, ¶m) != 0) { |
515 | ath6kl_get_hi_item_addr(ar, | ||
516 | HI_ITEM(hi_option_flag)), | ||
517 | (u8 *)¶m, 4) != 0) { | ||
518 | ath6kl_err("bmi_read_memory for setting fwmode failed\n"); | 515 | ath6kl_err("bmi_read_memory for setting fwmode failed\n"); |
519 | return -EIO; | 516 | return -EIO; |
520 | } | 517 | } |
@@ -526,11 +523,7 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
526 | param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); | 523 | param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); |
527 | param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); | 524 | param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); |
528 | 525 | ||
529 | if (ath6kl_bmi_write(ar, | 526 | if (ath6kl_bmi_write_hi32(ar, hi_option_flag, param) != 0) { |
530 | ath6kl_get_hi_item_addr(ar, | ||
531 | HI_ITEM(hi_option_flag)), | ||
532 | (u8 *)¶m, | ||
533 | 4) != 0) { | ||
534 | ath6kl_err("bmi_write_memory for setting fwmode failed\n"); | 527 | ath6kl_err("bmi_write_memory for setting fwmode failed\n"); |
535 | return -EIO; | 528 | return -EIO; |
536 | } | 529 | } |
@@ -549,16 +542,13 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
549 | param = ar->hw.board_ext_data_addr; | 542 | param = ar->hw.board_ext_data_addr; |
550 | ram_reserved_size = ar->hw.reserved_ram_size; | 543 | ram_reserved_size = ar->hw.reserved_ram_size; |
551 | 544 | ||
552 | if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, | 545 | if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) { |
553 | HI_ITEM(hi_board_ext_data)), | ||
554 | (u8 *)¶m, 4) != 0) { | ||
555 | ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); | 546 | ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); |
556 | return -EIO; | 547 | return -EIO; |
557 | } | 548 | } |
558 | 549 | ||
559 | if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, | 550 | if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, |
560 | HI_ITEM(hi_end_ram_reserve_sz)), | 551 | ram_reserved_size) != 0) { |
561 | (u8 *)&ram_reserved_size, 4) != 0) { | ||
562 | ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); | 552 | ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); |
563 | return -EIO; | 553 | return -EIO; |
564 | } | 554 | } |
@@ -569,20 +559,13 @@ int ath6kl_configure_target(struct ath6kl *ar) | |||
569 | return -EIO; | 559 | return -EIO; |
570 | 560 | ||
571 | /* Configure GPIO AR600x UART */ | 561 | /* Configure GPIO AR600x UART */ |
572 | param = ar->hw.uarttx_pin; | 562 | status = ath6kl_bmi_write_hi32(ar, hi_dbg_uart_txpin, |
573 | status = ath6kl_bmi_write(ar, | 563 | ar->hw.uarttx_pin); |
574 | ath6kl_get_hi_item_addr(ar, | ||
575 | HI_ITEM(hi_dbg_uart_txpin)), | ||
576 | (u8 *)¶m, 4); | ||
577 | if (status) | 564 | if (status) |
578 | return status; | 565 | return status; |
579 | 566 | ||
580 | /* Configure target refclk_hz */ | 567 | /* Configure target refclk_hz */ |
581 | param = ar->hw.refclk_hz; | 568 | status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, ar->hw.refclk_hz); |
582 | status = ath6kl_bmi_write(ar, | ||
583 | ath6kl_get_hi_item_addr(ar, | ||
584 | HI_ITEM(hi_refclk_hz)), | ||
585 | (u8 *)¶m, 4); | ||
586 | if (status) | 569 | if (status) |
587 | return status; | 570 | return status; |
588 | 571 | ||
@@ -832,13 +815,13 @@ static int ath6kl_fetch_testscript_file(struct ath6kl *ar) | |||
832 | return 0; | 815 | return 0; |
833 | 816 | ||
834 | snprintf(filename, sizeof(filename), "%s/%s", | 817 | snprintf(filename, sizeof(filename), "%s/%s", |
835 | ar->hw.fw.dir, ar->hw.fw.testscript); | 818 | ar->hw.fw.dir, ar->hw.fw.testscript); |
836 | 819 | ||
837 | ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript, | 820 | ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript, |
838 | &ar->fw_testscript_len); | 821 | &ar->fw_testscript_len); |
839 | if (ret) { | 822 | if (ret) { |
840 | ath6kl_err("Failed to get testscript file %s: %d\n", | 823 | ath6kl_err("Failed to get testscript file %s: %d\n", |
841 | filename, ret); | 824 | filename, ret); |
842 | return ret; | 825 | return ret; |
843 | } | 826 | } |
844 | 827 | ||
@@ -922,7 +905,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) | |||
922 | switch (ie_id) { | 905 | switch (ie_id) { |
923 | case ATH6KL_FW_IE_OTP_IMAGE: | 906 | case ATH6KL_FW_IE_OTP_IMAGE: |
924 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", | 907 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", |
925 | ie_len); | 908 | ie_len); |
926 | 909 | ||
927 | ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); | 910 | ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); |
928 | 911 | ||
@@ -935,7 +918,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) | |||
935 | break; | 918 | break; |
936 | case ATH6KL_FW_IE_FW_IMAGE: | 919 | case ATH6KL_FW_IE_FW_IMAGE: |
937 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", | 920 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", |
938 | ie_len); | 921 | ie_len); |
939 | 922 | ||
940 | /* in testmode we already might have a fw file */ | 923 | /* in testmode we already might have a fw file */ |
941 | if (ar->fw != NULL) | 924 | if (ar->fw != NULL) |
@@ -952,7 +935,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) | |||
952 | break; | 935 | break; |
953 | case ATH6KL_FW_IE_PATCH_IMAGE: | 936 | case ATH6KL_FW_IE_PATCH_IMAGE: |
954 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n", | 937 | ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n", |
955 | ie_len); | 938 | ie_len); |
956 | 939 | ||
957 | ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); | 940 | ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); |
958 | 941 | ||
@@ -1096,22 +1079,14 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
1096 | */ | 1079 | */ |
1097 | if (ar->hw.board_addr != 0) { | 1080 | if (ar->hw.board_addr != 0) { |
1098 | board_address = ar->hw.board_addr; | 1081 | board_address = ar->hw.board_addr; |
1099 | ath6kl_bmi_write(ar, | 1082 | ath6kl_bmi_write_hi32(ar, hi_board_data, |
1100 | ath6kl_get_hi_item_addr(ar, | 1083 | board_address); |
1101 | HI_ITEM(hi_board_data)), | ||
1102 | (u8 *) &board_address, 4); | ||
1103 | } else { | 1084 | } else { |
1104 | ath6kl_bmi_read(ar, | 1085 | ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address); |
1105 | ath6kl_get_hi_item_addr(ar, | ||
1106 | HI_ITEM(hi_board_data)), | ||
1107 | (u8 *) &board_address, 4); | ||
1108 | } | 1086 | } |
1109 | 1087 | ||
1110 | /* determine where in target ram to write extended board data */ | 1088 | /* determine where in target ram to write extended board data */ |
1111 | ath6kl_bmi_read(ar, | 1089 | ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address); |
1112 | ath6kl_get_hi_item_addr(ar, | ||
1113 | HI_ITEM(hi_board_ext_data)), | ||
1114 | (u8 *) &board_ext_address, 4); | ||
1115 | 1090 | ||
1116 | if (ar->target_type == TARGET_TYPE_AR6003 && | 1091 | if (ar->target_type == TARGET_TYPE_AR6003 && |
1117 | board_ext_address == 0) { | 1092 | board_ext_address == 0) { |
@@ -1123,6 +1098,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
1123 | case TARGET_TYPE_AR6003: | 1098 | case TARGET_TYPE_AR6003: |
1124 | board_data_size = AR6003_BOARD_DATA_SZ; | 1099 | board_data_size = AR6003_BOARD_DATA_SZ; |
1125 | board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ; | 1100 | board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ; |
1101 | if (ar->fw_board_len > (board_data_size + board_ext_data_size)) | ||
1102 | board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ_V2; | ||
1126 | break; | 1103 | break; |
1127 | case TARGET_TYPE_AR6004: | 1104 | case TARGET_TYPE_AR6004: |
1128 | board_data_size = AR6004_BOARD_DATA_SZ; | 1105 | board_data_size = AR6004_BOARD_DATA_SZ; |
@@ -1154,10 +1131,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
1154 | /* record that extended board data is initialized */ | 1131 | /* record that extended board data is initialized */ |
1155 | param = (board_ext_data_size << 16) | 1; | 1132 | param = (board_ext_data_size << 16) | 1; |
1156 | 1133 | ||
1157 | ath6kl_bmi_write(ar, | 1134 | ath6kl_bmi_write_hi32(ar, hi_board_ext_data_config, param); |
1158 | ath6kl_get_hi_item_addr(ar, | ||
1159 | HI_ITEM(hi_board_ext_data_config)), | ||
1160 | (unsigned char *) ¶m, 4); | ||
1161 | } | 1135 | } |
1162 | 1136 | ||
1163 | if (ar->fw_board_len < board_data_size) { | 1137 | if (ar->fw_board_len < board_data_size) { |
@@ -1178,11 +1152,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) | |||
1178 | } | 1152 | } |
1179 | 1153 | ||
1180 | /* record the fact that Board Data IS initialized */ | 1154 | /* record the fact that Board Data IS initialized */ |
1181 | param = 1; | 1155 | ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, 1); |
1182 | ath6kl_bmi_write(ar, | ||
1183 | ath6kl_get_hi_item_addr(ar, | ||
1184 | HI_ITEM(hi_board_data_initialized)), | ||
1185 | (u8 *)¶m, 4); | ||
1186 | 1156 | ||
1187 | return ret; | 1157 | return ret; |
1188 | } | 1158 | } |
@@ -1209,10 +1179,7 @@ static int ath6kl_upload_otp(struct ath6kl *ar) | |||
1209 | } | 1179 | } |
1210 | 1180 | ||
1211 | /* read firmware start address */ | 1181 | /* read firmware start address */ |
1212 | ret = ath6kl_bmi_read(ar, | 1182 | ret = ath6kl_bmi_read_hi32(ar, hi_app_start, &address); |
1213 | ath6kl_get_hi_item_addr(ar, | ||
1214 | HI_ITEM(hi_app_start)), | ||
1215 | (u8 *) &address, sizeof(address)); | ||
1216 | 1183 | ||
1217 | if (ret) { | 1184 | if (ret) { |
1218 | ath6kl_err("Failed to read hi_app_start: %d\n", ret); | 1185 | ath6kl_err("Failed to read hi_app_start: %d\n", ret); |
@@ -1270,7 +1237,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar) | |||
1270 | 1237 | ||
1271 | static int ath6kl_upload_patch(struct ath6kl *ar) | 1238 | static int ath6kl_upload_patch(struct ath6kl *ar) |
1272 | { | 1239 | { |
1273 | u32 address, param; | 1240 | u32 address; |
1274 | int ret; | 1241 | int ret; |
1275 | 1242 | ||
1276 | if (ar->fw_patch == NULL) | 1243 | if (ar->fw_patch == NULL) |
@@ -1287,18 +1254,14 @@ static int ath6kl_upload_patch(struct ath6kl *ar) | |||
1287 | return ret; | 1254 | return ret; |
1288 | } | 1255 | } |
1289 | 1256 | ||
1290 | param = address; | 1257 | ath6kl_bmi_write_hi32(ar, hi_dset_list_head, address); |
1291 | ath6kl_bmi_write(ar, | ||
1292 | ath6kl_get_hi_item_addr(ar, | ||
1293 | HI_ITEM(hi_dset_list_head)), | ||
1294 | (unsigned char *) ¶m, 4); | ||
1295 | 1258 | ||
1296 | return 0; | 1259 | return 0; |
1297 | } | 1260 | } |
1298 | 1261 | ||
1299 | static int ath6kl_upload_testscript(struct ath6kl *ar) | 1262 | static int ath6kl_upload_testscript(struct ath6kl *ar) |
1300 | { | 1263 | { |
1301 | u32 address, param; | 1264 | u32 address; |
1302 | int ret; | 1265 | int ret; |
1303 | 1266 | ||
1304 | if (ar->testmode != 2) | 1267 | if (ar->testmode != 2) |
@@ -1310,7 +1273,7 @@ static int ath6kl_upload_testscript(struct ath6kl *ar) | |||
1310 | address = ar->hw.testscript_addr; | 1273 | address = ar->hw.testscript_addr; |
1311 | 1274 | ||
1312 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n", | 1275 | ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n", |
1313 | address, ar->fw_testscript_len); | 1276 | address, ar->fw_testscript_len); |
1314 | 1277 | ||
1315 | ret = ath6kl_bmi_write(ar, address, ar->fw_testscript, | 1278 | ret = ath6kl_bmi_write(ar, address, ar->fw_testscript, |
1316 | ar->fw_testscript_len); | 1279 | ar->fw_testscript_len); |
@@ -1319,23 +1282,9 @@ static int ath6kl_upload_testscript(struct ath6kl *ar) | |||
1319 | return ret; | 1282 | return ret; |
1320 | } | 1283 | } |
1321 | 1284 | ||
1322 | param = address; | 1285 | ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address); |
1323 | ath6kl_bmi_write(ar, | 1286 | ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096); |
1324 | ath6kl_get_hi_item_addr(ar, | 1287 | ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1); |
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 | 1288 | ||
1340 | return 0; | 1289 | return 0; |
1341 | } | 1290 | } |
@@ -1346,7 +1295,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
1346 | int status = 0; | 1295 | int status = 0; |
1347 | 1296 | ||
1348 | if (ar->target_type != TARGET_TYPE_AR6003 && | 1297 | if (ar->target_type != TARGET_TYPE_AR6003 && |
1349 | ar->target_type != TARGET_TYPE_AR6004) | 1298 | ar->target_type != TARGET_TYPE_AR6004) |
1350 | return -EINVAL; | 1299 | return -EINVAL; |
1351 | 1300 | ||
1352 | /* temporarily disable system sleep */ | 1301 | /* temporarily disable system sleep */ |
@@ -1403,7 +1352,8 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
1403 | return status; | 1352 | return status; |
1404 | 1353 | ||
1405 | /* WAR to avoid SDIO CRC err */ | 1354 | /* WAR to avoid SDIO CRC err */ |
1406 | if (ar->version.target_ver == AR6003_HW_2_0_VERSION) { | 1355 | if (ar->version.target_ver == AR6003_HW_2_0_VERSION || |
1356 | ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { | ||
1407 | ath6kl_err("temporary war to avoid sdio crc error\n"); | 1357 | ath6kl_err("temporary war to avoid sdio crc error\n"); |
1408 | 1358 | ||
1409 | param = 0x20; | 1359 | param = 0x20; |
@@ -1726,9 +1676,11 @@ void ath6kl_stop_txrx(struct ath6kl *ar) | |||
1726 | * configure NOT to reset the target during a debug session. | 1676 | * configure NOT to reset the target during a debug session. |
1727 | */ | 1677 | */ |
1728 | ath6kl_dbg(ATH6KL_DBG_TRC, | 1678 | ath6kl_dbg(ATH6KL_DBG_TRC, |
1729 | "attempting to reset target on instance destroy\n"); | 1679 | "attempting to reset target on instance destroy\n"); |
1730 | ath6kl_reset_device(ar, ar->target_type, true, true); | 1680 | ath6kl_reset_device(ar, ar->target_type, true, true); |
1731 | 1681 | ||
1732 | clear_bit(WLAN_ENABLED, &ar->flag); | 1682 | clear_bit(WLAN_ENABLED, &ar->flag); |
1683 | |||
1684 | up(&ar->sem); | ||
1733 | } | 1685 | } |
1734 | EXPORT_SYMBOL(ath6kl_stop_txrx); | 1686 | EXPORT_SYMBOL(ath6kl_stop_txrx); |
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index b96d01a7919b..229e1922ebe4 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -80,11 +81,21 @@ static void ath6kl_add_new_sta(struct ath6kl_vif *vif, u8 *mac, u16 aid, | |||
80 | static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) | 81 | static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) |
81 | { | 82 | { |
82 | struct ath6kl_sta *sta = &ar->sta_list[i]; | 83 | struct ath6kl_sta *sta = &ar->sta_list[i]; |
84 | struct ath6kl_mgmt_buff *entry, *tmp; | ||
83 | 85 | ||
84 | /* empty the queued pkts in the PS queue if any */ | 86 | /* empty the queued pkts in the PS queue if any */ |
85 | spin_lock_bh(&sta->psq_lock); | 87 | spin_lock_bh(&sta->psq_lock); |
86 | skb_queue_purge(&sta->psq); | 88 | skb_queue_purge(&sta->psq); |
87 | skb_queue_purge(&sta->apsdq); | 89 | skb_queue_purge(&sta->apsdq); |
90 | |||
91 | if (sta->mgmt_psq_len != 0) { | ||
92 | list_for_each_entry_safe(entry, tmp, &sta->mgmt_psq, list) { | ||
93 | kfree(entry); | ||
94 | } | ||
95 | INIT_LIST_HEAD(&sta->mgmt_psq); | ||
96 | sta->mgmt_psq_len = 0; | ||
97 | } | ||
98 | |||
88 | spin_unlock_bh(&sta->psq_lock); | 99 | spin_unlock_bh(&sta->psq_lock); |
89 | 100 | ||
90 | memset(&ar->ap_stats.sta[sta->aid - 1], 0, | 101 | memset(&ar->ap_stats.sta[sta->aid - 1], 0, |
@@ -339,7 +350,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, | |||
339 | __le32 data; | 350 | __le32 data; |
340 | 351 | ||
341 | if (target_type != TARGET_TYPE_AR6003 && | 352 | if (target_type != TARGET_TYPE_AR6003 && |
342 | target_type != TARGET_TYPE_AR6004) | 353 | target_type != TARGET_TYPE_AR6004) |
343 | return; | 354 | return; |
344 | 355 | ||
345 | data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) : | 356 | data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) : |
@@ -588,11 +599,9 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, | |||
588 | memcpy(vif->bssid, bssid, sizeof(vif->bssid)); | 599 | memcpy(vif->bssid, bssid, sizeof(vif->bssid)); |
589 | vif->bss_ch = channel; | 600 | vif->bss_ch = channel; |
590 | 601 | ||
591 | if ((vif->nw_type == INFRA_NETWORK)) { | 602 | if ((vif->nw_type == INFRA_NETWORK)) |
592 | ar->listen_intvl_b = listen_int; | ||
593 | ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, | 603 | ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, |
594 | 0, ar->listen_intvl_b); | 604 | vif->listen_intvl_t, 0); |
595 | } | ||
596 | 605 | ||
597 | netif_wake_queue(vif->ndev); | 606 | netif_wake_queue(vif->ndev); |
598 | 607 | ||
@@ -810,6 +819,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) | |||
810 | struct sk_buff *skb; | 819 | struct sk_buff *skb; |
811 | bool psq_empty = false; | 820 | bool psq_empty = false; |
812 | struct ath6kl *ar = vif->ar; | 821 | struct ath6kl *ar = vif->ar; |
822 | struct ath6kl_mgmt_buff *mgmt_buf; | ||
813 | 823 | ||
814 | conn = ath6kl_find_sta_by_aid(ar, aid); | 824 | conn = ath6kl_find_sta_by_aid(ar, aid); |
815 | 825 | ||
@@ -820,7 +830,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) | |||
820 | * becomes empty update the PVB for this station. | 830 | * becomes empty update the PVB for this station. |
821 | */ | 831 | */ |
822 | spin_lock_bh(&conn->psq_lock); | 832 | spin_lock_bh(&conn->psq_lock); |
823 | psq_empty = skb_queue_empty(&conn->psq); | 833 | psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); |
824 | spin_unlock_bh(&conn->psq_lock); | 834 | spin_unlock_bh(&conn->psq_lock); |
825 | 835 | ||
826 | if (psq_empty) | 836 | if (psq_empty) |
@@ -828,15 +838,31 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) | |||
828 | return; | 838 | return; |
829 | 839 | ||
830 | spin_lock_bh(&conn->psq_lock); | 840 | spin_lock_bh(&conn->psq_lock); |
831 | skb = skb_dequeue(&conn->psq); | 841 | if (conn->mgmt_psq_len > 0) { |
832 | spin_unlock_bh(&conn->psq_lock); | 842 | mgmt_buf = list_first_entry(&conn->mgmt_psq, |
843 | struct ath6kl_mgmt_buff, list); | ||
844 | list_del(&mgmt_buf->list); | ||
845 | conn->mgmt_psq_len--; | ||
846 | spin_unlock_bh(&conn->psq_lock); | ||
847 | |||
848 | conn->sta_flags |= STA_PS_POLLED; | ||
849 | ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, | ||
850 | mgmt_buf->id, mgmt_buf->freq, | ||
851 | mgmt_buf->wait, mgmt_buf->buf, | ||
852 | mgmt_buf->len, mgmt_buf->no_cck); | ||
853 | conn->sta_flags &= ~STA_PS_POLLED; | ||
854 | kfree(mgmt_buf); | ||
855 | } else { | ||
856 | skb = skb_dequeue(&conn->psq); | ||
857 | spin_unlock_bh(&conn->psq_lock); | ||
833 | 858 | ||
834 | conn->sta_flags |= STA_PS_POLLED; | 859 | conn->sta_flags |= STA_PS_POLLED; |
835 | ath6kl_data_tx(skb, vif->ndev); | 860 | ath6kl_data_tx(skb, vif->ndev); |
836 | conn->sta_flags &= ~STA_PS_POLLED; | 861 | conn->sta_flags &= ~STA_PS_POLLED; |
862 | } | ||
837 | 863 | ||
838 | spin_lock_bh(&conn->psq_lock); | 864 | spin_lock_bh(&conn->psq_lock); |
839 | psq_empty = skb_queue_empty(&conn->psq); | 865 | psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); |
840 | spin_unlock_bh(&conn->psq_lock); | 866 | spin_unlock_bh(&conn->psq_lock); |
841 | 867 | ||
842 | if (psq_empty) | 868 | if (psq_empty) |
@@ -922,8 +948,8 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, | |||
922 | } | 948 | } |
923 | 949 | ||
924 | ath6kl_cfg80211_disconnect_event(vif, reason, bssid, | 950 | ath6kl_cfg80211_disconnect_event(vif, reason, bssid, |
925 | assoc_resp_len, assoc_info, | 951 | assoc_resp_len, assoc_info, |
926 | prot_reason_status); | 952 | prot_reason_status); |
927 | 953 | ||
928 | aggr_reset_state(vif->aggr_cntxt->aggr_conn); | 954 | aggr_reset_state(vif->aggr_cntxt->aggr_conn); |
929 | 955 | ||
@@ -943,9 +969,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, | |||
943 | } else { | 969 | } else { |
944 | set_bit(CONNECT_PEND, &vif->flags); | 970 | set_bit(CONNECT_PEND, &vif->flags); |
945 | if (((reason == ASSOC_FAILED) && | 971 | if (((reason == ASSOC_FAILED) && |
946 | (prot_reason_status == 0x11)) || | 972 | (prot_reason_status == 0x11)) || |
947 | ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) | 973 | ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) && |
948 | && (vif->reconnect_flag == 1))) { | 974 | (vif->reconnect_flag == 1))) { |
949 | set_bit(CONNECTED, &vif->flags); | 975 | set_bit(CONNECTED, &vif->flags); |
950 | return; | 976 | return; |
951 | } | 977 | } |
@@ -1079,7 +1105,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) | |||
1079 | if (mc_all_on || mc_all_off) { | 1105 | if (mc_all_on || mc_all_off) { |
1080 | /* Enable/disable all multicast */ | 1106 | /* Enable/disable all multicast */ |
1081 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", | 1107 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", |
1082 | mc_all_on ? "enabling" : "disabling"); | 1108 | mc_all_on ? "enabling" : "disabling"); |
1083 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, | 1109 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, |
1084 | mc_all_on); | 1110 | mc_all_on); |
1085 | if (ret) | 1111 | if (ret) |
@@ -1092,7 +1118,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) | |||
1092 | found = false; | 1118 | found = false; |
1093 | netdev_for_each_mc_addr(ha, ndev) { | 1119 | netdev_for_each_mc_addr(ha, ndev) { |
1094 | if (memcmp(ha->addr, mc_filter->hw_addr, | 1120 | if (memcmp(ha->addr, mc_filter->hw_addr, |
1095 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { | 1121 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { |
1096 | found = true; | 1122 | found = true; |
1097 | break; | 1123 | break; |
1098 | } | 1124 | } |
@@ -1111,7 +1137,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) | |||
1111 | false); | 1137 | false); |
1112 | if (ret) { | 1138 | if (ret) { |
1113 | ath6kl_warn("Failed to remove multicast filter:%pM\n", | 1139 | ath6kl_warn("Failed to remove multicast filter:%pM\n", |
1114 | mc_filter->hw_addr); | 1140 | mc_filter->hw_addr); |
1115 | return; | 1141 | return; |
1116 | } | 1142 | } |
1117 | 1143 | ||
@@ -1126,7 +1152,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) | |||
1126 | found = false; | 1152 | found = false; |
1127 | list_for_each_entry(mc_filter, &vif->mc_filter, list) { | 1153 | list_for_each_entry(mc_filter, &vif->mc_filter, list) { |
1128 | if (memcmp(ha->addr, mc_filter->hw_addr, | 1154 | if (memcmp(ha->addr, mc_filter->hw_addr, |
1129 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { | 1155 | ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { |
1130 | found = true; | 1156 | found = true; |
1131 | break; | 1157 | break; |
1132 | } | 1158 | } |
@@ -1151,7 +1177,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) | |||
1151 | true); | 1177 | true); |
1152 | if (ret) { | 1178 | if (ret) { |
1153 | ath6kl_warn("Failed to add multicast filter :%pM\n", | 1179 | ath6kl_warn("Failed to add multicast filter :%pM\n", |
1154 | mc_filter->hw_addr); | 1180 | mc_filter->hw_addr); |
1155 | kfree(mc_filter); | 1181 | kfree(mc_filter); |
1156 | goto out; | 1182 | goto out; |
1157 | } | 1183 | } |
@@ -1184,5 +1210,7 @@ void init_netdev(struct net_device *dev) | |||
1184 | sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH | 1210 | sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH |
1185 | + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES; | 1211 | + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES; |
1186 | 1212 | ||
1213 | dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; | ||
1214 | |||
1187 | return; | 1215 | return; |
1188 | } | 1216 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 4febee723495..53528648b425 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -31,6 +32,7 @@ | |||
31 | struct ath6kl_sdio { | 32 | struct ath6kl_sdio { |
32 | struct sdio_func *func; | 33 | struct sdio_func *func; |
33 | 34 | ||
35 | /* protects access to bus_req_freeq */ | ||
34 | spinlock_t lock; | 36 | spinlock_t lock; |
35 | 37 | ||
36 | /* free list */ | 38 | /* free list */ |
@@ -49,16 +51,20 @@ struct ath6kl_sdio { | |||
49 | /* scatter request list head */ | 51 | /* scatter request list head */ |
50 | struct list_head scat_req; | 52 | struct list_head scat_req; |
51 | 53 | ||
52 | /* Avoids disabling irq while the interrupts being handled */ | 54 | atomic_t irq_handling; |
53 | struct mutex mtx_irq; | 55 | wait_queue_head_t irq_wq; |
54 | 56 | ||
57 | /* protects access to scat_req */ | ||
55 | spinlock_t scat_lock; | 58 | spinlock_t scat_lock; |
59 | |||
56 | bool scatter_enabled; | 60 | bool scatter_enabled; |
57 | 61 | ||
58 | bool is_disabled; | 62 | bool is_disabled; |
59 | const struct sdio_device_id *id; | 63 | const struct sdio_device_id *id; |
60 | struct work_struct wr_async_work; | 64 | struct work_struct wr_async_work; |
61 | struct list_head wr_asyncq; | 65 | struct list_head wr_asyncq; |
66 | |||
67 | /* protects access to wr_asyncq */ | ||
62 | spinlock_t wr_async_lock; | 68 | spinlock_t wr_async_lock; |
63 | }; | 69 | }; |
64 | 70 | ||
@@ -404,7 +410,10 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, | |||
404 | return -ENOMEM; | 410 | return -ENOMEM; |
405 | mutex_lock(&ar_sdio->dma_buffer_mutex); | 411 | mutex_lock(&ar_sdio->dma_buffer_mutex); |
406 | tbuf = ar_sdio->dma_buffer; | 412 | tbuf = ar_sdio->dma_buffer; |
407 | memcpy(tbuf, buf, len); | 413 | |
414 | if (request & HIF_WRITE) | ||
415 | memcpy(tbuf, buf, len); | ||
416 | |||
408 | bounced = true; | 417 | bounced = true; |
409 | } else | 418 | } else |
410 | tbuf = buf; | 419 | tbuf = buf; |
@@ -462,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) | |||
462 | ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); | 471 | ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); |
463 | 472 | ||
464 | ar_sdio = sdio_get_drvdata(func); | 473 | ar_sdio = sdio_get_drvdata(func); |
465 | mutex_lock(&ar_sdio->mtx_irq); | 474 | atomic_set(&ar_sdio->irq_handling, 1); |
466 | /* | 475 | /* |
467 | * Release the host during interrups so we can pick it back up when | 476 | * Release the host during interrups so we can pick it back up when |
468 | * we process commands. | 477 | * we process commands. |
@@ -471,7 +480,10 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) | |||
471 | 480 | ||
472 | status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); | 481 | status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); |
473 | sdio_claim_host(ar_sdio->func); | 482 | sdio_claim_host(ar_sdio->func); |
474 | mutex_unlock(&ar_sdio->mtx_irq); | 483 | |
484 | atomic_set(&ar_sdio->irq_handling, 0); | ||
485 | wake_up(&ar_sdio->irq_wq); | ||
486 | |||
475 | WARN_ON(status && status != -ECANCELED); | 487 | WARN_ON(status && status != -ECANCELED); |
476 | } | 488 | } |
477 | 489 | ||
@@ -572,6 +584,13 @@ static void ath6kl_sdio_irq_enable(struct ath6kl *ar) | |||
572 | sdio_release_host(ar_sdio->func); | 584 | sdio_release_host(ar_sdio->func); |
573 | } | 585 | } |
574 | 586 | ||
587 | static bool ath6kl_sdio_is_on_irq(struct ath6kl *ar) | ||
588 | { | ||
589 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
590 | |||
591 | return !atomic_read(&ar_sdio->irq_handling); | ||
592 | } | ||
593 | |||
575 | static void ath6kl_sdio_irq_disable(struct ath6kl *ar) | 594 | static void ath6kl_sdio_irq_disable(struct ath6kl *ar) |
576 | { | 595 | { |
577 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | 596 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); |
@@ -579,14 +598,21 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar) | |||
579 | 598 | ||
580 | sdio_claim_host(ar_sdio->func); | 599 | sdio_claim_host(ar_sdio->func); |
581 | 600 | ||
582 | mutex_lock(&ar_sdio->mtx_irq); | 601 | if (atomic_read(&ar_sdio->irq_handling)) { |
602 | sdio_release_host(ar_sdio->func); | ||
603 | |||
604 | ret = wait_event_interruptible(ar_sdio->irq_wq, | ||
605 | ath6kl_sdio_is_on_irq(ar)); | ||
606 | if (ret) | ||
607 | return; | ||
608 | |||
609 | sdio_claim_host(ar_sdio->func); | ||
610 | } | ||
583 | 611 | ||
584 | ret = sdio_release_irq(ar_sdio->func); | 612 | ret = sdio_release_irq(ar_sdio->func); |
585 | if (ret) | 613 | if (ret) |
586 | ath6kl_err("Failed to release sdio irq: %d\n", ret); | 614 | ath6kl_err("Failed to release sdio irq: %d\n", ret); |
587 | 615 | ||
588 | mutex_unlock(&ar_sdio->mtx_irq); | ||
589 | |||
590 | sdio_release_host(ar_sdio->func); | 616 | sdio_release_host(ar_sdio->func); |
591 | } | 617 | } |
592 | 618 | ||
@@ -601,6 +627,8 @@ static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar) | |||
601 | node = list_first_entry(&ar_sdio->scat_req, | 627 | node = list_first_entry(&ar_sdio->scat_req, |
602 | struct hif_scatter_req, list); | 628 | struct hif_scatter_req, list); |
603 | list_del(&node->list); | 629 | list_del(&node->list); |
630 | |||
631 | node->scat_q_depth = get_queue_depth(&ar_sdio->scat_req); | ||
604 | } | 632 | } |
605 | 633 | ||
606 | spin_unlock_bh(&ar_sdio->scat_lock); | 634 | spin_unlock_bh(&ar_sdio->scat_lock); |
@@ -633,8 +661,8 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar, | |||
633 | return -EINVAL; | 661 | return -EINVAL; |
634 | 662 | ||
635 | ath6kl_dbg(ATH6KL_DBG_SCATTER, | 663 | ath6kl_dbg(ATH6KL_DBG_SCATTER, |
636 | "hif-scatter: total len: %d scatter entries: %d\n", | 664 | "hif-scatter: total len: %d scatter entries: %d\n", |
637 | scat_req->len, scat_req->scat_entries); | 665 | scat_req->len, scat_req->scat_entries); |
638 | 666 | ||
639 | if (request & HIF_SYNCHRONOUS) | 667 | if (request & HIF_SYNCHRONOUS) |
640 | status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); | 668 | status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); |
@@ -813,6 +841,7 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
813 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | 841 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); |
814 | struct sdio_func *func = ar_sdio->func; | 842 | struct sdio_func *func = ar_sdio->func; |
815 | mmc_pm_flag_t flags; | 843 | mmc_pm_flag_t flags; |
844 | bool try_deepsleep = false; | ||
816 | int ret; | 845 | int ret; |
817 | 846 | ||
818 | if (ar->state == ATH6KL_STATE_SCHED_SCAN) { | 847 | if (ar->state == ATH6KL_STATE_SCHED_SCAN) { |
@@ -839,14 +868,22 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
839 | goto cut_pwr; | 868 | goto cut_pwr; |
840 | 869 | ||
841 | ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); | 870 | ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); |
842 | if (ret) | 871 | if (ret && ret != -ENOTCONN) |
872 | ath6kl_err("wow suspend failed: %d\n", ret); | ||
873 | |||
874 | if (ret && | ||
875 | (!ar->wow_suspend_mode || | ||
876 | ar->wow_suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP)) | ||
877 | try_deepsleep = true; | ||
878 | else if (ret && | ||
879 | ar->wow_suspend_mode == WLAN_POWER_STATE_CUT_PWR) | ||
843 | goto cut_pwr; | 880 | goto cut_pwr; |
844 | 881 | if (!ret) | |
845 | return 0; | 882 | return 0; |
846 | } | 883 | } |
847 | 884 | ||
848 | if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP || | 885 | if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP || |
849 | !ar->suspend_mode) { | 886 | !ar->suspend_mode || try_deepsleep) { |
850 | 887 | ||
851 | flags = sdio_get_host_pm_caps(func); | 888 | flags = sdio_get_host_pm_caps(func); |
852 | if (!(flags & MMC_PM_KEEP_POWER)) | 889 | if (!(flags & MMC_PM_KEEP_POWER)) |
@@ -901,8 +938,15 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) | |||
901 | 938 | ||
902 | case ATH6KL_STATE_WOW: | 939 | case ATH6KL_STATE_WOW: |
903 | break; | 940 | break; |
941 | |||
904 | case ATH6KL_STATE_SCHED_SCAN: | 942 | case ATH6KL_STATE_SCHED_SCAN: |
905 | break; | 943 | break; |
944 | |||
945 | case ATH6KL_STATE_SUSPENDING: | ||
946 | break; | ||
947 | |||
948 | case ATH6KL_STATE_RESUMING: | ||
949 | break; | ||
906 | } | 950 | } |
907 | 951 | ||
908 | ath6kl_cfg80211_resume(ar); | 952 | ath6kl_cfg80211_resume(ar); |
@@ -981,7 +1025,7 @@ static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data) | |||
981 | (u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC); | 1025 | (u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC); |
982 | if (status) { | 1026 | if (status) { |
983 | ath6kl_err("%s: failed to read from window data addr\n", | 1027 | ath6kl_err("%s: failed to read from window data addr\n", |
984 | __func__); | 1028 | __func__); |
985 | return status; | 1029 | return status; |
986 | } | 1030 | } |
987 | 1031 | ||
@@ -1285,7 +1329,6 @@ static int ath6kl_sdio_probe(struct sdio_func *func, | |||
1285 | spin_lock_init(&ar_sdio->scat_lock); | 1329 | spin_lock_init(&ar_sdio->scat_lock); |
1286 | spin_lock_init(&ar_sdio->wr_async_lock); | 1330 | spin_lock_init(&ar_sdio->wr_async_lock); |
1287 | mutex_init(&ar_sdio->dma_buffer_mutex); | 1331 | mutex_init(&ar_sdio->dma_buffer_mutex); |
1288 | mutex_init(&ar_sdio->mtx_irq); | ||
1289 | 1332 | ||
1290 | INIT_LIST_HEAD(&ar_sdio->scat_req); | 1333 | INIT_LIST_HEAD(&ar_sdio->scat_req); |
1291 | INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); | 1334 | INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); |
@@ -1293,6 +1336,8 @@ static int ath6kl_sdio_probe(struct sdio_func *func, | |||
1293 | 1336 | ||
1294 | INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work); | 1337 | INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work); |
1295 | 1338 | ||
1339 | init_waitqueue_head(&ar_sdio->irq_wq); | ||
1340 | |||
1296 | for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) | 1341 | for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) |
1297 | ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); | 1342 | ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); |
1298 | 1343 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index 108a723a1085..78e0ef4567a5 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2010 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2010 Atheros Communications Inc. |
3 | * Copyright (c) 2011 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -19,6 +20,7 @@ | |||
19 | 20 | ||
20 | #define AR6003_BOARD_DATA_SZ 1024 | 21 | #define AR6003_BOARD_DATA_SZ 1024 |
21 | #define AR6003_BOARD_EXT_DATA_SZ 768 | 22 | #define AR6003_BOARD_EXT_DATA_SZ 768 |
23 | #define AR6003_BOARD_EXT_DATA_SZ_V2 1024 | ||
22 | 24 | ||
23 | #define AR6004_BOARD_DATA_SZ 6144 | 25 | #define AR6004_BOARD_DATA_SZ 6144 |
24 | #define AR6004_BOARD_EXT_DATA_SZ 0 | 26 | #define AR6004_BOARD_EXT_DATA_SZ 0 |
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c index f0cd61d6188a..6675c92b542b 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.c +++ b/drivers/net/wireless/ath/ath6kl/testmode.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.h b/drivers/net/wireless/ath/ath6kl/testmode.h index 7fd47a62d078..fe651d6707df 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.h +++ b/drivers/net/wireless/ath/ath6kl/testmode.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index a3dc6943c7f7..f85353fd1792 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -158,8 +159,8 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn, | |||
158 | */ | 159 | */ |
159 | if (is_apsdq_empty) { | 160 | if (is_apsdq_empty) { |
160 | ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, | 161 | ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, |
161 | vif->fw_vif_idx, | 162 | vif->fw_vif_idx, |
162 | conn->aid, 1, 0); | 163 | conn->aid, 1, 0); |
163 | } | 164 | } |
164 | *flags |= WMI_DATA_HDR_FLAGS_UAPSD; | 165 | *flags |= WMI_DATA_HDR_FLAGS_UAPSD; |
165 | 166 | ||
@@ -284,6 +285,9 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, | |||
284 | int status = 0; | 285 | int status = 0; |
285 | struct ath6kl_cookie *cookie = NULL; | 286 | struct ath6kl_cookie *cookie = NULL; |
286 | 287 | ||
288 | if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) | ||
289 | return -EACCES; | ||
290 | |||
287 | spin_lock_bh(&ar->lock); | 291 | spin_lock_bh(&ar->lock); |
288 | 292 | ||
289 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, | 293 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, |
@@ -359,6 +363,11 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
359 | return 0; | 363 | return 0; |
360 | } | 364 | } |
361 | 365 | ||
366 | if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) { | ||
367 | dev_kfree_skb(skb); | ||
368 | return 0; | ||
369 | } | ||
370 | |||
362 | if (!test_bit(WMI_READY, &ar->flag)) | 371 | if (!test_bit(WMI_READY, &ar->flag)) |
363 | goto fail_tx; | 372 | goto fail_tx; |
364 | 373 | ||
@@ -370,7 +379,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
370 | 379 | ||
371 | if (test_bit(WMI_ENABLED, &ar->flag)) { | 380 | if (test_bit(WMI_ENABLED, &ar->flag)) { |
372 | if ((dev->features & NETIF_F_IP_CSUM) && | 381 | if ((dev->features & NETIF_F_IP_CSUM) && |
373 | (csum == CHECKSUM_PARTIAL)) { | 382 | (csum == CHECKSUM_PARTIAL)) { |
374 | csum_start = skb->csum_start - | 383 | csum_start = skb->csum_start - |
375 | (skb_network_header(skb) - skb->head) + | 384 | (skb_network_header(skb) - skb->head) + |
376 | sizeof(struct ath6kl_llc_snap_hdr); | 385 | sizeof(struct ath6kl_llc_snap_hdr); |
@@ -394,7 +403,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
394 | } | 403 | } |
395 | 404 | ||
396 | if ((dev->features & NETIF_F_IP_CSUM) && | 405 | if ((dev->features & NETIF_F_IP_CSUM) && |
397 | (csum == CHECKSUM_PARTIAL)) { | 406 | (csum == CHECKSUM_PARTIAL)) { |
398 | meta_v2.csum_start = csum_start; | 407 | meta_v2.csum_start = csum_start; |
399 | meta_v2.csum_dest = csum_dest; | 408 | meta_v2.csum_dest = csum_dest; |
400 | 409 | ||
@@ -419,7 +428,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | |||
419 | } | 428 | } |
420 | 429 | ||
421 | if ((vif->nw_type == ADHOC_NETWORK) && | 430 | if ((vif->nw_type == ADHOC_NETWORK) && |
422 | ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags)) | 431 | ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags)) |
423 | chk_adhoc_ps_mapping = true; | 432 | chk_adhoc_ps_mapping = true; |
424 | else { | 433 | else { |
425 | /* get the stream mapping */ | 434 | /* get the stream mapping */ |
@@ -593,7 +602,8 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, | |||
593 | */ | 602 | */ |
594 | if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] < | 603 | if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] < |
595 | ar->hiac_stream_active_pri && | 604 | ar->hiac_stream_active_pri && |
596 | ar->cookie_count <= MAX_HI_COOKIE_NUM) | 605 | ar->cookie_count <= |
606 | target->endpoint[endpoint].tx_drop_packet_threshold) | ||
597 | /* | 607 | /* |
598 | * Give preference to the highest priority stream by | 608 | * Give preference to the highest priority stream by |
599 | * dropping the packets which overflowed. | 609 | * dropping the packets which overflowed. |
@@ -876,7 +886,7 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) | |||
876 | if (!IS_ALIGNED((unsigned long) skb->data, 4)) | 886 | if (!IS_ALIGNED((unsigned long) skb->data, 4)) |
877 | skb->data = PTR_ALIGN(skb->data - 4, 4); | 887 | skb->data = PTR_ALIGN(skb->data - 4, 4); |
878 | set_htc_rxpkt_info(packet, skb, skb->data, | 888 | set_htc_rxpkt_info(packet, skb, skb->data, |
879 | ATH6KL_BUFFER_SIZE, endpoint); | 889 | ATH6KL_BUFFER_SIZE, endpoint); |
880 | list_add_tail(&packet->list, &queue); | 890 | list_add_tail(&packet->list, &queue); |
881 | } | 891 | } |
882 | 892 | ||
@@ -1256,8 +1266,8 @@ static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif, | |||
1256 | flags = 0; | 1266 | flags = 0; |
1257 | 1267 | ||
1258 | ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, | 1268 | ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, |
1259 | vif->fw_vif_idx, | 1269 | vif->fw_vif_idx, |
1260 | conn->aid, 0, flags); | 1270 | conn->aid, 0, flags); |
1261 | } | 1271 | } |
1262 | 1272 | ||
1263 | return; | 1273 | return; |
@@ -1296,7 +1306,15 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1296 | skb_put(skb, packet->act_len + HTC_HDR_LENGTH); | 1306 | skb_put(skb, packet->act_len + HTC_HDR_LENGTH); |
1297 | skb_pull(skb, HTC_HDR_LENGTH); | 1307 | skb_pull(skb, HTC_HDR_LENGTH); |
1298 | 1308 | ||
1309 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ", | ||
1310 | skb->data, skb->len); | ||
1311 | |||
1299 | if (ept == ar->ctrl_ep) { | 1312 | if (ept == ar->ctrl_ep) { |
1313 | if (test_bit(WMI_ENABLED, &ar->flag)) { | ||
1314 | ath6kl_check_wow_status(ar); | ||
1315 | ath6kl_wmi_control_rx(ar->wmi, skb); | ||
1316 | return; | ||
1317 | } | ||
1300 | if_idx = | 1318 | if_idx = |
1301 | wmi_cmd_hdr_get_if_idx((struct wmi_cmd_hdr *) skb->data); | 1319 | wmi_cmd_hdr_get_if_idx((struct wmi_cmd_hdr *) skb->data); |
1302 | } else { | 1320 | } else { |
@@ -1321,10 +1339,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1321 | 1339 | ||
1322 | spin_unlock_bh(&vif->if_lock); | 1340 | spin_unlock_bh(&vif->if_lock); |
1323 | 1341 | ||
1324 | |||
1325 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ", | ||
1326 | skb->data, skb->len); | ||
1327 | |||
1328 | skb->dev = vif->ndev; | 1342 | skb->dev = vif->ndev; |
1329 | 1343 | ||
1330 | if (!test_bit(WMI_ENABLED, &ar->flag)) { | 1344 | if (!test_bit(WMI_ENABLED, &ar->flag)) { |
@@ -1336,11 +1350,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1336 | 1350 | ||
1337 | ath6kl_check_wow_status(ar); | 1351 | ath6kl_check_wow_status(ar); |
1338 | 1352 | ||
1339 | if (ept == ar->ctrl_ep) { | ||
1340 | ath6kl_wmi_control_rx(ar->wmi, skb); | ||
1341 | return; | ||
1342 | } | ||
1343 | |||
1344 | min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) + | 1353 | min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) + |
1345 | sizeof(struct ath6kl_llc_snap_hdr); | 1354 | sizeof(struct ath6kl_llc_snap_hdr); |
1346 | 1355 | ||
@@ -1416,8 +1425,33 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1416 | if (!(conn->sta_flags & STA_PS_SLEEP)) { | 1425 | if (!(conn->sta_flags & STA_PS_SLEEP)) { |
1417 | struct sk_buff *skbuff = NULL; | 1426 | struct sk_buff *skbuff = NULL; |
1418 | bool is_apsdq_empty; | 1427 | bool is_apsdq_empty; |
1428 | struct ath6kl_mgmt_buff *mgmt; | ||
1429 | u8 idx; | ||
1419 | 1430 | ||
1420 | spin_lock_bh(&conn->psq_lock); | 1431 | spin_lock_bh(&conn->psq_lock); |
1432 | while (conn->mgmt_psq_len > 0) { | ||
1433 | mgmt = list_first_entry( | ||
1434 | &conn->mgmt_psq, | ||
1435 | struct ath6kl_mgmt_buff, | ||
1436 | list); | ||
1437 | list_del(&mgmt->list); | ||
1438 | conn->mgmt_psq_len--; | ||
1439 | spin_unlock_bh(&conn->psq_lock); | ||
1440 | idx = vif->fw_vif_idx; | ||
1441 | |||
1442 | ath6kl_wmi_send_mgmt_cmd(ar->wmi, | ||
1443 | idx, | ||
1444 | mgmt->id, | ||
1445 | mgmt->freq, | ||
1446 | mgmt->wait, | ||
1447 | mgmt->buf, | ||
1448 | mgmt->len, | ||
1449 | mgmt->no_cck); | ||
1450 | |||
1451 | kfree(mgmt); | ||
1452 | spin_lock_bh(&conn->psq_lock); | ||
1453 | } | ||
1454 | conn->mgmt_psq_len = 0; | ||
1421 | while ((skbuff = skb_dequeue(&conn->psq))) { | 1455 | while ((skbuff = skb_dequeue(&conn->psq))) { |
1422 | spin_unlock_bh(&conn->psq_lock); | 1456 | spin_unlock_bh(&conn->psq_lock); |
1423 | ath6kl_data_tx(skbuff, vif->ndev); | 1457 | ath6kl_data_tx(skbuff, vif->ndev); |
@@ -1541,7 +1575,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | |||
1541 | aggr_conn = vif->aggr_cntxt->aggr_conn; | 1575 | aggr_conn = vif->aggr_cntxt->aggr_conn; |
1542 | 1576 | ||
1543 | if (aggr_process_recv_frm(aggr_conn, tid, seq_no, | 1577 | if (aggr_process_recv_frm(aggr_conn, tid, seq_no, |
1544 | is_amsdu, skb)) { | 1578 | is_amsdu, skb)) { |
1545 | /* aggregation code will handle the skb */ | 1579 | /* aggregation code will handle the skb */ |
1546 | return; | 1580 | return; |
1547 | } | 1581 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index c72567c6d338..325b1224c2b1 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2007-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2007-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 97abf4699b41..2b442332cd0f 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -126,7 +127,7 @@ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb) | |||
126 | 127 | ||
127 | if (!is_ethertype(be16_to_cpu(type))) { | 128 | if (!is_ethertype(be16_to_cpu(type))) { |
128 | ath6kl_dbg(ATH6KL_DBG_WMI, | 129 | ath6kl_dbg(ATH6KL_DBG_WMI, |
129 | "%s: pkt is already in 802.3 format\n", __func__); | 130 | "%s: pkt is already in 802.3 format\n", __func__); |
130 | return 0; | 131 | return 0; |
131 | } | 132 | } |
132 | 133 | ||
@@ -827,8 +828,8 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, | |||
827 | if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 && | 828 | if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 && |
828 | pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) { | 829 | pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) { |
829 | /* WMM OUT (00:50:F2) */ | 830 | /* WMM OUT (00:50:F2) */ |
830 | if (pie[1] > 5 | 831 | if (pie[1] > 5 && |
831 | && pie[6] == WMM_PARAM_OUI_SUBTYPE) | 832 | pie[6] == WMM_PARAM_OUI_SUBTYPE) |
832 | wmi->is_wmm_enabled = true; | 833 | wmi->is_wmm_enabled = true; |
833 | } | 834 | } |
834 | break; | 835 | break; |
@@ -912,17 +913,17 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) | |||
912 | regpair = ath6kl_get_regpair((u16) reg_code); | 913 | regpair = ath6kl_get_regpair((u16) reg_code); |
913 | country = ath6kl_regd_find_country_by_rd((u16) reg_code); | 914 | country = ath6kl_regd_find_country_by_rd((u16) reg_code); |
914 | ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", | 915 | ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", |
915 | regpair->regDmnEnum); | 916 | regpair->regDmnEnum); |
916 | } | 917 | } |
917 | 918 | ||
918 | if (country) { | 919 | if (country && wmi->parent_dev->wiphy_registered) { |
919 | alpha2[0] = country->isoName[0]; | 920 | alpha2[0] = country->isoName[0]; |
920 | alpha2[1] = country->isoName[1]; | 921 | alpha2[1] = country->isoName[1]; |
921 | 922 | ||
922 | regulatory_hint(wmi->parent_dev->wiphy, alpha2); | 923 | regulatory_hint(wmi->parent_dev->wiphy, alpha2); |
923 | 924 | ||
924 | ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n", | 925 | ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n", |
925 | alpha2[0], alpha2[1]); | 926 | alpha2[0], alpha2[1]); |
926 | } | 927 | } |
927 | } | 928 | } |
928 | 929 | ||
@@ -1033,8 +1034,9 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, | |||
1033 | if (len < 8 + 2 + 2) | 1034 | if (len < 8 + 2 + 2) |
1034 | return -EINVAL; | 1035 | return -EINVAL; |
1035 | 1036 | ||
1036 | if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &vif->flags) | 1037 | if (bih->frame_type == BEACON_FTYPE && |
1037 | && memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) { | 1038 | test_bit(CONNECTED, &vif->flags) && |
1039 | memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) { | ||
1038 | const u8 *tim; | 1040 | const u8 *tim; |
1039 | tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2, | 1041 | tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2, |
1040 | len - 8 - 2 - 2); | 1042 | len - 8 - 2 - 2); |
@@ -1366,8 +1368,8 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, | |||
1366 | /* Upper threshold breached */ | 1368 | /* Upper threshold breached */ |
1367 | if (rssi < sq_thresh->upper_threshold[0]) { | 1369 | if (rssi < sq_thresh->upper_threshold[0]) { |
1368 | ath6kl_dbg(ATH6KL_DBG_WMI, | 1370 | ath6kl_dbg(ATH6KL_DBG_WMI, |
1369 | "spurious upper rssi threshold event: %d\n", | 1371 | "spurious upper rssi threshold event: %d\n", |
1370 | rssi); | 1372 | rssi); |
1371 | } else if ((rssi < sq_thresh->upper_threshold[1]) && | 1373 | } else if ((rssi < sq_thresh->upper_threshold[1]) && |
1372 | (rssi >= sq_thresh->upper_threshold[0])) { | 1374 | (rssi >= sq_thresh->upper_threshold[0])) { |
1373 | new_threshold = WMI_RSSI_THRESHOLD1_ABOVE; | 1375 | new_threshold = WMI_RSSI_THRESHOLD1_ABOVE; |
@@ -1390,7 +1392,7 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, | |||
1390 | /* Lower threshold breached */ | 1392 | /* Lower threshold breached */ |
1391 | if (rssi > sq_thresh->lower_threshold[0]) { | 1393 | if (rssi > sq_thresh->lower_threshold[0]) { |
1392 | ath6kl_dbg(ATH6KL_DBG_WMI, | 1394 | ath6kl_dbg(ATH6KL_DBG_WMI, |
1393 | "spurious lower rssi threshold event: %d %d\n", | 1395 | "spurious lower rssi threshold event: %d %d\n", |
1394 | rssi, sq_thresh->lower_threshold[0]); | 1396 | rssi, sq_thresh->lower_threshold[0]); |
1395 | } else if ((rssi > sq_thresh->lower_threshold[1]) && | 1397 | } else if ((rssi > sq_thresh->lower_threshold[1]) && |
1396 | (rssi <= sq_thresh->lower_threshold[0])) { | 1398 | (rssi <= sq_thresh->lower_threshold[0])) { |
@@ -1551,8 +1553,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, | |||
1551 | /* Upper threshold breached */ | 1553 | /* Upper threshold breached */ |
1552 | if (snr < sq_thresh->upper_threshold[0]) { | 1554 | if (snr < sq_thresh->upper_threshold[0]) { |
1553 | ath6kl_dbg(ATH6KL_DBG_WMI, | 1555 | ath6kl_dbg(ATH6KL_DBG_WMI, |
1554 | "spurious upper snr threshold event: %d\n", | 1556 | "spurious upper snr threshold event: %d\n", |
1555 | snr); | 1557 | snr); |
1556 | } else if ((snr < sq_thresh->upper_threshold[1]) && | 1558 | } else if ((snr < sq_thresh->upper_threshold[1]) && |
1557 | (snr >= sq_thresh->upper_threshold[0])) { | 1559 | (snr >= sq_thresh->upper_threshold[0])) { |
1558 | new_threshold = WMI_SNR_THRESHOLD1_ABOVE; | 1560 | new_threshold = WMI_SNR_THRESHOLD1_ABOVE; |
@@ -1569,8 +1571,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, | |||
1569 | /* Lower threshold breached */ | 1571 | /* Lower threshold breached */ |
1570 | if (snr > sq_thresh->lower_threshold[0]) { | 1572 | if (snr > sq_thresh->lower_threshold[0]) { |
1571 | ath6kl_dbg(ATH6KL_DBG_WMI, | 1573 | ath6kl_dbg(ATH6KL_DBG_WMI, |
1572 | "spurious lower snr threshold event: %d\n", | 1574 | "spurious lower snr threshold event: %d\n", |
1573 | sq_thresh->lower_threshold[0]); | 1575 | sq_thresh->lower_threshold[0]); |
1574 | } else if ((snr > sq_thresh->lower_threshold[1]) && | 1576 | } else if ((snr > sq_thresh->lower_threshold[1]) && |
1575 | (snr <= sq_thresh->lower_threshold[0])) { | 1577 | (snr <= sq_thresh->lower_threshold[0])) { |
1576 | new_threshold = WMI_SNR_THRESHOLD4_BELOW; | 1578 | new_threshold = WMI_SNR_THRESHOLD4_BELOW; |
@@ -2028,6 +2030,26 @@ int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx, | |||
2028 | return ret; | 2030 | return ret; |
2029 | } | 2031 | } |
2030 | 2032 | ||
2033 | int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx, | ||
2034 | u16 bmiss_time, u16 num_beacons) | ||
2035 | { | ||
2036 | struct sk_buff *skb; | ||
2037 | struct wmi_bmiss_time_cmd *cmd; | ||
2038 | int ret; | ||
2039 | |||
2040 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2041 | if (!skb) | ||
2042 | return -ENOMEM; | ||
2043 | |||
2044 | cmd = (struct wmi_bmiss_time_cmd *) skb->data; | ||
2045 | cmd->bmiss_time = cpu_to_le16(bmiss_time); | ||
2046 | cmd->num_beacons = cpu_to_le16(num_beacons); | ||
2047 | |||
2048 | ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BMISS_TIME_CMDID, | ||
2049 | NO_SYNC_WMIFLAG); | ||
2050 | return ret; | ||
2051 | } | ||
2052 | |||
2031 | int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode) | 2053 | int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode) |
2032 | { | 2054 | { |
2033 | struct sk_buff *skb; | 2055 | struct sk_buff *skb; |
@@ -2613,7 +2635,7 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, | |||
2613 | int ret; | 2635 | int ret; |
2614 | 2636 | ||
2615 | if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) && | 2637 | if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) && |
2616 | wow_mode != ATH6KL_WOW_MODE_DISABLE) { | 2638 | wow_mode != ATH6KL_WOW_MODE_DISABLE) { |
2617 | ath6kl_err("invalid wow mode: %d\n", wow_mode); | 2639 | ath6kl_err("invalid wow mode: %d\n", wow_mode); |
2618 | return -EINVAL; | 2640 | return -EINVAL; |
2619 | } | 2641 | } |
@@ -3014,6 +3036,22 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac, | |||
3014 | NO_SYNC_WMIFLAG); | 3036 | NO_SYNC_WMIFLAG); |
3015 | } | 3037 | } |
3016 | 3038 | ||
3039 | int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable) | ||
3040 | { | ||
3041 | struct sk_buff *skb; | ||
3042 | struct wmi_ap_hidden_ssid_cmd *cmd; | ||
3043 | |||
3044 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
3045 | if (!skb) | ||
3046 | return -ENOMEM; | ||
3047 | |||
3048 | cmd = (struct wmi_ap_hidden_ssid_cmd *) skb->data; | ||
3049 | cmd->hidden_ssid = enable ? 1 : 0; | ||
3050 | |||
3051 | return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_HIDDEN_SSID_CMDID, | ||
3052 | NO_SYNC_WMIFLAG); | ||
3053 | } | ||
3054 | |||
3017 | /* This command will be used to enable/disable AP uAPSD feature */ | 3055 | /* This command will be used to enable/disable AP uAPSD feature */ |
3018 | int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable) | 3056 | int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable) |
3019 | { | 3057 | { |
@@ -3183,8 +3221,9 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur) | |||
3183 | * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P | 3221 | * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P |
3184 | * mgmt operations using station interface. | 3222 | * mgmt operations using station interface. |
3185 | */ | 3223 | */ |
3186 | int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, | 3224 | static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, |
3187 | u32 wait, const u8 *data, u16 data_len) | 3225 | u32 freq, u32 wait, const u8 *data, |
3226 | u16 data_len) | ||
3188 | { | 3227 | { |
3189 | struct sk_buff *skb; | 3228 | struct sk_buff *skb; |
3190 | struct wmi_send_action_cmd *p; | 3229 | struct wmi_send_action_cmd *p; |
@@ -3220,9 +3259,9 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, | |||
3220 | NO_SYNC_WMIFLAG); | 3259 | NO_SYNC_WMIFLAG); |
3221 | } | 3260 | } |
3222 | 3261 | ||
3223 | int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, | 3262 | static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, |
3224 | u32 wait, const u8 *data, u16 data_len, | 3263 | u32 freq, u32 wait, const u8 *data, |
3225 | u32 no_cck) | 3264 | u16 data_len, u32 no_cck) |
3226 | { | 3265 | { |
3227 | struct sk_buff *skb; | 3266 | struct sk_buff *skb; |
3228 | struct wmi_send_mgmt_cmd *p; | 3267 | struct wmi_send_mgmt_cmd *p; |
@@ -3259,6 +3298,32 @@ int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, | |||
3259 | NO_SYNC_WMIFLAG); | 3298 | NO_SYNC_WMIFLAG); |
3260 | } | 3299 | } |
3261 | 3300 | ||
3301 | int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, | ||
3302 | u32 wait, const u8 *data, u16 data_len, | ||
3303 | u32 no_cck) | ||
3304 | { | ||
3305 | int status; | ||
3306 | struct ath6kl *ar = wmi->parent_dev; | ||
3307 | |||
3308 | if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, | ||
3309 | ar->fw_capabilities)) { | ||
3310 | /* | ||
3311 | * If capable of doing P2P mgmt operations using | ||
3312 | * station interface, send additional information like | ||
3313 | * supported rates to advertise and xmit rates for | ||
3314 | * probe requests | ||
3315 | */ | ||
3316 | status = __ath6kl_wmi_send_mgmt_cmd(ar->wmi, if_idx, id, freq, | ||
3317 | wait, data, data_len, | ||
3318 | no_cck); | ||
3319 | } else { | ||
3320 | status = ath6kl_wmi_send_action_cmd(ar->wmi, if_idx, id, freq, | ||
3321 | wait, data, data_len); | ||
3322 | } | ||
3323 | |||
3324 | return status; | ||
3325 | } | ||
3326 | |||
3262 | int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq, | 3327 | int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq, |
3263 | const u8 *dst, const u8 *data, | 3328 | const u8 *dst, const u8 *data, |
3264 | u16 data_len) | 3329 | u16 data_len) |
@@ -3370,32 +3435,101 @@ static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len) | |||
3370 | return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len); | 3435 | return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len); |
3371 | } | 3436 | } |
3372 | 3437 | ||
3373 | /* Control Path */ | 3438 | /* Process interface specific wmi events, caller would free the datap */ |
3374 | int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | 3439 | static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id, |
3440 | u8 *datap, u32 len) | ||
3375 | { | 3441 | { |
3376 | struct wmi_cmd_hdr *cmd; | ||
3377 | struct ath6kl_vif *vif; | 3442 | struct ath6kl_vif *vif; |
3378 | u32 len; | ||
3379 | u16 id; | ||
3380 | u8 if_idx; | ||
3381 | u8 *datap; | ||
3382 | int ret = 0; | ||
3383 | 3443 | ||
3384 | if (WARN_ON(skb == NULL)) | 3444 | vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx); |
3445 | if (!vif) { | ||
3446 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
3447 | "Wmi event for unavailable vif, vif_index:%d\n", | ||
3448 | if_idx); | ||
3385 | return -EINVAL; | 3449 | return -EINVAL; |
3450 | } | ||
3386 | 3451 | ||
3387 | if (skb->len < sizeof(struct wmi_cmd_hdr)) { | 3452 | switch (cmd_id) { |
3388 | ath6kl_err("bad packet 1\n"); | 3453 | case WMI_CONNECT_EVENTID: |
3389 | dev_kfree_skb(skb); | 3454 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n"); |
3455 | return ath6kl_wmi_connect_event_rx(wmi, datap, len, vif); | ||
3456 | case WMI_DISCONNECT_EVENTID: | ||
3457 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n"); | ||
3458 | return ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif); | ||
3459 | case WMI_TKIP_MICERR_EVENTID: | ||
3460 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n"); | ||
3461 | return ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif); | ||
3462 | case WMI_BSSINFO_EVENTID: | ||
3463 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); | ||
3464 | return ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif); | ||
3465 | case WMI_NEIGHBOR_REPORT_EVENTID: | ||
3466 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); | ||
3467 | return ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len, | ||
3468 | vif); | ||
3469 | case WMI_SCAN_COMPLETE_EVENTID: | ||
3470 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); | ||
3471 | return ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif); | ||
3472 | case WMI_REPORT_STATISTICS_EVENTID: | ||
3473 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n"); | ||
3474 | return ath6kl_wmi_stats_event_rx(wmi, datap, len, vif); | ||
3475 | case WMI_CAC_EVENTID: | ||
3476 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n"); | ||
3477 | return ath6kl_wmi_cac_event_rx(wmi, datap, len, vif); | ||
3478 | case WMI_PSPOLL_EVENTID: | ||
3479 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n"); | ||
3480 | return ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif); | ||
3481 | case WMI_DTIMEXPIRY_EVENTID: | ||
3482 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n"); | ||
3483 | return ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif); | ||
3484 | case WMI_ADDBA_REQ_EVENTID: | ||
3485 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n"); | ||
3486 | return ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif); | ||
3487 | case WMI_DELBA_REQ_EVENTID: | ||
3488 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n"); | ||
3489 | return ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif); | ||
3490 | case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID: | ||
3491 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
3492 | "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID"); | ||
3493 | return ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif); | ||
3494 | case WMI_REMAIN_ON_CHNL_EVENTID: | ||
3495 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); | ||
3496 | return ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif); | ||
3497 | case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: | ||
3498 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
3499 | "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); | ||
3500 | return ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap, | ||
3501 | len, vif); | ||
3502 | case WMI_TX_STATUS_EVENTID: | ||
3503 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); | ||
3504 | return ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif); | ||
3505 | case WMI_RX_PROBE_REQ_EVENTID: | ||
3506 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); | ||
3507 | return ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif); | ||
3508 | case WMI_RX_ACTION_EVENTID: | ||
3509 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); | ||
3510 | return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); | ||
3511 | default: | ||
3512 | ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id); | ||
3390 | return -EINVAL; | 3513 | return -EINVAL; |
3391 | } | 3514 | } |
3392 | 3515 | ||
3516 | return 0; | ||
3517 | } | ||
3518 | |||
3519 | static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) | ||
3520 | { | ||
3521 | struct wmi_cmd_hdr *cmd; | ||
3522 | int ret = 0; | ||
3523 | u32 len; | ||
3524 | u16 id; | ||
3525 | u8 if_idx; | ||
3526 | u8 *datap; | ||
3527 | |||
3393 | cmd = (struct wmi_cmd_hdr *) skb->data; | 3528 | cmd = (struct wmi_cmd_hdr *) skb->data; |
3394 | id = le16_to_cpu(cmd->cmd_id); | 3529 | id = le16_to_cpu(cmd->cmd_id); |
3395 | if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK; | 3530 | if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK; |
3396 | 3531 | ||
3397 | skb_pull(skb, sizeof(struct wmi_cmd_hdr)); | 3532 | skb_pull(skb, sizeof(struct wmi_cmd_hdr)); |
3398 | |||
3399 | datap = skb->data; | 3533 | datap = skb->data; |
3400 | len = skb->len; | 3534 | len = skb->len; |
3401 | 3535 | ||
@@ -3403,15 +3537,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
3403 | ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ", | 3537 | ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ", |
3404 | datap, len); | 3538 | datap, len); |
3405 | 3539 | ||
3406 | vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx); | ||
3407 | if (!vif) { | ||
3408 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
3409 | "Wmi event for unavailable vif, vif_index:%d\n", | ||
3410 | if_idx); | ||
3411 | dev_kfree_skb(skb); | ||
3412 | return -EINVAL; | ||
3413 | } | ||
3414 | |||
3415 | switch (id) { | 3540 | switch (id) { |
3416 | case WMI_GET_BITRATE_CMDID: | 3541 | case WMI_GET_BITRATE_CMDID: |
3417 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n"); | 3542 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n"); |
@@ -3429,26 +3554,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
3429 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n"); | 3554 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n"); |
3430 | ret = ath6kl_wmi_ready_event_rx(wmi, datap, len); | 3555 | ret = ath6kl_wmi_ready_event_rx(wmi, datap, len); |
3431 | break; | 3556 | break; |
3432 | case WMI_CONNECT_EVENTID: | ||
3433 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n"); | ||
3434 | ret = ath6kl_wmi_connect_event_rx(wmi, datap, len, vif); | ||
3435 | break; | ||
3436 | case WMI_DISCONNECT_EVENTID: | ||
3437 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n"); | ||
3438 | ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif); | ||
3439 | break; | ||
3440 | case WMI_PEER_NODE_EVENTID: | 3557 | case WMI_PEER_NODE_EVENTID: |
3441 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n"); | 3558 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n"); |
3442 | ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len); | 3559 | ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len); |
3443 | break; | 3560 | break; |
3444 | case WMI_TKIP_MICERR_EVENTID: | ||
3445 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n"); | ||
3446 | ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif); | ||
3447 | break; | ||
3448 | case WMI_BSSINFO_EVENTID: | ||
3449 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); | ||
3450 | ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif); | ||
3451 | break; | ||
3452 | case WMI_REGDOMAIN_EVENTID: | 3561 | case WMI_REGDOMAIN_EVENTID: |
3453 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); | 3562 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); |
3454 | ath6kl_wmi_regdomain_event(wmi, datap, len); | 3563 | ath6kl_wmi_regdomain_event(wmi, datap, len); |
@@ -3457,23 +3566,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
3457 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); | 3566 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); |
3458 | ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len); | 3567 | ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len); |
3459 | break; | 3568 | break; |
3460 | case WMI_NEIGHBOR_REPORT_EVENTID: | ||
3461 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); | ||
3462 | ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len, | ||
3463 | vif); | ||
3464 | break; | ||
3465 | case WMI_SCAN_COMPLETE_EVENTID: | ||
3466 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); | ||
3467 | ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif); | ||
3468 | break; | ||
3469 | case WMI_CMDERROR_EVENTID: | 3569 | case WMI_CMDERROR_EVENTID: |
3470 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n"); | 3570 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n"); |
3471 | ret = ath6kl_wmi_error_event_rx(wmi, datap, len); | 3571 | ret = ath6kl_wmi_error_event_rx(wmi, datap, len); |
3472 | break; | 3572 | break; |
3473 | case WMI_REPORT_STATISTICS_EVENTID: | ||
3474 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n"); | ||
3475 | ret = ath6kl_wmi_stats_event_rx(wmi, datap, len, vif); | ||
3476 | break; | ||
3477 | case WMI_RSSI_THRESHOLD_EVENTID: | 3573 | case WMI_RSSI_THRESHOLD_EVENTID: |
3478 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n"); | 3574 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n"); |
3479 | ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len); | 3575 | ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len); |
@@ -3493,10 +3589,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
3493 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n"); | 3589 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n"); |
3494 | ret = ath6kl_wmi_control_rx_xtnd(wmi, skb); | 3590 | ret = ath6kl_wmi_control_rx_xtnd(wmi, skb); |
3495 | break; | 3591 | break; |
3496 | case WMI_CAC_EVENTID: | ||
3497 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n"); | ||
3498 | ret = ath6kl_wmi_cac_event_rx(wmi, datap, len, vif); | ||
3499 | break; | ||
3500 | case WMI_CHANNEL_CHANGE_EVENTID: | 3592 | case WMI_CHANNEL_CHANGE_EVENTID: |
3501 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n"); | 3593 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n"); |
3502 | break; | 3594 | break; |
@@ -3536,28 +3628,12 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
3536 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n"); | 3628 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n"); |
3537 | ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len); | 3629 | ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len); |
3538 | break; | 3630 | break; |
3539 | case WMI_PSPOLL_EVENTID: | ||
3540 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n"); | ||
3541 | ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif); | ||
3542 | break; | ||
3543 | case WMI_DTIMEXPIRY_EVENTID: | ||
3544 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n"); | ||
3545 | ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif); | ||
3546 | break; | ||
3547 | case WMI_SET_PARAMS_REPLY_EVENTID: | 3631 | case WMI_SET_PARAMS_REPLY_EVENTID: |
3548 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n"); | 3632 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n"); |
3549 | break; | 3633 | break; |
3550 | case WMI_ADDBA_REQ_EVENTID: | ||
3551 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n"); | ||
3552 | ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif); | ||
3553 | break; | ||
3554 | case WMI_ADDBA_RESP_EVENTID: | 3634 | case WMI_ADDBA_RESP_EVENTID: |
3555 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n"); | 3635 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n"); |
3556 | break; | 3636 | break; |
3557 | case WMI_DELBA_REQ_EVENTID: | ||
3558 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n"); | ||
3559 | ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif); | ||
3560 | break; | ||
3561 | case WMI_REPORT_BTCOEX_CONFIG_EVENTID: | 3637 | case WMI_REPORT_BTCOEX_CONFIG_EVENTID: |
3562 | ath6kl_dbg(ATH6KL_DBG_WMI, | 3638 | ath6kl_dbg(ATH6KL_DBG_WMI, |
3563 | "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n"); | 3639 | "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n"); |
@@ -3570,52 +3646,39 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | |||
3570 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); | 3646 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); |
3571 | ret = ath6kl_wmi_tx_complete_event_rx(datap, len); | 3647 | ret = ath6kl_wmi_tx_complete_event_rx(datap, len); |
3572 | break; | 3648 | break; |
3573 | case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID: | ||
3574 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
3575 | "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID"); | ||
3576 | ret = ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif); | ||
3577 | break; | ||
3578 | case WMI_REMAIN_ON_CHNL_EVENTID: | ||
3579 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); | ||
3580 | ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif); | ||
3581 | break; | ||
3582 | case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: | ||
3583 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
3584 | "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); | ||
3585 | ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap, | ||
3586 | len, vif); | ||
3587 | break; | ||
3588 | case WMI_TX_STATUS_EVENTID: | ||
3589 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); | ||
3590 | ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif); | ||
3591 | break; | ||
3592 | case WMI_RX_PROBE_REQ_EVENTID: | ||
3593 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); | ||
3594 | ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif); | ||
3595 | break; | ||
3596 | case WMI_P2P_CAPABILITIES_EVENTID: | 3649 | case WMI_P2P_CAPABILITIES_EVENTID: |
3597 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n"); | 3650 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n"); |
3598 | ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len); | 3651 | ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len); |
3599 | break; | 3652 | break; |
3600 | case WMI_RX_ACTION_EVENTID: | ||
3601 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); | ||
3602 | ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); | ||
3603 | break; | ||
3604 | case WMI_P2P_INFO_EVENTID: | 3653 | case WMI_P2P_INFO_EVENTID: |
3605 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n"); | 3654 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n"); |
3606 | ret = ath6kl_wmi_p2p_info_event_rx(datap, len); | 3655 | ret = ath6kl_wmi_p2p_info_event_rx(datap, len); |
3607 | break; | 3656 | break; |
3608 | default: | 3657 | default: |
3609 | ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id); | 3658 | /* may be the event is interface specific */ |
3610 | ret = -EINVAL; | 3659 | ret = ath6kl_wmi_proc_events_vif(wmi, if_idx, id, datap, len); |
3611 | break; | 3660 | break; |
3612 | } | 3661 | } |
3613 | 3662 | ||
3614 | dev_kfree_skb(skb); | 3663 | dev_kfree_skb(skb); |
3615 | |||
3616 | return ret; | 3664 | return ret; |
3617 | } | 3665 | } |
3618 | 3666 | ||
3667 | /* Control Path */ | ||
3668 | int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | ||
3669 | { | ||
3670 | if (WARN_ON(skb == NULL)) | ||
3671 | return -EINVAL; | ||
3672 | |||
3673 | if (skb->len < sizeof(struct wmi_cmd_hdr)) { | ||
3674 | ath6kl_err("bad packet 1\n"); | ||
3675 | dev_kfree_skb(skb); | ||
3676 | return -EINVAL; | ||
3677 | } | ||
3678 | |||
3679 | return ath6kl_wmi_proc_events(wmi, skb); | ||
3680 | } | ||
3681 | |||
3619 | void ath6kl_wmi_reset(struct wmi *wmi) | 3682 | void ath6kl_wmi_reset(struct wmi *wmi) |
3620 | { | 3683 | { |
3621 | spin_lock_bh(&wmi->lock); | 3684 | spin_lock_bh(&wmi->lock); |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index e7919869725e..4092e3e80790 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -110,6 +111,8 @@ struct wmi { | |||
110 | u8 fat_pipe_exist; | 111 | u8 fat_pipe_exist; |
111 | struct ath6kl *parent_dev; | 112 | struct ath6kl *parent_dev; |
112 | u8 pwr_mode; | 113 | u8 pwr_mode; |
114 | |||
115 | /* protects fat_pipe_exist and stream_exist_for_ac */ | ||
113 | spinlock_t lock; | 116 | spinlock_t lock; |
114 | enum htc_endpoint_id ep_id; | 117 | enum htc_endpoint_id ep_id; |
115 | struct sq_threshold_params | 118 | struct sq_threshold_params |
@@ -997,6 +1000,12 @@ struct wmi_listen_int_cmd { | |||
997 | __le16 num_beacons; | 1000 | __le16 num_beacons; |
998 | } __packed; | 1001 | } __packed; |
999 | 1002 | ||
1003 | /* WMI_SET_BMISS_TIME_CMDID */ | ||
1004 | struct wmi_bmiss_time_cmd { | ||
1005 | __le16 bmiss_time; | ||
1006 | __le16 num_beacons; | ||
1007 | }; | ||
1008 | |||
1000 | /* WMI_SET_POWER_MODE_CMDID */ | 1009 | /* WMI_SET_POWER_MODE_CMDID */ |
1001 | enum wmi_power_mode { | 1010 | enum wmi_power_mode { |
1002 | REC_POWER = 0x01, | 1011 | REC_POWER = 0x01, |
@@ -1014,7 +1023,7 @@ struct wmi_power_mode_cmd { | |||
1014 | */ | 1023 | */ |
1015 | enum power_save_fail_event_policy { | 1024 | enum power_save_fail_event_policy { |
1016 | SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1, | 1025 | SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1, |
1017 | IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2, | 1026 | IGNORE_PS_FAIL_DURING_SCAN = 2, |
1018 | }; | 1027 | }; |
1019 | 1028 | ||
1020 | struct wmi_power_params_cmd { | 1029 | struct wmi_power_params_cmd { |
@@ -1212,7 +1221,7 @@ struct wmi_snr_threshold_params_cmd { | |||
1212 | 1221 | ||
1213 | enum wmi_preamble_policy { | 1222 | enum wmi_preamble_policy { |
1214 | WMI_IGNORE_BARKER_IN_ERP = 0, | 1223 | WMI_IGNORE_BARKER_IN_ERP = 0, |
1215 | WMI_DONOT_IGNORE_BARKER_IN_ERP | 1224 | WMI_FOLLOW_BARKER_IN_ERP, |
1216 | }; | 1225 | }; |
1217 | 1226 | ||
1218 | struct wmi_set_lpreamble_cmd { | 1227 | struct wmi_set_lpreamble_cmd { |
@@ -2128,6 +2137,10 @@ struct wmi_rx_frame_format_cmd { | |||
2128 | u8 reserved[1]; | 2137 | u8 reserved[1]; |
2129 | } __packed; | 2138 | } __packed; |
2130 | 2139 | ||
2140 | struct wmi_ap_hidden_ssid_cmd { | ||
2141 | u8 hidden_ssid; | ||
2142 | } __packed; | ||
2143 | |||
2131 | /* AP mode events */ | 2144 | /* AP mode events */ |
2132 | struct wmi_ap_set_apsd_cmd { | 2145 | struct wmi_ap_set_apsd_cmd { |
2133 | u8 enable; | 2146 | u8 enable; |
@@ -2413,6 +2426,8 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag, | |||
2413 | int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx, | 2426 | int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx, |
2414 | u16 listen_interval, | 2427 | u16 listen_interval, |
2415 | u16 listen_beacons); | 2428 | u16 listen_beacons); |
2429 | int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx, | ||
2430 | u16 bmiss_time, u16 num_beacons); | ||
2416 | int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode); | 2431 | int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode); |
2417 | int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u8 if_idx, u16 idle_period, | 2432 | int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u8 if_idx, u16 idle_period, |
2418 | u16 ps_poll_num, u16 dtim_policy, | 2433 | u16 ps_poll_num, u16 dtim_policy, |
@@ -2484,6 +2499,7 @@ u8 ath6kl_wmi_get_traffic_class(u8 user_priority); | |||
2484 | 2499 | ||
2485 | u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri); | 2500 | u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri); |
2486 | /* AP mode */ | 2501 | /* AP mode */ |
2502 | int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable); | ||
2487 | int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx, | 2503 | int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx, |
2488 | struct wmi_connect_cmd *p); | 2504 | struct wmi_connect_cmd *p); |
2489 | 2505 | ||
@@ -2505,9 +2521,6 @@ int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); | |||
2505 | int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, | 2521 | int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, |
2506 | u32 dur); | 2522 | u32 dur); |
2507 | 2523 | ||
2508 | int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, | ||
2509 | u32 wait, const u8 *data, u16 data_len); | ||
2510 | |||
2511 | int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, | 2524 | int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, |
2512 | u32 wait, const u8 *data, u16 data_len, | 2525 | u32 wait, const u8 *data, u16 data_len, |
2513 | u32 no_cck); | 2526 | u32 no_cck); |