Merge branch 'simplify_PRT' into release
[linux-2.6-microblaze.git] / net / mac80211 / ht.c
index 42c3e59..5f510a1 100644 (file)
@@ -36,7 +36,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
 
        ht_cap->ht_supported = true;
 
-       ht_cap->cap = ht_cap->cap & sband->ht_cap.cap;
+       ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap;
        ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS;
        ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
 
@@ -98,6 +98,7 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_bss_ht_conf ht;
        u32 changed = 0;
        bool enable_ht = true, ht_changed;
+       enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
@@ -112,24 +113,36 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
            ieee80211_channel_to_frequency(hti->control_chan))
                enable_ht = false;
 
-       /*
-        * XXX: This is totally incorrect when there are multiple virtual
-        *      interfaces, needs to be fixed later.
-        */
-       ht_changed = local->hw.conf.ht.enabled != enable_ht;
+       if (enable_ht) {
+               channel_type = NL80211_CHAN_HT20;
+
+               if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+                   (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
+                   (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
+                       switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+                       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+                               channel_type = NL80211_CHAN_HT40PLUS;
+                               break;
+                       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+                               channel_type = NL80211_CHAN_HT40MINUS;
+                               break;
+                       }
+               }
+       }
+
+       ht_changed = local->hw.conf.ht.enabled != enable_ht ||
+                    channel_type != local->hw.conf.ht.channel_type;
+
+       local->oper_channel_type = channel_type;
        local->hw.conf.ht.enabled = enable_ht;
+
        if (ht_changed)
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
 
        /* disable HT */
        if (!enable_ht)
                return 0;
-       ht.secondary_channel_offset =
-               hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
-       ht.width_40_ok =
-               !(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
-               (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
-               (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY);
+
        ht.operation_mode = le16_to_cpu(hti->operation_mode);
 
        /* if bss configuration changed store the new one */
@@ -458,7 +471,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
        u8 *state;
        int ret;
 
-       if (tid >= STA_TID_NUM)
+       if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
                return -EINVAL;
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -515,17 +528,19 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                        (unsigned long)&sta->timer_to_tid[tid];
        init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
 
-       /* create a new queue for this aggregation */
-       ret = ieee80211_ht_agg_queue_add(local, sta, tid);
+       if (hw->ampdu_queues) {
+               /* create a new queue for this aggregation */
+               ret = ieee80211_ht_agg_queue_add(local, sta, tid);
 
-       /* case no queue is available to aggregation
-        * don't switch to aggregation */
-       if (ret) {
+               /* case no queue is available to aggregation
+                * don't switch to aggregation */
+               if (ret) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA request denied - queue unavailable for"
-                                       " tid %d\n", tid);
+                       printk(KERN_DEBUG "BA request denied - "
+                              "queue unavailable for tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
-               goto err_unlock_queue;
+                       goto err_unlock_queue;
+               }
        }
        sdata = sta->sdata;
 
@@ -544,7 +559,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                /* No need to requeue the packets in the agg queue, since we
                 * held the tx lock: no packet could be enqueued to the newly
                 * allocated queue */
-               ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+               if (hw->ampdu_queues)
+                       ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "BA request denied - HW unavailable for"
                                        " tid %d\n", tid);
@@ -554,7 +570,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
        }
 
        /* Will put all the packets in the new SW queue */
-       ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
+       if (hw->ampdu_queues)
+               ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
        spin_unlock_bh(&sta->lock);
 
        /* send an addBA request */
@@ -622,7 +639,8 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
               ra, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-       ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
+       if (hw->ampdu_queues)
+               ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
 
        *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
                (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
@@ -635,7 +653,8 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
        if (ret) {
                WARN_ON(ret != -EBUSY);
                *state = HT_AGG_STATE_OPERATIONAL;
-               ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+               if (hw->ampdu_queues)
+                       ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
                goto stop_BA_exit;
        }
 
@@ -691,7 +710,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
 #endif
-               ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+               if (hw->ampdu_queues)
+                       ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
        }
        spin_unlock_bh(&sta->lock);
        rcu_read_unlock();
@@ -745,16 +765,18 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
                ieee80211_send_delba(sta->sdata, ra, tid,
                        WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
 
-       agg_queue = sta->tid_to_tx_q[tid];
-
-       ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
-
-       /* We just requeued the all the frames that were in the
-        * removed queue, and since we might miss a softirq we do
-        * netif_schedule_queue.  ieee80211_wake_queue is not used
-        * here as this queue is not necessarily stopped
-        */
-       netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue));
+       if (hw->ampdu_queues) {
+               agg_queue = sta->tid_to_tx_q[tid];
+               ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+
+               /* We just requeued the all the frames that were in the
+                * removed queue, and since we might miss a softirq we do
+                * netif_schedule_queue.  ieee80211_wake_queue is not used
+                * here as this queue is not necessarily stopped
+                */
+               netif_schedule_queue(netdev_get_tx_queue(local->mdev,
+                                                        agg_queue));
+       }
        spin_lock_bh(&sta->lock);
        *state = HT_AGG_STATE_IDLE;
        sta->ampdu_mlme.addba_req_num[tid] = 0;
@@ -978,7 +1000,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 {
        struct ieee80211_hw *hw = &local->hw;
        u16 capab;
-       u16 tid;
+       u16 tid, start_seq_num;
        u8 *state;
 
        capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
@@ -1011,9 +1033,18 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
                *state |= HT_ADDBA_RECEIVED_MSK;
                sta->ampdu_mlme.addba_req_num[tid] = 0;
 
-               if (*state == HT_AGG_STATE_OPERATIONAL)
+               if (*state == HT_AGG_STATE_OPERATIONAL &&
+                   local->hw.ampdu_queues)
                        ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
 
+               if (local->ops->ampdu_action) {
+                       (void)local->ops->ampdu_action(hw,
+                                              IEEE80211_AMPDU_TX_RESUME,
+                                              &sta->sta, tid, &start_seq_num);
+               }
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
                spin_unlock_bh(&sta->lock);
        } else {
                sta->ampdu_mlme.addba_req_num[tid]++;