linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] ath6kl: scheduled scan support
@ 2011-12-13 12:50 Kalle Valo
  2011-12-13 12:51 ` [PATCH v2 1/6] ath6kl: remove a workaround from ath6kl_cfg80211_stop() Kalle Valo
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Kalle Valo @ 2011-12-13 12:50 UTC (permalink / raw)
  To: kvalo; +Cc: ath6kl-devel, linux-wireless

Here's v2 of my sched scan patches. Changes from v1 are just a
proper a commit log for patch 6 and removed a fixme comment which
I had already fixed.

---

Kalle Valo (6):
      ath6kl: remove a workaround from ath6kl_cfg80211_stop()
      ath6kl: call ath6kl_cfg80211_stop() from ath6kl_close()
      ath6kl: implement ath6kl_cfg80211_stop_all()
      ath6kl: fix value of WOW_FILTER_SSID
      ath6kl: fix reading of FW IE capabilities
      ath6kl: implement scheduled scan


 drivers/net/wireless/ath/ath6kl/cfg80211.c |  203 ++++++++++++++++++++++++----
 drivers/net/wireless/ath/ath6kl/cfg80211.h |    6 +
 drivers/net/wireless/ath/ath6kl/core.h     |    7 +
 drivers/net/wireless/ath/ath6kl/init.c     |    8 +
 drivers/net/wireless/ath/ath6kl/main.c     |   12 --
 drivers/net/wireless/ath/ath6kl/sdio.c     |   26 +++-
 drivers/net/wireless/ath/ath6kl/wmi.c      |   27 ++++
 drivers/net/wireless/ath/ath6kl/wmi.h      |    4 -
 8 files changed, 249 insertions(+), 44 deletions(-)


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/6] ath6kl: remove a workaround from ath6kl_cfg80211_stop()
  2011-12-13 12:50 [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
@ 2011-12-13 12:51 ` Kalle Valo
  2011-12-13 12:51 ` [PATCH v2 2/6] ath6kl: call ath6kl_cfg80211_stop() from ath6kl_close() Kalle Valo
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Kalle Valo @ 2011-12-13 12:51 UTC (permalink / raw)
  To: kvalo; +Cc: ath6kl-devel, linux-wireless

There's a workaround in ath6kl_cfg80211_stop() which emits disconnected
even when sme_state was disconnected. This is legacy from the old
staging driver and I can't repoduce the old problem anymore. I assume the
bug got fixed while the driver was cleaned up so let's get
rid of the hack.

This makes it possible to call ath6kl_cfg80211_stop from ath6kl_close()
which happens in a followup patch.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath6kl/cfg80211.c |    8 ++------
 1 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index aa93527..5f12c04 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2406,6 +2406,8 @@ void ath6kl_cfg80211_stop(struct ath6kl *ar)
 	}
 
 	switch (vif->sme_state) {
+	case SME_DISCONNECTED:
+		break;
 	case SME_CONNECTING:
 		cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
 					NULL, 0,
@@ -2413,12 +2415,6 @@ void ath6kl_cfg80211_stop(struct ath6kl *ar)
 					GFP_KERNEL);
 		break;
 	case SME_CONNECTED:
-	default:
-		/*
-		 * FIXME: oddly enough smeState is in DISCONNECTED during
-		 * suspend, why? Need to send disconnected event in that
-		 * state.
-		 */
 		cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
 		break;
 	}


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/6] ath6kl: call ath6kl_cfg80211_stop() from ath6kl_close()
  2011-12-13 12:50 [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
  2011-12-13 12:51 ` [PATCH v2 1/6] ath6kl: remove a workaround from ath6kl_cfg80211_stop() Kalle Valo
@ 2011-12-13 12:51 ` Kalle Valo
  2011-12-13 12:51 ` [PATCH v2 3/6] ath6kl: implement ath6kl_cfg80211_stop_all() Kalle Valo
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Kalle Valo @ 2011-12-13 12:51 UTC (permalink / raw)
  To: kvalo; +Cc: ath6kl-devel, linux-wireless

This way it's possible to keep all disconnect logic in one function and
easier to add new functionality, like stopping scheduled scan.

There are some changes to commands called during network interface close,
but there should not be any visible changes in functionality.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath6kl/main.c |   11 +----------
 1 files changed, 1 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index d9b4ba4..0c7a013 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -1005,16 +1005,7 @@ static int ath6kl_close(struct net_device *dev)
 
 	netif_stop_queue(dev);
 
-	ath6kl_disconnect(vif);
-
-	if (test_bit(WMI_READY, &ar->flag)) {
-		if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF,
-					      0, 0, 0, 0, 0, 0, 0, 0, 0))
-			return -EIO;
-
-	}
-
-	ath6kl_cfg80211_scan_complete_event(vif, true);
+	ath6kl_cfg80211_stop(ar);
 
 	clear_bit(WLAN_ENABLED, &vif->flags);
 


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/6] ath6kl: implement ath6kl_cfg80211_stop_all()
  2011-12-13 12:50 [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
  2011-12-13 12:51 ` [PATCH v2 1/6] ath6kl: remove a workaround from ath6kl_cfg80211_stop() Kalle Valo
  2011-12-13 12:51 ` [PATCH v2 2/6] ath6kl: call ath6kl_cfg80211_stop() from ath6kl_close() Kalle Valo
@ 2011-12-13 12:51 ` Kalle Valo
  2011-12-13 12:51 ` [PATCH v2 4/6] ath6kl: fix value of WOW_FILTER_SSID Kalle Valo
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Kalle Valo @ 2011-12-13 12:51 UTC (permalink / raw)
  To: kvalo; +Cc: ath6kl-devel, linux-wireless

During suspend we need to stop all vifs, not just the first.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath6kl/cfg80211.c |   53 ++++++++++++++++------------
 drivers/net/wireless/ath/ath6kl/cfg80211.h |    3 +-
 drivers/net/wireless/ath/ath6kl/main.c     |    3 +-
 3 files changed, 34 insertions(+), 25 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 5f12c04..2bab65f 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1799,7 +1799,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
 
 	case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
 
-		ath6kl_cfg80211_stop(ar);
+		ath6kl_cfg80211_stop_all(ar);
 
 		/* save the current power mode before enabling power save */
 		ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
@@ -1816,7 +1816,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
 
 	case ATH6KL_CFG_SUSPEND_CUTPOWER:
 
-		ath6kl_cfg80211_stop(ar);
+		ath6kl_cfg80211_stop_all(ar);
 
 		if (ar->state == ATH6KL_STATE_OFF) {
 			ath6kl_dbg(ATH6KL_DBG_SUSPEND,
@@ -2389,22 +2389,8 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
 	.mgmt_frame_register = ath6kl_mgmt_frame_register,
 };
 
-void ath6kl_cfg80211_stop(struct ath6kl *ar)
+void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
 {
-	struct ath6kl_vif *vif;
-
-	/* FIXME: for multi vif */
-	vif = ath6kl_vif_first(ar);
-	if (!vif) {
-		/* save the current power mode before enabling power save */
-		ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
-
-		if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
-			ath6kl_warn("ath6kl_deep_sleep_enable: "
-				    "wmi_powermode_cmd failed\n");
-		return;
-	}
-
 	switch (vif->sme_state) {
 	case SME_DISCONNECTED:
 		break;
@@ -2421,21 +2407,44 @@ void ath6kl_cfg80211_stop(struct ath6kl *ar)
 
 	if (test_bit(CONNECTED, &vif->flags) ||
 	    test_bit(CONNECT_PEND, &vif->flags))
-		ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
+		ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
 
 	vif->sme_state = SME_DISCONNECTED;
 	clear_bit(CONNECTED, &vif->flags);
 	clear_bit(CONNECT_PEND, &vif->flags);
 
 	/* disable scanning */
-	if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0,
-				      0, 0, 0, 0, 0, 0, 0) != 0)
-		printk(KERN_WARNING "ath6kl: failed to disable scan "
-		       "during suspend\n");
+	if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
+				      0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
+		ath6kl_warn("failed to disable scan during stop\n");
 
 	ath6kl_cfg80211_scan_complete_event(vif, true);
 }
 
+void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
+{
+	struct ath6kl_vif *vif;
+
+	vif = ath6kl_vif_first(ar);
+	if (!vif) {
+		/* save the current power mode before enabling power save */
+		ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
+
+		if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
+			ath6kl_warn("ath6kl_deep_sleep_enable: "
+				    "wmi_powermode_cmd failed\n");
+		return;
+	}
+
+	/*
+	 * FIXME: we should take ar->list_lock to protect changes in the
+	 * vif_list, but that's not trivial to do as ath6kl_cfg80211_stop()
+	 * sleeps.
+	 */
+	list_for_each_entry(vif, &ar->vif_list, list)
+		ath6kl_cfg80211_stop(vif);
+}
+
 struct ath6kl *ath6kl_core_alloc(struct device *dev)
 {
 	struct ath6kl *ar;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index 59fa9d8..226a734 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -52,6 +52,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
 
 int ath6kl_cfg80211_resume(struct ath6kl *ar);
 
-void ath6kl_cfg80211_stop(struct ath6kl *ar);
+void ath6kl_cfg80211_stop(struct ath6kl_vif *vif);
+void ath6kl_cfg80211_stop_all(struct ath6kl *ar);
 
 #endif /* ATH6KL_CFG80211_H */
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 0c7a013..f96e9f3 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -1000,12 +1000,11 @@ static int ath6kl_open(struct net_device *dev)
 
 static int ath6kl_close(struct net_device *dev)
 {
-	struct ath6kl *ar = ath6kl_priv(dev);
 	struct ath6kl_vif *vif = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
-	ath6kl_cfg80211_stop(ar);
+	ath6kl_cfg80211_stop(vif);
 
 	clear_bit(WLAN_ENABLED, &vif->flags);
 


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/6] ath6kl: fix value of WOW_FILTER_SSID
  2011-12-13 12:50 [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
                   ` (2 preceding siblings ...)
  2011-12-13 12:51 ` [PATCH v2 3/6] ath6kl: implement ath6kl_cfg80211_stop_all() Kalle Valo
@ 2011-12-13 12:51 ` Kalle Valo
  2011-12-13 12:51 ` [PATCH v2 5/6] ath6kl: fix reading of FW IE capabilities Kalle Valo
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Kalle Valo @ 2011-12-13 12:51 UTC (permalink / raw)
  To: kvalo; +Cc: ath6kl-devel, linux-wireless

According to the firmware engineers WOW_FILTER_SSID is actually the
second bit, not the first.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath6kl/wmi.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 4e4f0f7..cbde79c 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1808,7 +1808,7 @@ struct wmi_set_ip_cmd {
 } __packed;
 
 enum ath6kl_wow_filters {
-	WOW_FILTER_SSID			= BIT(0),
+	WOW_FILTER_SSID			= BIT(1),
 	WOW_FILTER_OPTION_MAGIC_PACKET  = BIT(2),
 	WOW_FILTER_OPTION_EAP_REQ	= BIT(3),
 	WOW_FILTER_OPTION_PATTERNS	= BIT(4),


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 5/6] ath6kl: fix reading of FW IE capabilities
  2011-12-13 12:50 [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
                   ` (3 preceding siblings ...)
  2011-12-13 12:51 ` [PATCH v2 4/6] ath6kl: fix value of WOW_FILTER_SSID Kalle Valo
@ 2011-12-13 12:51 ` Kalle Valo
  2011-12-13 12:52 ` [PATCH v2 6/6] ath6kl: implement scheduled scan Kalle Valo
  2011-12-13 13:06 ` [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
  6 siblings, 0 replies; 8+ messages in thread
From: Kalle Valo @ 2011-12-13 12:51 UTC (permalink / raw)
  To: kvalo; +Cc: ath6kl-devel, linux-wireless

For some strange reason I used ALIGN() to calculate index to the
buffer. That is totally bogus and wouldn't work when it tried to read
the second bit. Fix it by removing the ALIGN() altogether.

Also check that ie_len is not too short.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath6kl/init.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index c97f83c..5753f00 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -913,12 +913,15 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
 				   ar->hw.reserved_ram_size);
 			break;
 		case ATH6KL_FW_IE_CAPABILITIES:
+			if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
+				break;
+
 			ath6kl_dbg(ATH6KL_DBG_BOOT,
 				   "found firmware capabilities ie (%zd B)\n",
 				   ie_len);
 
 			for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
-				index = ALIGN(i, 8) / 8;
+				index = i / 8;
 				bit = i % 8;
 
 				if (data[index] & (1 << bit))


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 6/6] ath6kl: implement scheduled scan
  2011-12-13 12:50 [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
                   ` (4 preceding siblings ...)
  2011-12-13 12:51 ` [PATCH v2 5/6] ath6kl: fix reading of FW IE capabilities Kalle Valo
@ 2011-12-13 12:52 ` Kalle Valo
  2011-12-13 13:06 ` [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
  6 siblings, 0 replies; 8+ messages in thread
From: Kalle Valo @ 2011-12-13 12:52 UTC (permalink / raw)
  To: kvalo; +Cc: ath6kl-devel, linux-wireless

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>
---
 drivers/net/wireless/ath/ath6kl/cfg80211.c |  144 ++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath6kl/cfg80211.h |    3 -
 drivers/net/wireless/ath/ath6kl/core.h     |    7 +
 drivers/net/wireless/ath/ath6kl/init.c     |    3 +
 drivers/net/wireless/ath/ath6kl/sdio.c     |   26 +++++
 drivers/net/wireless/ath/ath6kl/wmi.c      |   27 +++++
 drivers/net/wireless/ath/ath6kl/wmi.h      |    2 
 7 files changed, 209 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 2bab65f..484da6e 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -125,6 +125,37 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
 
 #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
 
+/* returns true if scheduled scan was stopped */
+static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
+{
+	struct ath6kl *ar = vif->ar;
+
+	if (ar->state != ATH6KL_STATE_SCHED_SCAN)
+		return false;
+
+	del_timer_sync(&vif->sched_scan_timer);
+
+	ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
+					   ATH6KL_HOST_MODE_AWAKE);
+
+	ar->state = ATH6KL_STATE_ON;
+
+	return true;
+}
+
+static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
+{
+	struct ath6kl *ar = vif->ar;
+	bool stopped;
+
+	stopped = __ath6kl_cfg80211_sscan_stop(vif);
+
+	if (!stopped)
+		return;
+
+	cfg80211_sched_scan_stopped(ar->wiphy);
+}
+
 static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
 				  enum nl80211_wpa_versions wpa_version)
 {
@@ -385,6 +416,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 	struct ath6kl_vif *vif = netdev_priv(dev);
 	int status;
 
+	ath6kl_cfg80211_sscan_disable(vif);
+
 	vif->sme_state = SME_CONNECTING;
 
 	if (!ath6kl_cfg80211_ready(vif))
@@ -712,6 +745,8 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
 	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
 		   reason_code);
 
+	ath6kl_cfg80211_sscan_disable(vif);
+
 	if (!ath6kl_cfg80211_ready(vif))
 		return -EIO;
 
@@ -814,6 +849,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
 	if (!ath6kl_cfg80211_ready(vif))
 		return -EIO;
 
+	ath6kl_cfg80211_sscan_disable(vif);
+
 	if (!ar->usr_bss_filter) {
 		clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
 		ret = ath6kl_wmi_bssfilter_cmd(
@@ -839,6 +876,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
 						  request->ssids[i].ssid);
 	}
 
+	/*
+	 * FIXME: we should clear the IE in fw if it's not set so just
+	 * remove the check altogether
+	 */
 	if (request->ie) {
 		ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
 					       WMI_FRAME_PROBE_REQ,
@@ -1836,6 +1877,13 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
 
 		break;
 
+	case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
+		/*
+		 * Nothing needed for schedule scan, firmware is already in
+		 * wow mode and sleeping most of the time.
+		 */
+		break;
+
 	default:
 		break;
 	}
@@ -1884,6 +1932,9 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
 		}
 		break;
 
+	case ATH6KL_STATE_SCHED_SCAN:
+		break;
+
 	default:
 		break;
 	}
@@ -2330,6 +2381,90 @@ static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
 	}
 }
 
+static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
+			struct net_device *dev,
+			struct cfg80211_sched_scan_request *request)
+{
+	struct ath6kl *ar = ath6kl_priv(dev);
+	struct ath6kl_vif *vif = netdev_priv(dev);
+	u16 interval;
+	int ret;
+	u8 i;
+
+	if (ar->state != ATH6KL_STATE_ON)
+		return -EIO;
+
+	if (vif->sme_state != SME_DISCONNECTED)
+		return -EBUSY;
+
+	for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
+		ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
+					  i, DISABLE_SSID_FLAG,
+					  0, NULL);
+	}
+
+	/* fw uses seconds, also make sure that it's >0 */
+	interval = max_t(u16, 1, request->interval / 1000);
+
+	ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
+				  interval, interval,
+				  10, 0, 0, 0, 3, 0, 0, 0);
+
+	if (request->n_ssids && request->ssids[0].ssid_len) {
+		for (i = 0; i < request->n_ssids; i++) {
+			ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
+						  i, SPECIFIC_SSID_FLAG,
+						  request->ssids[i].ssid_len,
+						  request->ssids[i].ssid);
+		}
+	}
+
+	ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
+					  ATH6KL_WOW_MODE_ENABLE,
+					  WOW_FILTER_SSID,
+					  WOW_HOST_REQ_DELAY);
+	if (ret) {
+		ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
+		return ret;
+	}
+
+	/* this also clears IE in fw if it's not set */
+	ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
+				       WMI_FRAME_PROBE_REQ,
+				       request->ie, request->ie_len);
+	if (ret) {
+		ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
+			    ret);
+		return ret;
+	}
+
+	ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
+						 ATH6KL_HOST_MODE_ASLEEP);
+	if (ret) {
+		ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
+			    ret);
+		return ret;
+	}
+
+	ar->state = ATH6KL_STATE_SCHED_SCAN;
+
+	return ret;
+}
+
+static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
+				      struct net_device *dev)
+{
+	struct ath6kl_vif *vif = netdev_priv(dev);
+	bool stopped;
+
+	stopped = __ath6kl_cfg80211_sscan_stop(vif);
+
+	if (!stopped)
+		return -EIO;
+
+	return 0;
+}
+
 static const struct ieee80211_txrx_stypes
 ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
 	[NL80211_IFTYPE_STATION] = {
@@ -2387,10 +2522,14 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
 	.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
 	.mgmt_tx = ath6kl_mgmt_tx,
 	.mgmt_frame_register = ath6kl_mgmt_frame_register,
+	.sched_scan_start = ath6kl_cfg80211_sscan_start,
+	.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
 };
 
 void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
 {
+	ath6kl_cfg80211_sscan_disable(vif);
+
 	switch (vif->sme_state) {
 	case SME_DISCONNECTED:
 		break;
@@ -2547,6 +2686,8 @@ int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
 	wiphy->wowlan.pattern_min_len = 1;
 	wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
 
+	wiphy->max_sched_scan_ssids = 10;
+
 	ret = wiphy_register(wiphy);
 	if (ret < 0) {
 		ath6kl_err("couldn't register wiphy device\n");
@@ -2566,6 +2707,9 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)
 
 	setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
 		    (unsigned long) vif->ndev);
+	setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
+		    (unsigned long) vif);
+
 	set_bit(WMM_ENABLED, &vif->flags);
 	spin_lock_init(&vif->if_lock);
 
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index 226a734..81f20a5 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -20,7 +20,8 @@
 enum ath6kl_cfg_suspend_mode {
 	ATH6KL_CFG_SUSPEND_DEEPSLEEP,
 	ATH6KL_CFG_SUSPEND_CUTPOWER,
-	ATH6KL_CFG_SUSPEND_WOW
+	ATH6KL_CFG_SUSPEND_WOW,
+	ATH6KL_CFG_SUSPEND_SCHED_SCAN,
 };
 
 struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 96f65c9..3d2abdb 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -76,6 +76,7 @@ enum ath6kl_fw_ie_type {
 
 enum ath6kl_fw_capability {
 	ATH6KL_FW_CAPABILITY_HOST_P2P = 0,
+	ATH6KL_FW_CAPABILITY_SCHED_SCAN = 1,
 
 	/* this needs to be last */
 	ATH6KL_FW_CAPABILITY_MAX,
@@ -447,7 +448,10 @@ struct ath6kl_vif {
 	struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
 	struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
 	struct aggr_info *aggr_cntxt;
+
 	struct timer_list disconnect_timer;
+	struct timer_list sched_scan_timer;
+
 	struct cfg80211_scan_request *scan_req;
 	enum sme_state sme_state;
 	int reconnect_flag;
@@ -465,6 +469,8 @@ struct ath6kl_vif {
 #define WOW_LIST_ID		0
 #define WOW_HOST_REQ_DELAY	500 /* ms */
 
+#define ATH6KL_SCHED_SCAN_RESULT_DELAY 5000 /* ms */
+
 /* Flag info */
 enum ath6kl_dev_state {
 	WMI_ENABLED,
@@ -483,6 +489,7 @@ enum ath6kl_state {
 	ATH6KL_STATE_DEEPSLEEP,
 	ATH6KL_STATE_CUTPOWER,
 	ATH6KL_STATE_WOW,
+	ATH6KL_STATE_SCHED_SCAN,
 };
 
 struct ath6kl {
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 5753f00..040a79f 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1644,6 +1644,9 @@ int ath6kl_core_init(struct ath6kl *ar)
 			    WIPHY_FLAG_HAVE_AP_SME |
 			    WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
 
+	if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
+		ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+
 	ar->wiphy->probe_resp_offload =
 		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
 		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 5f19910..15c3f56 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -807,7 +807,28 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
 		return ret;
 	}
 
-	if ((flags & MMC_PM_WAKE_SDIO_IRQ) && wow) {
+	if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
+		goto deepsleep;
+
+	/* sdio irq wakes up host */
+
+	if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
+		ret =  ath6kl_cfg80211_suspend(ar,
+					       ATH6KL_CFG_SUSPEND_SCHED_SCAN,
+					       NULL);
+		if (ret) {
+			ath6kl_warn("Schedule scan suspend failed: %d", ret);
+			return ret;
+		}
+
+		ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+		if (ret)
+			ath6kl_warn("set sdio wake irq flag failed: %d\n", ret);
+
+		return ret;
+	}
+
+	if (wow) {
 		/*
 		 * The host sdio controller is capable of keep power and
 		 * sdio irq wake up at this point. It's fine to continue
@@ -824,6 +845,7 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
 		return ret;
 	}
 
+deepsleep:
 	return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
 }
 
@@ -847,6 +869,8 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
 
 	case ATH6KL_STATE_WOW:
 		break;
+	case ATH6KL_STATE_SCHED_SCAN:
+		break;
 	}
 
 	ath6kl_cfg80211_resume(ar);
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index aa1a252..75e0f5e 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -977,6 +977,13 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len,
 	return 0;
 }
 
+void ath6kl_wmi_sscan_timer(unsigned long ptr)
+{
+	struct ath6kl_vif *vif = (struct ath6kl_vif *) ptr;
+
+	cfg80211_sched_scan_results(vif->ar->wiphy);
+}
+
 static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
 				       struct ath6kl_vif *vif)
 {
@@ -1066,6 +1073,21 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
 		return -ENOMEM;
 	cfg80211_put_bss(bss);
 
+	/*
+	 * Firmware doesn't return any event when scheduled scan has
+	 * finished, so we need to use a timer to find out when there are
+	 * no more results.
+	 *
+	 * The timer is started from the first bss info received, otherwise
+	 * the timer would not ever fire if the scan interval is short
+	 * enough.
+	 */
+	if (ar->state == ATH6KL_STATE_SCHED_SCAN &&
+	    !timer_pending(&vif->sched_scan_timer)) {
+		mod_timer(&vif->sched_scan_timer, jiffies +
+			  msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
+	}
+
 	return 0;
 }
 
@@ -2940,7 +2962,10 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
 	p = (struct wmi_set_appie_cmd *) skb->data;
 	p->mgmt_frm_type = mgmt_frm_type;
 	p->ie_len = ie_len;
-	memcpy(p->ie_info, ie, ie_len);
+
+	if (ie != NULL && ie_len > 0)
+		memcpy(p->ie_info, ie, ie_len);
+
 	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID,
 				   NO_SYNC_WMIFLAG);
 }
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index cbde79c..85dcdad 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -2349,6 +2349,8 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx);
 int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
 			     const u8 *ie, u8 ie_len);
 
+void ath6kl_wmi_sscan_timer(unsigned long ptr);
+
 struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);
 void *ath6kl_wmi_init(struct ath6kl *devt);
 void ath6kl_wmi_shutdown(struct wmi *wmi);


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 0/6] ath6kl: scheduled scan support
  2011-12-13 12:50 [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
                   ` (5 preceding siblings ...)
  2011-12-13 12:52 ` [PATCH v2 6/6] ath6kl: implement scheduled scan Kalle Valo
@ 2011-12-13 13:06 ` Kalle Valo
  6 siblings, 0 replies; 8+ messages in thread
From: Kalle Valo @ 2011-12-13 13:06 UTC (permalink / raw)
  To: Kalle Valo; +Cc: ath6kl-devel, linux-wireless

On 12/13/2011 02:50 PM, Kalle Valo wrote:
> Here's v2 of my sched scan patches. Changes from v1 are just a
> proper a commit log for patch 6 and removed a fixme comment which
> I had already fixed.

All six applied.

Kalle

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-12-13 13:06 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-13 12:50 [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo
2011-12-13 12:51 ` [PATCH v2 1/6] ath6kl: remove a workaround from ath6kl_cfg80211_stop() Kalle Valo
2011-12-13 12:51 ` [PATCH v2 2/6] ath6kl: call ath6kl_cfg80211_stop() from ath6kl_close() Kalle Valo
2011-12-13 12:51 ` [PATCH v2 3/6] ath6kl: implement ath6kl_cfg80211_stop_all() Kalle Valo
2011-12-13 12:51 ` [PATCH v2 4/6] ath6kl: fix value of WOW_FILTER_SSID Kalle Valo
2011-12-13 12:51 ` [PATCH v2 5/6] ath6kl: fix reading of FW IE capabilities Kalle Valo
2011-12-13 12:52 ` [PATCH v2 6/6] ath6kl: implement scheduled scan Kalle Valo
2011-12-13 13:06 ` [PATCH v2 0/6] ath6kl: scheduled scan support Kalle Valo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).