diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-12-18 11:20:47 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-01-05 16:07:12 -0500 |
commit | 21f83589644bb2ed98079bf1e2154c8e70ca6a6c (patch) | |
tree | ede391a8c788a43f7c4ea3baa3367e020d45f179 /net/mac80211/offchannel.c | |
parent | c96e96354a6c9456cdf1f150eca504e2ea35301e (diff) |
mac80211: implement hardware offload for remain-on-channel
This allows drivers to support remain-on-channel
offload if they implement smarter timing or need
to use a device implementation like iwlwifi.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/offchannel.c')
-rw-r--r-- | net/mac80211/offchannel.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 4b564091e51d..49b9ec22d9b6 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | #include <net/mac80211.h> | 15 | #include <net/mac80211.h> |
16 | #include "ieee80211_i.h" | 16 | #include "ieee80211_i.h" |
17 | #include "driver-trace.h" | ||
17 | 18 | ||
18 | /* | 19 | /* |
19 | * inform AP that we will go to sleep so that it will buffer the frames | 20 | * inform AP that we will go to sleep so that it will buffer the frames |
@@ -190,3 +191,77 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
190 | } | 191 | } |
191 | mutex_unlock(&local->iflist_mtx); | 192 | mutex_unlock(&local->iflist_mtx); |
192 | } | 193 | } |
194 | |||
195 | static void ieee80211_hw_roc_start(struct work_struct *work) | ||
196 | { | ||
197 | struct ieee80211_local *local = | ||
198 | container_of(work, struct ieee80211_local, hw_roc_start); | ||
199 | |||
200 | mutex_lock(&local->mtx); | ||
201 | |||
202 | if (!local->hw_roc_channel) { | ||
203 | mutex_unlock(&local->mtx); | ||
204 | return; | ||
205 | } | ||
206 | |||
207 | ieee80211_recalc_idle(local); | ||
208 | |||
209 | cfg80211_ready_on_channel(local->hw_roc_dev, local->hw_roc_cookie, | ||
210 | local->hw_roc_channel, | ||
211 | local->hw_roc_channel_type, | ||
212 | local->hw_roc_duration, | ||
213 | GFP_KERNEL); | ||
214 | mutex_unlock(&local->mtx); | ||
215 | } | ||
216 | |||
217 | void ieee80211_ready_on_channel(struct ieee80211_hw *hw) | ||
218 | { | ||
219 | struct ieee80211_local *local = hw_to_local(hw); | ||
220 | |||
221 | trace_api_ready_on_channel(local); | ||
222 | |||
223 | ieee80211_queue_work(hw, &local->hw_roc_start); | ||
224 | } | ||
225 | EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel); | ||
226 | |||
227 | static void ieee80211_hw_roc_done(struct work_struct *work) | ||
228 | { | ||
229 | struct ieee80211_local *local = | ||
230 | container_of(work, struct ieee80211_local, hw_roc_done); | ||
231 | |||
232 | mutex_lock(&local->mtx); | ||
233 | |||
234 | if (!local->hw_roc_channel) { | ||
235 | mutex_unlock(&local->mtx); | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | cfg80211_remain_on_channel_expired(local->hw_roc_dev, | ||
240 | local->hw_roc_cookie, | ||
241 | local->hw_roc_channel, | ||
242 | local->hw_roc_channel_type, | ||
243 | GFP_KERNEL); | ||
244 | |||
245 | local->hw_roc_channel = NULL; | ||
246 | local->hw_roc_cookie = 0; | ||
247 | |||
248 | ieee80211_recalc_idle(local); | ||
249 | |||
250 | mutex_unlock(&local->mtx); | ||
251 | } | ||
252 | |||
253 | void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw) | ||
254 | { | ||
255 | struct ieee80211_local *local = hw_to_local(hw); | ||
256 | |||
257 | trace_api_remain_on_channel_expired(local); | ||
258 | |||
259 | ieee80211_queue_work(hw, &local->hw_roc_done); | ||
260 | } | ||
261 | EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired); | ||
262 | |||
263 | void ieee80211_hw_roc_setup(struct ieee80211_local *local) | ||
264 | { | ||
265 | INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start); | ||
266 | INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done); | ||
267 | } | ||