mac80211: implement hardware offload for remain-on-channel
[deliverable/linux.git] / net / mac80211 / cfg.c
index 5892b030245466af2e8132a8323c5a58fe87433c..168a6ba8fc283c939b9b05e87fb634ab492e2c2a 100644 (file)
@@ -1593,6 +1593,37 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
        return 0;
 }
 
+static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local,
+                                         struct net_device *dev,
+                                         struct ieee80211_channel *chan,
+                                         enum nl80211_channel_type chantype,
+                                         unsigned int duration, u64 *cookie)
+{
+       int ret;
+       u32 random_cookie;
+
+       lockdep_assert_held(&local->mtx);
+
+       if (local->hw_roc_cookie)
+               return -EBUSY;
+       /* must be nonzero */
+       random_cookie = random32() | 1;
+
+       *cookie = random_cookie;
+       local->hw_roc_dev = dev;
+       local->hw_roc_cookie = random_cookie;
+       local->hw_roc_channel = chan;
+       local->hw_roc_channel_type = chantype;
+       local->hw_roc_duration = duration;
+       ret = drv_remain_on_channel(local, chan, chantype, duration);
+       if (ret) {
+               local->hw_roc_channel = NULL;
+               local->hw_roc_cookie = 0;
+       }
+
+       return ret;
+}
+
 static int ieee80211_remain_on_channel(struct wiphy *wiphy,
                                       struct net_device *dev,
                                       struct ieee80211_channel *chan,
@@ -1601,16 +1632,62 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
                                       u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+
+       if (local->ops->remain_on_channel) {
+               int ret;
+
+               mutex_lock(&local->mtx);
+               ret = ieee80211_remain_on_channel_hw(local, dev,
+                                                    chan, channel_type,
+                                                    duration, cookie);
+               mutex_unlock(&local->mtx);
+
+               return ret;
+       }
 
        return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
                                              duration, cookie);
 }
 
+static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
+                                                u64 cookie)
+{
+       int ret;
+
+       lockdep_assert_held(&local->mtx);
+
+       if (local->hw_roc_cookie != cookie)
+               return -ENOENT;
+
+       ret = drv_cancel_remain_on_channel(local);
+       if (ret)
+               return ret;
+
+       local->hw_roc_cookie = 0;
+       local->hw_roc_channel = NULL;
+
+       ieee80211_recalc_idle(local);
+
+       return 0;
+}
+
 static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
                                              struct net_device *dev,
                                              u64 cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+
+       if (local->ops->cancel_remain_on_channel) {
+               int ret;
+
+               mutex_lock(&local->mtx);
+               ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
+               mutex_unlock(&local->mtx);
+
+               return ret;
+       }
 
        return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
 }
@@ -1662,6 +1739,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
             channel_type != local->_oper_channel_type))
                is_offchan = true;
 
+       if (chan == local->hw_roc_channel) {
+               /* TODO: check channel type? */
+               is_offchan = false;
+               flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
+       }
+
        if (is_offchan && !offchan)
                return -EBUSY;
 
This page took 0.028194 seconds and 5 git commands to generate.