aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/offchannel.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-12-18 11:20:47 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-05 16:07:12 -0500
commit21f83589644bb2ed98079bf1e2154c8e70ca6a6c (patch)
treeede391a8c788a43f7c4ea3baa3367e020d45f179 /net/mac80211/offchannel.c
parentc96e96354a6c9456cdf1f150eca504e2ea35301e (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.c75
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
195static 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
217void 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}
225EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel);
226
227static 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
253void 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}
261EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired);
262
263void 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}