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: Eliad Peller <eliad@wizery.com> Reviewed-by: Stanislaw Gruszka <sgruszka@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
eb40e3e8bb
commit
b856439b1b
@@ -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 {
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
* - 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user