summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c9
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c131
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.h5
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h7
4 files changed, 100 insertions, 52 deletions
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index aff1ea0b2b2e..9f67c9896042 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
+#include <linux/workqueue.h>
#include "wcn36xx.h"
unsigned int wcn36xx_dbg_mask;
@@ -501,8 +502,7 @@ static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw,
{
struct wcn36xx *wcn = hw->priv;
- wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN);
- wcn36xx_smd_start_scan(wcn);
+ wcn36xx_smd_init_scan(wcn);
}
static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw,
@@ -510,8 +510,7 @@ static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw,
{
struct wcn36xx *wcn = hw->priv;
- wcn36xx_smd_end_scan(wcn);
- wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+ wcn36xx_smd_finish_scan(wcn);
}
static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
@@ -1035,7 +1034,7 @@ static int wcn36xx_probe(struct platform_device *pdev)
wcn->chip_version = wcn->ctrl_ops->get_chip_type();
mutex_init(&wcn->hal_mutex);
-
+ INIT_DELAYED_WORK(&wcn->scan_work, wcn36xx_scan_work);
if (!wcn->ctrl_ops->get_hw_mac(addr)) {
wcn36xx_info("mac address: %pM\n", addr);
SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index e9bf8bd32ec5..91b7a1eaad81 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -19,6 +19,7 @@
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <linux/bitops.h>
+#include <linux/workqueue.h>
#include "smd.h"
static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value)
@@ -432,126 +433,168 @@ out:
return ret;
}
-int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode)
+int _wcn36xx_smd_finish_scan(struct wcn36xx *wcn)
{
- struct wcn36xx_hal_init_scan_req_msg msg_body;
- int ret = 0;
+ struct wcn36xx_hal_finish_scan_req_msg msg_body;
+ int ret = 0;
- mutex_lock(&wcn->hal_mutex);
- INIT_HAL_MSG(msg_body, WCN36XX_HAL_INIT_SCAN_REQ);
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_FINISH_SCAN_REQ);
- msg_body.mode = mode;
+ msg_body.mode = HAL_SYS_MODE_SCAN;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
- wcn36xx_dbg(WCN36XX_DBG_HAL, "hal init scan mode %d\n", msg_body.mode);
+ wcn36xx_dbg(WCN36XX_DBG_HAL, "hal finish scan mode %d\n",
+ msg_body.mode);
ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
if (ret) {
- wcn36xx_err("Sending hal_init_scan failed\n");
- goto out;
+ wcn36xx_err("Sending hal_finish_scan failed\n");
+ return ret;
}
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
if (ret) {
- wcn36xx_err("hal_init_scan response failed err=%d\n", ret);
- goto out;
+ wcn36xx_err("hal_finish_scan response failed err=%d\n", ret);
+ return ret;
}
-out:
- mutex_unlock(&wcn->hal_mutex);
- return ret;
+
+ return 0;
}
-int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
+int _wcn36xx_smd_end_scan(struct wcn36xx *wcn)
{
- struct wcn36xx_hal_start_scan_req_msg msg_body;
+ struct wcn36xx_hal_end_scan_req_msg msg_body;
int ret = 0;
- mutex_lock(&wcn->hal_mutex);
- INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ);
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ);
- msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+ msg_body.scan_channel = wcn->scan_channel;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
- wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start scan channel %d\n",
+ wcn36xx_dbg(WCN36XX_DBG_HAL, "hal end scan channel %d\n",
msg_body.scan_channel);
ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
if (ret) {
- wcn36xx_err("Sending hal_start_scan failed\n");
- goto out;
+ wcn36xx_err("Sending hal_end_scan failed\n");
+ return ret;
}
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
if (ret) {
- wcn36xx_err("hal_start_scan response failed err=%d\n", ret);
- goto out;
+ wcn36xx_err("hal_end_scan response failed err=%d\n", ret);
+ return ret;
}
-out:
- mutex_unlock(&wcn->hal_mutex);
- return ret;
+
+ wcn->scan_started = false;
+
+ return 0;
}
-int wcn36xx_smd_end_scan(struct wcn36xx *wcn)
+void wcn36xx_scan_work(struct work_struct *work)
{
- struct wcn36xx_hal_end_scan_req_msg msg_body;
+ struct wcn36xx *wcn = container_of(work, struct wcn36xx, scan_work.work);
+ struct wcn36xx_hal_start_scan_req_msg msg_body;
int ret = 0;
mutex_lock(&wcn->hal_mutex);
- INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ);
- msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+ if (wcn->scan_started) {
+ ret = _wcn36xx_smd_end_scan(wcn);
+ if (ret)
+ goto out;
+
+ /* we just do only the one start -> stop then finish scan */
+ wcn->scan_finishing = true;
+ }
+ if (wcn->scan_finishing) {
+ ret = _wcn36xx_smd_finish_scan(wcn);
+ goto out;
+ }
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ);
+
+ wcn->scan_channel = WCN36XX_HW_CHANNEL(wcn);
+ msg_body.scan_channel = wcn->scan_channel;
+ dev_dbg(wcn->dev, "%s: ch %d\n", __func__, wcn->scan_channel);
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
- wcn36xx_dbg(WCN36XX_DBG_HAL, "hal end scan channel %d\n",
+ wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start scan channel %d\n",
msg_body.scan_channel);
ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
if (ret) {
- wcn36xx_err("Sending hal_end_scan failed\n");
+ wcn36xx_err("Sending hal_start_scan failed\n");
goto out;
}
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
if (ret) {
- wcn36xx_err("hal_end_scan response failed err=%d\n", ret);
+ wcn36xx_err("hal_start_scan response failed err=%d\n", ret);
goto out;
}
+
+ wcn->scan_started = true;
+ /* we will come back in around 166ms and stop the scan */
+ schedule_delayed_work(&wcn->scan_work, HZ / 6);
+
out:
mutex_unlock(&wcn->hal_mutex);
- return ret;
}
-int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
- enum wcn36xx_hal_sys_mode mode)
+int wcn36xx_smd_init_scan(struct wcn36xx *wcn)
{
- struct wcn36xx_hal_finish_scan_req_msg msg_body;
+ struct wcn36xx_hal_init_scan_req_msg msg_body;
int ret = 0;
mutex_lock(&wcn->hal_mutex);
- INIT_HAL_MSG(msg_body, WCN36XX_HAL_FINISH_SCAN_REQ);
- msg_body.mode = mode;
+ wcn->scan_started = false;
+ wcn->scan_finishing = false;
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_INIT_SCAN_REQ);
+
+ msg_body.mode = HAL_SYS_MODE_SCAN;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
- wcn36xx_dbg(WCN36XX_DBG_HAL, "hal finish scan mode %d\n",
- msg_body.mode);
+ wcn36xx_dbg(WCN36XX_DBG_HAL, "hal init scan mode %d\n", msg_body.mode);
ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
if (ret) {
- wcn36xx_err("Sending hal_finish_scan failed\n");
+ wcn36xx_err("Sending hal_init_scan failed\n");
goto out;
}
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
if (ret) {
- wcn36xx_err("hal_finish_scan response failed err=%d\n", ret);
+ wcn36xx_err("hal_init_scan response failed err=%d\n", ret);
goto out;
}
+
+ schedule_delayed_work(&wcn->scan_work, 0);
+
out:
mutex_unlock(&wcn->hal_mutex);
return ret;
}
+int wcn36xx_smd_finish_scan(struct wcn36xx *wcn)
+{
+ int ret = 0;
+
+ mutex_lock(&wcn->hal_mutex);
+
+ cancel_delayed_work(&wcn->scan_work);
+
+ if (wcn->scan_started) {
+ wcn->scan_finishing = true;
+ ret = _wcn36xx_smd_end_scan(wcn);
+ }
+
+ mutex_unlock(&wcn->hal_mutex);
+ return ret;
+}
+
static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len)
{
struct wcn36xx_hal_switch_channel_rsp_msg *rsp;
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index 8361f9e3995b..299d60ef7410 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -67,11 +67,10 @@ void wcn36xx_smd_close(struct wcn36xx *wcn);
int wcn36xx_smd_load_nv(struct wcn36xx *wcn);
int wcn36xx_smd_start(struct wcn36xx *wcn);
int wcn36xx_smd_stop(struct wcn36xx *wcn);
-int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode);
+int wcn36xx_smd_init_scan(struct wcn36xx *wcn);
int wcn36xx_smd_start_scan(struct wcn36xx *wcn);
int wcn36xx_smd_end_scan(struct wcn36xx *wcn);
-int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
- enum wcn36xx_hal_sys_mode mode);
+int wcn36xx_smd_finish_scan(struct wcn36xx *wcn);
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn);
int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 04793c687682..82d96bb7642e 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -228,6 +228,12 @@ struct wcn36xx {
struct sk_buff *tx_ack_skb;
+ /* we restrict the amount of time scan can block normal operation */
+ struct delayed_work scan_work;
+ bool scan_started;
+ bool scan_finishing;
+ u8 scan_channel;
+
#ifdef CONFIG_WCN36XX_DEBUGFS
/* Debug file system entry */
struct wcn36xx_dfs_entry dfs;
@@ -247,5 +253,6 @@ static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
wcn->fw_revision == revision);
}
void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates);
+void wcn36xx_scan_work(struct work_struct *work);
#endif /* _WCN36XX_H_ */