|
@@ -286,8 +286,10 @@ static struct conf_drv_settings default_conf = {
|
|
|
},
|
|
|
},
|
|
|
.ht = {
|
|
|
+ .rx_ba_win_size = 8,
|
|
|
.tx_ba_win_size = 64,
|
|
|
.inactivity_timeout = 10000,
|
|
|
+ .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
|
|
|
},
|
|
|
.mem_wl127x = {
|
|
|
.num_stations = 1,
|
|
@@ -3191,9 +3193,12 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
- sta = ieee80211_find_sta(vif, bss_conf->bssid);
|
|
|
- if (sta) {
|
|
|
+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
|
|
|
+ rcu_read_lock();
|
|
|
+ sta = ieee80211_find_sta(vif, bss_conf->bssid);
|
|
|
+ if (!sta)
|
|
|
+ goto sta_not_found;
|
|
|
+
|
|
|
/* save the supp_rates of the ap */
|
|
|
sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
|
|
|
if (sta->ht_cap.ht_supported)
|
|
@@ -3201,38 +3206,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
|
|
|
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
|
|
|
sta_ht_cap = sta->ht_cap;
|
|
|
sta_exists = true;
|
|
|
- }
|
|
|
- rcu_read_unlock();
|
|
|
|
|
|
- if (sta_exists) {
|
|
|
- /* handle new association with HT and HT information change */
|
|
|
- if ((changed & BSS_CHANGED_HT) &&
|
|
|
- (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
|
|
|
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
|
|
|
- true);
|
|
|
- if (ret < 0) {
|
|
|
- wl1271_warning("Set ht cap true failed %d",
|
|
|
- ret);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- ret = wl1271_acx_set_ht_information(wl,
|
|
|
- bss_conf->ht_operation_mode);
|
|
|
- if (ret < 0) {
|
|
|
- wl1271_warning("Set ht information failed %d",
|
|
|
- ret);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
- /* handle new association without HT and disassociation */
|
|
|
- else if (changed & BSS_CHANGED_ASSOC) {
|
|
|
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
|
|
|
- false);
|
|
|
- if (ret < 0) {
|
|
|
- wl1271_warning("Set ht cap false failed %d",
|
|
|
- ret);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
+sta_not_found:
|
|
|
+ rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
if ((changed & BSS_CHANGED_ASSOC)) {
|
|
@@ -3440,6 +3416,41 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /* Handle new association with HT. Do this only after join. */
|
|
|
+ if (sta_exists) {
|
|
|
+ if ((changed & BSS_CHANGED_HT) &&
|
|
|
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
|
|
|
+ ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
|
|
|
+ true);
|
|
|
+ if (ret < 0) {
|
|
|
+ wl1271_warning("Set ht cap true failed %d",
|
|
|
+ ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* handle new association without HT and disassociation */
|
|
|
+ else if (changed & BSS_CHANGED_ASSOC) {
|
|
|
+ ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
|
|
|
+ false);
|
|
|
+ if (ret < 0) {
|
|
|
+ wl1271_warning("Set ht cap false failed %d",
|
|
|
+ ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Handle HT information change. Only after join. */
|
|
|
+ if (sta_exists && (changed & BSS_CHANGED_HT) &&
|
|
|
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
|
|
|
+ ret = wl1271_acx_set_ht_information(wl,
|
|
|
+ bss_conf->ht_operation_mode);
|
|
|
+ if (ret < 0) {
|
|
|
+ wl1271_warning("Set ht information failed %d", ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
out:
|
|
|
return;
|
|
|
}
|
|
@@ -3623,6 +3634,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
|
|
|
|
|
|
__clear_bit(id, wl->ap_hlid_map);
|
|
|
memset(wl->links[hlid].addr, 0, ETH_ALEN);
|
|
|
+ wl->links[hlid].ba_bitmap = 0;
|
|
|
wl1271_tx_reset_link_queues(wl, hlid);
|
|
|
__clear_bit(hlid, &wl->ap_ps_map);
|
|
|
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
|
|
@@ -3725,6 +3737,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
|
|
{
|
|
|
struct wl1271 *wl = hw->priv;
|
|
|
int ret;
|
|
|
+ u8 hlid, *ba_bitmap;
|
|
|
+
|
|
|
+ wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
|
|
|
+ tid);
|
|
|
+
|
|
|
+ /* sanity check - the fields in FW are only 8bits wide */
|
|
|
+ if (WARN_ON(tid > 0xFF))
|
|
|
+ return -ENOTSUPP;
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
|
|
|
@@ -3733,6 +3753,20 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+ if (wl->bss_type == BSS_TYPE_STA_BSS) {
|
|
|
+ hlid = wl->sta_hlid;
|
|
|
+ ba_bitmap = &wl->ba_rx_bitmap;
|
|
|
+ } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
|
|
|
+ struct wl1271_station *wl_sta;
|
|
|
+
|
|
|
+ wl_sta = (struct wl1271_station *)sta->drv_priv;
|
|
|
+ hlid = wl_sta->hlid;
|
|
|
+ ba_bitmap = &wl->links[hlid].ba_bitmap;
|
|
|
+ } else {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
ret = wl1271_ps_elp_wakeup(wl);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
@@ -3742,20 +3776,46 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
|
|
|
|
|
switch (action) {
|
|
|
case IEEE80211_AMPDU_RX_START:
|
|
|
- if ((wl->ba_support) && (wl->ba_allowed)) {
|
|
|
- ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
|
|
|
- true);
|
|
|
- if (!ret)
|
|
|
- wl->ba_rx_bitmap |= BIT(tid);
|
|
|
- } else {
|
|
|
+ if (!wl->ba_support || !wl->ba_allowed) {
|
|
|
ret = -ENOTSUPP;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
|
|
|
+ ret = -EBUSY;
|
|
|
+ wl1271_error("exceeded max RX BA sessions");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (*ba_bitmap & BIT(tid)) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ wl1271_error("cannot enable RX BA session on active "
|
|
|
+ "tid: %d", tid);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
|
|
|
+ hlid);
|
|
|
+ if (!ret) {
|
|
|
+ *ba_bitmap |= BIT(tid);
|
|
|
+ wl->ba_rx_session_count++;
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case IEEE80211_AMPDU_RX_STOP:
|
|
|
- ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
|
|
|
- if (!ret)
|
|
|
- wl->ba_rx_bitmap &= ~BIT(tid);
|
|
|
+ if (!(*ba_bitmap & BIT(tid))) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ wl1271_error("no active RX BA session on tid: %d",
|
|
|
+ tid);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
|
|
|
+ hlid);
|
|
|
+ if (!ret) {
|
|
|
+ *ba_bitmap &= ~BIT(tid);
|
|
|
+ wl->ba_rx_session_count--;
|
|
|
+ }
|
|
|
break;
|
|
|
|
|
|
/*
|