aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorThomas Pedersen <c_tpeder@qca.qualcomm.com>2012-08-15 19:51:24 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2012-10-24 04:49:46 -0400
commitb1f47e3a962b8b69612d1eecf4d50082b402fcc5 (patch)
tree0e7d9fc72282e9ac0e78ec8c3106cecb17176cff /drivers/net/wireless/ath
parenta3b3842c2e27ba07f8f7944a76013425d182c47b (diff)
ath6kl: rework scheduled scan
This patch reflects changes in the firmware scheduled scan implementation to behave better in cases with multiple concurrent vifs. Major changes: - scheduled scan filters and state are now programmed per-vif. - decouple scheduled scan from host sleep. To maintain graceful failure with old firmwares, a new firmware capability bit is introduced: ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2. ath6kl simply won't advertise scheduled scan to cfg80211 if the SCHED_SCAN_V2 is not supported. Since firmwares from here on out won't support the previous implicit API for scheduled scan (set WoW filters and host sleep), bump the firmware API to protect old drivers. Unfortunately, due to firmware RAM constraints ath6kl still cannot expect a scan complete event at the end of a scheduled scan results cycle, so the sched_scan_timer is retained. Signed-off-by: Thomas Pedersen <c_tpeder@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c45
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.h1
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h6
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c6
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c19
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c23
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h10
7 files changed, 50 insertions, 60 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 75ddfafb11b..850c94f6ebc 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -147,15 +147,11 @@ 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 ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false);
155 ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
156 ATH6KL_HOST_MODE_AWAKE);
157
158 ar->state = ATH6KL_STATE_ON;
159 155
160 return true; 156 return true;
161} 157}
@@ -2448,13 +2444,6 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
2448 2444
2449 break; 2445 break;
2450 2446
2451 case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
2452 /*
2453 * Nothing needed for schedule scan, firmware is already in
2454 * wow mode and sleeping most of the time.
2455 */
2456 break;
2457
2458 default: 2447 default:
2459 break; 2448 break;
2460 } 2449 }
@@ -2502,9 +2491,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
2502 } 2491 }
2503 break; 2492 break;
2504 2493
2505 case ATH6KL_STATE_SCHED_SCAN:
2506 break;
2507
2508 default: 2494 default:
2509 break; 2495 break;
2510 } 2496 }
@@ -3246,10 +3232,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
3246 if (vif->sme_state != SME_DISCONNECTED) 3232 if (vif->sme_state != SME_DISCONNECTED)
3247 return -EBUSY; 3233 return -EBUSY;
3248 3234
3249 /* The FW currently can't support multi-vif WoW properly. */
3250 if (ar->num_vif > 1)
3251 return -EIO;
3252
3253 ath6kl_cfg80211_scan_complete_event(vif, true); 3235 ath6kl_cfg80211_scan_complete_event(vif, true);
3254 3236
3255 ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, 3237 ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
@@ -3295,15 +3277,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
3295 interval, interval, 3277 interval, interval,
3296 vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); 3278 vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
3297 3279
3298 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
3299 ATH6KL_WOW_MODE_ENABLE,
3300 WOW_FILTER_SSID,
3301 WOW_HOST_REQ_DELAY);
3302 if (ret) {
3303 ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
3304 return ret;
3305 }
3306
3307 /* this also clears IE in fw if it's not set */ 3280 /* this also clears IE in fw if it's not set */
3308 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, 3281 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
3309 WMI_FRAME_PROBE_REQ, 3282 WMI_FRAME_PROBE_REQ,
@@ -3314,17 +3287,13 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
3314 return ret; 3287 return ret;
3315 } 3288 }
3316 3289
3317 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, 3290 ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true);
3318 ATH6KL_HOST_MODE_ASLEEP); 3291 if (ret)
3319 if (ret) {
3320 ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
3321 ret);
3322 return ret; 3292 return ret;
3323 }
3324 3293
3325 ar->state = ATH6KL_STATE_SCHED_SCAN; 3294 set_bit(SCHED_SCANNING, &vif->flags);
3326 3295
3327 return ret; 3296 return 0;
3328} 3297}
3329 3298
3330static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, 3299static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
@@ -3763,7 +3732,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
3763 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | 3732 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
3764 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; 3733 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
3765 3734
3766 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) 3735 if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities))
3767 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; 3736 ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
3768 3737
3769 if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, 3738 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
28struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, 27struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index a95bf6ab7ec..8b31b9a0f38 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -127,6 +127,9 @@ enum ath6kl_fw_capability {
127 /* supports WMI_SET_REGDOMAIN_CMDID command */ 127 /* supports WMI_SET_REGDOMAIN_CMDID command */
128 ATH6KL_FW_CAPABILITY_REGDOMAIN, 128 ATH6KL_FW_CAPABILITY_REGDOMAIN,
129 129
130 /* Firmware supports sched scan decoupled from host sleep */
131 ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2,
132
130 /* this needs to be last */ 133 /* this needs to be last */
131 ATH6KL_FW_CAPABILITY_MAX, 134 ATH6KL_FW_CAPABILITY_MAX,
132}; 135};
@@ -145,6 +148,7 @@ enum ath6kl_hw_flags {
145 148
146#define ATH6KL_FW_API2_FILE "fw-2.bin" 149#define ATH6KL_FW_API2_FILE "fw-2.bin"
147#define ATH6KL_FW_API3_FILE "fw-3.bin" 150#define ATH6KL_FW_API3_FILE "fw-3.bin"
151#define ATH6KL_FW_API4_FILE "fw-4.bin"
148 152
149/* AR6003 1.0 definitions */ 153/* AR6003 1.0 definitions */
150#define AR6003_HW_1_0_VERSION 0x300002ba 154#define AR6003_HW_1_0_VERSION 0x300002ba
@@ -555,6 +559,7 @@ enum ath6kl_vif_state {
555 HOST_SLEEP_MODE_CMD_PROCESSED, 559 HOST_SLEEP_MODE_CMD_PROCESSED,
556 NETDEV_MCAST_ALL_ON, 560 NETDEV_MCAST_ALL_ON,
557 NETDEV_MCAST_ALL_OFF, 561 NETDEV_MCAST_ALL_OFF,
562 SCHED_SCANNING,
558}; 563};
559 564
560struct ath6kl_vif { 565struct ath6kl_vif {
@@ -640,7 +645,6 @@ enum ath6kl_state {
640 ATH6KL_STATE_DEEPSLEEP, 645 ATH6KL_STATE_DEEPSLEEP,
641 ATH6KL_STATE_CUTPOWER, 646 ATH6KL_STATE_CUTPOWER,
642 ATH6KL_STATE_WOW, 647 ATH6KL_STATE_WOW,
643 ATH6KL_STATE_SCHED_SCAN,
644}; 648};
645 649
646struct ath6kl { 650struct ath6kl {
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 8bd429975e4..eb3677bd6e8 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1108,6 +1108,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar)
1108 if (ret) 1108 if (ret)
1109 return ret; 1109 return ret;
1110 1110
1111 ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE);
1112 if (ret == 0) {
1113 ar->fw_api = 4;
1114 goto out;
1115 }
1116
1111 ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); 1117 ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);
1112 if (ret == 0) { 1118 if (ret == 0) {
1113 ar->fw_api = 3; 1119 ar->fw_api = 3;
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 65e99833151..cc17fe02bda 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -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,9 +926,6 @@ 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
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 373751f9177..e95b035168a 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -1116,7 +1116,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 1116 * the timer would not ever fire if the scan interval is short
1117 * enough. 1117 * enough.
1118 */ 1118 */
1119 if (ar->state == ATH6KL_STATE_SCHED_SCAN && 1119 if (test_bit(SCHED_SCANNING, &vif->flags) &&
1120 !timer_pending(&vif->sched_scan_timer)) { 1120 !timer_pending(&vif->sched_scan_timer)) {
1121 mod_timer(&vif->sched_scan_timer, jiffies + 1121 mod_timer(&vif->sched_scan_timer, jiffies +
1122 msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY)); 1122 msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
@@ -2027,6 +2027,27 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
2027 return ret; 2027 return ret;
2028} 2028}
2029 2029
2030int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable)
2031{
2032 struct sk_buff *skb;
2033 struct wmi_enable_sched_scan_cmd *sc;
2034 int ret;
2035
2036 skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
2037 if (!skb)
2038 return -ENOMEM;
2039
2040 ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n",
2041 enable ? "enabling" : "disabling", if_idx);
2042 sc = (struct wmi_enable_sched_scan_cmd *) skb->data;
2043 sc->enable = enable ? 1 : 0;
2044
2045 ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
2046 WMI_ENABLE_SCHED_SCAN_CMDID,
2047 NO_SYNC_WMIFLAG);
2048 return ret;
2049}
2050
2030int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, 2051int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx,
2031 u16 fg_start_sec, 2052 u16 fg_start_sec,
2032 u16 fg_end_sec, u16 bg_sec, 2053 u16 fg_end_sec, u16 bg_sec,
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 9c73ae73f26..a791b1bbe0c 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -638,6 +638,10 @@ enum wmi_cmd_id {
638 WMI_VOICE_DETECTION_ENABLE_CMDID, 638 WMI_VOICE_DETECTION_ENABLE_CMDID,
639 639
640 WMI_SET_TXE_NOTIFY_CMDID, 640 WMI_SET_TXE_NOTIFY_CMDID,
641
642 WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/
643
644 WMI_ENABLE_SCHED_SCAN_CMDID,
641}; 645};
642 646
643enum wmi_mgmt_frame_type { 647enum wmi_mgmt_frame_type {
@@ -951,6 +955,11 @@ struct wmi_scan_params_cmd {
951 __le32 max_dfsch_act_time; 955 __le32 max_dfsch_act_time;
952} __packed; 956} __packed;
953 957
958/* WMI_ENABLE_SCHED_SCAN_CMDID */
959struct wmi_enable_sched_scan_cmd {
960 u8 enable;
961} __packed;
962
954/* WMI_SET_BSS_FILTER_CMDID */ 963/* WMI_SET_BSS_FILTER_CMDID */
955enum wmi_bss_filter { 964enum wmi_bss_filter {
956 /* no beacons forwarded */ 965 /* no beacons forwarded */
@@ -2559,6 +2568,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
2559 u32 home_dwell_time, u32 force_scan_interval, 2568 u32 home_dwell_time, u32 force_scan_interval,
2560 s8 num_chan, u16 *ch_list, u32 no_cck, 2569 s8 num_chan, u16 *ch_list, u32 no_cck,
2561 u32 *rates); 2570 u32 *rates);
2571int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable);
2562 2572
2563int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec, 2573int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec,
2564 u16 fg_end_sec, u16 bg_sec, 2574 u16 fg_end_sec, u16 bg_sec,