aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath6kl/cfg80211.c
diff options
context:
space:
mode:
authorKalle Valo <kvalo@qca.qualcomm.com>2011-12-13 07:52:07 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2011-12-13 08:03:49 -0500
commit10509f903ebb7d2a02571f30cb937dd923b023cf (patch)
tree6787da43aeb8eaecac6f9d82e640a639ceb3e20f /drivers/net/wireless/ath/ath6kl/cfg80211.c
parent277d90f4ba4b7ebb35b85a5d6c58dce2f1e1b58d (diff)
ath6kl: implement scheduled scan
ath6kl firmware supports scheduled scan functionality with the wow ssid filter. But the firmware does not send any events after scan results so I had to add a timer which notifies about new scan results. Sched scan needs firmware version 3.2.0.6 or later. If firmware doesn't support sched scan the driver will not enable the feature. Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/cfg80211.c')
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 074e2aabf41e..48d414acefee 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -123,6 +123,37 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
123 123
124#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ 124#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
125 125
126/* returns true if scheduled scan was stopped */
127static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
128{
129 struct ath6kl *ar = vif->ar;
130
131 if (ar->state != ATH6KL_STATE_SCHED_SCAN)
132 return false;
133
134 del_timer_sync(&vif->sched_scan_timer);
135
136 ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
137 ATH6KL_HOST_MODE_AWAKE);
138
139 ar->state = ATH6KL_STATE_ON;
140
141 return true;
142}
143
144static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
145{
146 struct ath6kl *ar = vif->ar;
147 bool stopped;
148
149 stopped = __ath6kl_cfg80211_sscan_stop(vif);
150
151 if (!stopped)
152 return;
153
154 cfg80211_sched_scan_stopped(ar->wiphy);
155}
156
126static int ath6kl_set_wpa_version(struct ath6kl_vif *vif, 157static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
127 enum nl80211_wpa_versions wpa_version) 158 enum nl80211_wpa_versions wpa_version)
128{ 159{
@@ -383,6 +414,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
383 struct ath6kl_vif *vif = netdev_priv(dev); 414 struct ath6kl_vif *vif = netdev_priv(dev);
384 int status; 415 int status;
385 416
417 ath6kl_cfg80211_sscan_disable(vif);
418
386 vif->sme_state = SME_CONNECTING; 419 vif->sme_state = SME_CONNECTING;
387 420
388 if (!ath6kl_cfg80211_ready(vif)) 421 if (!ath6kl_cfg80211_ready(vif))
@@ -710,6 +743,8 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
710 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__, 743 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
711 reason_code); 744 reason_code);
712 745
746 ath6kl_cfg80211_sscan_disable(vif);
747
713 if (!ath6kl_cfg80211_ready(vif)) 748 if (!ath6kl_cfg80211_ready(vif))
714 return -EIO; 749 return -EIO;
715 750
@@ -812,6 +847,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
812 if (!ath6kl_cfg80211_ready(vif)) 847 if (!ath6kl_cfg80211_ready(vif))
813 return -EIO; 848 return -EIO;
814 849
850 ath6kl_cfg80211_sscan_disable(vif);
851
815 if (!ar->usr_bss_filter) { 852 if (!ar->usr_bss_filter) {
816 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); 853 clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
817 ret = ath6kl_wmi_bssfilter_cmd( 854 ret = ath6kl_wmi_bssfilter_cmd(
@@ -837,6 +874,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
837 request->ssids[i].ssid); 874 request->ssids[i].ssid);
838 } 875 }
839 876
877 /*
878 * FIXME: we should clear the IE in fw if it's not set so just
879 * remove the check altogether
880 */
840 if (request->ie) { 881 if (request->ie) {
841 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, 882 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
842 WMI_FRAME_PROBE_REQ, 883 WMI_FRAME_PROBE_REQ,
@@ -1835,6 +1876,13 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
1835 1876
1836 break; 1877 break;
1837 1878
1879 case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
1880 /*
1881 * Nothing needed for schedule scan, firmware is already in
1882 * wow mode and sleeping most of the time.
1883 */
1884 break;
1885
1838 default: 1886 default:
1839 break; 1887 break;
1840 } 1888 }
@@ -1883,6 +1931,9 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
1883 } 1931 }
1884 break; 1932 break;
1885 1933
1934 case ATH6KL_STATE_SCHED_SCAN:
1935 break;
1936
1886 default: 1937 default:
1887 break; 1938 break;
1888 } 1939 }
@@ -2329,6 +2380,90 @@ static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
2329 } 2380 }
2330} 2381}
2331 2382
2383static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
2384 struct net_device *dev,
2385 struct cfg80211_sched_scan_request *request)
2386{
2387 struct ath6kl *ar = ath6kl_priv(dev);
2388 struct ath6kl_vif *vif = netdev_priv(dev);
2389 u16 interval;
2390 int ret;
2391 u8 i;
2392
2393 if (ar->state != ATH6KL_STATE_ON)
2394 return -EIO;
2395
2396 if (vif->sme_state != SME_DISCONNECTED)
2397 return -EBUSY;
2398
2399 for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
2400 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2401 i, DISABLE_SSID_FLAG,
2402 0, NULL);
2403 }
2404
2405 /* fw uses seconds, also make sure that it's >0 */
2406 interval = max_t(u16, 1, request->interval / 1000);
2407
2408 ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
2409 interval, interval,
2410 10, 0, 0, 0, 3, 0, 0, 0);
2411
2412 if (request->n_ssids && request->ssids[0].ssid_len) {
2413 for (i = 0; i < request->n_ssids; i++) {
2414 ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
2415 i, SPECIFIC_SSID_FLAG,
2416 request->ssids[i].ssid_len,
2417 request->ssids[i].ssid);
2418 }
2419 }
2420
2421 ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
2422 ATH6KL_WOW_MODE_ENABLE,
2423 WOW_FILTER_SSID,
2424 WOW_HOST_REQ_DELAY);
2425 if (ret) {
2426 ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
2427 return ret;
2428 }
2429
2430 /* this also clears IE in fw if it's not set */
2431 ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
2432 WMI_FRAME_PROBE_REQ,
2433 request->ie, request->ie_len);
2434 if (ret) {
2435 ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
2436 ret);
2437 return ret;
2438 }
2439
2440 ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
2441 ATH6KL_HOST_MODE_ASLEEP);
2442 if (ret) {
2443 ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
2444 ret);
2445 return ret;
2446 }
2447
2448 ar->state = ATH6KL_STATE_SCHED_SCAN;
2449
2450 return ret;
2451}
2452
2453static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
2454 struct net_device *dev)
2455{
2456 struct ath6kl_vif *vif = netdev_priv(dev);
2457 bool stopped;
2458
2459 stopped = __ath6kl_cfg80211_sscan_stop(vif);
2460
2461 if (!stopped)
2462 return -EIO;
2463
2464 return 0;
2465}
2466
2332static const struct ieee80211_txrx_stypes 2467static const struct ieee80211_txrx_stypes
2333ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { 2468ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
2334 [NL80211_IFTYPE_STATION] = { 2469 [NL80211_IFTYPE_STATION] = {
@@ -2386,10 +2521,14 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
2386 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, 2521 .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
2387 .mgmt_tx = ath6kl_mgmt_tx, 2522 .mgmt_tx = ath6kl_mgmt_tx,
2388 .mgmt_frame_register = ath6kl_mgmt_frame_register, 2523 .mgmt_frame_register = ath6kl_mgmt_frame_register,
2524 .sched_scan_start = ath6kl_cfg80211_sscan_start,
2525 .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
2389}; 2526};
2390 2527
2391void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) 2528void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
2392{ 2529{
2530 ath6kl_cfg80211_sscan_disable(vif);
2531
2393 switch (vif->sme_state) { 2532 switch (vif->sme_state) {
2394 case SME_DISCONNECTED: 2533 case SME_DISCONNECTED:
2395 break; 2534 break;
@@ -2546,6 +2685,8 @@ int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
2546 wiphy->wowlan.pattern_min_len = 1; 2685 wiphy->wowlan.pattern_min_len = 1;
2547 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; 2686 wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
2548 2687
2688 wiphy->max_sched_scan_ssids = 10;
2689
2549 ret = wiphy_register(wiphy); 2690 ret = wiphy_register(wiphy);
2550 if (ret < 0) { 2691 if (ret < 0) {
2551 ath6kl_err("couldn't register wiphy device\n"); 2692 ath6kl_err("couldn't register wiphy device\n");
@@ -2565,6 +2706,9 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)
2565 2706
2566 setup_timer(&vif->disconnect_timer, disconnect_timer_handler, 2707 setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
2567 (unsigned long) vif->ndev); 2708 (unsigned long) vif->ndev);
2709 setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
2710 (unsigned long) vif);
2711
2568 set_bit(WMM_ENABLED, &vif->flags); 2712 set_bit(WMM_ENABLED, &vif->flags);
2569 spin_lock_init(&vif->if_lock); 2713 spin_lock_init(&vif->if_lock);
2570 2714