aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorRon Rindjunsky <ron.rindjunsky@intel.com>2008-01-28 07:07:18 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-02-29 15:19:17 -0500
commit9e7234923789897858e1a475c579b5e2e6ad5b74 (patch)
tree69e97df9ff34f9237bfddee6e99100e8e16e1da1 /net/mac80211
parenteadc8d9e9047266a8914eb2ed4d36e797ce540d1 (diff)
mac80211: A-MPDU Tx adding qdisc support
This patch allows qdisc support in A-MPDU Tx. a method to handle QoS <-> TID switches is present in this patch. Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211.c8
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/tx.c2
-rw-r--r--net/mac80211/wme.c135
-rw-r--r--net/mac80211/wme.h23
5 files changed, 155 insertions, 18 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index c323c9af9b8f..f8e734f0da1a 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -462,7 +462,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
462 spin_lock_bh(&local->mdev->queue_lock); 462 spin_lock_bh(&local->mdev->queue_lock);
463 463
464 /* create a new queue for this aggregation */ 464 /* create a new queue for this aggregation */
465 /* ret = ieee80211_ht_agg_queue_add(local, sta, tid); */ 465 ret = ieee80211_ht_agg_queue_add(local, sta, tid);
466 466
467 /* case no queue is available to aggregation 467 /* case no queue is available to aggregation
468 * don't switch to aggregation */ 468 * don't switch to aggregation */
@@ -488,7 +488,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
488 /* No need to requeue the packets in the agg queue, since we 488 /* No need to requeue the packets in the agg queue, since we
489 * held the tx lock: no packet could be enqueued to the newly 489 * held the tx lock: no packet could be enqueued to the newly
490 * allocated queue */ 490 * allocated queue */
491 /* ieee80211_ht_agg_queue_remove(local, sta, tid, 0); */ 491 ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
492#ifdef CONFIG_MAC80211_HT_DEBUG 492#ifdef CONFIG_MAC80211_HT_DEBUG
493 printk(KERN_DEBUG "BA request denied - HW or queue unavailable" 493 printk(KERN_DEBUG "BA request denied - HW or queue unavailable"
494 " for tid %d\n", tid); 494 " for tid %d\n", tid);
@@ -499,7 +499,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
499 } 499 }
500 500
501 /* Will put all the packets in the new SW queue */ 501 /* Will put all the packets in the new SW queue */
502 /* ieee80211_requeue(local, ieee802_1d_to_ac[tid]); */ 502 ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
503 spin_unlock_bh(&local->mdev->queue_lock); 503 spin_unlock_bh(&local->mdev->queue_lock);
504 504
505 /* We have most probably almost emptied the legacy queue */ 505 /* We have most probably almost emptied the legacy queue */
@@ -675,7 +675,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
675 * the content of the qdiscs */ 675 * the content of the qdiscs */
676 spin_lock_bh(&local->mdev->queue_lock); 676 spin_lock_bh(&local->mdev->queue_lock);
677 /* remove the queue for this aggregation */ 677 /* remove the queue for this aggregation */
678 /* ieee80211_ht_agg_queue_remove(local, sta, tid, 1); */ 678 ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
679 spin_unlock_bh(&local->mdev->queue_lock); 679 spin_unlock_bh(&local->mdev->queue_lock);
680 680
681 /* we just requeued the all the frames that were in the removed 681 /* we just requeued the all the frames that were in the removed
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8a24c2c6ebc1..cfd0717c0033 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -165,6 +165,7 @@ struct ieee80211_txrx_data {
165#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) 165#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1)
166#define IEEE80211_TXPD_REQUEUE BIT(2) 166#define IEEE80211_TXPD_REQUEUE BIT(2)
167#define IEEE80211_TXPD_EAPOL_FRAME BIT(3) 167#define IEEE80211_TXPD_EAPOL_FRAME BIT(3)
168#define IEEE80211_TXPD_AMPDU BIT(4)
168/* Stored in sk_buff->cb */ 169/* Stored in sk_buff->cb */
169struct ieee80211_tx_packet_data { 170struct ieee80211_tx_packet_data {
170 int ifindex; 171 int ifindex;
@@ -452,8 +453,8 @@ struct ieee80211_local {
452 struct sta_info *sta_hash[STA_HASH_SIZE]; 453 struct sta_info *sta_hash[STA_HASH_SIZE];
453 struct timer_list sta_cleanup; 454 struct timer_list sta_cleanup;
454 455
455 unsigned long state[NUM_TX_DATA_QUEUES]; 456 unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
456 struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES]; 457 struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
457 struct tasklet_struct tx_pending_tasklet; 458 struct tasklet_struct tx_pending_tasklet;
458 459
459 /* number of interfaces with corresponding IFF_ flags */ 460 /* number of interfaces with corresponding IFF_ flags */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 85d01646abf5..38e1b2bd8245 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1260,6 +1260,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
1260 control.flags |= IEEE80211_TXCTL_REQUEUE; 1260 control.flags |= IEEE80211_TXCTL_REQUEUE;
1261 if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME) 1261 if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME)
1262 control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; 1262 control.flags |= IEEE80211_TXCTL_EAPOL_FRAME;
1263 if (pkt_data->flags & IEEE80211_TXPD_AMPDU)
1264 control.flags |= IEEE80211_TXCTL_AMPDU;
1263 control.queue = pkt_data->queue; 1265 control.queue = pkt_data->queue;
1264 1266
1265 ret = ieee80211_tx(odev, skb, &control); 1267 ret = ieee80211_tx(odev, skb, &control);
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 4e236599dd31..425aa8588ea0 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -19,10 +19,13 @@
19#include "wme.h" 19#include "wme.h"
20 20
21/* maximum number of hardware queues we support. */ 21/* maximum number of hardware queues we support. */
22#define TC_80211_MAX_QUEUES 8 22#define TC_80211_MAX_QUEUES 16
23
24const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
23 25
24struct ieee80211_sched_data 26struct ieee80211_sched_data
25{ 27{
28 unsigned long qdisc_pool;
26 struct tcf_proto *filter_list; 29 struct tcf_proto *filter_list;
27 struct Qdisc *queues[TC_80211_MAX_QUEUES]; 30 struct Qdisc *queues[TC_80211_MAX_QUEUES];
28 struct sk_buff_head requeued[TC_80211_MAX_QUEUES]; 31 struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
@@ -98,7 +101,6 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
98 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 101 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
99 unsigned short fc = le16_to_cpu(hdr->frame_control); 102 unsigned short fc = le16_to_cpu(hdr->frame_control);
100 int qos; 103 int qos;
101 const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
102 104
103 /* see if frame is data or non data frame */ 105 /* see if frame is data or non data frame */
104 if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) { 106 if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) {
@@ -146,9 +148,25 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
146 unsigned short fc = le16_to_cpu(hdr->frame_control); 148 unsigned short fc = le16_to_cpu(hdr->frame_control);
147 struct Qdisc *qdisc; 149 struct Qdisc *qdisc;
148 int err, queue; 150 int err, queue;
151 struct sta_info *sta;
152 u8 tid;
149 153
150 if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { 154 if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) {
151 skb_queue_tail(&q->requeued[pkt_data->queue], skb); 155 queue = pkt_data->queue;
156 sta = sta_info_get(local, hdr->addr1);
157 tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
158 if (sta) {
159 int ampdu_queue = sta->tid_to_tx_q[tid];
160 if ((ampdu_queue < local->hw.queues) &&
161 test_bit(ampdu_queue, &q->qdisc_pool)) {
162 queue = ampdu_queue;
163 pkt_data->flags |= IEEE80211_TXPD_AMPDU;
164 } else {
165 pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
166 }
167 sta_info_put(sta);
168 }
169 skb_queue_tail(&q->requeued[queue], skb);
152 qd->q.qlen++; 170 qd->q.qlen++;
153 return 0; 171 return 0;
154 } 172 }
@@ -159,14 +177,28 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
159 */ 177 */
160 if (WLAN_FC_IS_QOS_DATA(fc)) { 178 if (WLAN_FC_IS_QOS_DATA(fc)) {
161 u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2; 179 u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2;
162 u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK; 180 u8 ack_policy = 0;
181 tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
163 if (local->wifi_wme_noack_test) 182 if (local->wifi_wme_noack_test)
164 qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK << 183 ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
165 QOS_CONTROL_ACK_POLICY_SHIFT; 184 QOS_CONTROL_ACK_POLICY_SHIFT;
166 /* qos header is 2 bytes, second reserved */ 185 /* qos header is 2 bytes, second reserved */
167 *p = qos_hdr; 186 *p = ack_policy | tid;
168 p++; 187 p++;
169 *p = 0; 188 *p = 0;
189
190 sta = sta_info_get(local, hdr->addr1);
191 if (sta) {
192 int ampdu_queue = sta->tid_to_tx_q[tid];
193 if ((ampdu_queue < local->hw.queues) &&
194 test_bit(ampdu_queue, &q->qdisc_pool)) {
195 queue = ampdu_queue;
196 pkt_data->flags |= IEEE80211_TXPD_AMPDU;
197 } else {
198 pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
199 }
200 sta_info_put(sta);
201 }
170 } 202 }
171 203
172 if (unlikely(queue >= local->hw.queues)) { 204 if (unlikely(queue >= local->hw.queues)) {
@@ -184,6 +216,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
184 kfree_skb(skb); 216 kfree_skb(skb);
185 err = NET_XMIT_DROP; 217 err = NET_XMIT_DROP;
186 } else { 218 } else {
219 tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
187 pkt_data->queue = (unsigned int) queue; 220 pkt_data->queue = (unsigned int) queue;
188 qdisc = q->queues[queue]; 221 qdisc = q->queues[queue];
189 err = qdisc->enqueue(skb, qdisc); 222 err = qdisc->enqueue(skb, qdisc);
@@ -235,10 +268,11 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd)
235 /* check all the h/w queues in numeric/priority order */ 268 /* check all the h/w queues in numeric/priority order */
236 for (queue = 0; queue < hw->queues; queue++) { 269 for (queue = 0; queue < hw->queues; queue++) {
237 /* see if there is room in this hardware queue */ 270 /* see if there is room in this hardware queue */
238 if (test_bit(IEEE80211_LINK_STATE_XOFF, 271 if ((test_bit(IEEE80211_LINK_STATE_XOFF,
239 &local->state[queue]) || 272 &local->state[queue])) ||
240 test_bit(IEEE80211_LINK_STATE_PENDING, 273 (test_bit(IEEE80211_LINK_STATE_PENDING,
241 &local->state[queue])) 274 &local->state[queue])) ||
275 (!test_bit(queue, &q->qdisc_pool)))
242 continue; 276 continue;
243 277
244 /* there is space - try and get a frame */ 278 /* there is space - try and get a frame */
@@ -360,6 +394,10 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
360 } 394 }
361 } 395 }
362 396
397 /* reserve all legacy QoS queues */
398 for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++)
399 set_bit(i, &q->qdisc_pool);
400
363 return err; 401 return err;
364} 402}
365 403
@@ -605,3 +643,80 @@ void ieee80211_wme_unregister(void)
605{ 643{
606 unregister_qdisc(&wme_qdisc_ops); 644 unregister_qdisc(&wme_qdisc_ops);
607} 645}
646
647int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
648 struct sta_info *sta, u16 tid)
649{
650 int i;
651 struct ieee80211_sched_data *q =
652 qdisc_priv(local->mdev->qdisc_sleeping);
653 DECLARE_MAC_BUF(mac);
654
655 /* prepare the filter and save it for the SW queue
656 * matching the recieved HW queue */
657
658 /* try to get a Qdisc from the pool */
659 for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++)
660 if (!test_and_set_bit(i, &q->qdisc_pool)) {
661 ieee80211_stop_queue(local_to_hw(local), i);
662 sta->tid_to_tx_q[tid] = i;
663
664 /* IF there are already pending packets
665 * on this tid first we need to drain them
666 * on the previous queue
667 * since HT is strict in order */
668#ifdef CONFIG_MAC80211_HT_DEBUG
669 if (net_ratelimit())
670 printk(KERN_DEBUG "allocated aggregation queue"
671 " %d tid %d addr %s pool=0x%lX\n",
672 i, tid, print_mac(mac, sta->addr),
673 q->qdisc_pool);
674#endif /* CONFIG_MAC80211_HT_DEBUG */
675 return 0;
676 }
677
678 return -EAGAIN;
679}
680
681/**
682 * the caller needs to hold local->mdev->queue_lock
683 */
684void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
685 struct sta_info *sta, u16 tid,
686 u8 requeue)
687{
688 struct ieee80211_sched_data *q =
689 qdisc_priv(local->mdev->qdisc_sleeping);
690 int agg_queue = sta->tid_to_tx_q[tid];
691
692 /* return the qdisc to the pool */
693 clear_bit(agg_queue, &q->qdisc_pool);
694 sta->tid_to_tx_q[tid] = local->hw.queues;
695
696 if (requeue)
697 ieee80211_requeue(local, agg_queue);
698 else
699 q->queues[agg_queue]->ops->reset(q->queues[agg_queue]);
700}
701
702void ieee80211_requeue(struct ieee80211_local *local, int queue)
703{
704 struct Qdisc *root_qd = local->mdev->qdisc_sleeping;
705 struct ieee80211_sched_data *q = qdisc_priv(root_qd);
706 struct Qdisc *qdisc = q->queues[queue];
707 struct sk_buff *skb = NULL;
708 u32 len = qdisc->q.qlen;
709
710 if (!qdisc || !qdisc->dequeue)
711 return;
712
713 printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen);
714 for (len = qdisc->q.qlen; len > 0; len--) {
715 skb = qdisc->dequeue(qdisc);
716 root_qd->q.qlen--;
717 /* packet will be classified again and */
718 /* skb->packet_data->queue will be overridden if needed */
719 if (skb)
720 wme_qdiscop_enqueue(skb, root_qd);
721 }
722}
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index 76c713a6450c..fcc6b05508cc 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -24,6 +24,8 @@
24 24
25#define QOS_CONTROL_TAG1D_MASK 0x07 25#define QOS_CONTROL_TAG1D_MASK 0x07
26 26
27extern const int ieee802_1d_to_ac[8];
28
27static inline int WLAN_FC_IS_QOS_DATA(u16 fc) 29static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
28{ 30{
29 return (fc & 0x8C) == 0x88; 31 return (fc & 0x8C) == 0x88;
@@ -32,7 +34,12 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
32#ifdef CONFIG_NET_SCHED 34#ifdef CONFIG_NET_SCHED
33void ieee80211_install_qdisc(struct net_device *dev); 35void ieee80211_install_qdisc(struct net_device *dev);
34int ieee80211_qdisc_installed(struct net_device *dev); 36int ieee80211_qdisc_installed(struct net_device *dev);
35 37int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
38 struct sta_info *sta, u16 tid);
39void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
40 struct sta_info *sta, u16 tid,
41 u8 requeue);
42void ieee80211_requeue(struct ieee80211_local *local, int queue);
36int ieee80211_wme_register(void); 43int ieee80211_wme_register(void);
37void ieee80211_wme_unregister(void); 44void ieee80211_wme_unregister(void);
38#else 45#else
@@ -43,7 +50,19 @@ static inline int ieee80211_qdisc_installed(struct net_device *dev)
43{ 50{
44 return 0; 51 return 0;
45} 52}
46 53static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
54 struct sta_info *sta, u16 tid)
55{
56 return -EAGAIN;
57}
58static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
59 struct sta_info *sta, u16 tid,
60 u8 requeue)
61{
62}
63static inline void ieee80211_requeue(struct ieee80211_local *local, int queue)
64{
65}
47static inline int ieee80211_wme_register(void) 66static inline int ieee80211_wme_register(void)
48{ 67{
49 return 0; 68 return 0;