Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 195240
b: refs/heads/master
c: 5ce6e43
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed May 12, 2010
1 parent 61c3e26 commit 40f93f9
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 6 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b29e7eb4b8b3e5f4ff8066af648e9fe2fc707b16
refs/heads/master: 5ce6e438d5d9ed8ed775cd1e94f92002c8da2bad
39 changes: 39 additions & 0 deletions trunk/include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,28 @@ struct ieee80211_conf {
enum ieee80211_smps_mode smps_mode;
};

/**
* struct ieee80211_channel_switch - holds the channel switch data
*
* The information provided in this structure is required for channel switch
* operation.
*
* @timestamp: value in microseconds of the 64-bit Time Synchronization
* Function (TSF) timer when the frame containing the channel switch
* announcement was received. This is simply the rx.mactime parameter
* the driver passed into mac80211.
* @block_tx: Indicates whether transmission must be blocked before the
* scheduled channel switch, as indicated by the AP.
* @channel: the new channel to switch to
* @count: the number of TBTT's until the channel switch event
*/
struct ieee80211_channel_switch {
u64 timestamp;
bool block_tx;
struct ieee80211_channel *channel;
u8 count;
};

/**
* struct ieee80211_vif - per-interface data
*
Expand Down Expand Up @@ -1631,6 +1653,11 @@ enum ieee80211_ampdu_mlme_action {
* @flush: Flush all pending frames from the hardware queue, making sure
* that the hardware queues are empty. If the parameter @drop is set
* to %true, pending frames may be dropped. The callback can sleep.
*
* @channel_switch: Drivers that need (or want) to offload the channel
* switch operation for CSAs received from the AP may implement this
* callback. They must then call ieee80211_chswitch_done() to indicate
* completion of the channel switch.
*/
struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
Expand Down Expand Up @@ -1694,6 +1721,8 @@ struct ieee80211_ops {
int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
#endif
void (*flush)(struct ieee80211_hw *hw, bool drop);
void (*channel_switch)(struct ieee80211_hw *hw,
struct ieee80211_channel_switch *ch_switch);
};

/**
Expand Down Expand Up @@ -2444,6 +2473,16 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
enum nl80211_cqm_rssi_threshold_event rssi_event,
gfp_t gfp);

/**
* ieee80211_chswitch_done - Complete channel switch process
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @success: make the channel switch successful or not
*
* Complete the channel switch post-process: set the new operational channel
* and wake up the suspended queues.
*/
void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);

/* Rate control API */

/**
Expand Down
11 changes: 11 additions & 0 deletions trunk/net/mac80211/driver-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,4 +373,15 @@ static inline void drv_flush(struct ieee80211_local *local, bool drop)
if (local->ops->flush)
local->ops->flush(&local->hw, drop);
}

static inline void drv_channel_switch(struct ieee80211_local *local,
struct ieee80211_channel_switch *ch_switch)
{
might_sleep();

local->ops->channel_switch(&local->hw, ch_switch);

trace_drv_channel_switch(local, ch_switch);
}

#endif /* __MAC80211_DRIVER_OPS */
49 changes: 49 additions & 0 deletions trunk/net/mac80211/driver-trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,34 @@ TRACE_EVENT(drv_flush,
)
);

TRACE_EVENT(drv_channel_switch,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_channel_switch *ch_switch),

TP_ARGS(local, ch_switch),

TP_STRUCT__entry(
LOCAL_ENTRY
__field(u64, timestamp)
__field(bool, block_tx)
__field(u16, freq)
__field(u8, count)
),

TP_fast_assign(
LOCAL_ASSIGN;
__entry->timestamp = ch_switch->timestamp;
__entry->block_tx = ch_switch->block_tx;
__entry->freq = ch_switch->channel->center_freq;
__entry->count = ch_switch->count;
),

TP_printk(
LOCAL_PR_FMT " new freq:%u count:%d",
LOCAL_PR_ARG, __entry->freq, __entry->count
)
);

/*
* Tracing for API calls that drivers call.
*/
Expand Down Expand Up @@ -992,6 +1020,27 @@ TRACE_EVENT(api_sta_block_awake,
)
);

TRACE_EVENT(api_chswitch_done,
TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success),

TP_ARGS(sdata, success),

TP_STRUCT__entry(
VIF_ENTRY
__field(bool, success)
),

TP_fast_assign(
VIF_ASSIGN;
__entry->success = success;
),

TP_printk(
VIF_PR_FMT " success=%d",
VIF_PR_ARG, __entry->success
)
);

/*
* Tracing for internal functions
* (which may also be called in response to driver calls)
Expand Down
3 changes: 2 additions & 1 deletion trunk/net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,8 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy);
void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel_sw_ie *sw_elem,
struct ieee80211_bss *bss);
struct ieee80211_bss *bss,
u64 timestamp);
void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);

Expand Down
56 changes: 52 additions & 4 deletions trunk/net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,11 @@ static void ieee80211_chswitch_work(struct work_struct *work)
goto out;

sdata->local->oper_channel = sdata->local->csa_channel;
ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
if (!sdata->local->ops->channel_switch) {
/* call "hw_config" only if doing sw channel switch */
ieee80211_hw_config(sdata->local,
IEEE80211_CONF_CHANGE_CHANNEL);
}

/* XXX: shouldn't really modify cfg80211-owned data! */
ifmgd->associated->channel = sdata->local->oper_channel;
Expand All @@ -353,6 +357,29 @@ static void ieee80211_chswitch_work(struct work_struct *work)
mutex_unlock(&ifmgd->mtx);
}

void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_managed *ifmgd;

sdata = vif_to_sdata(vif);
ifmgd = &sdata->u.mgd;

trace_api_chswitch_done(sdata, success);
if (!success) {
/*
* If the channel switch was not successful, stay
* around on the old channel. We currently lack
* good handling of this situation, possibly we
* should just drop the association.
*/
sdata->local->csa_channel = sdata->local->oper_channel;
}

ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
}
EXPORT_SYMBOL(ieee80211_chswitch_done);

static void ieee80211_chswitch_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
Expand All @@ -369,7 +396,8 @@ static void ieee80211_chswitch_timer(unsigned long data)

void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel_sw_ie *sw_elem,
struct ieee80211_bss *bss)
struct ieee80211_bss *bss,
u64 timestamp)
{
struct cfg80211_bss *cbss =
container_of((void *)bss, struct cfg80211_bss, priv);
Expand Down Expand Up @@ -397,6 +425,24 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,

sdata->local->csa_channel = new_ch;

if (sdata->local->ops->channel_switch) {
/* use driver's channel switch callback */
struct ieee80211_channel_switch ch_switch;
memset(&ch_switch, 0, sizeof(ch_switch));
ch_switch.timestamp = timestamp;
if (sw_elem->mode) {
ch_switch.block_tx = true;
ieee80211_stop_queues_by_reason(&sdata->local->hw,
IEEE80211_QUEUE_STOP_REASON_CSA);
}
ch_switch.channel = new_ch;
ch_switch.count = sw_elem->count;
ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
drv_channel_switch(sdata->local, &ch_switch);
return;
}

/* channel switch handled in software */
if (sw_elem->count <= 1) {
ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
} else {
Expand Down Expand Up @@ -1316,7 +1362,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
ETH_ALEN) == 0)) {
struct ieee80211_channel_sw_ie *sw_elem =
(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
ieee80211_sta_process_chanswitch(sdata, sw_elem,
bss, rx_status->mactime);
}
}

Expand Down Expand Up @@ -1648,7 +1695,8 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,

ieee80211_sta_process_chanswitch(sdata,
&mgmt->u.action.u.chan_switch.sw_elem,
(void *)ifmgd->associated->priv);
(void *)ifmgd->associated->priv,
rx_status->mactime);
break;
}
mutex_unlock(&ifmgd->mtx);
Expand Down

0 comments on commit 40f93f9

Please sign in to comment.