mac80211: Re-enable aggregation
authorSujith <Sujith.Manoharan@atheros.com>
Fri, 24 Oct 2008 04:25:27 +0000 (09:55 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 31 Oct 2008 23:02:14 +0000 (19:02 -0400)
Wireless HW without any dedicated queues for aggregation
do not need the ampdu_queues mechanism present right now
in mac80211. Since mac80211 is still incomplete wrt TX MQ
changes, do not allow aggregation sessions for drivers that
set ampdu_queues.

This is only an interim hack until Intel fixes the requeue issue.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: Luis Rodriguez <Luis.Rodriguez@Atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath9k/main.c
drivers/net/wireless/iwlwifi/iwl-core.c
include/linux/skbuff.h
include/net/mac80211.h
net/core/skbuff.c
net/mac80211/ht.c
net/mac80211/main.c
net/mac80211/rx.c
net/mac80211/tx.c
net/mac80211/wme.c

index 795fed5..f6dc4c8 100644 (file)
@@ -953,10 +953,7 @@ static int ath_attach(u16 devid,
                        &sc->sbands[IEEE80211_BAND_5GHZ];
        }
 
-       /* FIXME: Have to figure out proper hw init values later */
-
        hw->queues = 4;
-       hw->ampdu_queues = 1;
 
        /* Register rate control */
        hw->rate_control_algorithm = "ath9k_rate_control";
@@ -1745,7 +1742,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                IEEE80211_HW_SIGNAL_DBM |
-               IEEE80211_HW_NOISE_DBM;
+               IEEE80211_HW_NOISE_DBM |
+               IEEE80211_HW_AMPDU_AGGREGATION;
 
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
index 20c7ff3..ba05f5d 100644 (file)
@@ -871,7 +871,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM;
+                   IEEE80211_HW_NOISE_DBM |
+                   IEEE80211_HW_AMPDU_AGGREGATION;
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_STATION) |
index 487e345..a01b6f8 100644 (file)
@@ -250,6 +250,9 @@ typedef unsigned char *sk_buff_data_t;
  *     @tc_verd: traffic control verdict
  *     @ndisc_nodetype: router type (from link layer)
  *     @do_not_encrypt: set to prevent encryption of this frame
+ *     @requeue: set to indicate that the wireless core should attempt
+ *             a software retry on this frame if we failed to
+ *             receive an ACK for it
  *     @dma_cookie: a cookie to one of several possible DMA operations
  *             done by skb DMA functions
  *     @secmark: security marking
@@ -326,6 +329,7 @@ struct sk_buff {
 #endif
 #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
        __u8                    do_not_encrypt:1;
+       __u8                    requeue:1;
 #endif
        /* 0/13/14 bit hole */
 
index 16c8959..bba96a2 100644 (file)
@@ -242,7 +242,6 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
  *     set by rate control algorithms to indicate probe rate, will
  *     be cleared for fragmented frames (except on the last fragment)
- * @IEEE80211_TX_CTL_REQUEUE: REMOVE THIS
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
@@ -258,9 +257,6 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_STAT_AMPDU                 = BIT(10),
        IEEE80211_TX_STAT_AMPDU_NO_BACK         = BIT(11),
        IEEE80211_TX_CTL_RATE_CTRL_PROBE        = BIT(12),
-
-       /* XXX: remove this */
-       IEEE80211_TX_CTL_REQUEUE                = BIT(13),
 };
 
 enum mac80211_rate_control_flags {
@@ -847,6 +843,9 @@ enum ieee80211_tkip_key_type {
  * @IEEE80211_HW_SPECTRUM_MGMT:
  *     Hardware supports spectrum management defined in 802.11h
  *     Measurement, Channel Switch, Quieting, TPC
+ *
+ * @IEEE80211_HW_AMPDU_AGGREGATION:
+ *     Hardware supports 11n A-MPDU aggregation.
  */
 enum ieee80211_hw_flags {
        IEEE80211_HW_RX_INCLUDES_FCS                    = 1<<1,
@@ -858,6 +857,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_SIGNAL_DBM                         = 1<<7,
        IEEE80211_HW_NOISE_DBM                          = 1<<8,
        IEEE80211_HW_SPECTRUM_MGMT                      = 1<<9,
+       IEEE80211_HW_AMPDU_AGGREGATION                  = 1<<10,
 };
 
 /**
index cdfe473..c4c8a33 100644 (file)
@@ -544,6 +544,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
        C(truesize);
 #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
        C(do_not_encrypt);
+       C(requeue);
 #endif
        atomic_set(&n->users, 1);
 
index 42c3e59..08009d4 100644 (file)
@@ -458,7 +458,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 +515,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 +546,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 +557,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 +626,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 +640,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 +697,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 +752,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;
@@ -1011,7 +1020,8 @@ 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]);
 
                spin_unlock_bh(&sta->lock);
index 88c1975..fa0cc7a 100644 (file)
@@ -386,8 +386,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                                            struct sta_info *sta,
                                            struct sk_buff *skb)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
        sta->tx_filtered_count++;
 
        /*
@@ -434,10 +432,9 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                return;
        }
 
-       if (!test_sta_flags(sta, WLAN_STA_PS) &&
-           !(info->flags & IEEE80211_TX_CTL_REQUEUE)) {
+       if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) {
                /* Software retry the packet once */
-               info->flags |= IEEE80211_TX_CTL_REQUEUE;
+               skb->requeue = 1;
                ieee80211_remove_tx_extra(local, sta->key, skb);
                dev_queue_xmit(skb);
                return;
index c4c95f1..648a1d0 100644 (file)
@@ -669,7 +669,6 @@ static int ap_sta_ps_end(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        int sent = 0;
-       struct ieee80211_tx_info *info;
 
        atomic_dec(&sdata->bss->num_sta_ps);
 
@@ -685,13 +684,11 @@ static int ap_sta_ps_end(struct sta_info *sta)
 
        /* Send all buffered frames to the station */
        while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
-               info = IEEE80211_SKB_CB(skb);
                sent++;
-               info->flags |= IEEE80211_TX_CTL_REQUEUE;
+               skb->requeue = 1;
                dev_queue_xmit(skb);
        }
        while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
-               info = IEEE80211_SKB_CB(skb);
                local->total_ps_buffered--;
                sent++;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -699,7 +696,7 @@ static int ap_sta_ps_end(struct sta_info *sta)
                       "since STA not sleeping anymore\n", sdata->dev->name,
                       sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-               info->flags |= IEEE80211_TX_CTL_REQUEUE;
+               skb->requeue = 1;
                dev_queue_xmit(skb);
        }
 
index 541e3e6..d6392af 100644 (file)
@@ -661,6 +661,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        size_t hdrlen, per_fragm, num_fragm, payload_len, left;
        struct sk_buff **frags, *first, *frag;
@@ -677,9 +678,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
         * This scenario is handled in __ieee80211_tx_prepare but extra
         * caution taken here as fragmented ampdu may cause Tx stop.
         */
-       if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU ||
-                   skb_get_queue_mapping(tx->skb) >=
-                       ieee80211_num_regular_queues(&tx->local->hw)))
+       if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
                return TX_DROP;
 
        first = tx->skb;
@@ -951,7 +950,8 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
-       int hdrlen;
+       int hdrlen, tid;
+       u8 *qc, *state;
 
        memset(tx, 0, sizeof(*tx));
        tx->skb = skb;
@@ -982,6 +982,15 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
 
        tx->sta = sta_info_get(local, hdr->addr1);
 
+       if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) {
+               qc = ieee80211_get_qos_ctl(hdr);
+               tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+
+               state = &tx->sta->ampdu_mlme.tid_state_tx[tid];
+               if (*state == HT_AGG_STATE_OPERATIONAL)
+                       info->flags |= IEEE80211_TX_CTL_AMPDU;
+       }
+
        if (is_multicast_ether_addr(hdr->addr1)) {
                tx->flags &= ~IEEE80211_TX_UNICAST;
                info->flags |= IEEE80211_TX_CTL_NO_ACK;
@@ -1172,7 +1181,7 @@ retry:
                 * queues, there's no reason for a driver to reject
                 * a frame there, warn and drop it.
                 */
-               if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw)))
+               if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
                        goto drop;
 
                store = &local->pending_packet[queue];
index d27ef7f..ac71b38 100644 (file)
@@ -114,8 +114,8 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
        struct ieee80211_master_priv *mpriv = netdev_priv(dev);
        struct ieee80211_local *local = mpriv->local;
+       struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct sta_info *sta;
        u16 queue;
        u8 tid;
@@ -124,21 +124,19 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
        if (unlikely(queue >= local->hw.queues))
                queue = local->hw.queues - 1;
 
-       if (info->flags & IEEE80211_TX_CTL_REQUEUE) {
+       if (skb->requeue) {
+               if (!hw->ampdu_queues)
+                       return queue;
+
                rcu_read_lock();
                sta = sta_info_get(local, hdr->addr1);
                tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
                if (sta) {
-                       struct ieee80211_hw *hw = &local->hw;
                        int ampdu_queue = sta->tid_to_tx_q[tid];
 
                        if ((ampdu_queue < ieee80211_num_queues(hw)) &&
-                           test_bit(ampdu_queue, local->queue_pool)) {
+                           test_bit(ampdu_queue, local->queue_pool))
                                queue = ampdu_queue;
-                               info->flags |= IEEE80211_TX_CTL_AMPDU;
-                       } else {
-                               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-                       }
                }
                rcu_read_unlock();
 
@@ -159,20 +157,18 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
                *p++ = ack_policy | tid;
                *p = 0;
 
+               if (!hw->ampdu_queues)
+                       return queue;
+
                rcu_read_lock();
 
                sta = sta_info_get(local, hdr->addr1);
                if (sta) {
                        int ampdu_queue = sta->tid_to_tx_q[tid];
-                       struct ieee80211_hw *hw = &local->hw;
 
                        if ((ampdu_queue < ieee80211_num_queues(hw)) &&
-                           test_bit(ampdu_queue, local->queue_pool)) {
+                           test_bit(ampdu_queue, local->queue_pool))
                                queue = ampdu_queue;
-                               info->flags |= IEEE80211_TX_CTL_AMPDU;
-                       } else {
-                               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-                       }
                }
 
                rcu_read_unlock();