summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ti/wl18xx
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2012-11-26 20:05:41 +0400
committerLuciano Coelho <coelho@ti.com>2012-11-28 13:45:42 +0400
commit5f9b67770be4201f4449b0f180effecaac4e2686 (patch)
tree5ac83cde8a352c12db4715e83743915de03a961f /drivers/net/wireless/ti/wl18xx
parent7c482c1040ae54e89a8fd4d6415577070d5a915d (diff)
downloadlinux-5f9b67770be4201f4449b0f180effecaac4e2686.tar.xz
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/wl18xx')
-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
3 files changed, 83 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:
kfree(acx);
return ret;
}
+
+int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide)
+{
+ struct wlcore_peer_ht_operation_mode *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d",
+ hlid, wide);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->hlid = hlid;
+ acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ;
+
+ ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx,
+ sizeof(*acx));
+
+ if (ret < 0) {
+ wl1271_warning("acx peer ht operation mode failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+
+}
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 {
struct acx_header header;
};
+enum wlcore_bandwidth {
+ WLCORE_BANDWIDTH_20MHZ,
+ WLCORE_BANDWIDTH_40MHZ,
+};
+
+struct wlcore_peer_ht_operation_mode {
+ struct acx_header header;
+
+ u8 hlid;
+ u8 bandwidth; /* enum wlcore_bandwidth */
+ u8 padding[2];
+};
+
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
u32 len_field_size);
int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
int wl18xx_acx_clear_statistics(struct wl1271 *wl);
+int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide);
#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,
return buf_offset;
}
+static void wl18xx_sta_rc_update(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct ieee80211_sta *sta,
+ u32 changed)
+{
+ bool wide = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
+
+ if (!(changed & IEEE80211_RC_BW_CHANGED))
+ return;
+
+ mutex_lock(&wl->mutex);
+
+ /* sanity */
+ if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
+ goto out;
+
+ /* ignore the change before association */
+ if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ goto out;
+
+ /*
+ * If we started out as wide, we can change the operation mode. If we
+ * thought this was a 20mhz AP, we have to reconnect
+ */
+ if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS ||
+ wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS)
+ wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
+ else
+ ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+
static int wl18xx_setup(struct wl1271 *wl);
static struct wlcore_ops wl18xx_ops = {
@@ -1354,6 +1391,7 @@ static struct wlcore_ops wl18xx_ops = {
.set_key = wl18xx_set_key,
.channel_switch = wl18xx_cmd_channel_switch,
.pre_pkt_send = wl18xx_pre_pkt_send,
+ .sta_rc_update = wl18xx_sta_rc_update,
};
/* HT cap appropriate for wide channels in 2Ghz */