diff options
author | Arik Nemtsov <arik@wizery.com> | 2012-11-26 11:05:41 -0500 |
---|---|---|
committer | Luciano Coelho <coelho@ti.com> | 2012-11-28 04:45:42 -0500 |
commit | 5f9b67770be4201f4449b0f180effecaac4e2686 (patch) | |
tree | 5ac83cde8a352c12db4715e83743915de03a961f /drivers/net/wireless/ti | |
parent | 7c482c1040ae54e89a8fd4d6415577070d5a915d (diff) |
wlcore: use new set bandwidth command to adjusting channel BW
We support changing the channel BW when we started the STA role on
a 40Mhz bandwidth. Otherwise a reconnection is required.
Save the started channel width and use it when channel width updates
arrive.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/ti')
-rw-r--r-- | drivers/net/wireless/ti/wl18xx/acx.c | 31 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl18xx/acx.h | 14 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wl18xx/main.c | 38 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/cmd.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/hw_ops.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/main.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/wlcore.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/wlcore_i.h | 2 |
8 files changed, 108 insertions, 0 deletions
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c index adff9cde7db7..801d8af5cef2 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.c +++ b/drivers/net/wireless/ti/wl18xx/acx.c | |||
@@ -109,3 +109,34 @@ out: | |||
109 | kfree(acx); | 109 | kfree(acx); |
110 | return ret; | 110 | return ret; |
111 | } | 111 | } |
112 | |||
113 | int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide) | ||
114 | { | ||
115 | struct wlcore_peer_ht_operation_mode *acx; | ||
116 | int ret; | ||
117 | |||
118 | wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d", | ||
119 | hlid, wide); | ||
120 | |||
121 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
122 | if (!acx) { | ||
123 | ret = -ENOMEM; | ||
124 | goto out; | ||
125 | } | ||
126 | |||
127 | acx->hlid = hlid; | ||
128 | acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ; | ||
129 | |||
130 | ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx, | ||
131 | sizeof(*acx)); | ||
132 | |||
133 | if (ret < 0) { | ||
134 | wl1271_warning("acx peer ht operation mode failed: %d", ret); | ||
135 | goto out; | ||
136 | } | ||
137 | |||
138 | out: | ||
139 | kfree(acx); | ||
140 | return ret; | ||
141 | |||
142 | } | ||
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index 394d12500834..b57e3483509d 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h | |||
@@ -284,10 +284,24 @@ struct wl18xx_acx_clear_statistics { | |||
284 | struct acx_header header; | 284 | struct acx_header header; |
285 | }; | 285 | }; |
286 | 286 | ||
287 | enum wlcore_bandwidth { | ||
288 | WLCORE_BANDWIDTH_20MHZ, | ||
289 | WLCORE_BANDWIDTH_40MHZ, | ||
290 | }; | ||
291 | |||
292 | struct wlcore_peer_ht_operation_mode { | ||
293 | struct acx_header header; | ||
294 | |||
295 | u8 hlid; | ||
296 | u8 bandwidth; /* enum wlcore_bandwidth */ | ||
297 | u8 padding[2]; | ||
298 | }; | ||
299 | |||
287 | int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, | 300 | int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, |
288 | u32 sdio_blk_size, u32 extra_mem_blks, | 301 | u32 sdio_blk_size, u32 extra_mem_blks, |
289 | u32 len_field_size); | 302 | u32 len_field_size); |
290 | int wl18xx_acx_set_checksum_state(struct wl1271 *wl); | 303 | int wl18xx_acx_set_checksum_state(struct wl1271 *wl); |
291 | int wl18xx_acx_clear_statistics(struct wl1271 *wl); | 304 | int wl18xx_acx_clear_statistics(struct wl1271 *wl); |
305 | int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide); | ||
292 | 306 | ||
293 | #endif /* __WL18XX_ACX_H__ */ | 307 | #endif /* __WL18XX_ACX_H__ */ |
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index c015231d295f..c616c21bd6b7 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c | |||
@@ -1319,6 +1319,43 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl, | |||
1319 | return buf_offset; | 1319 | return buf_offset; |
1320 | } | 1320 | } |
1321 | 1321 | ||
1322 | static void wl18xx_sta_rc_update(struct wl1271 *wl, | ||
1323 | struct wl12xx_vif *wlvif, | ||
1324 | struct ieee80211_sta *sta, | ||
1325 | u32 changed) | ||
1326 | { | ||
1327 | bool wide = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
1328 | |||
1329 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); | ||
1330 | |||
1331 | if (!(changed & IEEE80211_RC_BW_CHANGED)) | ||
1332 | return; | ||
1333 | |||
1334 | mutex_lock(&wl->mutex); | ||
1335 | |||
1336 | /* sanity */ | ||
1337 | if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) | ||
1338 | goto out; | ||
1339 | |||
1340 | /* ignore the change before association */ | ||
1341 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
1342 | goto out; | ||
1343 | |||
1344 | /* | ||
1345 | * If we started out as wide, we can change the operation mode. If we | ||
1346 | * thought this was a 20mhz AP, we have to reconnect | ||
1347 | */ | ||
1348 | if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS || | ||
1349 | wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS) | ||
1350 | wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide); | ||
1351 | else | ||
1352 | ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif)); | ||
1353 | |||
1354 | out: | ||
1355 | mutex_unlock(&wl->mutex); | ||
1356 | } | ||
1357 | |||
1358 | |||
1322 | static int wl18xx_setup(struct wl1271 *wl); | 1359 | static int wl18xx_setup(struct wl1271 *wl); |
1323 | 1360 | ||
1324 | static struct wlcore_ops wl18xx_ops = { | 1361 | static struct wlcore_ops wl18xx_ops = { |
@@ -1354,6 +1391,7 @@ static struct wlcore_ops wl18xx_ops = { | |||
1354 | .set_key = wl18xx_set_key, | 1391 | .set_key = wl18xx_set_key, |
1355 | .channel_switch = wl18xx_cmd_channel_switch, | 1392 | .channel_switch = wl18xx_cmd_channel_switch, |
1356 | .pre_pkt_send = wl18xx_pre_pkt_send, | 1393 | .pre_pkt_send = wl18xx_pre_pkt_send, |
1394 | .sta_rc_update = wl18xx_sta_rc_update, | ||
1357 | }; | 1395 | }; |
1358 | 1396 | ||
1359 | /* HT cap appropriate for wide channels in 2Ghz */ | 1397 | /* HT cap appropriate for wide channels in 2Ghz */ |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 599c006f4c47..65f071d90727 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c | |||
@@ -480,6 +480,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
480 | goto err_hlid; | 480 | goto err_hlid; |
481 | } | 481 | } |
482 | 482 | ||
483 | wlvif->sta.role_chan_type = wlvif->channel_type; | ||
483 | goto out_free; | 484 | goto out_free; |
484 | 485 | ||
485 | err_hlid: | 486 | err_hlid: |
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index 2673d783ec1e..0e0b6563a3ff 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h | |||
@@ -201,4 +201,12 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len) | |||
201 | return buf_offset; | 201 | return buf_offset; |
202 | } | 202 | } |
203 | 203 | ||
204 | static inline void | ||
205 | wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
206 | struct ieee80211_sta *sta, u32 changed) | ||
207 | { | ||
208 | if (wl->ops->sta_rc_update) | ||
209 | wl->ops->sta_rc_update(wl, wlvif, sta, changed); | ||
210 | } | ||
211 | |||
204 | #endif | 212 | #endif |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index cce73c417dec..59ad288a1b8f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -4948,6 +4948,17 @@ static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw) | |||
4948 | return 0; | 4948 | return 0; |
4949 | } | 4949 | } |
4950 | 4950 | ||
4951 | static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, | ||
4952 | struct ieee80211_vif *vif, | ||
4953 | struct ieee80211_sta *sta, | ||
4954 | u32 changed) | ||
4955 | { | ||
4956 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4957 | struct wl1271 *wl = hw->priv; | ||
4958 | |||
4959 | wlcore_hw_sta_rc_update(wl, wlvif, sta, changed); | ||
4960 | } | ||
4961 | |||
4951 | static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) | 4962 | static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) |
4952 | { | 4963 | { |
4953 | struct wl1271 *wl = hw->priv; | 4964 | struct wl1271 *wl = hw->priv; |
@@ -5146,6 +5157,7 @@ static const struct ieee80211_ops wl1271_ops = { | |||
5146 | .change_chanctx = wlcore_op_change_chanctx, | 5157 | .change_chanctx = wlcore_op_change_chanctx, |
5147 | .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, | 5158 | .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, |
5148 | .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, | 5159 | .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, |
5160 | .sta_rc_update = wlcore_op_sta_rc_update, | ||
5149 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) | 5161 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) |
5150 | }; | 5162 | }; |
5151 | 5163 | ||
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index b31589792dfd..037c56e6cae0 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h | |||
@@ -101,6 +101,8 @@ struct wlcore_ops { | |||
101 | struct wl12xx_vif *wlvif, | 101 | struct wl12xx_vif *wlvif, |
102 | struct ieee80211_channel_switch *ch_switch); | 102 | struct ieee80211_channel_switch *ch_switch); |
103 | u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len); | 103 | u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len); |
104 | void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
105 | struct ieee80211_sta *sta, u32 changed); | ||
104 | }; | 106 | }; |
105 | 107 | ||
106 | enum wlcore_partitions { | 108 | enum wlcore_partitions { |
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 6be1e8ef55bc..e3a77aa932d2 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h | |||
@@ -341,6 +341,8 @@ struct wl12xx_vif { | |||
341 | u8 klv_template_id; | 341 | u8 klv_template_id; |
342 | 342 | ||
343 | bool qos; | 343 | bool qos; |
344 | /* channel type we started the STA role with */ | ||
345 | enum nl80211_channel_type role_chan_type; | ||
344 | } sta; | 346 | } sta; |
345 | struct { | 347 | struct { |
346 | u8 global_hlid; | 348 | u8 global_hlid; |