diff options
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/main.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/smd.c | 131 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/smd.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 7 |
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_ */ |