diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-11-16 14:08:14 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-11-16 14:08:14 -0500 |
commit | 1e5023c7cc11158f74a637aa92897da954572a25 (patch) | |
tree | a0b2234b331abf9b2c80dbce20a018d537e541a6 | |
parent | dfbebe14428803402293d9a8bf1efef7221d8b78 (diff) | |
parent | ff7e68670c49b6404acc4fce6ca90d6c89ef0efe (diff) |
Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/Kconfig | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 370 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.h | 69 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/debug.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/hif.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/htc_mbox.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/htc_pipe.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/init.c | 92 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/main.c | 55 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/recovery.c | 160 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/sdio.c | 27 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/txrx.c | 47 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/usb.c | 32 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.c | 279 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.h | 78 |
18 files changed, 990 insertions, 285 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index d755a5e7ed2..26c4b722085 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig | |||
@@ -30,3 +30,12 @@ config ATH6KL_DEBUG | |||
30 | depends on ATH6KL | 30 | depends on ATH6KL |
31 | ---help--- | 31 | ---help--- |
32 | Enables debug support | 32 | Enables debug support |
33 | |||
34 | config ATH6KL_REGDOMAIN | ||
35 | bool "Atheros ath6kl regdomain support" | ||
36 | depends on ATH6KL | ||
37 | depends on CFG80211_CERTIFICATION_ONUS | ||
38 | ---help--- | ||
39 | Enabling this makes it possible to change the regdomain in | ||
40 | the firmware. This can be only enabled if regulatory requirements | ||
41 | are taken into account. | ||
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 8cae8886f17..cab0ec0d538 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile | |||
@@ -34,6 +34,7 @@ ath6kl_core-y += main.o | |||
34 | ath6kl_core-y += txrx.o | 34 | ath6kl_core-y += txrx.o |
35 | ath6kl_core-y += wmi.o | 35 | ath6kl_core-y += wmi.o |
36 | ath6kl_core-y += core.o | 36 | ath6kl_core-y += core.o |
37 | ath6kl_core-y += recovery.o | ||
37 | ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o | 38 | ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o |
38 | 39 | ||
39 | obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o | 40 | obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index d615f9f7506..83d8c5eabbe 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -147,15 +147,15 @@ static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif) | |||
147 | { | 147 | { |
148 | struct ath6kl *ar = vif->ar; | 148 | struct ath6kl *ar = vif->ar; |
149 | 149 | ||
150 | if (ar->state != ATH6KL_STATE_SCHED_SCAN) | 150 | if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags)) |
151 | return false; | 151 | return false; |
152 | 152 | ||
153 | del_timer_sync(&vif->sched_scan_timer); | 153 | del_timer_sync(&vif->sched_scan_timer); |
154 | 154 | ||
155 | ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, | 155 | if (ar->state == ATH6KL_STATE_RECOVERY) |
156 | ATH6KL_HOST_MODE_AWAKE); | 156 | return true; |
157 | 157 | ||
158 | ar->state = ATH6KL_STATE_ON; | 158 | ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false); |
159 | 159 | ||
160 | return true; | 160 | return true; |
161 | } | 161 | } |
@@ -369,17 +369,13 @@ static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type) | |||
369 | { | 369 | { |
370 | switch (type) { | 370 | switch (type) { |
371 | case NL80211_IFTYPE_STATION: | 371 | case NL80211_IFTYPE_STATION: |
372 | case NL80211_IFTYPE_P2P_CLIENT: | ||
372 | *nw_type = INFRA_NETWORK; | 373 | *nw_type = INFRA_NETWORK; |
373 | break; | 374 | break; |
374 | case NL80211_IFTYPE_ADHOC: | 375 | case NL80211_IFTYPE_ADHOC: |
375 | *nw_type = ADHOC_NETWORK; | 376 | *nw_type = ADHOC_NETWORK; |
376 | break; | 377 | break; |
377 | case NL80211_IFTYPE_AP: | 378 | case NL80211_IFTYPE_AP: |
378 | *nw_type = AP_NETWORK; | ||
379 | break; | ||
380 | case NL80211_IFTYPE_P2P_CLIENT: | ||
381 | *nw_type = INFRA_NETWORK; | ||
382 | break; | ||
383 | case NL80211_IFTYPE_P2P_GO: | 379 | case NL80211_IFTYPE_P2P_GO: |
384 | *nw_type = AP_NETWORK; | 380 | *nw_type = AP_NETWORK; |
385 | break; | 381 | break; |
@@ -1031,30 +1027,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, | |||
1031 | 1027 | ||
1032 | vif->scan_req = request; | 1028 | vif->scan_req = request; |
1033 | 1029 | ||
1034 | if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, | 1030 | ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, |
1035 | ar->fw_capabilities)) { | 1031 | WMI_LONG_SCAN, force_fg_scan, |
1036 | /* | 1032 | false, 0, |
1037 | * If capable of doing P2P mgmt operations using | 1033 | ATH6KL_FG_SCAN_INTERVAL, |
1038 | * station interface, send additional information like | 1034 | n_channels, channels, |
1039 | * supported rates to advertise and xmit rates for | 1035 | request->no_cck, |
1040 | * probe requests | 1036 | request->rates); |
1041 | */ | ||
1042 | ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, | ||
1043 | WMI_LONG_SCAN, force_fg_scan, | ||
1044 | false, 0, | ||
1045 | ATH6KL_FG_SCAN_INTERVAL, | ||
1046 | n_channels, channels, | ||
1047 | request->no_cck, | ||
1048 | request->rates); | ||
1049 | } else { | ||
1050 | ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, | ||
1051 | WMI_LONG_SCAN, force_fg_scan, | ||
1052 | false, 0, | ||
1053 | ATH6KL_FG_SCAN_INTERVAL, | ||
1054 | n_channels, channels); | ||
1055 | } | ||
1056 | if (ret) { | 1037 | if (ret) { |
1057 | ath6kl_err("wmi_startscan_cmd failed\n"); | 1038 | ath6kl_err("failed to start scan: %d\n", ret); |
1058 | vif->scan_req = NULL; | 1039 | vif->scan_req = NULL; |
1059 | } | 1040 | } |
1060 | 1041 | ||
@@ -1888,7 +1869,7 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif, | |||
1888 | struct cfg80211_wowlan *wow, u32 *filter) | 1869 | struct cfg80211_wowlan *wow, u32 *filter) |
1889 | { | 1870 | { |
1890 | int ret, pos; | 1871 | int ret, pos; |
1891 | u8 mask[WOW_MASK_SIZE]; | 1872 | u8 mask[WOW_PATTERN_SIZE]; |
1892 | u16 i; | 1873 | u16 i; |
1893 | 1874 | ||
1894 | /* Configure the patterns that we received from the user. */ | 1875 | /* Configure the patterns that we received from the user. */ |
@@ -2106,33 +2087,16 @@ static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif) | |||
2106 | return ret; | 2087 | return ret; |
2107 | } | 2088 | } |
2108 | 2089 | ||
2109 | static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | 2090 | static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif, |
2091 | struct cfg80211_wowlan *wow, u32 *filter) | ||
2110 | { | 2092 | { |
2093 | struct ath6kl *ar = vif->ar; | ||
2111 | struct in_device *in_dev; | 2094 | struct in_device *in_dev; |
2112 | struct in_ifaddr *ifa; | 2095 | struct in_ifaddr *ifa; |
2113 | struct ath6kl_vif *vif; | ||
2114 | int ret; | 2096 | int ret; |
2115 | u32 filter = 0; | ||
2116 | u16 i, bmiss_time; | 2097 | u16 i, bmiss_time; |
2117 | u8 index = 0; | ||
2118 | __be32 ips[MAX_IP_ADDRS]; | 2098 | __be32 ips[MAX_IP_ADDRS]; |
2119 | 2099 | u8 index = 0; | |
2120 | /* The FW currently can't support multi-vif WoW properly. */ | ||
2121 | if (ar->num_vif > 1) | ||
2122 | return -EIO; | ||
2123 | |||
2124 | vif = ath6kl_vif_first(ar); | ||
2125 | if (!vif) | ||
2126 | return -EIO; | ||
2127 | |||
2128 | if (!ath6kl_cfg80211_ready(vif)) | ||
2129 | return -EIO; | ||
2130 | |||
2131 | if (!test_bit(CONNECTED, &vif->flags)) | ||
2132 | return -ENOTCONN; | ||
2133 | |||
2134 | if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) | ||
2135 | return -EINVAL; | ||
2136 | 2100 | ||
2137 | if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) && | 2101 | if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) && |
2138 | test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, | 2102 | test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, |
@@ -2154,7 +2118,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
2154 | * the user. | 2118 | * the user. |
2155 | */ | 2119 | */ |
2156 | if (wow) | 2120 | if (wow) |
2157 | ret = ath6kl_wow_usr(ar, vif, wow, &filter); | 2121 | ret = ath6kl_wow_usr(ar, vif, wow, filter); |
2158 | else if (vif->nw_type == AP_NETWORK) | 2122 | else if (vif->nw_type == AP_NETWORK) |
2159 | ret = ath6kl_wow_ap(ar, vif); | 2123 | ret = ath6kl_wow_ap(ar, vif); |
2160 | else | 2124 | else |
@@ -2189,12 +2153,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
2189 | return ret; | 2153 | return ret; |
2190 | } | 2154 | } |
2191 | 2155 | ||
2192 | ar->state = ATH6KL_STATE_SUSPENDING; | ||
2193 | |||
2194 | /* Setup own IP addr for ARP agent. */ | 2156 | /* Setup own IP addr for ARP agent. */ |
2195 | in_dev = __in_dev_get_rtnl(vif->ndev); | 2157 | in_dev = __in_dev_get_rtnl(vif->ndev); |
2196 | if (!in_dev) | 2158 | if (!in_dev) |
2197 | goto skip_arp; | 2159 | return 0; |
2198 | 2160 | ||
2199 | ifa = in_dev->ifa_list; | 2161 | ifa = in_dev->ifa_list; |
2200 | memset(&ips, 0, sizeof(ips)); | 2162 | memset(&ips, 0, sizeof(ips)); |
@@ -2217,41 +2179,61 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
2217 | return ret; | 2179 | return ret; |
2218 | } | 2180 | } |
2219 | 2181 | ||
2220 | skip_arp: | 2182 | return ret; |
2221 | ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, | 2183 | } |
2184 | |||
2185 | static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | ||
2186 | { | ||
2187 | struct ath6kl_vif *first_vif, *vif; | ||
2188 | int ret = 0; | ||
2189 | u32 filter = 0; | ||
2190 | bool connected = false; | ||
2191 | |||
2192 | /* enter / leave wow suspend on first vif always */ | ||
2193 | first_vif = ath6kl_vif_first(ar); | ||
2194 | if (WARN_ON(unlikely(!first_vif)) || | ||
2195 | !ath6kl_cfg80211_ready(first_vif)) | ||
2196 | return -EIO; | ||
2197 | |||
2198 | if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) | ||
2199 | return -EINVAL; | ||
2200 | |||
2201 | /* install filters for each connected vif */ | ||
2202 | spin_lock_bh(&ar->list_lock); | ||
2203 | list_for_each_entry(vif, &ar->vif_list, list) { | ||
2204 | if (!test_bit(CONNECTED, &vif->flags) || | ||
2205 | !ath6kl_cfg80211_ready(vif)) | ||
2206 | continue; | ||
2207 | connected = true; | ||
2208 | |||
2209 | ret = ath6kl_wow_suspend_vif(vif, wow, &filter); | ||
2210 | if (ret) | ||
2211 | break; | ||
2212 | } | ||
2213 | spin_unlock_bh(&ar->list_lock); | ||
2214 | |||
2215 | if (!connected) | ||
2216 | return -ENOTCONN; | ||
2217 | else if (ret) | ||
2218 | return ret; | ||
2219 | |||
2220 | ar->state = ATH6KL_STATE_SUSPENDING; | ||
2221 | |||
2222 | ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx, | ||
2222 | ATH6KL_WOW_MODE_ENABLE, | 2223 | ATH6KL_WOW_MODE_ENABLE, |
2223 | filter, | 2224 | filter, |
2224 | WOW_HOST_REQ_DELAY); | 2225 | WOW_HOST_REQ_DELAY); |
2225 | if (ret) | 2226 | if (ret) |
2226 | return ret; | 2227 | return ret; |
2227 | 2228 | ||
2228 | ret = ath6kl_cfg80211_host_sleep(ar, vif); | 2229 | return ath6kl_cfg80211_host_sleep(ar, first_vif); |
2229 | if (ret) | ||
2230 | return ret; | ||
2231 | |||
2232 | return 0; | ||
2233 | } | 2230 | } |
2234 | 2231 | ||
2235 | static int ath6kl_wow_resume(struct ath6kl *ar) | 2232 | static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif) |
2236 | { | 2233 | { |
2237 | struct ath6kl_vif *vif; | 2234 | struct ath6kl *ar = vif->ar; |
2238 | int ret; | 2235 | int ret; |
2239 | 2236 | ||
2240 | vif = ath6kl_vif_first(ar); | ||
2241 | if (!vif) | ||
2242 | return -EIO; | ||
2243 | |||
2244 | ar->state = ATH6KL_STATE_RESUMING; | ||
2245 | |||
2246 | ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, | ||
2247 | ATH6KL_HOST_MODE_AWAKE); | ||
2248 | if (ret) { | ||
2249 | ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", | ||
2250 | ret); | ||
2251 | ar->state = ATH6KL_STATE_WOW; | ||
2252 | return ret; | ||
2253 | } | ||
2254 | |||
2255 | if (vif->nw_type != AP_NETWORK) { | 2237 | if (vif->nw_type != AP_NETWORK) { |
2256 | ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, | 2238 | ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, |
2257 | 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); | 2239 | 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); |
@@ -2269,13 +2251,11 @@ static int ath6kl_wow_resume(struct ath6kl *ar) | |||
2269 | return ret; | 2251 | return ret; |
2270 | } | 2252 | } |
2271 | 2253 | ||
2272 | ar->state = ATH6KL_STATE_ON; | ||
2273 | |||
2274 | if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) && | 2254 | if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) && |
2275 | test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, | 2255 | test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, |
2276 | ar->fw_capabilities)) { | 2256 | ar->fw_capabilities)) { |
2277 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, | 2257 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, |
2278 | vif->fw_vif_idx, true); | 2258 | vif->fw_vif_idx, true); |
2279 | if (ret) | 2259 | if (ret) |
2280 | return ret; | 2260 | return ret; |
2281 | } | 2261 | } |
@@ -2285,6 +2265,48 @@ static int ath6kl_wow_resume(struct ath6kl *ar) | |||
2285 | return 0; | 2265 | return 0; |
2286 | } | 2266 | } |
2287 | 2267 | ||
2268 | static int ath6kl_wow_resume(struct ath6kl *ar) | ||
2269 | { | ||
2270 | struct ath6kl_vif *vif; | ||
2271 | int ret; | ||
2272 | |||
2273 | vif = ath6kl_vif_first(ar); | ||
2274 | if (WARN_ON(unlikely(!vif)) || | ||
2275 | !ath6kl_cfg80211_ready(vif)) | ||
2276 | return -EIO; | ||
2277 | |||
2278 | ar->state = ATH6KL_STATE_RESUMING; | ||
2279 | |||
2280 | ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, | ||
2281 | ATH6KL_HOST_MODE_AWAKE); | ||
2282 | if (ret) { | ||
2283 | ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", | ||
2284 | ret); | ||
2285 | goto cleanup; | ||
2286 | } | ||
2287 | |||
2288 | spin_lock_bh(&ar->list_lock); | ||
2289 | list_for_each_entry(vif, &ar->vif_list, list) { | ||
2290 | if (!test_bit(CONNECTED, &vif->flags) || | ||
2291 | !ath6kl_cfg80211_ready(vif)) | ||
2292 | continue; | ||
2293 | ret = ath6kl_wow_resume_vif(vif); | ||
2294 | if (ret) | ||
2295 | break; | ||
2296 | } | ||
2297 | spin_unlock_bh(&ar->list_lock); | ||
2298 | |||
2299 | if (ret) | ||
2300 | goto cleanup; | ||
2301 | |||
2302 | ar->state = ATH6KL_STATE_ON; | ||
2303 | return 0; | ||
2304 | |||
2305 | cleanup: | ||
2306 | ar->state = ATH6KL_STATE_WOW; | ||
2307 | return ret; | ||
2308 | } | ||
2309 | |||
2288 | static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) | 2310 | static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) |
2289 | { | 2311 | { |
2290 | struct ath6kl_vif *vif; | 2312 | struct ath6kl_vif *vif; |
@@ -2421,13 +2443,6 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, | |||
2421 | 2443 | ||
2422 | break; | 2444 | break; |
2423 | 2445 | ||
2424 | case ATH6KL_CFG_SUSPEND_SCHED_SCAN: | ||
2425 | /* | ||
2426 | * Nothing needed for schedule scan, firmware is already in | ||
2427 | * wow mode and sleeping most of the time. | ||
2428 | */ | ||
2429 | break; | ||
2430 | |||
2431 | default: | 2446 | default: |
2432 | break; | 2447 | break; |
2433 | } | 2448 | } |
@@ -2475,9 +2490,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) | |||
2475 | } | 2490 | } |
2476 | break; | 2491 | break; |
2477 | 2492 | ||
2478 | case ATH6KL_STATE_SCHED_SCAN: | ||
2479 | break; | ||
2480 | |||
2481 | default: | 2493 | default: |
2482 | break; | 2494 | break; |
2483 | } | 2495 | } |
@@ -2494,14 +2506,23 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy, | |||
2494 | { | 2506 | { |
2495 | struct ath6kl *ar = wiphy_priv(wiphy); | 2507 | struct ath6kl *ar = wiphy_priv(wiphy); |
2496 | 2508 | ||
2509 | ath6kl_recovery_suspend(ar); | ||
2510 | |||
2497 | return ath6kl_hif_suspend(ar, wow); | 2511 | return ath6kl_hif_suspend(ar, wow); |
2498 | } | 2512 | } |
2499 | 2513 | ||
2500 | static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) | 2514 | static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) |
2501 | { | 2515 | { |
2502 | struct ath6kl *ar = wiphy_priv(wiphy); | 2516 | struct ath6kl *ar = wiphy_priv(wiphy); |
2517 | int err; | ||
2518 | |||
2519 | err = ath6kl_hif_resume(ar); | ||
2520 | if (err) | ||
2521 | return err; | ||
2522 | |||
2523 | ath6kl_recovery_resume(ar); | ||
2503 | 2524 | ||
2504 | return ath6kl_hif_resume(ar); | 2525 | return 0; |
2505 | } | 2526 | } |
2506 | 2527 | ||
2507 | /* | 2528 | /* |
@@ -2738,6 +2759,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2738 | int res; | 2759 | int res; |
2739 | int i, ret; | 2760 | int i, ret; |
2740 | u16 rsn_capab = 0; | 2761 | u16 rsn_capab = 0; |
2762 | int inactivity_timeout = 0; | ||
2741 | 2763 | ||
2742 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); | 2764 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); |
2743 | 2765 | ||
@@ -2874,8 +2896,15 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2874 | } | 2896 | } |
2875 | 2897 | ||
2876 | if (info->inactivity_timeout) { | 2898 | if (info->inactivity_timeout) { |
2899 | |||
2900 | inactivity_timeout = info->inactivity_timeout; | ||
2901 | |||
2902 | if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS) | ||
2903 | inactivity_timeout = DIV_ROUND_UP(inactivity_timeout, | ||
2904 | 60); | ||
2905 | |||
2877 | res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx, | 2906 | res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx, |
2878 | info->inactivity_timeout); | 2907 | inactivity_timeout); |
2879 | if (res < 0) | 2908 | if (res < 0) |
2880 | return res; | 2909 | return res; |
2881 | } | 2910 | } |
@@ -2897,6 +2926,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2897 | WLAN_EID_RSN, WMI_RSN_IE_CAPB, | 2926 | WLAN_EID_RSN, WMI_RSN_IE_CAPB, |
2898 | (const u8 *) &rsn_capab, | 2927 | (const u8 *) &rsn_capab, |
2899 | sizeof(rsn_capab)); | 2928 | sizeof(rsn_capab)); |
2929 | vif->rsn_capab = rsn_capab; | ||
2900 | if (res < 0) | 2930 | if (res < 0) |
2901 | return res; | 2931 | return res; |
2902 | } | 2932 | } |
@@ -3210,7 +3240,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, | |||
3210 | struct ath6kl *ar = ath6kl_priv(dev); | 3240 | struct ath6kl *ar = ath6kl_priv(dev); |
3211 | struct ath6kl_vif *vif = netdev_priv(dev); | 3241 | struct ath6kl_vif *vif = netdev_priv(dev); |
3212 | u16 interval; | 3242 | u16 interval; |
3213 | int ret; | 3243 | int ret, rssi_thold; |
3214 | 3244 | ||
3215 | if (ar->state != ATH6KL_STATE_ON) | 3245 | if (ar->state != ATH6KL_STATE_ON) |
3216 | return -EIO; | 3246 | return -EIO; |
@@ -3218,10 +3248,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, | |||
3218 | if (vif->sme_state != SME_DISCONNECTED) | 3248 | if (vif->sme_state != SME_DISCONNECTED) |
3219 | return -EBUSY; | 3249 | return -EBUSY; |
3220 | 3250 | ||
3221 | /* The FW currently can't support multi-vif WoW properly. */ | ||
3222 | if (ar->num_vif > 1) | ||
3223 | return -EIO; | ||
3224 | |||
3225 | ath6kl_cfg80211_scan_complete_event(vif, true); | 3251 | ath6kl_cfg80211_scan_complete_event(vif, true); |
3226 | 3252 | ||
3227 | ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, | 3253 | ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, |
@@ -3243,6 +3269,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, | |||
3243 | return ret; | 3269 | return ret; |
3244 | } | 3270 | } |
3245 | 3271 | ||
3272 | if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, | ||
3273 | ar->fw_capabilities)) { | ||
3274 | if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) | ||
3275 | rssi_thold = 0; | ||
3276 | else if (request->rssi_thold < -127) | ||
3277 | rssi_thold = -127; | ||
3278 | else | ||
3279 | rssi_thold = request->rssi_thold; | ||
3280 | |||
3281 | ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, | ||
3282 | rssi_thold); | ||
3283 | if (ret) { | ||
3284 | ath6kl_err("failed to set RSSI threshold for scan\n"); | ||
3285 | return ret; | ||
3286 | } | ||
3287 | } | ||
3288 | |||
3246 | /* fw uses seconds, also make sure that it's >0 */ | 3289 | /* fw uses seconds, also make sure that it's >0 */ |
3247 | interval = max_t(u16, 1, request->interval / 1000); | 3290 | interval = max_t(u16, 1, request->interval / 1000); |
3248 | 3291 | ||
@@ -3250,15 +3293,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, | |||
3250 | interval, interval, | 3293 | interval, interval, |
3251 | vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); | 3294 | vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); |
3252 | 3295 | ||
3253 | ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, | ||
3254 | ATH6KL_WOW_MODE_ENABLE, | ||
3255 | WOW_FILTER_SSID, | ||
3256 | WOW_HOST_REQ_DELAY); | ||
3257 | if (ret) { | ||
3258 | ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret); | ||
3259 | return ret; | ||
3260 | } | ||
3261 | |||
3262 | /* this also clears IE in fw if it's not set */ | 3296 | /* this also clears IE in fw if it's not set */ |
3263 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, | 3297 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, |
3264 | WMI_FRAME_PROBE_REQ, | 3298 | WMI_FRAME_PROBE_REQ, |
@@ -3269,17 +3303,13 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, | |||
3269 | return ret; | 3303 | return ret; |
3270 | } | 3304 | } |
3271 | 3305 | ||
3272 | ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, | 3306 | ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true); |
3273 | ATH6KL_HOST_MODE_ASLEEP); | 3307 | if (ret) |
3274 | if (ret) { | ||
3275 | ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n", | ||
3276 | ret); | ||
3277 | return ret; | 3308 | return ret; |
3278 | } | ||
3279 | 3309 | ||
3280 | ar->state = ATH6KL_STATE_SCHED_SCAN; | 3310 | set_bit(SCHED_SCANNING, &vif->flags); |
3281 | 3311 | ||
3282 | return ret; | 3312 | return 0; |
3283 | } | 3313 | } |
3284 | 3314 | ||
3285 | static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, | 3315 | static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, |
@@ -3308,6 +3338,27 @@ static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy, | |||
3308 | mask); | 3338 | mask); |
3309 | } | 3339 | } |
3310 | 3340 | ||
3341 | static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy, | ||
3342 | struct net_device *dev, | ||
3343 | u32 rate, u32 pkts, u32 intvl) | ||
3344 | { | ||
3345 | struct ath6kl *ar = ath6kl_priv(dev); | ||
3346 | struct ath6kl_vif *vif = netdev_priv(dev); | ||
3347 | |||
3348 | if (vif->nw_type != INFRA_NETWORK || | ||
3349 | !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities)) | ||
3350 | return -EOPNOTSUPP; | ||
3351 | |||
3352 | if (vif->sme_state != SME_CONNECTED) | ||
3353 | return -ENOTCONN; | ||
3354 | |||
3355 | /* save this since the firmware won't report the interval */ | ||
3356 | vif->txe_intvl = intvl; | ||
3357 | |||
3358 | return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx, | ||
3359 | rate, pkts, intvl); | ||
3360 | } | ||
3361 | |||
3311 | static const struct ieee80211_txrx_stypes | 3362 | static const struct ieee80211_txrx_stypes |
3312 | ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { | 3363 | ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { |
3313 | [NL80211_IFTYPE_STATION] = { | 3364 | [NL80211_IFTYPE_STATION] = { |
@@ -3374,6 +3425,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { | |||
3374 | .sched_scan_start = ath6kl_cfg80211_sscan_start, | 3425 | .sched_scan_start = ath6kl_cfg80211_sscan_start, |
3375 | .sched_scan_stop = ath6kl_cfg80211_sscan_stop, | 3426 | .sched_scan_stop = ath6kl_cfg80211_sscan_stop, |
3376 | .set_bitrate_mask = ath6kl_cfg80211_set_bitrate, | 3427 | .set_bitrate_mask = ath6kl_cfg80211_set_bitrate, |
3428 | .set_cqm_txe_config = ath6kl_cfg80211_set_txe_config, | ||
3377 | }; | 3429 | }; |
3378 | 3430 | ||
3379 | void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) | 3431 | void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) |
@@ -3394,16 +3446,22 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) | |||
3394 | break; | 3446 | break; |
3395 | } | 3447 | } |
3396 | 3448 | ||
3397 | if (test_bit(CONNECTED, &vif->flags) || | 3449 | if (vif->ar->state != ATH6KL_STATE_RECOVERY && |
3398 | test_bit(CONNECT_PEND, &vif->flags)) | 3450 | (test_bit(CONNECTED, &vif->flags) || |
3451 | test_bit(CONNECT_PEND, &vif->flags))) | ||
3399 | ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx); | 3452 | ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx); |
3400 | 3453 | ||
3401 | vif->sme_state = SME_DISCONNECTED; | 3454 | vif->sme_state = SME_DISCONNECTED; |
3402 | clear_bit(CONNECTED, &vif->flags); | 3455 | clear_bit(CONNECTED, &vif->flags); |
3403 | clear_bit(CONNECT_PEND, &vif->flags); | 3456 | clear_bit(CONNECT_PEND, &vif->flags); |
3404 | 3457 | ||
3458 | /* Stop netdev queues, needed during recovery */ | ||
3459 | netif_stop_queue(vif->ndev); | ||
3460 | netif_carrier_off(vif->ndev); | ||
3461 | |||
3405 | /* disable scanning */ | 3462 | /* disable scanning */ |
3406 | if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, | 3463 | if (vif->ar->state != ATH6KL_STATE_RECOVERY && |
3464 | ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, | ||
3407 | 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0) | 3465 | 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0) |
3408 | ath6kl_warn("failed to disable scan during stop\n"); | 3466 | ath6kl_warn("failed to disable scan during stop\n"); |
3409 | 3467 | ||
@@ -3415,7 +3473,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) | |||
3415 | struct ath6kl_vif *vif; | 3473 | struct ath6kl_vif *vif; |
3416 | 3474 | ||
3417 | vif = ath6kl_vif_first(ar); | 3475 | vif = ath6kl_vif_first(ar); |
3418 | if (!vif) { | 3476 | if (!vif && ar->state != ATH6KL_STATE_RECOVERY) { |
3419 | /* save the current power mode before enabling power save */ | 3477 | /* save the current power mode before enabling power save */ |
3420 | ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; | 3478 | ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; |
3421 | 3479 | ||
@@ -3433,6 +3491,56 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) | |||
3433 | ath6kl_cfg80211_stop(vif); | 3491 | ath6kl_cfg80211_stop(vif); |
3434 | } | 3492 | } |
3435 | 3493 | ||
3494 | static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, | ||
3495 | struct regulatory_request *request) | ||
3496 | { | ||
3497 | struct ath6kl *ar = wiphy_priv(wiphy); | ||
3498 | u32 rates[IEEE80211_NUM_BANDS]; | ||
3499 | int ret, i; | ||
3500 | |||
3501 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
3502 | "cfg reg_notify %c%c%s%s initiator %d hint_type %d\n", | ||
3503 | request->alpha2[0], request->alpha2[1], | ||
3504 | request->intersect ? " intersect" : "", | ||
3505 | request->processed ? " processed" : "", | ||
3506 | request->initiator, request->user_reg_hint_type); | ||
3507 | |||
3508 | /* | ||
3509 | * As firmware is not able intersect regdoms, we can only listen to | ||
3510 | * cellular hints. | ||
3511 | */ | ||
3512 | if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE) | ||
3513 | return -EOPNOTSUPP; | ||
3514 | |||
3515 | ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2); | ||
3516 | if (ret) { | ||
3517 | ath6kl_err("failed to set regdomain: %d\n", ret); | ||
3518 | return ret; | ||
3519 | } | ||
3520 | |||
3521 | /* | ||
3522 | * Firmware will apply the regdomain change only after a scan is | ||
3523 | * issued and it will send a WMI_REGDOMAIN_EVENTID when it has been | ||
3524 | * changed. | ||
3525 | */ | ||
3526 | |||
3527 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
3528 | if (wiphy->bands[i]) | ||
3529 | rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; | ||
3530 | |||
3531 | |||
3532 | ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false, | ||
3533 | false, 0, ATH6KL_FG_SCAN_INTERVAL, | ||
3534 | 0, NULL, false, rates); | ||
3535 | if (ret) { | ||
3536 | ath6kl_err("failed to start scan for a regdomain change: %d\n", | ||
3537 | ret); | ||
3538 | return ret; | ||
3539 | } | ||
3540 | |||
3541 | return 0; | ||
3542 | } | ||
3543 | |||
3436 | static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) | 3544 | static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) |
3437 | { | 3545 | { |
3438 | vif->aggr_cntxt = aggr_init(vif); | 3546 | vif->aggr_cntxt = aggr_init(vif); |
@@ -3505,9 +3613,13 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, | |||
3505 | vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true; | 3613 | vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true; |
3506 | 3614 | ||
3507 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); | 3615 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); |
3508 | if (fw_vif_idx != 0) | 3616 | if (fw_vif_idx != 0) { |
3509 | ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) | | 3617 | ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) | |
3510 | 0x2; | 3618 | 0x2; |
3619 | if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, | ||
3620 | ar->fw_capabilities)) | ||
3621 | ndev->dev_addr[4] ^= 0x80; | ||
3622 | } | ||
3511 | 3623 | ||
3512 | init_netdev(ndev); | 3624 | init_netdev(ndev); |
3513 | 3625 | ||
@@ -3561,6 +3673,12 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | |||
3561 | BIT(NL80211_IFTYPE_P2P_CLIENT); | 3673 | BIT(NL80211_IFTYPE_P2P_CLIENT); |
3562 | } | 3674 | } |
3563 | 3675 | ||
3676 | if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) && | ||
3677 | test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) { | ||
3678 | wiphy->reg_notifier = ath6kl_cfg80211_reg_notify; | ||
3679 | ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS; | ||
3680 | } | ||
3681 | |||
3564 | /* max num of ssids that can be probed during scanning */ | 3682 | /* max num of ssids that can be probed during scanning */ |
3565 | wiphy->max_scan_ssids = MAX_PROBED_SSIDS; | 3683 | wiphy->max_scan_ssids = MAX_PROBED_SSIDS; |
3566 | 3684 | ||
@@ -3606,7 +3724,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | |||
3606 | ath6kl_band_5ghz.ht_cap.ht_supported = false; | 3724 | ath6kl_band_5ghz.ht_cap.ht_supported = false; |
3607 | } | 3725 | } |
3608 | 3726 | ||
3609 | if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) { | 3727 | if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) { |
3610 | ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; | 3728 | ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; |
3611 | ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; | 3729 | ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; |
3612 | ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; | 3730 | ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; |
@@ -3645,7 +3763,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | |||
3645 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | | 3763 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | |
3646 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | 3764 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; |
3647 | 3765 | ||
3648 | if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) | 3766 | if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities)) |
3649 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | 3767 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; |
3650 | 3768 | ||
3651 | if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, | 3769 | if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 780f77775a9..e5e70f3a8ca 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h | |||
@@ -22,7 +22,6 @@ enum ath6kl_cfg_suspend_mode { | |||
22 | ATH6KL_CFG_SUSPEND_DEEPSLEEP, | 22 | ATH6KL_CFG_SUSPEND_DEEPSLEEP, |
23 | ATH6KL_CFG_SUSPEND_CUTPOWER, | 23 | ATH6KL_CFG_SUSPEND_CUTPOWER, |
24 | ATH6KL_CFG_SUSPEND_WOW, | 24 | ATH6KL_CFG_SUSPEND_WOW, |
25 | ATH6KL_CFG_SUSPEND_SCHED_SCAN, | ||
26 | }; | 25 | }; |
27 | 26 | ||
28 | struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, | 27 | struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, |
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 82c4dd2a960..4b46adbe8c9 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c | |||
@@ -33,6 +33,8 @@ static unsigned int wow_mode; | |||
33 | static unsigned int uart_debug; | 33 | static unsigned int uart_debug; |
34 | static unsigned int ath6kl_p2p; | 34 | static unsigned int ath6kl_p2p; |
35 | static unsigned int testmode; | 35 | static unsigned int testmode; |
36 | static unsigned int recovery_enable; | ||
37 | static unsigned int heart_beat_poll; | ||
36 | 38 | ||
37 | module_param(debug_mask, uint, 0644); | 39 | module_param(debug_mask, uint, 0644); |
38 | module_param(suspend_mode, uint, 0644); | 40 | module_param(suspend_mode, uint, 0644); |
@@ -40,6 +42,12 @@ module_param(wow_mode, uint, 0644); | |||
40 | module_param(uart_debug, uint, 0644); | 42 | module_param(uart_debug, uint, 0644); |
41 | module_param(ath6kl_p2p, uint, 0644); | 43 | module_param(ath6kl_p2p, uint, 0644); |
42 | module_param(testmode, uint, 0644); | 44 | module_param(testmode, uint, 0644); |
45 | module_param(recovery_enable, uint, 0644); | ||
46 | module_param(heart_beat_poll, uint, 0644); | ||
47 | MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error"); | ||
48 | MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \ | ||
49 | "polling. This also specifies the polling interval in" \ | ||
50 | "msecs. Set reocvery_enable for this to be effective"); | ||
43 | 51 | ||
44 | void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) | 52 | void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) |
45 | { | 53 | { |
@@ -202,6 +210,17 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) | |||
202 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", | 210 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", |
203 | __func__, wdev->netdev->name, wdev->netdev, ar); | 211 | __func__, wdev->netdev->name, wdev->netdev, ar); |
204 | 212 | ||
213 | ar->fw_recovery.enable = !!recovery_enable; | ||
214 | if (!ar->fw_recovery.enable) | ||
215 | return ret; | ||
216 | |||
217 | if (heart_beat_poll && | ||
218 | test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, | ||
219 | ar->fw_capabilities)) | ||
220 | ar->fw_recovery.hb_poll = heart_beat_poll; | ||
221 | |||
222 | ath6kl_recovery_init(ar); | ||
223 | |||
205 | return ret; | 224 | return ret; |
206 | 225 | ||
207 | err_rxbuf_cleanup: | 226 | err_rxbuf_cleanup: |
@@ -291,6 +310,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar) | |||
291 | { | 310 | { |
292 | ath6kl_hif_power_off(ar); | 311 | ath6kl_hif_power_off(ar); |
293 | 312 | ||
313 | ath6kl_recovery_cleanup(ar); | ||
314 | |||
294 | destroy_workqueue(ar->ath6kl_wq); | 315 | destroy_workqueue(ar->ath6kl_wq); |
295 | 316 | ||
296 | if (ar->htc_target) | 317 | if (ar->htc_target) |
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index cec49a31029..189d8faf8c8 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -115,6 +115,27 @@ enum ath6kl_fw_capability { | |||
115 | */ | 115 | */ |
116 | ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, | 116 | ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, |
117 | 117 | ||
118 | /* Firmware supports filtering BSS results by RSSI */ | ||
119 | ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, | ||
120 | |||
121 | /* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */ | ||
122 | ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, | ||
123 | |||
124 | /* Firmware supports TX error rate notification */ | ||
125 | ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, | ||
126 | |||
127 | /* supports WMI_SET_REGDOMAIN_CMDID command */ | ||
128 | ATH6KL_FW_CAPABILITY_REGDOMAIN, | ||
129 | |||
130 | /* Firmware supports sched scan decoupled from host sleep */ | ||
131 | ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, | ||
132 | |||
133 | /* | ||
134 | * Firmware capability for hang detection through heart beat | ||
135 | * challenge messages. | ||
136 | */ | ||
137 | ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, | ||
138 | |||
118 | /* this needs to be last */ | 139 | /* this needs to be last */ |
119 | ATH6KL_FW_CAPABILITY_MAX, | 140 | ATH6KL_FW_CAPABILITY_MAX, |
120 | }; | 141 | }; |
@@ -128,11 +149,15 @@ struct ath6kl_fw_ie { | |||
128 | }; | 149 | }; |
129 | 150 | ||
130 | enum ath6kl_hw_flags { | 151 | enum ath6kl_hw_flags { |
131 | ATH6KL_HW_FLAG_64BIT_RATES = BIT(0), | 152 | ATH6KL_HW_64BIT_RATES = BIT(0), |
153 | ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1), | ||
154 | ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2), | ||
155 | ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3), | ||
132 | }; | 156 | }; |
133 | 157 | ||
134 | #define ATH6KL_FW_API2_FILE "fw-2.bin" | 158 | #define ATH6KL_FW_API2_FILE "fw-2.bin" |
135 | #define ATH6KL_FW_API3_FILE "fw-3.bin" | 159 | #define ATH6KL_FW_API3_FILE "fw-3.bin" |
160 | #define ATH6KL_FW_API4_FILE "fw-4.bin" | ||
136 | 161 | ||
137 | /* AR6003 1.0 definitions */ | 162 | /* AR6003 1.0 definitions */ |
138 | #define AR6003_HW_1_0_VERSION 0x300002ba | 163 | #define AR6003_HW_1_0_VERSION 0x300002ba |
@@ -186,6 +211,13 @@ enum ath6kl_hw_flags { | |||
186 | #define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \ | 211 | #define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \ |
187 | AR6004_HW_1_2_FW_DIR "/bdata.bin" | 212 | AR6004_HW_1_2_FW_DIR "/bdata.bin" |
188 | 213 | ||
214 | /* AR6004 1.3 definitions */ | ||
215 | #define AR6004_HW_1_3_VERSION 0x31c8088a | ||
216 | #define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3" | ||
217 | #define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin" | ||
218 | #define AR6004_HW_1_3_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" | ||
219 | #define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" | ||
220 | |||
189 | /* Per STA data, used in AP mode */ | 221 | /* Per STA data, used in AP mode */ |
190 | #define STA_PS_AWAKE BIT(0) | 222 | #define STA_PS_AWAKE BIT(0) |
191 | #define STA_PS_SLEEP BIT(1) | 223 | #define STA_PS_SLEEP BIT(1) |
@@ -536,6 +568,7 @@ enum ath6kl_vif_state { | |||
536 | HOST_SLEEP_MODE_CMD_PROCESSED, | 568 | HOST_SLEEP_MODE_CMD_PROCESSED, |
537 | NETDEV_MCAST_ALL_ON, | 569 | NETDEV_MCAST_ALL_ON, |
538 | NETDEV_MCAST_ALL_OFF, | 570 | NETDEV_MCAST_ALL_OFF, |
571 | SCHED_SCANNING, | ||
539 | }; | 572 | }; |
540 | 573 | ||
541 | struct ath6kl_vif { | 574 | struct ath6kl_vif { |
@@ -580,11 +613,13 @@ struct ath6kl_vif { | |||
580 | u16 assoc_bss_beacon_int; | 613 | u16 assoc_bss_beacon_int; |
581 | u16 listen_intvl_t; | 614 | u16 listen_intvl_t; |
582 | u16 bmiss_time_t; | 615 | u16 bmiss_time_t; |
616 | u32 txe_intvl; | ||
583 | u16 bg_scan_period; | 617 | u16 bg_scan_period; |
584 | u8 assoc_bss_dtim_period; | 618 | u8 assoc_bss_dtim_period; |
585 | struct net_device_stats net_stats; | 619 | struct net_device_stats net_stats; |
586 | struct target_stats target_stats; | 620 | struct target_stats target_stats; |
587 | struct wmi_connect_cmd profile; | 621 | struct wmi_connect_cmd profile; |
622 | u16 rsn_capab; | ||
588 | 623 | ||
589 | struct list_head mc_filter; | 624 | struct list_head mc_filter; |
590 | }; | 625 | }; |
@@ -609,6 +644,7 @@ enum ath6kl_dev_state { | |||
609 | SKIP_SCAN, | 644 | SKIP_SCAN, |
610 | ROAM_TBL_PEND, | 645 | ROAM_TBL_PEND, |
611 | FIRST_BOOT, | 646 | FIRST_BOOT, |
647 | RECOVERY_CLEANUP, | ||
612 | }; | 648 | }; |
613 | 649 | ||
614 | enum ath6kl_state { | 650 | enum ath6kl_state { |
@@ -619,7 +655,16 @@ enum ath6kl_state { | |||
619 | ATH6KL_STATE_DEEPSLEEP, | 655 | ATH6KL_STATE_DEEPSLEEP, |
620 | ATH6KL_STATE_CUTPOWER, | 656 | ATH6KL_STATE_CUTPOWER, |
621 | ATH6KL_STATE_WOW, | 657 | ATH6KL_STATE_WOW, |
622 | ATH6KL_STATE_SCHED_SCAN, | 658 | ATH6KL_STATE_RECOVERY, |
659 | }; | ||
660 | |||
661 | /* Fw error recovery */ | ||
662 | #define ATH6KL_HB_RESP_MISS_THRES 5 | ||
663 | |||
664 | enum ath6kl_fw_err { | ||
665 | ATH6KL_FW_ASSERT, | ||
666 | ATH6KL_FW_HB_RESP_FAILURE, | ||
667 | ATH6KL_FW_EP_FULL, | ||
623 | }; | 668 | }; |
624 | 669 | ||
625 | struct ath6kl { | 670 | struct ath6kl { |
@@ -679,6 +724,7 @@ struct ath6kl { | |||
679 | struct ath6kl_req_key ap_mode_bkey; | 724 | struct ath6kl_req_key ap_mode_bkey; |
680 | struct sk_buff_head mcastpsq; | 725 | struct sk_buff_head mcastpsq; |
681 | u32 want_ch_switch; | 726 | u32 want_ch_switch; |
727 | u16 last_ch; | ||
682 | 728 | ||
683 | /* | 729 | /* |
684 | * FIXME: protects access to mcastpsq but is actually useless as | 730 | * FIXME: protects access to mcastpsq but is actually useless as |
@@ -764,6 +810,17 @@ struct ath6kl { | |||
764 | 810 | ||
765 | bool wiphy_registered; | 811 | bool wiphy_registered; |
766 | 812 | ||
813 | struct ath6kl_fw_recovery { | ||
814 | struct work_struct recovery_work; | ||
815 | unsigned long err_reason; | ||
816 | unsigned long hb_poll; | ||
817 | struct timer_list hb_timer; | ||
818 | u32 seq_num; | ||
819 | bool hb_pending; | ||
820 | u8 hb_misscnt; | ||
821 | bool enable; | ||
822 | } fw_recovery; | ||
823 | |||
767 | #ifdef CONFIG_ATH6KL_DEBUG | 824 | #ifdef CONFIG_ATH6KL_DEBUG |
768 | struct { | 825 | struct { |
769 | struct sk_buff_head fwlog_queue; | 826 | struct sk_buff_head fwlog_queue; |
@@ -899,4 +956,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type); | |||
899 | void ath6kl_core_cleanup(struct ath6kl *ar); | 956 | void ath6kl_core_cleanup(struct ath6kl *ar); |
900 | void ath6kl_core_destroy(struct ath6kl *ar); | 957 | void ath6kl_core_destroy(struct ath6kl *ar); |
901 | 958 | ||
959 | /* Fw error recovery */ | ||
960 | void ath6kl_init_hw_restart(struct ath6kl *ar); | ||
961 | void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason); | ||
962 | void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie); | ||
963 | void ath6kl_recovery_init(struct ath6kl *ar); | ||
964 | void ath6kl_recovery_cleanup(struct ath6kl *ar); | ||
965 | void ath6kl_recovery_suspend(struct ath6kl *ar); | ||
966 | void ath6kl_recovery_resume(struct ath6kl *ar); | ||
902 | #endif /* CORE_H */ | 967 | #endif /* CORE_H */ |
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 49639d8266c..f97cd4ead54 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h | |||
@@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK { | |||
44 | ATH6KL_DBG_SUSPEND = BIT(20), | 44 | ATH6KL_DBG_SUSPEND = BIT(20), |
45 | ATH6KL_DBG_USB = BIT(21), | 45 | ATH6KL_DBG_USB = BIT(21), |
46 | ATH6KL_DBG_USB_BULK = BIT(22), | 46 | ATH6KL_DBG_USB_BULK = BIT(22), |
47 | ATH6KL_DBG_RECOVERY = BIT(23), | ||
47 | ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ | 48 | ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ |
48 | }; | 49 | }; |
49 | 50 | ||
diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index 9e47c4a138a..a6b614421fa 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c | |||
@@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) | |||
136 | 136 | ||
137 | ath6kl_hif_dump_fw_crash(dev->ar); | 137 | ath6kl_hif_dump_fw_crash(dev->ar); |
138 | ath6kl_read_fwlogs(dev->ar); | 138 | ath6kl_read_fwlogs(dev->ar); |
139 | ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT); | ||
139 | 140 | ||
140 | return ret; | 141 | return ret; |
141 | } | 142 | } |
@@ -693,11 +694,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev) | |||
693 | ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n", | 694 | ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n", |
694 | dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); | 695 | dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); |
695 | 696 | ||
696 | /* usb doesn't support enabling interrupts */ | ||
697 | /* FIXME: remove check once USB support is implemented */ | ||
698 | if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) | ||
699 | return 0; | ||
700 | |||
701 | status = ath6kl_hif_disable_intrs(dev); | 697 | status = ath6kl_hif_disable_intrs(dev); |
702 | 698 | ||
703 | fail_setup: | 699 | fail_setup: |
diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index cd0e1ba410d..fbb78dfe078 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c | |||
@@ -2492,7 +2492,8 @@ static int ath6kl_htc_mbox_conn_service(struct htc_target *target, | |||
2492 | max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); | 2492 | max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); |
2493 | } | 2493 | } |
2494 | 2494 | ||
2495 | if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { | 2495 | if (WARN_ON_ONCE(assigned_ep == ENDPOINT_UNUSED || |
2496 | assigned_ep >= ENDPOINT_MAX || !max_msg_sz)) { | ||
2496 | status = -ENOMEM; | 2497 | status = -ENOMEM; |
2497 | goto fail_tx; | 2498 | goto fail_tx; |
2498 | } | 2499 | } |
@@ -2655,12 +2656,6 @@ static int ath6kl_htc_mbox_wait_target(struct htc_target *target) | |||
2655 | struct htc_service_connect_resp resp; | 2656 | struct htc_service_connect_resp resp; |
2656 | int status; | 2657 | int status; |
2657 | 2658 | ||
2658 | /* FIXME: remove once USB support is implemented */ | ||
2659 | if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) { | ||
2660 | ath6kl_err("HTC doesn't support USB yet. Patience!\n"); | ||
2661 | return -EOPNOTSUPP; | ||
2662 | } | ||
2663 | |||
2664 | /* we should be getting 1 control message that the target is ready */ | 2659 | /* we should be getting 1 control message that the target is ready */ |
2665 | packet = htc_wait_for_ctrl_msg(target); | 2660 | packet = htc_wait_for_ctrl_msg(target); |
2666 | 2661 | ||
@@ -2890,9 +2885,7 @@ static void ath6kl_htc_mbox_cleanup(struct htc_target *target) | |||
2890 | { | 2885 | { |
2891 | struct htc_packet *packet, *tmp_packet; | 2886 | struct htc_packet *packet, *tmp_packet; |
2892 | 2887 | ||
2893 | /* FIXME: remove check once USB support is implemented */ | 2888 | ath6kl_hif_cleanup_scatter(target->dev->ar); |
2894 | if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB) | ||
2895 | ath6kl_hif_cleanup_scatter(target->dev->ar); | ||
2896 | 2889 | ||
2897 | list_for_each_entry_safe(packet, tmp_packet, | 2890 | list_for_each_entry_safe(packet, tmp_packet, |
2898 | &target->free_ctrl_txbuf, list) { | 2891 | &target->free_ctrl_txbuf, list) { |
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index f9626c72369..ba6bd497b78 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c | |||
@@ -374,9 +374,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, | |||
374 | packet = list_first_entry(txq, | 374 | packet = list_first_entry(txq, |
375 | struct htc_packet, | 375 | struct htc_packet, |
376 | list); | 376 | list); |
377 | list_del(&packet->list); | 377 | /* move to local queue */ |
378 | /* insert into local queue */ | 378 | list_move_tail(&packet->list, &send_queue); |
379 | list_add_tail(&packet->list, &send_queue); | ||
380 | } | 379 | } |
381 | 380 | ||
382 | /* | 381 | /* |
@@ -399,11 +398,10 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, | |||
399 | * for cleanup */ | 398 | * for cleanup */ |
400 | } else { | 399 | } else { |
401 | /* callback wants to keep this packet, | 400 | /* callback wants to keep this packet, |
402 | * remove from caller's queue */ | 401 | * move from caller's queue to the send |
403 | list_del(&packet->list); | 402 | * queue */ |
404 | /* put it in the send queue */ | 403 | list_move_tail(&packet->list, |
405 | list_add_tail(&packet->list, | 404 | &send_queue); |
406 | &send_queue); | ||
407 | } | 405 | } |
408 | 406 | ||
409 | } | 407 | } |
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index f90b5db741c..f21fa322e5c 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c | |||
@@ -42,7 +42,7 @@ static const struct ath6kl_hw hw_list[] = { | |||
42 | .reserved_ram_size = 6912, | 42 | .reserved_ram_size = 6912, |
43 | .refclk_hz = 26000000, | 43 | .refclk_hz = 26000000, |
44 | .uarttx_pin = 8, | 44 | .uarttx_pin = 8, |
45 | .flags = 0, | 45 | .flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR, |
46 | 46 | ||
47 | /* hw2.0 needs override address hardcoded */ | 47 | /* hw2.0 needs override address hardcoded */ |
48 | .app_start_override_addr = 0x944C00, | 48 | .app_start_override_addr = 0x944C00, |
@@ -68,7 +68,7 @@ static const struct ath6kl_hw hw_list[] = { | |||
68 | .refclk_hz = 26000000, | 68 | .refclk_hz = 26000000, |
69 | .uarttx_pin = 8, | 69 | .uarttx_pin = 8, |
70 | .testscript_addr = 0x57ef74, | 70 | .testscript_addr = 0x57ef74, |
71 | .flags = 0, | 71 | .flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR, |
72 | 72 | ||
73 | .fw = { | 73 | .fw = { |
74 | .dir = AR6003_HW_2_1_1_FW_DIR, | 74 | .dir = AR6003_HW_2_1_1_FW_DIR, |
@@ -93,7 +93,8 @@ static const struct ath6kl_hw hw_list[] = { | |||
93 | .board_addr = 0x433900, | 93 | .board_addr = 0x433900, |
94 | .refclk_hz = 26000000, | 94 | .refclk_hz = 26000000, |
95 | .uarttx_pin = 11, | 95 | .uarttx_pin = 11, |
96 | .flags = ATH6KL_HW_FLAG_64BIT_RATES, | 96 | .flags = ATH6KL_HW_64BIT_RATES | |
97 | ATH6KL_HW_AP_INACTIVITY_MINS, | ||
97 | 98 | ||
98 | .fw = { | 99 | .fw = { |
99 | .dir = AR6004_HW_1_0_FW_DIR, | 100 | .dir = AR6004_HW_1_0_FW_DIR, |
@@ -113,8 +114,8 @@ static const struct ath6kl_hw hw_list[] = { | |||
113 | .board_addr = 0x43d400, | 114 | .board_addr = 0x43d400, |
114 | .refclk_hz = 40000000, | 115 | .refclk_hz = 40000000, |
115 | .uarttx_pin = 11, | 116 | .uarttx_pin = 11, |
116 | .flags = ATH6KL_HW_FLAG_64BIT_RATES, | 117 | .flags = ATH6KL_HW_64BIT_RATES | |
117 | 118 | ATH6KL_HW_AP_INACTIVITY_MINS, | |
118 | .fw = { | 119 | .fw = { |
119 | .dir = AR6004_HW_1_1_FW_DIR, | 120 | .dir = AR6004_HW_1_1_FW_DIR, |
120 | .fw = AR6004_HW_1_1_FIRMWARE_FILE, | 121 | .fw = AR6004_HW_1_1_FIRMWARE_FILE, |
@@ -133,7 +134,8 @@ static const struct ath6kl_hw hw_list[] = { | |||
133 | .board_addr = 0x435c00, | 134 | .board_addr = 0x435c00, |
134 | .refclk_hz = 40000000, | 135 | .refclk_hz = 40000000, |
135 | .uarttx_pin = 11, | 136 | .uarttx_pin = 11, |
136 | .flags = ATH6KL_HW_FLAG_64BIT_RATES, | 137 | .flags = ATH6KL_HW_64BIT_RATES | |
138 | ATH6KL_HW_AP_INACTIVITY_MINS, | ||
137 | 139 | ||
138 | .fw = { | 140 | .fw = { |
139 | .dir = AR6004_HW_1_2_FW_DIR, | 141 | .dir = AR6004_HW_1_2_FW_DIR, |
@@ -142,6 +144,28 @@ static const struct ath6kl_hw hw_list[] = { | |||
142 | .fw_board = AR6004_HW_1_2_BOARD_DATA_FILE, | 144 | .fw_board = AR6004_HW_1_2_BOARD_DATA_FILE, |
143 | .fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE, | 145 | .fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE, |
144 | }, | 146 | }, |
147 | { | ||
148 | .id = AR6004_HW_1_3_VERSION, | ||
149 | .name = "ar6004 hw 1.3", | ||
150 | .dataset_patch_addr = 0x437860, | ||
151 | .app_load_addr = 0x1234, | ||
152 | .board_ext_data_addr = 0x437000, | ||
153 | .reserved_ram_size = 7168, | ||
154 | .board_addr = 0x436400, | ||
155 | .refclk_hz = 40000000, | ||
156 | .uarttx_pin = 11, | ||
157 | .flags = ATH6KL_HW_64BIT_RATES | | ||
158 | ATH6KL_HW_AP_INACTIVITY_MINS | | ||
159 | ATH6KL_HW_MAP_LP_ENDPOINT, | ||
160 | |||
161 | .fw = { | ||
162 | .dir = AR6004_HW_1_3_FW_DIR, | ||
163 | .fw = AR6004_HW_1_3_FIRMWARE_FILE, | ||
164 | }, | ||
165 | |||
166 | .fw_board = AR6004_HW_1_3_BOARD_DATA_FILE, | ||
167 | .fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE, | ||
168 | }, | ||
145 | }; | 169 | }; |
146 | 170 | ||
147 | /* | 171 | /* |
@@ -337,7 +361,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar) | |||
337 | if (ath6kl_connectservice(ar, &connect, "WMI DATA BK")) | 361 | if (ath6kl_connectservice(ar, &connect, "WMI DATA BK")) |
338 | return -EIO; | 362 | return -EIO; |
339 | 363 | ||
340 | /* connect to Video service, map this to to HI PRI */ | 364 | /* connect to Video service, map this to HI PRI */ |
341 | connect.svc_id = WMI_DATA_VI_SVC; | 365 | connect.svc_id = WMI_DATA_VI_SVC; |
342 | if (ath6kl_connectservice(ar, &connect, "WMI DATA VI")) | 366 | if (ath6kl_connectservice(ar, &connect, "WMI DATA VI")) |
343 | return -EIO; | 367 | return -EIO; |
@@ -1088,6 +1112,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar) | |||
1088 | if (ret) | 1112 | if (ret) |
1089 | return ret; | 1113 | return ret; |
1090 | 1114 | ||
1115 | ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE); | ||
1116 | if (ret == 0) { | ||
1117 | ar->fw_api = 4; | ||
1118 | goto out; | ||
1119 | } | ||
1120 | |||
1091 | ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); | 1121 | ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); |
1092 | if (ret == 0) { | 1122 | if (ret == 0) { |
1093 | ar->fw_api = 3; | 1123 | ar->fw_api = 3; |
@@ -1401,8 +1431,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) | |||
1401 | return status; | 1431 | return status; |
1402 | 1432 | ||
1403 | /* WAR to avoid SDIO CRC err */ | 1433 | /* WAR to avoid SDIO CRC err */ |
1404 | if (ar->version.target_ver == AR6003_HW_2_0_VERSION || | 1434 | if (ar->hw.flags & ATH6KL_HW_SDIO_CRC_ERROR_WAR) { |
1405 | ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { | ||
1406 | ath6kl_err("temporary war to avoid sdio crc error\n"); | 1435 | ath6kl_err("temporary war to avoid sdio crc error\n"); |
1407 | 1436 | ||
1408 | param = 0x28; | 1437 | param = 0x28; |
@@ -1520,7 +1549,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type) | |||
1520 | return NULL; | 1549 | return NULL; |
1521 | } | 1550 | } |
1522 | 1551 | ||
1523 | int ath6kl_init_hw_start(struct ath6kl *ar) | 1552 | static int __ath6kl_init_hw_start(struct ath6kl *ar) |
1524 | { | 1553 | { |
1525 | long timeleft; | 1554 | long timeleft; |
1526 | int ret, i; | 1555 | int ret, i; |
@@ -1616,8 +1645,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar) | |||
1616 | goto err_htc_stop; | 1645 | goto err_htc_stop; |
1617 | } | 1646 | } |
1618 | 1647 | ||
1619 | ar->state = ATH6KL_STATE_ON; | ||
1620 | |||
1621 | return 0; | 1648 | return 0; |
1622 | 1649 | ||
1623 | err_htc_stop: | 1650 | err_htc_stop: |
@@ -1630,7 +1657,18 @@ err_power_off: | |||
1630 | return ret; | 1657 | return ret; |
1631 | } | 1658 | } |
1632 | 1659 | ||
1633 | int ath6kl_init_hw_stop(struct ath6kl *ar) | 1660 | int ath6kl_init_hw_start(struct ath6kl *ar) |
1661 | { | ||
1662 | int err; | ||
1663 | |||
1664 | err = __ath6kl_init_hw_start(ar); | ||
1665 | if (err) | ||
1666 | return err; | ||
1667 | ar->state = ATH6KL_STATE_ON; | ||
1668 | return 0; | ||
1669 | } | ||
1670 | |||
1671 | static int __ath6kl_init_hw_stop(struct ath6kl *ar) | ||
1634 | { | 1672 | { |
1635 | int ret; | 1673 | int ret; |
1636 | 1674 | ||
@@ -1646,11 +1684,37 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) | |||
1646 | if (ret) | 1684 | if (ret) |
1647 | ath6kl_warn("failed to power off hif: %d\n", ret); | 1685 | ath6kl_warn("failed to power off hif: %d\n", ret); |
1648 | 1686 | ||
1649 | ar->state = ATH6KL_STATE_OFF; | 1687 | return 0; |
1688 | } | ||
1650 | 1689 | ||
1690 | int ath6kl_init_hw_stop(struct ath6kl *ar) | ||
1691 | { | ||
1692 | int err; | ||
1693 | |||
1694 | err = __ath6kl_init_hw_stop(ar); | ||
1695 | if (err) | ||
1696 | return err; | ||
1697 | ar->state = ATH6KL_STATE_OFF; | ||
1651 | return 0; | 1698 | return 0; |
1652 | } | 1699 | } |
1653 | 1700 | ||
1701 | void ath6kl_init_hw_restart(struct ath6kl *ar) | ||
1702 | { | ||
1703 | clear_bit(WMI_READY, &ar->flag); | ||
1704 | |||
1705 | ath6kl_cfg80211_stop_all(ar); | ||
1706 | |||
1707 | if (__ath6kl_init_hw_stop(ar)) { | ||
1708 | ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n"); | ||
1709 | return; | ||
1710 | } | ||
1711 | |||
1712 | if (__ath6kl_init_hw_start(ar)) { | ||
1713 | ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n"); | ||
1714 | return; | ||
1715 | } | ||
1716 | } | ||
1717 | |||
1654 | /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ | 1718 | /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ |
1655 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) | 1719 | void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) |
1656 | { | 1720 | { |
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index c189e28e86a..bd50b6b7b49 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c | |||
@@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) | |||
293 | } | 293 | } |
294 | 294 | ||
295 | address = TARG_VTOP(ar->target_type, debug_hdr_addr); | 295 | address = TARG_VTOP(ar->target_type, debug_hdr_addr); |
296 | ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); | 296 | ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); |
297 | if (ret) | ||
298 | goto out; | ||
297 | 299 | ||
298 | address = TARG_VTOP(ar->target_type, | 300 | address = TARG_VTOP(ar->target_type, |
299 | le32_to_cpu(debug_hdr.dbuf_addr)); | 301 | le32_to_cpu(debug_hdr.dbuf_addr)); |
300 | firstbuf = address; | 302 | firstbuf = address; |
301 | dropped = le32_to_cpu(debug_hdr.dropped); | 303 | dropped = le32_to_cpu(debug_hdr.dropped); |
302 | ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); | 304 | ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); |
305 | if (ret) | ||
306 | goto out; | ||
303 | 307 | ||
304 | loop = 100; | 308 | loop = 100; |
305 | 309 | ||
@@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) | |||
322 | 326 | ||
323 | address = TARG_VTOP(ar->target_type, | 327 | address = TARG_VTOP(ar->target_type, |
324 | le32_to_cpu(debug_buf.next)); | 328 | le32_to_cpu(debug_buf.next)); |
325 | ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); | 329 | ret = ath6kl_diag_read(ar, address, &debug_buf, |
330 | sizeof(debug_buf)); | ||
326 | if (ret) | 331 | if (ret) |
327 | goto out; | 332 | goto out; |
328 | 333 | ||
@@ -436,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) | |||
436 | break; | 441 | break; |
437 | } | 442 | } |
438 | 443 | ||
439 | if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) { | 444 | if (ar->last_ch != channel) |
440 | ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); | ||
441 | /* we actually don't know the phymode, default to HT20 */ | 445 | /* we actually don't know the phymode, default to HT20 */ |
442 | ath6kl_cfg80211_ch_switch_notify(vif, channel, | 446 | ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20); |
443 | WMI_11G_HT20); | ||
444 | } | ||
445 | 447 | ||
446 | ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); | 448 | ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); |
447 | set_bit(CONNECTED, &vif->flags); | 449 | set_bit(CONNECTED, &vif->flags); |
@@ -606,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) | |||
606 | 608 | ||
607 | switch (vif->nw_type) { | 609 | switch (vif->nw_type) { |
608 | case AP_NETWORK: | 610 | case AP_NETWORK: |
611 | /* | ||
612 | * reconfigure any saved RSN IE capabilites in the beacon / | ||
613 | * probe response to stay in sync with the supplicant. | ||
614 | */ | ||
615 | if (vif->rsn_capab && | ||
616 | test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, | ||
617 | ar->fw_capabilities)) | ||
618 | ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, | ||
619 | WLAN_EID_RSN, WMI_RSN_IE_CAPB, | ||
620 | (const u8 *) &vif->rsn_capab, | ||
621 | sizeof(vif->rsn_capab)); | ||
622 | |||
609 | return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, | 623 | return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, |
610 | &vif->profile); | 624 | &vif->profile); |
611 | default: | 625 | default: |
@@ -628,6 +642,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) | |||
628 | if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) | 642 | if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) |
629 | res = ath6kl_commit_ch_switch(vif, channel); | 643 | res = ath6kl_commit_ch_switch(vif, channel); |
630 | 644 | ||
645 | /* if channel switch failed, oh well we tried */ | ||
646 | ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); | ||
647 | |||
631 | if (res) | 648 | if (res) |
632 | ath6kl_err("channel switch failed nw_type %d res %d\n", | 649 | ath6kl_err("channel switch failed nw_type %d res %d\n", |
633 | vif->nw_type, res); | 650 | vif->nw_type, res); |
@@ -981,8 +998,25 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, | |||
981 | if (vif->nw_type == AP_NETWORK) { | 998 | if (vif->nw_type == AP_NETWORK) { |
982 | /* disconnect due to other STA vif switching channels */ | 999 | /* disconnect due to other STA vif switching channels */ |
983 | if (reason == BSS_DISCONNECTED && | 1000 | if (reason == BSS_DISCONNECTED && |
984 | prot_reason_status == WMI_AP_REASON_STA_ROAM) | 1001 | prot_reason_status == WMI_AP_REASON_STA_ROAM) { |
985 | ar->want_ch_switch |= 1 << vif->fw_vif_idx; | 1002 | ar->want_ch_switch |= 1 << vif->fw_vif_idx; |
1003 | /* bail back to this channel if STA vif fails connect */ | ||
1004 | ar->last_ch = le16_to_cpu(vif->profile.ch); | ||
1005 | } | ||
1006 | |||
1007 | if (prot_reason_status == WMI_AP_REASON_MAX_STA) { | ||
1008 | /* send max client reached notification to user space */ | ||
1009 | cfg80211_conn_failed(vif->ndev, bssid, | ||
1010 | NL80211_CONN_FAIL_MAX_CLIENTS, | ||
1011 | GFP_KERNEL); | ||
1012 | } | ||
1013 | |||
1014 | if (prot_reason_status == WMI_AP_REASON_ACL) { | ||
1015 | /* send blocked client notification to user space */ | ||
1016 | cfg80211_conn_failed(vif->ndev, bssid, | ||
1017 | NL80211_CONN_FAIL_BLOCKED_CLIENT, | ||
1018 | GFP_KERNEL); | ||
1019 | } | ||
986 | 1020 | ||
987 | if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) | 1021 | if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) |
988 | return; | 1022 | return; |
@@ -1041,6 +1075,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, | |||
1041 | } | 1075 | } |
1042 | } | 1076 | } |
1043 | 1077 | ||
1078 | /* restart disconnected concurrent vifs waiting for new channel */ | ||
1079 | ath6kl_check_ch_switch(ar, ar->last_ch); | ||
1080 | |||
1044 | /* update connect & link status atomically */ | 1081 | /* update connect & link status atomically */ |
1045 | spin_lock_bh(&vif->if_lock); | 1082 | spin_lock_bh(&vif->if_lock); |
1046 | clear_bit(CONNECTED, &vif->flags); | 1083 | clear_bit(CONNECTED, &vif->flags); |
diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c new file mode 100644 index 00000000000..3a8d5e97dc8 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/recovery.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "core.h" | ||
18 | #include "cfg80211.h" | ||
19 | #include "debug.h" | ||
20 | |||
21 | static void ath6kl_recovery_work(struct work_struct *work) | ||
22 | { | ||
23 | struct ath6kl *ar = container_of(work, struct ath6kl, | ||
24 | fw_recovery.recovery_work); | ||
25 | |||
26 | ar->state = ATH6KL_STATE_RECOVERY; | ||
27 | |||
28 | del_timer_sync(&ar->fw_recovery.hb_timer); | ||
29 | |||
30 | ath6kl_init_hw_restart(ar); | ||
31 | |||
32 | ar->state = ATH6KL_STATE_ON; | ||
33 | clear_bit(WMI_CTRL_EP_FULL, &ar->flag); | ||
34 | |||
35 | ar->fw_recovery.err_reason = 0; | ||
36 | |||
37 | if (ar->fw_recovery.hb_poll) | ||
38 | mod_timer(&ar->fw_recovery.hb_timer, jiffies + | ||
39 | msecs_to_jiffies(ar->fw_recovery.hb_poll)); | ||
40 | } | ||
41 | |||
42 | void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason) | ||
43 | { | ||
44 | if (!ar->fw_recovery.enable) | ||
45 | return; | ||
46 | |||
47 | ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n", | ||
48 | reason); | ||
49 | |||
50 | set_bit(reason, &ar->fw_recovery.err_reason); | ||
51 | |||
52 | if (!test_bit(RECOVERY_CLEANUP, &ar->flag) && | ||
53 | ar->state != ATH6KL_STATE_RECOVERY) | ||
54 | queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work); | ||
55 | } | ||
56 | |||
57 | void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie) | ||
58 | { | ||
59 | if (cookie == ar->fw_recovery.seq_num) | ||
60 | ar->fw_recovery.hb_pending = false; | ||
61 | } | ||
62 | |||
63 | static void ath6kl_recovery_hb_timer(unsigned long data) | ||
64 | { | ||
65 | struct ath6kl *ar = (struct ath6kl *) data; | ||
66 | int err; | ||
67 | |||
68 | if (test_bit(RECOVERY_CLEANUP, &ar->flag) || | ||
69 | (ar->state == ATH6KL_STATE_RECOVERY)) | ||
70 | return; | ||
71 | |||
72 | if (ar->fw_recovery.hb_pending) | ||
73 | ar->fw_recovery.hb_misscnt++; | ||
74 | else | ||
75 | ar->fw_recovery.hb_misscnt = 0; | ||
76 | |||
77 | if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) { | ||
78 | ar->fw_recovery.hb_misscnt = 0; | ||
79 | ar->fw_recovery.seq_num = 0; | ||
80 | ar->fw_recovery.hb_pending = false; | ||
81 | ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE); | ||
82 | return; | ||
83 | } | ||
84 | |||
85 | ar->fw_recovery.seq_num++; | ||
86 | ar->fw_recovery.hb_pending = true; | ||
87 | |||
88 | err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi, | ||
89 | ar->fw_recovery.seq_num, 0); | ||
90 | if (err) | ||
91 | ath6kl_warn("Failed to send hb challenge request, err:%d\n", | ||
92 | err); | ||
93 | |||
94 | mod_timer(&ar->fw_recovery.hb_timer, jiffies + | ||
95 | msecs_to_jiffies(ar->fw_recovery.hb_poll)); | ||
96 | } | ||
97 | |||
98 | void ath6kl_recovery_init(struct ath6kl *ar) | ||
99 | { | ||
100 | struct ath6kl_fw_recovery *recovery = &ar->fw_recovery; | ||
101 | |||
102 | clear_bit(RECOVERY_CLEANUP, &ar->flag); | ||
103 | INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work); | ||
104 | recovery->seq_num = 0; | ||
105 | recovery->hb_misscnt = 0; | ||
106 | ar->fw_recovery.hb_pending = false; | ||
107 | ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer; | ||
108 | ar->fw_recovery.hb_timer.data = (unsigned long) ar; | ||
109 | init_timer_deferrable(&ar->fw_recovery.hb_timer); | ||
110 | |||
111 | if (ar->fw_recovery.hb_poll) | ||
112 | mod_timer(&ar->fw_recovery.hb_timer, jiffies + | ||
113 | msecs_to_jiffies(ar->fw_recovery.hb_poll)); | ||
114 | } | ||
115 | |||
116 | void ath6kl_recovery_cleanup(struct ath6kl *ar) | ||
117 | { | ||
118 | if (!ar->fw_recovery.enable) | ||
119 | return; | ||
120 | |||
121 | set_bit(RECOVERY_CLEANUP, &ar->flag); | ||
122 | |||
123 | del_timer_sync(&ar->fw_recovery.hb_timer); | ||
124 | cancel_work_sync(&ar->fw_recovery.recovery_work); | ||
125 | } | ||
126 | |||
127 | void ath6kl_recovery_suspend(struct ath6kl *ar) | ||
128 | { | ||
129 | if (!ar->fw_recovery.enable) | ||
130 | return; | ||
131 | |||
132 | ath6kl_recovery_cleanup(ar); | ||
133 | |||
134 | if (!ar->fw_recovery.err_reason) | ||
135 | return; | ||
136 | |||
137 | /* Process pending fw error detection */ | ||
138 | ar->fw_recovery.err_reason = 0; | ||
139 | WARN_ON(ar->state != ATH6KL_STATE_ON); | ||
140 | ar->state = ATH6KL_STATE_RECOVERY; | ||
141 | ath6kl_init_hw_restart(ar); | ||
142 | ar->state = ATH6KL_STATE_ON; | ||
143 | } | ||
144 | |||
145 | void ath6kl_recovery_resume(struct ath6kl *ar) | ||
146 | { | ||
147 | if (!ar->fw_recovery.enable) | ||
148 | return; | ||
149 | |||
150 | clear_bit(RECOVERY_CLEANUP, &ar->flag); | ||
151 | |||
152 | if (!ar->fw_recovery.hb_poll) | ||
153 | return; | ||
154 | |||
155 | ar->fw_recovery.hb_pending = false; | ||
156 | ar->fw_recovery.seq_num = 0; | ||
157 | ar->fw_recovery.hb_misscnt = 0; | ||
158 | mod_timer(&ar->fw_recovery.hb_timer, | ||
159 | jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll)); | ||
160 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 05b95405f7b..d111980d44c 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c | |||
@@ -709,7 +709,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) | |||
709 | { | 709 | { |
710 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | 710 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); |
711 | struct htc_target *target = ar->htc_target; | 711 | struct htc_target *target = ar->htc_target; |
712 | int ret; | 712 | int ret = 0; |
713 | bool virt_scat = false; | 713 | bool virt_scat = false; |
714 | 714 | ||
715 | if (ar_sdio->scatter_enabled) | 715 | if (ar_sdio->scatter_enabled) |
@@ -844,22 +844,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
844 | bool try_deepsleep = false; | 844 | bool try_deepsleep = false; |
845 | int ret; | 845 | int ret; |
846 | 846 | ||
847 | if (ar->state == ATH6KL_STATE_SCHED_SCAN) { | ||
848 | ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n"); | ||
849 | |||
850 | ret = ath6kl_set_sdio_pm_caps(ar); | ||
851 | if (ret) | ||
852 | goto cut_pwr; | ||
853 | |||
854 | ret = ath6kl_cfg80211_suspend(ar, | ||
855 | ATH6KL_CFG_SUSPEND_SCHED_SCAN, | ||
856 | NULL); | ||
857 | if (ret) | ||
858 | goto cut_pwr; | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | if (ar->suspend_mode == WLAN_POWER_STATE_WOW || | 847 | if (ar->suspend_mode == WLAN_POWER_STATE_WOW || |
864 | (!ar->suspend_mode && wow)) { | 848 | (!ar->suspend_mode && wow)) { |
865 | 849 | ||
@@ -942,14 +926,14 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) | |||
942 | case ATH6KL_STATE_WOW: | 926 | case ATH6KL_STATE_WOW: |
943 | break; | 927 | break; |
944 | 928 | ||
945 | case ATH6KL_STATE_SCHED_SCAN: | ||
946 | break; | ||
947 | |||
948 | case ATH6KL_STATE_SUSPENDING: | 929 | case ATH6KL_STATE_SUSPENDING: |
949 | break; | 930 | break; |
950 | 931 | ||
951 | case ATH6KL_STATE_RESUMING: | 932 | case ATH6KL_STATE_RESUMING: |
952 | break; | 933 | break; |
934 | |||
935 | case ATH6KL_STATE_RECOVERY: | ||
936 | break; | ||
953 | } | 937 | } |
954 | 938 | ||
955 | ath6kl_cfg80211_resume(ar); | 939 | ath6kl_cfg80211_resume(ar); |
@@ -1462,3 +1446,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); | |||
1462 | MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE); | 1446 | MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE); |
1463 | MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); | 1447 | MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); |
1464 | MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); | 1448 | MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); |
1449 | MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE); | ||
1450 | MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE); | ||
1451 | MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE); | ||
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 7dfa0fd86d7..78b36928657 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c | |||
@@ -288,8 +288,16 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, | |||
288 | int status = 0; | 288 | int status = 0; |
289 | struct ath6kl_cookie *cookie = NULL; | 289 | struct ath6kl_cookie *cookie = NULL; |
290 | 290 | ||
291 | if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) | 291 | if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) { |
292 | dev_kfree_skb(skb); | ||
292 | return -EACCES; | 293 | return -EACCES; |
294 | } | ||
295 | |||
296 | if (WARN_ON_ONCE(eid == ENDPOINT_UNUSED || | ||
297 | eid >= ENDPOINT_MAX)) { | ||
298 | status = -EINVAL; | ||
299 | goto fail_ctrl_tx; | ||
300 | } | ||
293 | 301 | ||
294 | spin_lock_bh(&ar->lock); | 302 | spin_lock_bh(&ar->lock); |
295 | 303 | ||
@@ -591,6 +599,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, | |||
591 | */ | 599 | */ |
592 | set_bit(WMI_CTRL_EP_FULL, &ar->flag); | 600 | set_bit(WMI_CTRL_EP_FULL, &ar->flag); |
593 | ath6kl_err("wmi ctrl ep is full\n"); | 601 | ath6kl_err("wmi ctrl ep is full\n"); |
602 | ath6kl_recovery_err_notify(ar, ATH6KL_FW_EP_FULL); | ||
594 | return action; | 603 | return action; |
595 | } | 604 | } |
596 | 605 | ||
@@ -695,22 +704,31 @@ void ath6kl_tx_complete(struct htc_target *target, | |||
695 | list); | 704 | list); |
696 | list_del(&packet->list); | 705 | list_del(&packet->list); |
697 | 706 | ||
707 | if (WARN_ON_ONCE(packet->endpoint == ENDPOINT_UNUSED || | ||
708 | packet->endpoint >= ENDPOINT_MAX)) | ||
709 | continue; | ||
710 | |||
698 | ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; | 711 | ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; |
699 | if (!ath6kl_cookie) | 712 | if (WARN_ON_ONCE(!ath6kl_cookie)) |
700 | goto fatal; | 713 | continue; |
701 | 714 | ||
702 | status = packet->status; | 715 | status = packet->status; |
703 | skb = ath6kl_cookie->skb; | 716 | skb = ath6kl_cookie->skb; |
704 | eid = packet->endpoint; | 717 | eid = packet->endpoint; |
705 | map_no = ath6kl_cookie->map_no; | 718 | map_no = ath6kl_cookie->map_no; |
706 | 719 | ||
707 | if (!skb || !skb->data) | 720 | if (WARN_ON_ONCE(!skb || !skb->data)) { |
708 | goto fatal; | 721 | dev_kfree_skb(skb); |
722 | ath6kl_free_cookie(ar, ath6kl_cookie); | ||
723 | continue; | ||
724 | } | ||
709 | 725 | ||
710 | __skb_queue_tail(&skb_queue, skb); | 726 | __skb_queue_tail(&skb_queue, skb); |
711 | 727 | ||
712 | if (!status && (packet->act_len != skb->len)) | 728 | if (WARN_ON_ONCE(!status && (packet->act_len != skb->len))) { |
713 | goto fatal; | 729 | ath6kl_free_cookie(ar, ath6kl_cookie); |
730 | continue; | ||
731 | } | ||
714 | 732 | ||
715 | ar->tx_pending[eid]--; | 733 | ar->tx_pending[eid]--; |
716 | 734 | ||
@@ -792,11 +810,6 @@ void ath6kl_tx_complete(struct htc_target *target, | |||
792 | wake_up(&ar->event_wq); | 810 | wake_up(&ar->event_wq); |
793 | 811 | ||
794 | return; | 812 | return; |
795 | |||
796 | fatal: | ||
797 | WARN_ON(1); | ||
798 | spin_unlock_bh(&ar->lock); | ||
799 | return; | ||
800 | } | 813 | } |
801 | 814 | ||
802 | void ath6kl_tx_data_cleanup(struct ath6kl *ar) | 815 | void ath6kl_tx_data_cleanup(struct ath6kl *ar) |
@@ -885,8 +898,11 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) | |||
885 | break; | 898 | break; |
886 | 899 | ||
887 | packet = (struct htc_packet *) skb->head; | 900 | packet = (struct htc_packet *) skb->head; |
888 | if (!IS_ALIGNED((unsigned long) skb->data, 4)) | 901 | if (!IS_ALIGNED((unsigned long) skb->data, 4)) { |
902 | size_t len = skb_headlen(skb); | ||
889 | skb->data = PTR_ALIGN(skb->data - 4, 4); | 903 | skb->data = PTR_ALIGN(skb->data - 4, 4); |
904 | skb_set_tail_pointer(skb, len); | ||
905 | } | ||
890 | set_htc_rxpkt_info(packet, skb, skb->data, | 906 | set_htc_rxpkt_info(packet, skb, skb->data, |
891 | ATH6KL_BUFFER_SIZE, endpoint); | 907 | ATH6KL_BUFFER_SIZE, endpoint); |
892 | packet->skb = skb; | 908 | packet->skb = skb; |
@@ -908,8 +924,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) | |||
908 | return; | 924 | return; |
909 | 925 | ||
910 | packet = (struct htc_packet *) skb->head; | 926 | packet = (struct htc_packet *) skb->head; |
911 | if (!IS_ALIGNED((unsigned long) skb->data, 4)) | 927 | if (!IS_ALIGNED((unsigned long) skb->data, 4)) { |
928 | size_t len = skb_headlen(skb); | ||
912 | skb->data = PTR_ALIGN(skb->data - 4, 4); | 929 | skb->data = PTR_ALIGN(skb->data - 4, 4); |
930 | skb_set_tail_pointer(skb, len); | ||
931 | } | ||
913 | set_htc_rxpkt_info(packet, skb, skb->data, | 932 | set_htc_rxpkt_info(packet, skb, skb->data, |
914 | ATH6KL_AMSDU_BUFFER_SIZE, 0); | 933 | ATH6KL_AMSDU_BUFFER_SIZE, 0); |
915 | packet->skb = skb; | 934 | packet->skb = skb; |
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 3740c3d6ab8..62bcc0d5bc2 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c | |||
@@ -185,9 +185,10 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, | |||
185 | for (i = 0; i < urb_cnt; i++) { | 185 | for (i = 0; i < urb_cnt; i++) { |
186 | urb_context = kzalloc(sizeof(struct ath6kl_urb_context), | 186 | urb_context = kzalloc(sizeof(struct ath6kl_urb_context), |
187 | GFP_KERNEL); | 187 | GFP_KERNEL); |
188 | if (urb_context == NULL) | 188 | if (urb_context == NULL) { |
189 | /* FIXME: set status to -ENOMEM */ | 189 | status = -ENOMEM; |
190 | break; | 190 | goto fail_alloc_pipe_resources; |
191 | } | ||
191 | 192 | ||
192 | urb_context->pipe = pipe; | 193 | urb_context->pipe = pipe; |
193 | 194 | ||
@@ -204,6 +205,7 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, | |||
204 | pipe->logical_pipe_num, pipe->usb_pipe_handle, | 205 | pipe->logical_pipe_num, pipe->usb_pipe_handle, |
205 | pipe->urb_alloc); | 206 | pipe->urb_alloc); |
206 | 207 | ||
208 | fail_alloc_pipe_resources: | ||
207 | return status; | 209 | return status; |
208 | } | 210 | } |
209 | 211 | ||
@@ -803,7 +805,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, | |||
803 | *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; | 805 | *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; |
804 | break; | 806 | break; |
805 | case WMI_DATA_VI_SVC: | 807 | case WMI_DATA_VI_SVC: |
806 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; | 808 | |
809 | if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) | ||
810 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; | ||
811 | else | ||
812 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; | ||
807 | /* | 813 | /* |
808 | * Disable rxdata2 directly, it will be enabled | 814 | * Disable rxdata2 directly, it will be enabled |
809 | * if FW enable rxdata2 | 815 | * if FW enable rxdata2 |
@@ -811,7 +817,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, | |||
811 | *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; | 817 | *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; |
812 | break; | 818 | break; |
813 | case WMI_DATA_VO_SVC: | 819 | case WMI_DATA_VO_SVC: |
814 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP; | 820 | |
821 | if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) | ||
822 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; | ||
823 | else | ||
824 | *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; | ||
815 | /* | 825 | /* |
816 | * Disable rxdata2 directly, it will be enabled | 826 | * Disable rxdata2 directly, it will be enabled |
817 | * if FW enable rxdata2 | 827 | * if FW enable rxdata2 |
@@ -1196,7 +1206,14 @@ static struct usb_driver ath6kl_usb_driver = { | |||
1196 | 1206 | ||
1197 | static int ath6kl_usb_init(void) | 1207 | static int ath6kl_usb_init(void) |
1198 | { | 1208 | { |
1199 | usb_register(&ath6kl_usb_driver); | 1209 | int ret; |
1210 | |||
1211 | ret = usb_register(&ath6kl_usb_driver); | ||
1212 | if (ret) { | ||
1213 | ath6kl_err("usb registration failed: %d\n", ret); | ||
1214 | return ret; | ||
1215 | } | ||
1216 | |||
1200 | return 0; | 1217 | return 0; |
1201 | } | 1218 | } |
1202 | 1219 | ||
@@ -1220,3 +1237,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); | |||
1220 | MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE); | 1237 | MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE); |
1221 | MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); | 1238 | MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); |
1222 | MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); | 1239 | MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); |
1240 | MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE); | ||
1241 | MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE); | ||
1242 | MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE); | ||
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index c30ab4b11d6..55ccf977033 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -936,8 +936,12 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) | |||
936 | 936 | ||
937 | regpair = ath6kl_get_regpair((u16) reg_code); | 937 | regpair = ath6kl_get_regpair((u16) reg_code); |
938 | country = ath6kl_regd_find_country_by_rd((u16) reg_code); | 938 | country = ath6kl_regd_find_country_by_rd((u16) reg_code); |
939 | ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", | 939 | if (regpair) |
940 | regpair->regDmnEnum); | 940 | ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", |
941 | regpair->regDmnEnum); | ||
942 | else | ||
943 | ath6kl_warn("Regpair not found reg_code 0x%0x\n", | ||
944 | reg_code); | ||
941 | } | 945 | } |
942 | 946 | ||
943 | if (country && wmi->parent_dev->wiphy_registered) { | 947 | if (country && wmi->parent_dev->wiphy_registered) { |
@@ -1116,7 +1120,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, | |||
1116 | * the timer would not ever fire if the scan interval is short | 1120 | * the timer would not ever fire if the scan interval is short |
1117 | * enough. | 1121 | * enough. |
1118 | */ | 1122 | */ |
1119 | if (ar->state == ATH6KL_STATE_SCHED_SCAN && | 1123 | if (test_bit(SCHED_SCANNING, &vif->flags) && |
1120 | !timer_pending(&vif->sched_scan_timer)) { | 1124 | !timer_pending(&vif->sched_scan_timer)) { |
1121 | mod_timer(&vif->sched_scan_timer, jiffies + | 1125 | mod_timer(&vif->sched_scan_timer, jiffies + |
1122 | msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY)); | 1126 | msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY)); |
@@ -1170,6 +1174,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) | |||
1170 | rate = RATE_AUTO; | 1174 | rate = RATE_AUTO; |
1171 | } else { | 1175 | } else { |
1172 | index = reply->rate_index & 0x7f; | 1176 | index = reply->rate_index & 0x7f; |
1177 | if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1))) | ||
1178 | return -EINVAL; | ||
1179 | |||
1173 | sgi = (reply->rate_index & 0x80) ? 1 : 0; | 1180 | sgi = (reply->rate_index & 0x80) ? 1 : 0; |
1174 | rate = wmi_rate_tbl[index][sgi]; | 1181 | rate = wmi_rate_tbl[index][sgi]; |
1175 | } | 1182 | } |
@@ -1531,6 +1538,68 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, | |||
1531 | return 0; | 1538 | return 0; |
1532 | } | 1539 | } |
1533 | 1540 | ||
1541 | static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len, | ||
1542 | struct ath6kl_vif *vif) | ||
1543 | { | ||
1544 | struct wmi_txe_notify_event *ev; | ||
1545 | u32 rate, pkts; | ||
1546 | |||
1547 | if (len < sizeof(*ev)) | ||
1548 | return -EINVAL; | ||
1549 | |||
1550 | if (vif->sme_state != SME_CONNECTED) | ||
1551 | return -ENOTCONN; | ||
1552 | |||
1553 | ev = (struct wmi_txe_notify_event *) datap; | ||
1554 | rate = le32_to_cpu(ev->rate); | ||
1555 | pkts = le32_to_cpu(ev->pkts); | ||
1556 | |||
1557 | ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d% pkts %d intvl %ds\n", | ||
1558 | vif->bssid, rate, pkts, vif->txe_intvl); | ||
1559 | |||
1560 | cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts, | ||
1561 | rate, vif->txe_intvl, GFP_KERNEL); | ||
1562 | |||
1563 | return 0; | ||
1564 | } | ||
1565 | |||
1566 | int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, | ||
1567 | u32 rate, u32 pkts, u32 intvl) | ||
1568 | { | ||
1569 | struct sk_buff *skb; | ||
1570 | struct wmi_txe_notify_cmd *cmd; | ||
1571 | |||
1572 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1573 | if (!skb) | ||
1574 | return -ENOMEM; | ||
1575 | |||
1576 | cmd = (struct wmi_txe_notify_cmd *) skb->data; | ||
1577 | cmd->rate = cpu_to_le32(rate); | ||
1578 | cmd->pkts = cpu_to_le32(pkts); | ||
1579 | cmd->intvl = cpu_to_le32(intvl); | ||
1580 | |||
1581 | return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID, | ||
1582 | NO_SYNC_WMIFLAG); | ||
1583 | } | ||
1584 | |||
1585 | int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi) | ||
1586 | { | ||
1587 | struct sk_buff *skb; | ||
1588 | struct wmi_set_rssi_filter_cmd *cmd; | ||
1589 | int ret; | ||
1590 | |||
1591 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1592 | if (!skb) | ||
1593 | return -ENOMEM; | ||
1594 | |||
1595 | cmd = (struct wmi_set_rssi_filter_cmd *) skb->data; | ||
1596 | cmd->rssi = rssi; | ||
1597 | |||
1598 | ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID, | ||
1599 | NO_SYNC_WMIFLAG); | ||
1600 | return ret; | ||
1601 | } | ||
1602 | |||
1534 | static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi, | 1603 | static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi, |
1535 | struct wmi_snr_threshold_params_cmd *snr_cmd) | 1604 | struct wmi_snr_threshold_params_cmd *snr_cmd) |
1536 | { | 1605 | { |
@@ -1677,8 +1746,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb, | |||
1677 | int ret; | 1746 | int ret; |
1678 | u16 info1; | 1747 | u16 info1; |
1679 | 1748 | ||
1680 | if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1)))) | 1749 | if (WARN_ON(skb == NULL || |
1750 | (if_idx > (wmi->parent_dev->vif_max - 1)))) { | ||
1751 | dev_kfree_skb(skb); | ||
1681 | return -EINVAL; | 1752 | return -EINVAL; |
1753 | } | ||
1682 | 1754 | ||
1683 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n", | 1755 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n", |
1684 | cmd_id, skb->len, sync_flag); | 1756 | cmd_id, skb->len, sync_flag); |
@@ -1833,6 +1905,59 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx) | |||
1833 | return ret; | 1905 | return ret; |
1834 | } | 1906 | } |
1835 | 1907 | ||
1908 | /* ath6kl_wmi_start_scan_cmd is to be deprecated. Use | ||
1909 | * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P | ||
1910 | * mgmt operations using station interface. | ||
1911 | */ | ||
1912 | static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, | ||
1913 | enum wmi_scan_type scan_type, | ||
1914 | u32 force_fgscan, u32 is_legacy, | ||
1915 | u32 home_dwell_time, | ||
1916 | u32 force_scan_interval, | ||
1917 | s8 num_chan, u16 *ch_list) | ||
1918 | { | ||
1919 | struct sk_buff *skb; | ||
1920 | struct wmi_start_scan_cmd *sc; | ||
1921 | s8 size; | ||
1922 | int i, ret; | ||
1923 | |||
1924 | size = sizeof(struct wmi_start_scan_cmd); | ||
1925 | |||
1926 | if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) | ||
1927 | return -EINVAL; | ||
1928 | |||
1929 | if (num_chan > WMI_MAX_CHANNELS) | ||
1930 | return -EINVAL; | ||
1931 | |||
1932 | if (num_chan) | ||
1933 | size += sizeof(u16) * (num_chan - 1); | ||
1934 | |||
1935 | skb = ath6kl_wmi_get_new_buf(size); | ||
1936 | if (!skb) | ||
1937 | return -ENOMEM; | ||
1938 | |||
1939 | sc = (struct wmi_start_scan_cmd *) skb->data; | ||
1940 | sc->scan_type = scan_type; | ||
1941 | sc->force_fg_scan = cpu_to_le32(force_fgscan); | ||
1942 | sc->is_legacy = cpu_to_le32(is_legacy); | ||
1943 | sc->home_dwell_time = cpu_to_le32(home_dwell_time); | ||
1944 | sc->force_scan_intvl = cpu_to_le32(force_scan_interval); | ||
1945 | sc->num_ch = num_chan; | ||
1946 | |||
1947 | for (i = 0; i < num_chan; i++) | ||
1948 | sc->ch_list[i] = cpu_to_le16(ch_list[i]); | ||
1949 | |||
1950 | ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID, | ||
1951 | NO_SYNC_WMIFLAG); | ||
1952 | |||
1953 | return ret; | ||
1954 | } | ||
1955 | |||
1956 | /* | ||
1957 | * beginscan supports (compared to old startscan) P2P mgmt operations using | ||
1958 | * station interface, send additional information like supported rates to | ||
1959 | * advertise and xmit rates for probe requests | ||
1960 | */ | ||
1836 | int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, | 1961 | int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, |
1837 | enum wmi_scan_type scan_type, | 1962 | enum wmi_scan_type scan_type, |
1838 | u32 force_fgscan, u32 is_legacy, | 1963 | u32 force_fgscan, u32 is_legacy, |
@@ -1848,6 +1973,15 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, | |||
1848 | int num_rates; | 1973 | int num_rates; |
1849 | u32 ratemask; | 1974 | u32 ratemask; |
1850 | 1975 | ||
1976 | if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, | ||
1977 | ar->fw_capabilities)) { | ||
1978 | return ath6kl_wmi_startscan_cmd(wmi, if_idx, | ||
1979 | scan_type, force_fgscan, | ||
1980 | is_legacy, home_dwell_time, | ||
1981 | force_scan_interval, | ||
1982 | num_chan, ch_list); | ||
1983 | } | ||
1984 | |||
1851 | size = sizeof(struct wmi_begin_scan_cmd); | 1985 | size = sizeof(struct wmi_begin_scan_cmd); |
1852 | 1986 | ||
1853 | if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) | 1987 | if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) |
@@ -1900,50 +2034,24 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, | |||
1900 | return ret; | 2034 | return ret; |
1901 | } | 2035 | } |
1902 | 2036 | ||
1903 | /* ath6kl_wmi_start_scan_cmd is to be deprecated. Use | 2037 | int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable) |
1904 | * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P | ||
1905 | * mgmt operations using station interface. | ||
1906 | */ | ||
1907 | int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, | ||
1908 | enum wmi_scan_type scan_type, | ||
1909 | u32 force_fgscan, u32 is_legacy, | ||
1910 | u32 home_dwell_time, u32 force_scan_interval, | ||
1911 | s8 num_chan, u16 *ch_list) | ||
1912 | { | 2038 | { |
1913 | struct sk_buff *skb; | 2039 | struct sk_buff *skb; |
1914 | struct wmi_start_scan_cmd *sc; | 2040 | struct wmi_enable_sched_scan_cmd *sc; |
1915 | s8 size; | 2041 | int ret; |
1916 | int i, ret; | ||
1917 | |||
1918 | size = sizeof(struct wmi_start_scan_cmd); | ||
1919 | |||
1920 | if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) | ||
1921 | return -EINVAL; | ||
1922 | |||
1923 | if (num_chan > WMI_MAX_CHANNELS) | ||
1924 | return -EINVAL; | ||
1925 | |||
1926 | if (num_chan) | ||
1927 | size += sizeof(u16) * (num_chan - 1); | ||
1928 | 2042 | ||
1929 | skb = ath6kl_wmi_get_new_buf(size); | 2043 | skb = ath6kl_wmi_get_new_buf(sizeof(*sc)); |
1930 | if (!skb) | 2044 | if (!skb) |
1931 | return -ENOMEM; | 2045 | return -ENOMEM; |
1932 | 2046 | ||
1933 | sc = (struct wmi_start_scan_cmd *) skb->data; | 2047 | ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n", |
1934 | sc->scan_type = scan_type; | 2048 | enable ? "enabling" : "disabling", if_idx); |
1935 | sc->force_fg_scan = cpu_to_le32(force_fgscan); | 2049 | sc = (struct wmi_enable_sched_scan_cmd *) skb->data; |
1936 | sc->is_legacy = cpu_to_le32(is_legacy); | 2050 | sc->enable = enable ? 1 : 0; |
1937 | sc->home_dwell_time = cpu_to_le32(home_dwell_time); | ||
1938 | sc->force_scan_intvl = cpu_to_le32(force_scan_interval); | ||
1939 | sc->num_ch = num_chan; | ||
1940 | |||
1941 | for (i = 0; i < num_chan; i++) | ||
1942 | sc->ch_list[i] = cpu_to_le16(ch_list[i]); | ||
1943 | 2051 | ||
1944 | ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID, | 2052 | ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, |
2053 | WMI_ENABLE_SCHED_SCAN_CMDID, | ||
1945 | NO_SYNC_WMIFLAG); | 2054 | NO_SYNC_WMIFLAG); |
1946 | |||
1947 | return ret; | 2055 | return ret; |
1948 | } | 2056 | } |
1949 | 2057 | ||
@@ -2275,8 +2383,10 @@ static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb, | |||
2275 | struct wmi_data_hdr *data_hdr; | 2383 | struct wmi_data_hdr *data_hdr; |
2276 | int ret; | 2384 | int ret; |
2277 | 2385 | ||
2278 | if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) | 2386 | if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) { |
2387 | dev_kfree_skb(skb); | ||
2279 | return -EINVAL; | 2388 | return -EINVAL; |
2389 | } | ||
2280 | 2390 | ||
2281 | skb_push(skb, sizeof(struct wmi_data_hdr)); | 2391 | skb_push(skb, sizeof(struct wmi_data_hdr)); |
2282 | 2392 | ||
@@ -2313,10 +2423,8 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) | |||
2313 | spin_unlock_bh(&wmi->lock); | 2423 | spin_unlock_bh(&wmi->lock); |
2314 | 2424 | ||
2315 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | 2425 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); |
2316 | if (!skb) { | 2426 | if (!skb) |
2317 | ret = -ENOMEM; | 2427 | return -ENOMEM; |
2318 | goto free_skb; | ||
2319 | } | ||
2320 | 2428 | ||
2321 | cmd = (struct wmi_sync_cmd *) skb->data; | 2429 | cmd = (struct wmi_sync_cmd *) skb->data; |
2322 | 2430 | ||
@@ -2339,7 +2447,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) | |||
2339 | * then do not send the Synchronize cmd on the control ep | 2447 | * then do not send the Synchronize cmd on the control ep |
2340 | */ | 2448 | */ |
2341 | if (ret) | 2449 | if (ret) |
2342 | goto free_skb; | 2450 | goto free_cmd_skb; |
2343 | 2451 | ||
2344 | /* | 2452 | /* |
2345 | * Send sync cmd followed by sync data messages on all | 2453 | * Send sync cmd followed by sync data messages on all |
@@ -2349,15 +2457,12 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) | |||
2349 | NO_SYNC_WMIFLAG); | 2457 | NO_SYNC_WMIFLAG); |
2350 | 2458 | ||
2351 | if (ret) | 2459 | if (ret) |
2352 | goto free_skb; | 2460 | goto free_data_skb; |
2353 | |||
2354 | /* cmd buffer sent, we no longer own it */ | ||
2355 | skb = NULL; | ||
2356 | 2461 | ||
2357 | for (index = 0; index < num_pri_streams; index++) { | 2462 | for (index = 0; index < num_pri_streams; index++) { |
2358 | 2463 | ||
2359 | if (WARN_ON(!data_sync_bufs[index].skb)) | 2464 | if (WARN_ON(!data_sync_bufs[index].skb)) |
2360 | break; | 2465 | goto free_data_skb; |
2361 | 2466 | ||
2362 | ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, | 2467 | ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, |
2363 | data_sync_bufs[index]. | 2468 | data_sync_bufs[index]. |
@@ -2366,17 +2471,20 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) | |||
2366 | ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb, | 2471 | ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb, |
2367 | ep_id, if_idx); | 2472 | ep_id, if_idx); |
2368 | 2473 | ||
2369 | if (ret) | ||
2370 | break; | ||
2371 | |||
2372 | data_sync_bufs[index].skb = NULL; | 2474 | data_sync_bufs[index].skb = NULL; |
2475 | |||
2476 | if (ret) | ||
2477 | goto free_data_skb; | ||
2373 | } | 2478 | } |
2374 | 2479 | ||
2375 | free_skb: | 2480 | return 0; |
2481 | |||
2482 | free_cmd_skb: | ||
2376 | /* free up any resources left over (possibly due to an error) */ | 2483 | /* free up any resources left over (possibly due to an error) */ |
2377 | if (skb) | 2484 | if (skb) |
2378 | dev_kfree_skb(skb); | 2485 | dev_kfree_skb(skb); |
2379 | 2486 | ||
2487 | free_data_skb: | ||
2380 | for (index = 0; index < num_pri_streams; index++) { | 2488 | for (index = 0; index < num_pri_streams; index++) { |
2381 | if (data_sync_bufs[index].skb != NULL) { | 2489 | if (data_sync_bufs[index].skb != NULL) { |
2382 | dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. | 2490 | dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. |
@@ -2618,11 +2726,13 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx, | |||
2618 | { | 2726 | { |
2619 | struct sk_buff *skb; | 2727 | struct sk_buff *skb; |
2620 | int ret, mode, band; | 2728 | int ret, mode, band; |
2621 | u64 mcsrate, ratemask[IEEE80211_NUM_BANDS]; | 2729 | u64 mcsrate, ratemask[ATH6KL_NUM_BANDS]; |
2622 | struct wmi_set_tx_select_rates64_cmd *cmd; | 2730 | struct wmi_set_tx_select_rates64_cmd *cmd; |
2623 | 2731 | ||
2624 | memset(&ratemask, 0, sizeof(ratemask)); | 2732 | memset(&ratemask, 0, sizeof(ratemask)); |
2625 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 2733 | |
2734 | /* only check 2.4 and 5 GHz bands, skip the rest */ | ||
2735 | for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) { | ||
2626 | /* copy legacy rate mask */ | 2736 | /* copy legacy rate mask */ |
2627 | ratemask[band] = mask->control[band].legacy; | 2737 | ratemask[band] = mask->control[band].legacy; |
2628 | if (band == IEEE80211_BAND_5GHZ) | 2738 | if (band == IEEE80211_BAND_5GHZ) |
@@ -2668,11 +2778,13 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx, | |||
2668 | { | 2778 | { |
2669 | struct sk_buff *skb; | 2779 | struct sk_buff *skb; |
2670 | int ret, mode, band; | 2780 | int ret, mode, band; |
2671 | u32 mcsrate, ratemask[IEEE80211_NUM_BANDS]; | 2781 | u32 mcsrate, ratemask[ATH6KL_NUM_BANDS]; |
2672 | struct wmi_set_tx_select_rates32_cmd *cmd; | 2782 | struct wmi_set_tx_select_rates32_cmd *cmd; |
2673 | 2783 | ||
2674 | memset(&ratemask, 0, sizeof(ratemask)); | 2784 | memset(&ratemask, 0, sizeof(ratemask)); |
2675 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 2785 | |
2786 | /* only check 2.4 and 5 GHz bands, skip the rest */ | ||
2787 | for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) { | ||
2676 | /* copy legacy rate mask */ | 2788 | /* copy legacy rate mask */ |
2677 | ratemask[band] = mask->control[band].legacy; | 2789 | ratemask[band] = mask->control[band].legacy; |
2678 | if (band == IEEE80211_BAND_5GHZ) | 2790 | if (band == IEEE80211_BAND_5GHZ) |
@@ -2716,7 +2828,7 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx, | |||
2716 | { | 2828 | { |
2717 | struct ath6kl *ar = wmi->parent_dev; | 2829 | struct ath6kl *ar = wmi->parent_dev; |
2718 | 2830 | ||
2719 | if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) | 2831 | if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) |
2720 | return ath6kl_set_bitrate_mask64(wmi, if_idx, mask); | 2832 | return ath6kl_set_bitrate_mask64(wmi, if_idx, mask); |
2721 | else | 2833 | else |
2722 | return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); | 2834 | return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); |
@@ -3139,12 +3251,40 @@ int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance) | |||
3139 | return ret; | 3251 | return ret; |
3140 | } | 3252 | } |
3141 | 3253 | ||
3254 | int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) | ||
3255 | { | ||
3256 | struct sk_buff *skb; | ||
3257 | struct wmi_set_regdomain_cmd *cmd; | ||
3258 | |||
3259 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
3260 | if (!skb) | ||
3261 | return -ENOMEM; | ||
3262 | |||
3263 | cmd = (struct wmi_set_regdomain_cmd *) skb->data; | ||
3264 | memcpy(cmd->iso_name, alpha2, 2); | ||
3265 | |||
3266 | return ath6kl_wmi_cmd_send(wmi, 0, skb, | ||
3267 | WMI_SET_REGDOMAIN_CMDID, | ||
3268 | NO_SYNC_WMIFLAG); | ||
3269 | } | ||
3270 | |||
3142 | s32 ath6kl_wmi_get_rate(s8 rate_index) | 3271 | s32 ath6kl_wmi_get_rate(s8 rate_index) |
3143 | { | 3272 | { |
3273 | u8 sgi = 0; | ||
3274 | |||
3144 | if (rate_index == RATE_AUTO) | 3275 | if (rate_index == RATE_AUTO) |
3145 | return 0; | 3276 | return 0; |
3146 | 3277 | ||
3147 | return wmi_rate_tbl[(u32) rate_index][0]; | 3278 | /* SGI is stored as the MSB of the rate_index */ |
3279 | if (rate_index & RATE_INDEX_MSB) { | ||
3280 | rate_index &= RATE_INDEX_WITHOUT_SGI_MASK; | ||
3281 | sgi = 1; | ||
3282 | } | ||
3283 | |||
3284 | if (WARN_ON(rate_index > RATE_MCS_7_40)) | ||
3285 | rate_index = RATE_MCS_7_40; | ||
3286 | |||
3287 | return wmi_rate_tbl[(u32) rate_index][sgi]; | ||
3148 | } | 3288 | } |
3149 | 3289 | ||
3150 | static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, | 3290 | static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, |
@@ -3634,6 +3774,19 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout) | |||
3634 | NO_SYNC_WMIFLAG); | 3774 | NO_SYNC_WMIFLAG); |
3635 | } | 3775 | } |
3636 | 3776 | ||
3777 | static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap, | ||
3778 | int len) | ||
3779 | { | ||
3780 | struct wmix_hb_challenge_resp_cmd *cmd; | ||
3781 | |||
3782 | if (len < sizeof(struct wmix_hb_challenge_resp_cmd)) | ||
3783 | return; | ||
3784 | |||
3785 | cmd = (struct wmix_hb_challenge_resp_cmd *) datap; | ||
3786 | ath6kl_recovery_hb_event(wmi->parent_dev, | ||
3787 | le32_to_cpu(cmd->cookie)); | ||
3788 | } | ||
3789 | |||
3637 | static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) | 3790 | static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) |
3638 | { | 3791 | { |
3639 | struct wmix_cmd_hdr *cmd; | 3792 | struct wmix_cmd_hdr *cmd; |
@@ -3658,6 +3811,7 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) | |||
3658 | switch (id) { | 3811 | switch (id) { |
3659 | case WMIX_HB_CHALLENGE_RESP_EVENTID: | 3812 | case WMIX_HB_CHALLENGE_RESP_EVENTID: |
3660 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n"); | 3813 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n"); |
3814 | ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len); | ||
3661 | break; | 3815 | break; |
3662 | case WMIX_DBGLOG_EVENTID: | 3816 | case WMIX_DBGLOG_EVENTID: |
3663 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len); | 3817 | ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len); |
@@ -3750,6 +3904,9 @@ static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id, | |||
3750 | case WMI_RX_ACTION_EVENTID: | 3904 | case WMI_RX_ACTION_EVENTID: |
3751 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); | 3905 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); |
3752 | return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); | 3906 | return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); |
3907 | case WMI_TXE_NOTIFY_EVENTID: | ||
3908 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n"); | ||
3909 | return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif); | ||
3753 | default: | 3910 | default: |
3754 | ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id); | 3911 | ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id); |
3755 | return -EINVAL; | 3912 | return -EINVAL; |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 43339aca585..98b1755e67f 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
@@ -48,7 +48,7 @@ | |||
48 | 48 | ||
49 | #define A_BAND_24GHZ 0 | 49 | #define A_BAND_24GHZ 0 |
50 | #define A_BAND_5GHZ 1 | 50 | #define A_BAND_5GHZ 1 |
51 | #define A_NUM_BANDS 2 | 51 | #define ATH6KL_NUM_BANDS 2 |
52 | 52 | ||
53 | /* in ms */ | 53 | /* in ms */ |
54 | #define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 | 54 | #define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 |
@@ -628,6 +628,20 @@ enum wmi_cmd_id { | |||
628 | WMI_SET_MCASTRATE, | 628 | WMI_SET_MCASTRATE, |
629 | 629 | ||
630 | WMI_STA_BMISS_ENHANCE_CMDID, | 630 | WMI_STA_BMISS_ENHANCE_CMDID, |
631 | |||
632 | WMI_SET_REGDOMAIN_CMDID, | ||
633 | |||
634 | WMI_SET_RSSI_FILTER_CMDID, | ||
635 | |||
636 | WMI_SET_KEEP_ALIVE_EXT, | ||
637 | |||
638 | WMI_VOICE_DETECTION_ENABLE_CMDID, | ||
639 | |||
640 | WMI_SET_TXE_NOTIFY_CMDID, | ||
641 | |||
642 | WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/ | ||
643 | |||
644 | WMI_ENABLE_SCHED_SCAN_CMDID, | ||
631 | }; | 645 | }; |
632 | 646 | ||
633 | enum wmi_mgmt_frame_type { | 647 | enum wmi_mgmt_frame_type { |
@@ -843,7 +857,7 @@ struct wmi_begin_scan_cmd { | |||
843 | u8 scan_type; | 857 | u8 scan_type; |
844 | 858 | ||
845 | /* Supported rates to advertise in the probe request frames */ | 859 | /* Supported rates to advertise in the probe request frames */ |
846 | struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS]; | 860 | struct wmi_supp_rates supp_rates[ATH6KL_NUM_BANDS]; |
847 | 861 | ||
848 | /* how many channels follow */ | 862 | /* how many channels follow */ |
849 | u8 num_ch; | 863 | u8 num_ch; |
@@ -941,6 +955,11 @@ struct wmi_scan_params_cmd { | |||
941 | __le32 max_dfsch_act_time; | 955 | __le32 max_dfsch_act_time; |
942 | } __packed; | 956 | } __packed; |
943 | 957 | ||
958 | /* WMI_ENABLE_SCHED_SCAN_CMDID */ | ||
959 | struct wmi_enable_sched_scan_cmd { | ||
960 | u8 enable; | ||
961 | } __packed; | ||
962 | |||
944 | /* WMI_SET_BSS_FILTER_CMDID */ | 963 | /* WMI_SET_BSS_FILTER_CMDID */ |
945 | enum wmi_bss_filter { | 964 | enum wmi_bss_filter { |
946 | /* no beacons forwarded */ | 965 | /* no beacons forwarded */ |
@@ -1032,6 +1051,11 @@ struct wmi_sta_bmiss_enhance_cmd { | |||
1032 | u8 enable; | 1051 | u8 enable; |
1033 | } __packed; | 1052 | } __packed; |
1034 | 1053 | ||
1054 | struct wmi_set_regdomain_cmd { | ||
1055 | u8 length; | ||
1056 | u8 iso_name[2]; | ||
1057 | } __packed; | ||
1058 | |||
1035 | /* WMI_SET_POWER_MODE_CMDID */ | 1059 | /* WMI_SET_POWER_MODE_CMDID */ |
1036 | enum wmi_power_mode { | 1060 | enum wmi_power_mode { |
1037 | REC_POWER = 0x01, | 1061 | REC_POWER = 0x01, |
@@ -1276,6 +1300,11 @@ struct wmi_snr_threshold_params_cmd { | |||
1276 | u8 reserved[3]; | 1300 | u8 reserved[3]; |
1277 | } __packed; | 1301 | } __packed; |
1278 | 1302 | ||
1303 | /* Don't report BSSs with signal (RSSI) below this threshold */ | ||
1304 | struct wmi_set_rssi_filter_cmd { | ||
1305 | s8 rssi; | ||
1306 | } __packed; | ||
1307 | |||
1279 | enum wmi_preamble_policy { | 1308 | enum wmi_preamble_policy { |
1280 | WMI_IGNORE_BARKER_IN_ERP = 0, | 1309 | WMI_IGNORE_BARKER_IN_ERP = 0, |
1281 | WMI_FOLLOW_BARKER_IN_ERP, | 1310 | WMI_FOLLOW_BARKER_IN_ERP, |
@@ -1455,6 +1484,20 @@ enum wmi_event_id { | |||
1455 | WMI_P2P_CAPABILITIES_EVENTID, | 1484 | WMI_P2P_CAPABILITIES_EVENTID, |
1456 | WMI_RX_ACTION_EVENTID, | 1485 | WMI_RX_ACTION_EVENTID, |
1457 | WMI_P2P_INFO_EVENTID, | 1486 | WMI_P2P_INFO_EVENTID, |
1487 | |||
1488 | /* WPS Events */ | ||
1489 | WMI_WPS_GET_STATUS_EVENTID, | ||
1490 | WMI_WPS_PROFILE_EVENTID, | ||
1491 | |||
1492 | /* more P2P events */ | ||
1493 | WMI_NOA_INFO_EVENTID, | ||
1494 | WMI_OPPPS_INFO_EVENTID, | ||
1495 | WMI_PORT_STATUS_EVENTID, | ||
1496 | |||
1497 | /* 802.11w */ | ||
1498 | WMI_GET_RSN_CAP_EVENTID, | ||
1499 | |||
1500 | WMI_TXE_NOTIFY_EVENTID, | ||
1458 | }; | 1501 | }; |
1459 | 1502 | ||
1460 | struct wmi_ready_event_2 { | 1503 | struct wmi_ready_event_2 { |
@@ -1749,6 +1792,9 @@ struct rx_stats { | |||
1749 | a_sle32 ucast_rate; | 1792 | a_sle32 ucast_rate; |
1750 | } __packed; | 1793 | } __packed; |
1751 | 1794 | ||
1795 | #define RATE_INDEX_WITHOUT_SGI_MASK 0x7f | ||
1796 | #define RATE_INDEX_MSB 0x80 | ||
1797 | |||
1752 | struct tkip_ccmp_stats { | 1798 | struct tkip_ccmp_stats { |
1753 | __le32 tkip_local_mic_fail; | 1799 | __le32 tkip_local_mic_fail; |
1754 | __le32 tkip_cnter_measures_invoked; | 1800 | __le32 tkip_cnter_measures_invoked; |
@@ -2019,7 +2065,6 @@ struct wmi_set_ie_cmd { | |||
2019 | 2065 | ||
2020 | #define WOW_MAX_FILTERS_PER_LIST 4 | 2066 | #define WOW_MAX_FILTERS_PER_LIST 4 |
2021 | #define WOW_PATTERN_SIZE 64 | 2067 | #define WOW_PATTERN_SIZE 64 |
2022 | #define WOW_MASK_SIZE 64 | ||
2023 | 2068 | ||
2024 | #define MAC_MAX_FILTERS_PER_LIST 4 | 2069 | #define MAC_MAX_FILTERS_PER_LIST 4 |
2025 | 2070 | ||
@@ -2028,7 +2073,7 @@ struct wow_filter { | |||
2028 | u8 wow_filter_id; | 2073 | u8 wow_filter_id; |
2029 | u8 wow_filter_size; | 2074 | u8 wow_filter_size; |
2030 | u8 wow_filter_offset; | 2075 | u8 wow_filter_offset; |
2031 | u8 wow_filter_mask[WOW_MASK_SIZE]; | 2076 | u8 wow_filter_mask[WOW_PATTERN_SIZE]; |
2032 | u8 wow_filter_pattern[WOW_PATTERN_SIZE]; | 2077 | u8 wow_filter_pattern[WOW_PATTERN_SIZE]; |
2033 | } __packed; | 2078 | } __packed; |
2034 | 2079 | ||
@@ -2087,6 +2132,19 @@ struct wmi_del_wow_pattern_cmd { | |||
2087 | __le16 filter_id; | 2132 | __le16 filter_id; |
2088 | } __packed; | 2133 | } __packed; |
2089 | 2134 | ||
2135 | /* WMI_SET_TXE_NOTIFY_CMDID */ | ||
2136 | struct wmi_txe_notify_cmd { | ||
2137 | __le32 rate; | ||
2138 | __le32 pkts; | ||
2139 | __le32 intvl; | ||
2140 | } __packed; | ||
2141 | |||
2142 | /* WMI_TXE_NOTIFY_EVENTID */ | ||
2143 | struct wmi_txe_notify_event { | ||
2144 | __le32 rate; | ||
2145 | __le32 pkts; | ||
2146 | } __packed; | ||
2147 | |||
2090 | /* WMI_SET_AKMP_PARAMS_CMD */ | 2148 | /* WMI_SET_AKMP_PARAMS_CMD */ |
2091 | 2149 | ||
2092 | struct wmi_pmkid { | 2150 | struct wmi_pmkid { |
@@ -2505,11 +2563,6 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx, | |||
2505 | int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid, | 2563 | int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid, |
2506 | u16 channel); | 2564 | u16 channel); |
2507 | int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx); | 2565 | int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx); |
2508 | int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, | ||
2509 | enum wmi_scan_type scan_type, | ||
2510 | u32 force_fgscan, u32 is_legacy, | ||
2511 | u32 home_dwell_time, u32 force_scan_interval, | ||
2512 | s8 num_chan, u16 *ch_list); | ||
2513 | 2566 | ||
2514 | int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, | 2567 | int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, |
2515 | enum wmi_scan_type scan_type, | 2568 | enum wmi_scan_type scan_type, |
@@ -2517,6 +2570,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, | |||
2517 | u32 home_dwell_time, u32 force_scan_interval, | 2570 | u32 home_dwell_time, u32 force_scan_interval, |
2518 | s8 num_chan, u16 *ch_list, u32 no_cck, | 2571 | s8 num_chan, u16 *ch_list, u32 no_cck, |
2519 | u32 *rates); | 2572 | u32 *rates); |
2573 | int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable); | ||
2520 | 2574 | ||
2521 | int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec, | 2575 | int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec, |
2522 | u16 fg_end_sec, u16 bg_sec, | 2576 | u16 fg_end_sec, u16 bg_sec, |
@@ -2592,6 +2646,7 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | |||
2592 | const u8 *mask); | 2646 | const u8 *mask); |
2593 | int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | 2647 | int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, |
2594 | u16 list_id, u16 filter_id); | 2648 | u16 list_id, u16 filter_id); |
2649 | int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi); | ||
2595 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); | 2650 | int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); |
2596 | int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); | 2651 | int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); |
2597 | int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); | 2652 | int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); |
@@ -2600,6 +2655,9 @@ int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); | |||
2600 | int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, | 2655 | int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, |
2601 | u8 *filter, bool add_filter); | 2656 | u8 *filter, bool add_filter); |
2602 | int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); | 2657 | int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); |
2658 | int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, | ||
2659 | u32 rate, u32 pkts, u32 intvl); | ||
2660 | int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2); | ||
2603 | 2661 | ||
2604 | /* AP mode uAPSD */ | 2662 | /* AP mode uAPSD */ |
2605 | int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); | 2663 | int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); |
@@ -2658,6 +2716,8 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout); | |||
2658 | 2716 | ||
2659 | void ath6kl_wmi_sscan_timer(unsigned long ptr); | 2717 | void ath6kl_wmi_sscan_timer(unsigned long ptr); |
2660 | 2718 | ||
2719 | int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); | ||
2720 | |||
2661 | struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx); | 2721 | struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx); |
2662 | void *ath6kl_wmi_init(struct ath6kl *devt); | 2722 | void *ath6kl_wmi_init(struct ath6kl *devt); |
2663 | void ath6kl_wmi_shutdown(struct wmi *wmi); | 2723 | void ath6kl_wmi_shutdown(struct wmi *wmi); |