odhcpd: update to latest git HEAD
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / rt2x00 / 702-rt2800mmio-use-txdone-txstatus-routines-from-lib.patch
1 From 7993486bbab17f8916993710a8660eb47fd991e9 Mon Sep 17 00:00:00 2001
2 From: Stanislaw Gruszka <sgruszka@redhat.com>
3 Date: Mon, 9 Jul 2018 16:07:42 +0200
4 Subject: [PATCH 2/5] rt2800mmio: use txdone/txstatus routines from lib
5
6 Use usb txdone/txstatus routines (now in rt2800libc) for mmio devices.
7
8 Note this also change how we handle INT_SOURCE_CSR_TX_FIFO_STATUS
9 interrupt. Now it is disabled since IRQ routine till end of the txstatus
10 tasklet (the same behaviour like others interrupts). Reason to do not
11 disable this interrupt was not to miss any tx status from 16 entries
12 FIFO register. Now, since we check for tx status timeout, we can
13 allow to miss some tx statuses. However this will be improved in further
14 patch where I also implement read status FIFO register in the tasklet.
15
16 Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
17 ---
18 .../net/wireless/ralink/rt2x00/rt2800mmio.c | 180 +-----------------
19 .../net/wireless/ralink/rt2x00/rt2x00queue.c | 1 +
20 2 files changed, 9 insertions(+), 172 deletions(-)
21
22 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
23 +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
24 @@ -175,161 +175,6 @@ static void rt2800mmio_wakeup(struct rt2
25 rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
26 }
27
28 -static bool rt2800mmio_txdone_entry_check(struct queue_entry *entry, u32 status)
29 -{
30 - __le32 *txwi;
31 - u32 word;
32 - int wcid, tx_wcid;
33 -
34 - wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID);
35 -
36 - txwi = rt2800_drv_get_txwi(entry);
37 - word = rt2x00_desc_read(txwi, 1);
38 - tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
39 -
40 - return (tx_wcid == wcid);
41 -}
42 -
43 -static bool rt2800mmio_txdone_find_entry(struct queue_entry *entry, void *data)
44 -{
45 - u32 status = *(u32 *)data;
46 -
47 - /*
48 - * rt2800pci hardware might reorder frames when exchanging traffic
49 - * with multiple BA enabled STAs.
50 - *
51 - * For example, a tx queue
52 - * [ STA1 | STA2 | STA1 | STA2 ]
53 - * can result in tx status reports
54 - * [ STA1 | STA1 | STA2 | STA2 ]
55 - * when the hw decides to aggregate the frames for STA1 into one AMPDU.
56 - *
57 - * To mitigate this effect, associate the tx status to the first frame
58 - * in the tx queue with a matching wcid.
59 - */
60 - if (rt2800mmio_txdone_entry_check(entry, status) &&
61 - !test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
62 - /*
63 - * Got a matching frame, associate the tx status with
64 - * the frame
65 - */
66 - entry->status = status;
67 - set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
68 - return true;
69 - }
70 -
71 - /* Check the next frame */
72 - return false;
73 -}
74 -
75 -static bool rt2800mmio_txdone_match_first(struct queue_entry *entry, void *data)
76 -{
77 - u32 status = *(u32 *)data;
78 -
79 - /*
80 - * Find the first frame without tx status and assign this status to it
81 - * regardless if it matches or not.
82 - */
83 - if (!test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
84 - /*
85 - * Got a matching frame, associate the tx status with
86 - * the frame
87 - */
88 - entry->status = status;
89 - set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
90 - return true;
91 - }
92 -
93 - /* Check the next frame */
94 - return false;
95 -}
96 -static bool rt2800mmio_txdone_release_entries(struct queue_entry *entry,
97 - void *data)
98 -{
99 - if (test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
100 - rt2800_txdone_entry(entry, entry->status,
101 - rt2800mmio_get_txwi(entry), true);
102 - return false;
103 - }
104 -
105 - /* No more frames to release */
106 - return true;
107 -}
108 -
109 -static bool rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev)
110 -{
111 - struct data_queue *queue;
112 - u32 status;
113 - u8 qid;
114 - int max_tx_done = 16;
115 -
116 - while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
117 - qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
118 - if (unlikely(qid >= QID_RX)) {
119 - /*
120 - * Unknown queue, this shouldn't happen. Just drop
121 - * this tx status.
122 - */
123 - rt2x00_warn(rt2x00dev, "Got TX status report with unexpected pid %u, dropping\n",
124 - qid);
125 - break;
126 - }
127 -
128 - queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
129 - if (unlikely(queue == NULL)) {
130 - /*
131 - * The queue is NULL, this shouldn't happen. Stop
132 - * processing here and drop the tx status
133 - */
134 - rt2x00_warn(rt2x00dev, "Got TX status for an unavailable queue %u, dropping\n",
135 - qid);
136 - break;
137 - }
138 -
139 - if (unlikely(rt2x00queue_empty(queue))) {
140 - /*
141 - * The queue is empty. Stop processing here
142 - * and drop the tx status.
143 - */
144 - rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
145 - qid);
146 - break;
147 - }
148 -
149 - /*
150 - * Let's associate this tx status with the first
151 - * matching frame.
152 - */
153 - if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
154 - Q_INDEX, &status,
155 - rt2800mmio_txdone_find_entry)) {
156 - /*
157 - * We cannot match the tx status to any frame, so just
158 - * use the first one.
159 - */
160 - if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
161 - Q_INDEX, &status,
162 - rt2800mmio_txdone_match_first)) {
163 - rt2x00_warn(rt2x00dev, "No frame found for TX status on queue %u, dropping\n",
164 - qid);
165 - break;
166 - }
167 - }
168 -
169 - /*
170 - * Release all frames with a valid tx status.
171 - */
172 - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
173 - Q_INDEX, NULL,
174 - rt2800mmio_txdone_release_entries);
175 -
176 - if (--max_tx_done == 0)
177 - break;
178 - }
179 -
180 - return !max_tx_done;
181 -}
182 -
183 static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev,
184 struct rt2x00_field32 irq_field)
185 {
186 @@ -349,14 +194,14 @@ static inline void rt2800mmio_enable_int
187 void rt2800mmio_txstatus_tasklet(unsigned long data)
188 {
189 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
190 - if (rt2800mmio_txdone(rt2x00dev))
191 - tasklet_schedule(&rt2x00dev->txstatus_tasklet);
192
193 - /*
194 - * No need to enable the tx status interrupt here as we always
195 - * leave it enabled to minimize the possibility of a tx status
196 - * register overflow. See comment in interrupt handler.
197 - */
198 + rt2800_txdone(rt2x00dev);
199 +
200 + rt2800_txdone_nostatus(rt2x00dev);
201 +
202 + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
203 + rt2800mmio_enable_interrupt(rt2x00dev,
204 + INT_SOURCE_CSR_TX_FIFO_STATUS);
205 }
206 EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
207
208 @@ -440,10 +285,6 @@ static void rt2800mmio_txstatus_interrup
209 * because we can schedule the tasklet multiple times (when the
210 * interrupt fires again during tx status processing).
211 *
212 - * Furthermore we don't disable the TX_FIFO_STATUS
213 - * interrupt here but leave it enabled so that the TX_STA_FIFO
214 - * can also be read while the tx status tasklet gets executed.
215 - *
216 * Since we have only one producer and one consumer we don't
217 * need to lock the kfifo.
218 */
219 @@ -485,13 +326,8 @@ irqreturn_t rt2800mmio_interrupt(int irq
220 */
221 mask = ~reg;
222
223 - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
224 + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
225 rt2800mmio_txstatus_interrupt(rt2x00dev);
226 - /*
227 - * Never disable the TX_FIFO_STATUS interrupt.
228 - */
229 - rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
230 - }
231
232 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
233 tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);
234 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
235 +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
236 @@ -113,6 +113,7 @@ int rt2x00queue_map_txskb(struct queue_e
237 return -ENOMEM;
238
239 skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
240 + rt2x00lib_dmadone(entry);
241 return 0;
242 }
243 EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);