Commit d339d5ca authored by Ilan Peer's avatar Ilan Peer Committed by Johannes Berg

mac80211: Allow drivers to differentiate between ROC types

Some devices can handle remain on channel requests differently
based on the request type/priority. Add support to
differentiate between different ROC types, i.e., indicate that
the ROC is required for sending managment frames.
Signed-off-by: default avatarIlan Peer <ilan.peer@intel.com>
Reviewed-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f62fab73
...@@ -1137,7 +1137,8 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) ...@@ -1137,7 +1137,8 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_channel *channel, struct ieee80211_channel *channel,
int duration) int duration,
enum ieee80211_roc_type type)
{ {
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
......
...@@ -1081,7 +1081,8 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, ...@@ -1081,7 +1081,8 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
static int iwl_mvm_roc(struct ieee80211_hw *hw, static int iwl_mvm_roc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_channel *channel, struct ieee80211_channel *channel,
int duration) int duration,
enum ieee80211_roc_type type)
{ {
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
...@@ -1092,8 +1093,8 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, ...@@ -1092,8 +1093,8 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
return -EINVAL; return -EINVAL;
} }
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d)\n", channel->hw_value, IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
duration); duration, type);
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
......
...@@ -1535,7 +1535,8 @@ static void hw_roc_done(struct work_struct *work) ...@@ -1535,7 +1535,8 @@ static void hw_roc_done(struct work_struct *work)
static int mac80211_hwsim_roc(struct ieee80211_hw *hw, static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
int duration) int duration,
enum ieee80211_roc_type type)
{ {
struct mac80211_hwsim_data *hwsim = hw->priv; struct mac80211_hwsim_data *hwsim = hw->priv;
......
...@@ -4956,7 +4956,8 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop) ...@@ -4956,7 +4956,8 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop)
static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
int duration) int duration,
enum ieee80211_roc_type type)
{ {
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
......
...@@ -2134,6 +2134,24 @@ enum ieee80211_rate_control_changed { ...@@ -2134,6 +2134,24 @@ enum ieee80211_rate_control_changed {
IEEE80211_RC_NSS_CHANGED = BIT(3), IEEE80211_RC_NSS_CHANGED = BIT(3),
}; };
/**
* enum ieee80211_roc_type - remain on channel type
*
* With the support for multi channel contexts and multi channel operations,
* remain on channel operations might be limited/deferred/aborted by other
* flows/operations which have higher priority (and vise versa).
* Specifying the ROC type can be used by devices to prioritize the ROC
* operations compared to other operations/flows.
*
* @IEEE80211_ROC_TYPE_NORMAL: There are no special requirements for this ROC.
* @IEEE80211_ROC_TYPE_MGMT_TX: The remain on channel request is required
* for sending managment frames offchannel.
*/
enum ieee80211_roc_type {
IEEE80211_ROC_TYPE_NORMAL = 0,
IEEE80211_ROC_TYPE_MGMT_TX,
};
/** /**
* struct ieee80211_ops - callbacks from mac80211 to the driver * struct ieee80211_ops - callbacks from mac80211 to the driver
* *
...@@ -2687,7 +2705,8 @@ struct ieee80211_ops { ...@@ -2687,7 +2705,8 @@ struct ieee80211_ops {
int (*remain_on_channel)(struct ieee80211_hw *hw, int (*remain_on_channel)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
int duration); int duration,
enum ieee80211_roc_type type);
int (*cancel_remain_on_channel)(struct ieee80211_hw *hw); int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx); int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
void (*get_ringparam)(struct ieee80211_hw *hw, void (*get_ringparam)(struct ieee80211_hw *hw,
......
...@@ -2410,7 +2410,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, ...@@ -2410,7 +2410,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel, struct ieee80211_channel *channel,
unsigned int duration, u64 *cookie, unsigned int duration, u64 *cookie,
struct sk_buff *txskb) struct sk_buff *txskb,
enum ieee80211_roc_type type)
{ {
struct ieee80211_roc_work *roc, *tmp; struct ieee80211_roc_work *roc, *tmp;
bool queued = false; bool queued = false;
...@@ -2429,6 +2430,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, ...@@ -2429,6 +2430,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
roc->duration = duration; roc->duration = duration;
roc->req_duration = duration; roc->req_duration = duration;
roc->frame = txskb; roc->frame = txskb;
roc->type = type;
roc->mgmt_tx_cookie = (unsigned long)txskb; roc->mgmt_tx_cookie = (unsigned long)txskb;
roc->sdata = sdata; roc->sdata = sdata;
INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
...@@ -2459,7 +2461,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, ...@@ -2459,7 +2461,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
if (!duration) if (!duration)
duration = 10; duration = 10;
ret = drv_remain_on_channel(local, sdata, channel, duration); ret = drv_remain_on_channel(local, sdata, channel, duration, type);
if (ret) { if (ret) {
kfree(roc); kfree(roc);
return ret; return ret;
...@@ -2478,10 +2480,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, ...@@ -2478,10 +2480,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
* *
* If it hasn't started yet, just increase the duration * If it hasn't started yet, just increase the duration
* and add the new one to the list of dependents. * and add the new one to the list of dependents.
* If the type of the new ROC has higher priority, modify the
* type of the previous one to match that of the new one.
*/ */
if (!tmp->started) { if (!tmp->started) {
list_add_tail(&roc->list, &tmp->dependents); list_add_tail(&roc->list, &tmp->dependents);
tmp->duration = max(tmp->duration, roc->duration); tmp->duration = max(tmp->duration, roc->duration);
tmp->type = max(tmp->type, roc->type);
queued = true; queued = true;
break; break;
} }
...@@ -2493,16 +2498,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, ...@@ -2493,16 +2498,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
/* /*
* In the offloaded ROC case, if it hasn't begun, add * In the offloaded ROC case, if it hasn't begun, add
* this new one to the dependent list to be handled * this new one to the dependent list to be handled
* when the the master one begins. If it has begun, * when the master one begins. If it has begun,
* check that there's still a minimum time left and * check that there's still a minimum time left and
* if so, start this one, transmitting the frame, but * if so, start this one, transmitting the frame, but
* add it to the list directly after this one with a * add it to the list directly after this one with
* a reduced time so we'll ask the driver to execute * a reduced time so we'll ask the driver to execute
* it right after finishing the previous one, in the * it right after finishing the previous one, in the
* hope that it'll also be executed right afterwards, * hope that it'll also be executed right afterwards,
* effectively extending the old one. * effectively extending the old one.
* If there's no minimum time left, just add it to the * If there's no minimum time left, just add it to the
* normal list. * normal list.
* TODO: the ROC type is ignored here, assuming that it
* is better to immediately use the current ROC.
*/ */
if (!tmp->hw_begun) { if (!tmp->hw_begun) {
list_add_tail(&roc->list, &tmp->dependents); list_add_tail(&roc->list, &tmp->dependents);
...@@ -2596,7 +2603,8 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy, ...@@ -2596,7 +2603,8 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
ret = ieee80211_start_roc_work(local, sdata, chan, ret = ieee80211_start_roc_work(local, sdata, chan,
duration, cookie, NULL); duration, cookie, NULL,
IEEE80211_ROC_TYPE_NORMAL);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
return ret; return ret;
...@@ -2829,7 +2837,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, ...@@ -2829,7 +2837,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
/* This will handle all kinds of coalescing and immediate TX */ /* This will handle all kinds of coalescing and immediate TX */
ret = ieee80211_start_roc_work(local, sdata, chan, ret = ieee80211_start_roc_work(local, sdata, chan,
wait, cookie, skb); wait, cookie, skb,
IEEE80211_ROC_TYPE_MGMT_TX);
if (ret) if (ret)
kfree_skb(skb); kfree_skb(skb);
out_unlock: out_unlock:
......
...@@ -787,15 +787,16 @@ static inline int drv_get_antenna(struct ieee80211_local *local, ...@@ -787,15 +787,16 @@ static inline int drv_get_antenna(struct ieee80211_local *local,
static inline int drv_remain_on_channel(struct ieee80211_local *local, static inline int drv_remain_on_channel(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
unsigned int duration) unsigned int duration,
enum ieee80211_roc_type type)
{ {
int ret; int ret;
might_sleep(); might_sleep();
trace_drv_remain_on_channel(local, sdata, chan, duration); trace_drv_remain_on_channel(local, sdata, chan, duration, type);
ret = local->ops->remain_on_channel(&local->hw, &sdata->vif, ret = local->ops->remain_on_channel(&local->hw, &sdata->vif,
chan, duration); chan, duration, type);
trace_drv_return_int(local, ret); trace_drv_return_int(local, ret);
return ret; return ret;
......
...@@ -315,6 +315,7 @@ struct ieee80211_roc_work { ...@@ -315,6 +315,7 @@ struct ieee80211_roc_work {
u32 duration, req_duration; u32 duration, req_duration;
struct sk_buff *frame; struct sk_buff *frame;
u64 cookie, mgmt_tx_cookie; u64 cookie, mgmt_tx_cookie;
enum ieee80211_roc_type type;
}; };
/* flags used in struct ieee80211_if_managed.flags */ /* flags used in struct ieee80211_if_managed.flags */
......
...@@ -277,7 +277,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) ...@@ -277,7 +277,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
duration = 10; duration = 10;
ret = drv_remain_on_channel(local, roc->sdata, roc->chan, ret = drv_remain_on_channel(local, roc->sdata, roc->chan,
duration); duration, roc->type);
roc->started = true; roc->started = true;
......
...@@ -1042,15 +1042,17 @@ TRACE_EVENT(drv_remain_on_channel, ...@@ -1042,15 +1042,17 @@ TRACE_EVENT(drv_remain_on_channel,
TP_PROTO(struct ieee80211_local *local, TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
unsigned int duration), unsigned int duration,
enum ieee80211_roc_type type),
TP_ARGS(local, sdata, chan, duration), TP_ARGS(local, sdata, chan, duration, type),
TP_STRUCT__entry( TP_STRUCT__entry(
LOCAL_ENTRY LOCAL_ENTRY
VIF_ENTRY VIF_ENTRY
__field(int, center_freq) __field(int, center_freq)
__field(unsigned int, duration) __field(unsigned int, duration)
__field(u32, type)
), ),
TP_fast_assign( TP_fast_assign(
...@@ -1058,12 +1060,13 @@ TRACE_EVENT(drv_remain_on_channel, ...@@ -1058,12 +1060,13 @@ TRACE_EVENT(drv_remain_on_channel,
VIF_ASSIGN; VIF_ASSIGN;
__entry->center_freq = chan->center_freq; __entry->center_freq = chan->center_freq;
__entry->duration = duration; __entry->duration = duration;
__entry->type = type;
), ),
TP_printk( TP_printk(
LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms", LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms type=%d",
LOCAL_PR_ARG, VIF_PR_ARG, LOCAL_PR_ARG, VIF_PR_ARG,
__entry->center_freq, __entry->duration __entry->center_freq, __entry->duration, __entry->type
) )
); );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment