aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>2014-02-27 09:20:44 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-02-28 14:33:30 -0500
commitb4490f423c0e61b77461be6557c62e533b8c60e3 (patch)
treec8e9c97285e48817737b4ac5c22afb7d16092f80
parent3df2cd361871eb4636c8ce9cf97e6899c90c588c (diff)
wil6210: Block ACK
When running multiple connections, hardware can't do BACK reordering and it should be done on the host. Model after mac80211's implementation. Drop RCU for now; to be re-added when BACK will be stabilized BACK handshaking is not implemented yet in the hardware, pretend it was done to support the way FW operating Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile1
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c25
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c12
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c177
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h7
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h47
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c22
8 files changed, 290 insertions, 7 deletions
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 990dd42ae79e..c7a3465fd02a 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -9,6 +9,7 @@ wil6210-y += wmi.o
9wil6210-y += interrupt.o 9wil6210-y += interrupt.o
10wil6210-y += txrx.o 10wil6210-y += txrx.o
11wil6210-y += debug.o 11wil6210-y += debug.o
12wil6210-y += rx_reorder.o
12wil6210-$(CONFIG_WIL6210_TRACING) += trace.o 13wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
13 14
14# for tracing framework to find trace.h 15# for tracing framework to find trace.h
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index f12aa0b1e1df..729e774ee96d 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -598,11 +598,24 @@ static const struct file_operations fops_temp = {
598}; 598};
599 599
600/*---------Station matrix------------*/ 600/*---------Station matrix------------*/
601static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
602{
603 int i;
604 u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
605 seq_printf(s, "0x%03x [", r->head_seq_num);
606 for (i = 0; i < r->buf_size; i++) {
607 if (i == index)
608 seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
609 else
610 seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
611 }
612 seq_puts(s, "]\n");
613}
601 614
602static int wil_sta_debugfs_show(struct seq_file *s, void *data) 615static int wil_sta_debugfs_show(struct seq_file *s, void *data)
603{ 616{
604 struct wil6210_priv *wil = s->private; 617 struct wil6210_priv *wil = s->private;
605 int i; 618 int i, tid;
606 619
607 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 620 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
608 struct wil_sta_info *p = &wil->sta[i]; 621 struct wil_sta_info *p = &wil->sta[i];
@@ -619,6 +632,16 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
619 break; 632 break;
620 } 633 }
621 seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); 634 seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
635
636 if (p->status == wil_sta_connected) {
637 for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
638 struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
639 if (r) {
640 seq_printf(s, "[%2d] ", tid);
641 wil_print_rxtid(s, r);
642 }
643 }
644 }
622 } 645 }
623 646
624 return 0; 647 return 0;
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index f68481de0ad7..38906f1bc769 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -18,6 +18,7 @@
18#include <linux/if_arp.h> 18#include <linux/if_arp.h>
19 19
20#include "wil6210.h" 20#include "wil6210.h"
21#include "txrx.h"
21 22
22/* 23/*
23 * Due to a hardware issue, 24 * Due to a hardware issue,
@@ -54,11 +55,20 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
54 55
55static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) 56static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
56{ 57{
57 uint i; 58 uint i, cid;
58 struct net_device *ndev = wil_to_ndev(wil); 59 struct net_device *ndev = wil_to_ndev(wil);
59 60
60 wil_dbg_misc(wil, "%s()\n", __func__); 61 wil_dbg_misc(wil, "%s()\n", __func__);
61 62
63 for (cid = 0; cid < WIL6210_MAX_CID; cid++) {
64 struct wil_sta_info *sta = &wil->sta[cid];
65 for (i = 0; i < WIL_STA_TID_NUM; i++) {
66 struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
67 sta->tid_rx[i] = NULL;
68 wil_tid_ampdu_rx_free(wil, r);
69 }
70 }
71
62 wil_link_off(wil); 72 wil_link_off(wil);
63 if (test_bit(wil_status_fwconnected, &wil->status)) { 73 if (test_bit(wil_status_fwconnected, &wil->status)) {
64 clear_bit(wil_status_fwconnected, &wil->status); 74 clear_bit(wil_status_fwconnected, &wil->status);
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
new file mode 100644
index 000000000000..d04629fe053f
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -0,0 +1,177 @@
1#include "wil6210.h"
2#include "txrx.h"
3
4#define SEQ_MODULO 0x1000
5#define SEQ_MASK 0xfff
6
7static inline int seq_less(u16 sq1, u16 sq2)
8{
9 return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
10}
11
12static inline u16 seq_inc(u16 sq)
13{
14 return (sq + 1) & SEQ_MASK;
15}
16
17static inline u16 seq_sub(u16 sq1, u16 sq2)
18{
19 return (sq1 - sq2) & SEQ_MASK;
20}
21
22static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq)
23{
24 return seq_sub(seq, r->ssn) % r->buf_size;
25}
26
27static void wil_release_reorder_frame(struct wil6210_priv *wil,
28 struct wil_tid_ampdu_rx *r,
29 int index)
30{
31 struct net_device *ndev = wil_to_ndev(wil);
32 struct sk_buff *skb = r->reorder_buf[index];
33
34 if (!skb)
35 goto no_frame;
36
37 /* release the frame from the reorder ring buffer */
38 r->stored_mpdu_num--;
39 r->reorder_buf[index] = NULL;
40 wil_netif_rx_any(skb, ndev);
41
42no_frame:
43 r->head_seq_num = seq_inc(r->head_seq_num);
44}
45
46static void wil_release_reorder_frames(struct wil6210_priv *wil,
47 struct wil_tid_ampdu_rx *r,
48 u16 hseq)
49{
50 int index;
51
52 while (seq_less(r->head_seq_num, hseq)) {
53 index = reorder_index(r, r->head_seq_num);
54 wil_release_reorder_frame(wil, r, index);
55 }
56}
57
58static void wil_reorder_release(struct wil6210_priv *wil,
59 struct wil_tid_ampdu_rx *r)
60{
61 int index = reorder_index(r, r->head_seq_num);
62
63 while (r->reorder_buf[index]) {
64 wil_release_reorder_frame(wil, r, index);
65 index = reorder_index(r, r->head_seq_num);
66 }
67}
68
69void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
70{
71 struct net_device *ndev = wil_to_ndev(wil);
72 struct vring_rx_desc *d = wil_skb_rxdesc(skb);
73 int tid = wil_rxdesc_tid(d);
74 int cid = wil_rxdesc_cid(d);
75 int mid = wil_rxdesc_mid(d);
76 u16 seq = wil_rxdesc_seq(d);
77 struct wil_sta_info *sta = &wil->sta[cid];
78 struct wil_tid_ampdu_rx *r = sta->tid_rx[tid];
79 u16 hseq;
80 int index;
81
82 wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
83 mid, cid, tid, seq);
84
85 if (!r) {
86 wil_netif_rx_any(skb, ndev);
87 return;
88 }
89
90 hseq = r->head_seq_num;
91
92 spin_lock(&r->reorder_lock);
93
94 /* frame with out of date sequence number */
95 if (seq_less(seq, r->head_seq_num)) {
96 dev_kfree_skb(skb);
97 goto out;
98 }
99
100 /*
101 * If frame the sequence number exceeds our buffering window
102 * size release some previous frames to make room for this one.
103 */
104 if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
105 hseq = seq_inc(seq_sub(seq, r->buf_size));
106 /* release stored frames up to new head to stack */
107 wil_release_reorder_frames(wil, r, hseq);
108 }
109
110 /* Now the new frame is always in the range of the reordering buffer */
111
112 index = reorder_index(r, seq);
113
114 /* check if we already stored this frame */
115 if (r->reorder_buf[index]) {
116 dev_kfree_skb(skb);
117 goto out;
118 }
119
120 /*
121 * If the current MPDU is in the right order and nothing else
122 * is stored we can process it directly, no need to buffer it.
123 * If it is first but there's something stored, we may be able
124 * to release frames after this one.
125 */
126 if (seq == r->head_seq_num && r->stored_mpdu_num == 0) {
127 r->head_seq_num = seq_inc(r->head_seq_num);
128 wil_netif_rx_any(skb, ndev);
129 goto out;
130 }
131
132 /* put the frame in the reordering buffer */
133 r->reorder_buf[index] = skb;
134 r->reorder_time[index] = jiffies;
135 r->stored_mpdu_num++;
136 wil_reorder_release(wil, r);
137
138out:
139 spin_unlock(&r->reorder_lock);
140}
141
142struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
143 int size, u16 ssn)
144{
145 struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
146 if (!r)
147 return NULL;
148
149 r->reorder_buf =
150 kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL);
151 r->reorder_time =
152 kcalloc(size, sizeof(unsigned long), GFP_KERNEL);
153 if (!r->reorder_buf || !r->reorder_time) {
154 kfree(r->reorder_buf);
155 kfree(r->reorder_time);
156 kfree(r);
157 return NULL;
158 }
159
160 spin_lock_init(&r->reorder_lock);
161 r->ssn = ssn;
162 r->head_seq_num = ssn;
163 r->buf_size = size;
164 r->stored_mpdu_num = 0;
165 return r;
166}
167
168void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
169 struct wil_tid_ampdu_rx *r)
170{
171 if (!r)
172 return;
173 wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size);
174 kfree(r->reorder_buf);
175 kfree(r->reorder_time);
176 kfree(r);
177}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index eb60023fa217..48d97156f3db 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -472,7 +472,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
472 * Pass Rx packet to the netif. Update statistics. 472 * Pass Rx packet to the netif. Update statistics.
473 * Called in softirq context (NAPI poll). 473 * Called in softirq context (NAPI poll).
474 */ 474 */
475static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) 475void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
476{ 476{
477 int rc; 477 int rc;
478 unsigned int len = skb->len; 478 unsigned int len = skb->len;
@@ -515,12 +515,12 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
515 skb->ip_summed = CHECKSUM_UNNECESSARY; 515 skb->ip_summed = CHECKSUM_UNNECESSARY;
516 skb->pkt_type = PACKET_OTHERHOST; 516 skb->pkt_type = PACKET_OTHERHOST;
517 skb->protocol = htons(ETH_P_802_2); 517 skb->protocol = htons(ETH_P_802_2);
518 518 wil_netif_rx_any(skb, ndev);
519 } else { 519 } else {
520 skb->protocol = eth_type_trans(skb, ndev); 520 skb->protocol = eth_type_trans(skb, ndev);
521 wil_rx_reorder(wil, skb);
521 } 522 }
522 523
523 wil_netif_rx_any(skb, ndev);
524 } 524 }
525 wil_rx_refill(wil, v->size); 525 wil_rx_refill(wil, v->size);
526} 526}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index b3828279204c..bc5706a4f007 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
436 return (void *)skb->cb; 436 return (void *)skb->cb;
437} 437}
438 438
439void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
440void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
441struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
442 int size, u16 ssn);
443void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
444 struct wil_tid_ampdu_rx *r);
445
439#endif /* WIL6210_TXRX_H */ 446#endif /* WIL6210_TXRX_H */
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 38df203f723d..304b990295b7 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -215,6 +215,46 @@ enum { /* for wil6210_priv.status */
215 215
216struct pci_dev; 216struct pci_dev;
217 217
218/**
219 * struct tid_ampdu_rx - TID aggregation information (Rx).
220 *
221 * @reorder_buf: buffer to reorder incoming aggregated MPDUs
222 * @reorder_time: jiffies when skb was added
223 * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
224 * @reorder_timer: releases expired frames from the reorder buffer.
225 * @last_rx: jiffies of last rx activity
226 * @head_seq_num: head sequence number in reordering buffer.
227 * @stored_mpdu_num: number of MPDUs in reordering buffer
228 * @ssn: Starting Sequence Number expected to be aggregated.
229 * @buf_size: buffer size for incoming A-MPDUs
230 * @timeout: reset timer value (in TUs).
231 * @dialog_token: dialog token for aggregation session
232 * @rcu_head: RCU head used for freeing this struct
233 * @reorder_lock: serializes access to reorder buffer, see below.
234 *
235 * This structure's lifetime is managed by RCU, assignments to
236 * the array holding it must hold the aggregation mutex.
237 *
238 * The @reorder_lock is used to protect the members of this
239 * struct, except for @timeout, @buf_size and @dialog_token,
240 * which are constant across the lifetime of the struct (the
241 * dialog token being used only for debugging).
242 */
243struct wil_tid_ampdu_rx {
244 spinlock_t reorder_lock; /* see above */
245 struct sk_buff **reorder_buf;
246 unsigned long *reorder_time;
247 struct timer_list session_timer;
248 struct timer_list reorder_timer;
249 unsigned long last_rx;
250 u16 head_seq_num;
251 u16 stored_mpdu_num;
252 u16 ssn;
253 u16 buf_size;
254 u16 timeout;
255 u8 dialog_token;
256};
257
218struct wil6210_stats { 258struct wil6210_stats {
219 u64 tsf; 259 u64 tsf;
220 u32 snr; 260 u32 snr;
@@ -231,6 +271,9 @@ enum wil_sta_status {
231 wil_sta_conn_pending = 1, 271 wil_sta_conn_pending = 1,
232 wil_sta_connected = 2, 272 wil_sta_connected = 2,
233}; 273};
274
275#define WIL_STA_TID_NUM (16)
276
234/** 277/**
235 * struct wil_sta_info - data for peer 278 * struct wil_sta_info - data for peer
236 * 279 *
@@ -242,6 +285,10 @@ enum wil_sta_status {
242struct wil_sta_info { 285struct wil_sta_info {
243 u8 addr[ETH_ALEN]; 286 u8 addr[ETH_ALEN];
244 enum wil_sta_status status; 287 enum wil_sta_status status;
288 /* Rx BACK */
289 struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
290 unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
291 unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
245}; 292};
246 293
247struct wil6210_priv { 294struct wil6210_priv {
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 2d602901675d..dfbc239b149d 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -563,10 +563,27 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
563 int len) 563 int len)
564{ 564{
565 struct wmi_vring_ba_status_event *evt = d; 565 struct wmi_vring_ba_status_event *evt = d;
566 uint cid, i;
566 567
567 wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", 568 wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
568 evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize, 569 evt->ringid, evt->status == WMI_BA_AGREED ? "OK" : "N/A",
569 __le16_to_cpu(evt->ba_timeout)); 570 evt->agg_wsize, __le16_to_cpu(evt->ba_timeout));
571 for (cid = 0; cid < WIL6210_MAX_CID; cid++) {
572 struct wil_sta_info *sta = &wil->sta[cid];
573
574 if (sta->status == wil_sta_unused)
575 continue;
576 wil_dbg_wmi(wil, "Init BACK for CID %d %pM\n", cid, sta->addr);
577 for (i = 0; i < WIL_STA_TID_NUM; i++) {
578 struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
579 sta->tid_rx[i] = NULL;
580 wil_tid_ampdu_rx_free(wil, r);
581 if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
582 sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
583 evt->agg_wsize, 0);
584 }
585 }
586
570} 587}
571 588
572static const struct { 589static const struct {
@@ -949,6 +966,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
949 }, 966 },
950 .mid = 0, /* TODO - what is it? */ 967 .mid = 0, /* TODO - what is it? */
951 .decap_trans_type = WMI_DECAP_TYPE_802_3, 968 .decap_trans_type = WMI_DECAP_TYPE_802_3,
969 .reorder_type = WMI_RX_SW_REORDER,
952 }; 970 };
953 struct { 971 struct {
954 struct wil6210_mbox_hdr_wmi wmi; 972 struct wil6210_mbox_hdr_wmi wmi;