提交 b856439b 编写于 作者: E Eliad Peller 提交者: John W. Linville

mac80211: add cancel_hw_scan() callback

When suspending, __ieee80211_suspend() calls ieee80211_scan_cancel(),
which will only cancel sw scan. In order to cancel hw scan, the
low-level driver has to cancel it in the suspend() callback. however,
this is too late, as a new scan_work will be enqueued (while the driver
is going into suspend).

Add a new cancel_hw_scan() callback, asking the driver to cancel an
active hw scan, and call it in ieee80211_scan_cancel().
Signed-off-by: NEliad Peller <eliad@wizery.com>
Reviewed-by: NStanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 eb40e3e8
...@@ -1708,6 +1708,14 @@ enum ieee80211_ampdu_mlme_action { ...@@ -1708,6 +1708,14 @@ enum ieee80211_ampdu_mlme_action {
* any error unless this callback returned a negative error code. * any error unless this callback returned a negative error code.
* The callback can sleep. * The callback can sleep.
* *
* @cancel_hw_scan: Ask the low-level tp cancel the active hw scan.
* The driver should ask the hardware to cancel the scan (if possible),
* but the scan will be completed only after the driver will call
* ieee80211_scan_completed().
* This callback is needed for wowlan, to prevent enqueueing a new
* scan_work after the low-level driver was already suspended.
* The callback can sleep.
*
* @sched_scan_start: Ask the hardware to start scanning repeatedly at * @sched_scan_start: Ask the hardware to start scanning repeatedly at
* specific intervals. The driver must call the * specific intervals. The driver must call the
* ieee80211_sched_scan_results() function whenever it finds results. * ieee80211_sched_scan_results() function whenever it finds results.
...@@ -1900,6 +1908,8 @@ struct ieee80211_ops { ...@@ -1900,6 +1908,8 @@ struct ieee80211_ops {
u32 iv32, u16 *phase1key); u32 iv32, u16 *phase1key);
int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_scan_request *req); struct cfg80211_scan_request *req);
void (*cancel_hw_scan)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int (*sched_scan_start)(struct ieee80211_hw *hw, int (*sched_scan_start)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req, struct cfg80211_sched_scan_request *req,
......
...@@ -218,6 +218,16 @@ static inline int drv_hw_scan(struct ieee80211_local *local, ...@@ -218,6 +218,16 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
return ret; return ret;
} }
static inline void drv_cancel_hw_scan(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
might_sleep();
trace_drv_cancel_hw_scan(local, sdata);
local->ops->cancel_hw_scan(&local->hw, &sdata->vif);
trace_drv_return_void(local);
}
static inline int static inline int
drv_sched_scan_start(struct ieee80211_local *local, drv_sched_scan_start(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
......
...@@ -460,6 +460,12 @@ DEFINE_EVENT(local_sdata_evt, drv_hw_scan, ...@@ -460,6 +460,12 @@ DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
TP_ARGS(local, sdata) TP_ARGS(local, sdata)
); );
DEFINE_EVENT(local_sdata_evt, drv_cancel_hw_scan,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata),
TP_ARGS(local, sdata)
);
DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start, DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
TP_PROTO(struct ieee80211_local *local, TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata), struct ieee80211_sub_if_data *sdata),
......
...@@ -821,10 +821,8 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, ...@@ -821,10 +821,8 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
*/ */
void ieee80211_scan_cancel(struct ieee80211_local *local) void ieee80211_scan_cancel(struct ieee80211_local *local)
{ {
bool abortscan;
/* /*
* We are only canceling software scan, or deferred scan that was not * We are canceling software scan, or deferred scan that was not
* yet really started (see __ieee80211_start_scan ). * yet really started (see __ieee80211_start_scan ).
* *
* Regarding hardware scan: * Regarding hardware scan:
...@@ -836,23 +834,30 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) ...@@ -836,23 +834,30 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
* - we can not cancel scan_work since driver can schedule it * - we can not cancel scan_work since driver can schedule it
* by ieee80211_scan_completed(..., true) to finish scan * by ieee80211_scan_completed(..., true) to finish scan
* *
* Hence low lever driver is responsible for canceling HW scan. * Hence we only call the cancel_hw_scan() callback, but the low-level
* driver is still responsible for calling ieee80211_scan_completed()
* after the scan was completed/aborted.
*/ */
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning); if (!local->scan_req)
if (abortscan) { goto out;
/*
* The scan is canceled, but stop work from being pending. if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
* if (local->ops->cancel_hw_scan)
* If the work is currently running, it must be blocked on drv_cancel_hw_scan(local, local->scan_sdata);
* the mutex, but we'll set scan_sdata = NULL and it'll goto out;
* simply exit once it acquires the mutex.
*/
cancel_delayed_work(&local->scan_work);
/* and clean up */
__ieee80211_scan_completed(&local->hw, true, false);
} }
/*
* If the work is currently running, it must be blocked on
* the mutex, but we'll set scan_sdata = NULL and it'll
* simply exit once it acquires the mutex.
*/
cancel_delayed_work(&local->scan_work);
/* and clean up */
__ieee80211_scan_completed(&local->hw, true, false);
out:
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册