On Tue, Sep 30, 2008 at 7:02 PM, Luis R. Rodriguez <lrodriguez@xxxxxxxxxxx> wrote: > Re-enable aggregation by addressing skb->cb overwrites > after insertion into the qdisc. Aggregation was disabled > after the new TX multiqueue changes were introduced > as it made a bug apparent in mac80211. > > Two flags (IEEE80211_TX_CTL_REQUEUE and IEEE80211_TX_CTL_AMPDU) > required for proper aggregation control cannot be relied on > after the new TX multiqueue changes went in due to the fact > that after an skb is insterted into the qdisc the skb->cb is > cleared. > > We deal with IEEE80211_TX_CTL_REQUEUE by moving this flag > directly into the skb. We deal with IEEE80211_TX_CTL_AMPDU > by setting this flag again later during the the TX sequence > handler, ieee80211_tx_h_sequence(), by checking if the tid > for the skb for the destination sta is in an active > High Throughput (HT) state. > > To properly correct aggregation under the new TX MQ work > we also have to use rtnl_lock() when starting starting > an aggregation session to prevent a possible race against > the skb's queue's removal. > > Signed-off-by: Luis R. Rodriguez <lrodriguez@xxxxxxxxxxx> > Signed-off-by: Tomas Winkler <tomas.winkler@xxxxxxxxx> > Signed-off-by: Luis R. Rodriguez <lrodriguez@xxxxxxxxxxx> > --- > > This guy uses list_for_each_entry() and shuffles locking > handling a bit. It leaves locking as it used to for our > driver amdpu handler. I'm about to test it. > > include/linux/skbuff.h | 4 + > include/net/mac80211.h | 4 +- > net/mac80211/ieee80211_i.h | 7 ++ > net/mac80211/main.c | 144 +++++++++++++++++++++++++++----------------- > net/mac80211/rx.c | 7 +-- > net/mac80211/sta_info.c | 42 +++++++++++++ > net/mac80211/sta_info.h | 3 + > net/mac80211/tx.c | 3 + > net/mac80211/wme.c | 19 +----- > 9 files changed, 155 insertions(+), 78 deletions(-) > > diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h > index 9099237..4724211 100644 > --- a/include/linux/skbuff.h > +++ b/include/linux/skbuff.h > @@ -244,6 +244,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 > @@ -319,6 +322,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 */ > > diff --git a/include/net/mac80211.h b/include/net/mac80211.h > index ff137fd..f1b5fcf 100644 > --- a/include/net/mac80211.h > +++ b/include/net/mac80211.h > @@ -215,7 +215,6 @@ struct ieee80211_bss_conf { > * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: TBD > * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination > * station > - * @IEEE80211_TX_CTL_REQUEUE: TBD > * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame > * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD > * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the > @@ -257,12 +256,11 @@ enum mac80211_tx_control_flags { > IEEE80211_TX_CTL_NO_ACK = BIT(4), > IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(5), > IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(6), > - IEEE80211_TX_CTL_REQUEUE = BIT(7), > IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8), > IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9), > IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10), > IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12), > - IEEE80211_TX_CTL_AMPDU = BIT(13), > + IEEE80211_TX_CTL_AMPDU = BIT(13), > IEEE80211_TX_CTL_OFDM_HT = BIT(14), > IEEE80211_TX_CTL_GREEN_FIELD = BIT(15), > IEEE80211_TX_CTL_40_MHZ_WIDTH = BIT(16), > diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h > index 4498d87..549610c 100644 > --- a/net/mac80211/ieee80211_i.h > +++ b/net/mac80211/ieee80211_i.h > @@ -594,6 +594,10 @@ struct ieee80211_local { > struct sta_info *sta_hash[STA_HASH_SIZE]; > struct timer_list sta_cleanup; > > + spinlock_t sta_ba_lock; > + struct list_head sta_ba_session_list; > + struct work_struct sta_ba_session_work; > + > unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; > unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; > struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; > @@ -912,6 +916,9 @@ void ieee80211_send_bar(struct net_device *dev, u8 *ra, u16 tid, u16 ssn); > > void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, > u16 tid, u16 initiator, u16 reason); > +void initiate_aggr_and_timer(struct sta_info *sta, u16 tid, u16 start_seq_num); > +int __ieee80211_start_tx_ba_session(struct ieee80211_local *local, > + struct sta_info *sta, u16 tid, u16 *start_seq_num); > void sta_addba_resp_timer_expired(unsigned long data); > void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr); > u64 ieee80211_sta_get_rates(struct ieee80211_local *local, > diff --git a/net/mac80211/main.c b/net/mac80211/main.c > index aa5a191..7acb3de 100644 > --- a/net/mac80211/main.c > +++ b/net/mac80211/main.c > @@ -557,12 +557,35 @@ static int ieee80211_stop(struct net_device *dev) > return 0; > } > > -int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) > +/* send an addBA request and set timer for it */ > +void initiate_aggr_and_timer(struct sta_info *sta, u16 tid, > + u16 start_seq_num) > +{ > + sta->ampdu_mlme.dialog_token_allocator++; > + sta->ampdu_mlme.tid_tx[tid]->dialog_token = > + sta->ampdu_mlme.dialog_token_allocator; > + sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; > + > + > + > + ieee80211_send_addba_request(sta->sdata->dev, sta->addr, tid, > + sta->ampdu_mlme.tid_tx[tid]->dialog_token, > + sta->ampdu_mlme.tid_tx[tid]->ssn, > + 0x40, 5000); > + > + /* activate the timer for the recipient's addBA response */ > + sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = > + jiffies + ADDBA_RESP_INTERVAL; > + add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); > +#ifdef CONFIG_MAC80211_HT_DEBUG > + printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); > +#endif > +} > + > +int __ieee80211_start_tx_ba_session(struct ieee80211_local *local, > + struct sta_info *sta, u16 tid, u16 *start_seq_num) > { > - struct ieee80211_local *local = hw_to_local(hw); > - struct sta_info *sta; > struct ieee80211_sub_if_data *sdata; > - u16 start_seq_num = 0; > u8 *state; > int ret; > DECLARE_MAC_BUF(mac); > @@ -572,26 +595,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) > > #ifdef CONFIG_MAC80211_HT_DEBUG > printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", > - print_mac(mac, ra), tid); > + print_mac(mac, sta->addr), tid); > #endif /* CONFIG_MAC80211_HT_DEBUG */ > > - rcu_read_lock(); > - > - sta = sta_info_get(local, ra); > - if (!sta) { > -#ifdef CONFIG_MAC80211_HT_DEBUG > - printk(KERN_DEBUG "Could not find the station\n"); > -#endif > - ret = -ENOENT; > - goto exit; > - } > - > - spin_lock_bh(&sta->lock); > - > /* we have tried too many times, receiver does not want A-MPDU */ > if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { > - ret = -EBUSY; > - goto err_unlock_sta; > + printk(KERN_DEBUG "BA too many retries tid %u\n", tid); > + return -EBUSY; > } > > state = &sta->ampdu_mlme.tid_state_tx[tid]; > @@ -601,8 +611,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) > printk(KERN_DEBUG "BA request denied - session is not " > "idle on tid %u\n", tid); > #endif /* CONFIG_MAC80211_HT_DEBUG */ > - ret = -EAGAIN; > - goto err_unlock_sta; > + return -EAGAIN; > } > > /* prepare A-MPDU MLME for Tx aggregation */ > @@ -614,8 +623,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) > printk(KERN_ERR "allocate tx mlme to tid %d failed\n", > tid); > #endif > - ret = -ENOMEM; > - goto err_unlock_sta; > + return -ENOMEM; > } > /* Tx timer */ > sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = > @@ -634,7 +642,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 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; > } > sdata = sta->sdata; > > @@ -642,9 +650,11 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) > * call back right away, it must see that the flow has begun */ > *state |= HT_ADDBA_REQUESTED_MSK; > > + > if (local->ops->ampdu_action) > - ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, > - ra, tid, &start_seq_num); > + ret = local->ops->ampdu_action(local_to_hw(local), > + IEEE80211_AMPDU_TX_START, > + sta->addr, tid, start_seq_num); Doesn't look good, we need to get the sequence number from the driver Tomas > > if (ret) { > /* No need to requeue the packets in the agg queue, since we > @@ -656,40 +666,65 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) > " tid %d\n", tid); > #endif /* CONFIG_MAC80211_HT_DEBUG */ > *state = HT_AGG_STATE_IDLE; > - goto err_unlock_queue; > + goto err; > } > > /* Will put all the packets in the new SW queue */ > ieee80211_requeue(local, ieee802_1d_to_ac[tid]); > - spin_unlock_bh(&sta->lock); > > - /* send an addBA request */ > - sta->ampdu_mlme.dialog_token_allocator++; > - sta->ampdu_mlme.tid_tx[tid]->dialog_token = > - sta->ampdu_mlme.dialog_token_allocator; > - sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; > + return 0; > > +err: > + kfree(sta->ampdu_mlme.tid_tx[tid]); > + sta->ampdu_mlme.tid_tx[tid] = NULL; > + return ret; > +} > > - ieee80211_send_addba_request(sta->sdata->dev, ra, tid, > - sta->ampdu_mlme.tid_tx[tid]->dialog_token, > - sta->ampdu_mlme.tid_tx[tid]->ssn, > - 0x40, 5000); > - /* activate the timer for the recipient's addBA response */ > - sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = > - jiffies + ADDBA_RESP_INTERVAL; > - add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); > +int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) > +{ > + struct ieee80211_local *local = hw_to_local(hw); > + struct sta_info *sta; > + u8 *state; > + int ret; > + > + rcu_read_lock(); > + > + sta = sta_info_get(local, ra); > + if (!sta) { > #ifdef CONFIG_MAC80211_HT_DEBUG > - printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); > + printk(KERN_DEBUG "Could not find the station\n"); > #endif > - goto exit; > + ret = -ENOENT; > + goto err; > + } > > -err_unlock_queue: > - kfree(sta->ampdu_mlme.tid_tx[tid]); > - sta->ampdu_mlme.tid_tx[tid] = NULL; > - ret = -EBUSY; > -err_unlock_sta: > + spin_lock_bh(&sta->lock); > + > + state = &sta->ampdu_mlme.tid_state_tx[tid]; > + if (*state != HT_AGG_STATE_IDLE) { > +#ifdef CONFIG_MAC80211_HT_DEBUG > + printk(KERN_DEBUG "BA request denied - session is not " > + "idle on tid %u\n", tid); > +#endif /* CONFIG_MAC80211_HT_DEBUG */ > + ret = -EAGAIN; > + spin_unlock_bh(&sta->lock); > + goto err; > + } > + > + *state = HT_AGG_START_PEND_REQ; > spin_unlock_bh(&sta->lock); > -exit: > + > + spin_lock_bh(&local->sta_ba_lock); > + list_add_tail(&sta->ba_list, &local->sta_ba_session_list); > + spin_unlock_bh(&local->sta_ba_lock); > + > + rcu_read_unlock(); > + > + schedule_work(&local->sta_ba_session_work); > + > + return 0; > + > +err: > rcu_read_unlock(); > return ret; > } > @@ -858,7 +893,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) > > agg_queue = sta->tid_to_tx_q[tid]; > > + rtnl_lock(); > ieee80211_ht_agg_queue_remove(local, sta, tid, 1); > + rtnl_unlock(); > > /* We just requeued the all the frames that were in the > * removed queue, and since we might miss a softirq we do > @@ -1293,8 +1330,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++; > > /* > @@ -1341,10 +1376,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; > diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c > index 6db8545..3e3c870 100644 > --- a/net/mac80211/rx.c > +++ b/net/mac80211/rx.c > @@ -666,7 +666,6 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) > struct sk_buff *skb; > int sent = 0; > struct ieee80211_sub_if_data *sdata; > - struct ieee80211_tx_info *info; > DECLARE_MAC_BUF(mac); > > sdata = sta->sdata; > @@ -685,13 +684,11 @@ static int ap_sta_ps_end(struct net_device *dev, 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 net_device *dev, struct sta_info *sta) > "since STA not sleeping anymore\n", dev->name, > print_mac(mac, sta->addr), sta->aid); > #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ > - info->flags |= IEEE80211_TX_CTL_REQUEUE; > + skb->requeue = 1; > dev_queue_xmit(skb); > } > > diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c > index f2ba653..b8dbbb7 100644 > --- a/net/mac80211/sta_info.c > +++ b/net/mac80211/sta_info.c > @@ -690,12 +690,53 @@ static void ieee80211_sta_flush_work(struct work_struct *work) > rtnl_unlock(); > } > > +static void __ieee80211_run_ba_session(struct ieee80211_local *local) > +{ > + struct sta_info *sta, *sta_tmp; > + u8 *state; > + u16 start_seq_num = 0; > + int tid, r = -EINVAL; > + > + ASSERT_RTNL(); > + > + spin_lock_bh(&local->sta_ba_lock); > + list_for_each_entry_safe(sta, sta_tmp, > + &local->sta_ba_session_list, ba_list) { > + list_del(&sta->ba_list); > + spin_lock_bh(&sta->lock); > + for (tid = 0; tid < STA_TID_NUM; tid++) { > + state = &sta->ampdu_mlme.tid_state_tx[tid]; > + r = -EINVAL; > + if (*state & HT_AGG_START_PEND_REQ) { > + *state &= ~HT_AGG_START_PEND_REQ; > + r = __ieee80211_start_tx_ba_session(local, > + sta, tid, &start_seq_num); > + } > + if (!r) > + initiate_aggr_and_timer(sta, tid, start_seq_num); This is rather a strange name for a function, > + } > + spin_unlock_bh(&sta->lock); Don't think you can hold this lock across the whole loop > + } > + spin_unlock_bh(&local->sta_ba_lock); > +} > + > +static void ieee80211_sta_ba_session_work(struct work_struct *work) > +{ > + struct ieee80211_local *local = > + container_of(work, struct ieee80211_local, sta_ba_session_work); > + > + rtnl_lock(); > + __ieee80211_run_ba_session(local); > + rtnl_unlock(); > +} > void sta_info_init(struct ieee80211_local *local) > { > spin_lock_init(&local->sta_lock); > INIT_LIST_HEAD(&local->sta_list); > INIT_LIST_HEAD(&local->sta_flush_list); > + INIT_LIST_HEAD(&local->sta_ba_session_list); > INIT_WORK(&local->sta_flush_work, ieee80211_sta_flush_work); > + INIT_WORK(&local->sta_ba_session_work, ieee80211_sta_ba_session_work); > > setup_timer(&local->sta_cleanup, sta_info_cleanup, > (unsigned long)local); > @@ -717,6 +758,7 @@ void sta_info_stop(struct ieee80211_local *local) > { > del_timer(&local->sta_cleanup); > cancel_work_sync(&local->sta_flush_work); > + cancel_work_sync(&local->sta_ba_session_work); > #ifdef CONFIG_MAC80211_DEBUGFS > /* > * Make sure the debugfs adding work isn't pending after this > diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h > index 109db78..cd8626c 100644 > --- a/net/mac80211/sta_info.h > +++ b/net/mac80211/sta_info.h > @@ -63,6 +63,8 @@ enum ieee80211_sta_info_flags { > #define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \ > HT_ADDBA_DRV_READY_MSK | \ > HT_ADDBA_RECEIVED_MSK) > +#define HT_AGG_START_PEND_REQ BIT(5) > +#define HT_AGG_STOP_PEND_REQ BIT(6) > #define HT_AGG_STATE_DEBUGFS_CTL BIT(7) > > /** > @@ -223,6 +225,7 @@ struct sta_info { > struct list_head list; > struct sta_info *hnext; > struct ieee80211_local *local; > + struct list_head ba_list; > struct ieee80211_sub_if_data *sdata; > struct ieee80211_key *key; > struct rate_control_ref *rate_ctrl; > diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c > index 4788f7b..b25113f 100644 > --- a/net/mac80211/tx.c > +++ b/net/mac80211/tx.c > @@ -655,6 +655,9 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) > tid = *qc & IEEE80211_QOS_CTL_TID_MASK; > seq = &tx->sta->tid_seq[tid]; > > + if (tx->sta->ampdu_mlme.tid_state_tx[tid] == HT_AGG_STATE_OPERATIONAL) > + info->flags |= IEEE80211_TX_CTL_AMPDU; > + > hdr->seq_ctrl = cpu_to_le16(*seq); > > /* Increase the sequence number. */ > diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c > index 4310e2f..c53bd56 100644 > --- a/net/mac80211/wme.c > +++ b/net/mac80211/wme.c > @@ -113,11 +113,11 @@ static u16 classify80211(struct sk_buff *skb, struct net_device *dev) > return ieee802_1d_to_ac[skb->priority]; > } > > +/* XXX: Remove usage of tid_to_tx_q and only map frames to an AC */ > u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) > { > struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; > struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); > - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); > struct sta_info *sta; > u16 queue; > u8 tid; > @@ -126,7 +126,7 @@ 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) { > rcu_read_lock(); > sta = sta_info_get(local, hdr->addr1); > tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; > @@ -135,12 +135,8 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) > 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(); > > @@ -169,12 +165,8 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) > 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(); > @@ -188,9 +180,6 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, > { > int i; > > - /* XXX: currently broken due to cb/requeue use */ > - return -EPERM; > - > /* prepare the filter and save it for the SW queue > * matching the received HW queue */ > > -- > 1.5.6.3 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-wireless" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html