aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ti
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2012-11-26 11:05:41 -0500
committerLuciano Coelho <coelho@ti.com>2012-11-28 04:45:42 -0500
commit5f9b67770be4201f4449b0f180effecaac4e2686 (patch)
tree5ac83cde8a352c12db4715e83743915de03a961f /drivers/net/wireless/ti
parent7c482c1040ae54e89a8fd4d6415577070d5a915d (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.c31
-rw-r--r--drivers/net/wireless/ti/wl18xx/acx.h14
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c38
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/hw_ops.h8
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c12
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h2
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore_i.h2
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
113int 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
138out:
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
287enum wlcore_bandwidth {
288 WLCORE_BANDWIDTH_20MHZ,
289 WLCORE_BANDWIDTH_40MHZ,
290};
291
292struct 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
287int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, 300int 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);
290int wl18xx_acx_set_checksum_state(struct wl1271 *wl); 303int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
291int wl18xx_acx_clear_statistics(struct wl1271 *wl); 304int wl18xx_acx_clear_statistics(struct wl1271 *wl);
305int 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
1322static 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
1354out:
1355 mutex_unlock(&wl->mutex);
1356}
1357
1358
1322static int wl18xx_setup(struct wl1271 *wl); 1359static int wl18xx_setup(struct wl1271 *wl);
1323 1360
1324static struct wlcore_ops wl18xx_ops = { 1361static 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
485err_hlid: 486err_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
204static inline void
205wlcore_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
4951static 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
4951static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) 4962static 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
106enum wlcore_partitions { 108enum 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;