Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : :
4 : : Broadcom B43legacy wireless driver
5 : :
6 : : PIO Transmission
7 : :
8 : : Copyright (c) 2005 Michael Buesch <m@bues.ch>
9 : :
10 : :
11 : : */
12 : :
13 : : #include "b43legacy.h"
14 : : #include "pio.h"
15 : : #include "main.h"
16 : : #include "xmit.h"
17 : :
18 : : #include <linux/delay.h>
19 : : #include <linux/slab.h>
20 : :
21 : :
22 : 0 : static void tx_start(struct b43legacy_pioqueue *queue)
23 : : {
24 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
25 : : B43legacy_PIO_TXCTL_INIT);
26 : : }
27 : :
28 : 0 : static void tx_octet(struct b43legacy_pioqueue *queue,
29 : : u8 octet)
30 : : {
31 [ # # ]: 0 : if (queue->need_workarounds) {
32 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
33 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
34 : : B43legacy_PIO_TXCTL_WRITELO);
35 : : } else {
36 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
37 : : B43legacy_PIO_TXCTL_WRITELO);
38 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
39 : : }
40 : 0 : }
41 : :
42 : 0 : static u16 tx_get_next_word(const u8 *txhdr,
43 : : const u8 *packet,
44 : : size_t txhdr_size,
45 : : unsigned int *pos)
46 : : {
47 : 0 : const u8 *source;
48 : 0 : unsigned int i = *pos;
49 : 0 : u16 ret;
50 : :
51 : 0 : if (i < txhdr_size)
52 : : source = txhdr;
53 : : else {
54 : 0 : source = packet;
55 : 0 : i -= txhdr_size;
56 : : }
57 : 0 : ret = le16_to_cpu(*((__le16 *)(source + i)));
58 : 0 : *pos += 2;
59 : :
60 : 0 : return ret;
61 : : }
62 : :
63 : 0 : static void tx_data(struct b43legacy_pioqueue *queue,
64 : : u8 *txhdr,
65 : : const u8 *packet,
66 : : unsigned int octets)
67 : : {
68 : 0 : u16 data;
69 : 0 : unsigned int i = 0;
70 : :
71 [ # # ]: 0 : if (queue->need_workarounds) {
72 : 0 : data = tx_get_next_word(txhdr, packet,
73 : : sizeof(struct b43legacy_txhdr_fw3), &i);
74 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
75 : : }
76 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
77 : : B43legacy_PIO_TXCTL_WRITELO |
78 : : B43legacy_PIO_TXCTL_WRITEHI);
79 [ # # ]: 0 : while (i < octets - 1) {
80 [ # # ]: 0 : data = tx_get_next_word(txhdr, packet,
81 : : sizeof(struct b43legacy_txhdr_fw3), &i);
82 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
83 : : }
84 [ # # ]: 0 : if (octets % 2)
85 : 0 : tx_octet(queue, packet[octets -
86 : : sizeof(struct b43legacy_txhdr_fw3) - 1]);
87 : 0 : }
88 : :
89 : : static void tx_complete(struct b43legacy_pioqueue *queue,
90 : : struct sk_buff *skb)
91 : : {
92 : : if (queue->need_workarounds) {
93 : : b43legacy_pio_write(queue, B43legacy_PIO_TXDATA,
94 : : skb->data[skb->len - 1]);
95 : : b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
96 : : B43legacy_PIO_TXCTL_WRITELO |
97 : : B43legacy_PIO_TXCTL_COMPLETE);
98 : : } else
99 : : b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
100 : : B43legacy_PIO_TXCTL_COMPLETE);
101 : : }
102 : :
103 : : static u16 generate_cookie(struct b43legacy_pioqueue *queue,
104 : : struct b43legacy_pio_txpacket *packet)
105 : : {
106 : : u16 cookie = 0x0000;
107 : : int packetindex;
108 : :
109 : : /* We use the upper 4 bits for the PIO
110 : : * controller ID and the lower 12 bits
111 : : * for the packet index (in the cache).
112 : : */
113 : : switch (queue->mmio_base) {
114 : : case B43legacy_MMIO_PIO1_BASE:
115 : : break;
116 : : case B43legacy_MMIO_PIO2_BASE:
117 : : cookie = 0x1000;
118 : : break;
119 : : case B43legacy_MMIO_PIO3_BASE:
120 : : cookie = 0x2000;
121 : : break;
122 : : case B43legacy_MMIO_PIO4_BASE:
123 : : cookie = 0x3000;
124 : : break;
125 : : default:
126 : : B43legacy_WARN_ON(1);
127 : : }
128 : : packetindex = pio_txpacket_getindex(packet);
129 : : B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000));
130 : : cookie |= (u16)packetindex;
131 : :
132 : : return cookie;
133 : : }
134 : :
135 : : static
136 : 0 : struct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev,
137 : : u16 cookie,
138 : : struct b43legacy_pio_txpacket **packet)
139 : : {
140 : 0 : struct b43legacy_pio *pio = &dev->pio;
141 : 0 : struct b43legacy_pioqueue *queue = NULL;
142 : 0 : int packetindex;
143 : :
144 [ # # # # : 0 : switch (cookie & 0xF000) {
# ]
145 : 0 : case 0x0000:
146 : 0 : queue = pio->queue0;
147 : 0 : break;
148 : 0 : case 0x1000:
149 : 0 : queue = pio->queue1;
150 : 0 : break;
151 : 0 : case 0x2000:
152 : 0 : queue = pio->queue2;
153 : 0 : break;
154 : 0 : case 0x3000:
155 : 0 : queue = pio->queue3;
156 : 0 : break;
157 : : default:
158 : 0 : B43legacy_WARN_ON(1);
159 : : }
160 : 0 : packetindex = (cookie & 0x0FFF);
161 [ # # ]: 0 : B43legacy_WARN_ON(!(packetindex >= 0 && packetindex
162 : : < B43legacy_PIO_MAXTXPACKETS));
163 : 0 : *packet = &(queue->tx_packets_cache[packetindex]);
164 : :
165 : 0 : return queue;
166 : : }
167 : :
168 : : union txhdr_union {
169 : : struct b43legacy_txhdr_fw3 txhdr_fw3;
170 : : };
171 : :
172 : 0 : static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
173 : : struct sk_buff *skb,
174 : : struct b43legacy_pio_txpacket *packet,
175 : : size_t txhdr_size)
176 : : {
177 : 0 : union txhdr_union txhdr_data;
178 : 0 : u8 *txhdr = NULL;
179 : 0 : unsigned int octets;
180 : 0 : int err;
181 : :
182 : 0 : txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
183 : :
184 [ # # ]: 0 : B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
185 : 0 : err = b43legacy_generate_txhdr(queue->dev,
186 : 0 : txhdr, skb->data, skb->len,
187 : : IEEE80211_SKB_CB(skb),
188 : 0 : generate_cookie(queue, packet));
189 [ # # ]: 0 : if (err)
190 : : return err;
191 : :
192 : 0 : tx_start(queue);
193 : 0 : octets = skb->len + txhdr_size;
194 [ # # ]: 0 : if (queue->need_workarounds)
195 : 0 : octets--;
196 : 0 : tx_data(queue, txhdr, (u8 *)skb->data, octets);
197 : 0 : tx_complete(queue, skb);
198 : :
199 : 0 : return 0;
200 : : }
201 : :
202 : 0 : static void free_txpacket(struct b43legacy_pio_txpacket *packet,
203 : : int irq_context)
204 : : {
205 : 0 : struct b43legacy_pioqueue *queue = packet->queue;
206 : :
207 [ # # ]: 0 : if (packet->skb) {
208 [ # # ]: 0 : if (irq_context)
209 : 0 : dev_kfree_skb_irq(packet->skb);
210 : : else
211 : 0 : dev_kfree_skb(packet->skb);
212 : : }
213 : 0 : list_move(&packet->list, &queue->txfree);
214 : 0 : queue->nr_txfree++;
215 : 0 : }
216 : :
217 : 0 : static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
218 : : {
219 : 0 : struct b43legacy_pioqueue *queue = packet->queue;
220 : 0 : struct sk_buff *skb = packet->skb;
221 : 0 : u16 octets;
222 : 0 : int err;
223 : :
224 : 0 : octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
225 [ # # ]: 0 : if (queue->tx_devq_size < octets) {
226 : 0 : b43legacywarn(queue->dev->wl, "PIO queue too small. "
227 : : "Dropping packet.\n");
228 : : /* Drop it silently (return success) */
229 : 0 : free_txpacket(packet, 1);
230 : 0 : return 0;
231 : : }
232 [ # # ]: 0 : B43legacy_WARN_ON(queue->tx_devq_packets >
233 : : B43legacy_PIO_MAXTXDEVQPACKETS);
234 [ # # ]: 0 : B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
235 : : /* Check if there is sufficient free space on the device
236 : : * TX queue. If not, return and let the TX tasklet
237 : : * retry later.
238 : : */
239 [ # # ]: 0 : if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS)
240 : : return -EBUSY;
241 [ # # ]: 0 : if (queue->tx_devq_used + octets > queue->tx_devq_size)
242 : : return -EBUSY;
243 : : /* Now poke the device. */
244 : 0 : err = pio_tx_write_fragment(queue, skb, packet,
245 : : sizeof(struct b43legacy_txhdr_fw3));
246 [ # # ]: 0 : if (unlikely(err == -ENOKEY)) {
247 : : /* Drop this packet, as we don't have the encryption key
248 : : * anymore and must not transmit it unencrypted. */
249 : 0 : free_txpacket(packet, 1);
250 : 0 : return 0;
251 : : }
252 : :
253 : : /* Account for the packet size.
254 : : * (We must not overflow the device TX queue)
255 : : */
256 : 0 : queue->tx_devq_packets++;
257 : 0 : queue->tx_devq_used += octets;
258 : :
259 : : /* Transmission started, everything ok, move the
260 : : * packet to the txrunning list.
261 : : */
262 : 0 : list_move_tail(&packet->list, &queue->txrunning);
263 : :
264 : 0 : return 0;
265 : : }
266 : :
267 : 0 : static void tx_tasklet(unsigned long d)
268 : : {
269 : 0 : struct b43legacy_pioqueue *queue = (struct b43legacy_pioqueue *)d;
270 : 0 : struct b43legacy_wldev *dev = queue->dev;
271 : 0 : unsigned long flags;
272 : 0 : struct b43legacy_pio_txpacket *packet, *tmp_packet;
273 : 0 : int err;
274 : 0 : u16 txctl;
275 : :
276 : 0 : spin_lock_irqsave(&dev->wl->irq_lock, flags);
277 [ # # ]: 0 : if (queue->tx_frozen)
278 : 0 : goto out_unlock;
279 : 0 : txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL);
280 [ # # ]: 0 : if (txctl & B43legacy_PIO_TXCTL_SUSPEND)
281 : 0 : goto out_unlock;
282 : :
283 [ # # ]: 0 : list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
284 : : /* Try to transmit the packet. This can fail, if
285 : : * the device queue is full. In case of failure, the
286 : : * packet is left in the txqueue.
287 : : * If transmission succeed, the packet is moved to txrunning.
288 : : * If it is impossible to transmit the packet, it
289 : : * is dropped.
290 : : */
291 : 0 : err = pio_tx_packet(packet);
292 [ # # ]: 0 : if (err)
293 : : break;
294 : : }
295 : 0 : out_unlock:
296 : 0 : spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
297 : 0 : }
298 : :
299 : 0 : static void setup_txqueues(struct b43legacy_pioqueue *queue)
300 : : {
301 : 0 : struct b43legacy_pio_txpacket *packet;
302 : 0 : int i;
303 : :
304 : 0 : queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS;
305 [ # # ]: 0 : for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) {
306 : 0 : packet = &(queue->tx_packets_cache[i]);
307 : :
308 : 0 : packet->queue = queue;
309 : 0 : INIT_LIST_HEAD(&packet->list);
310 : :
311 : 0 : list_add(&packet->list, &queue->txfree);
312 : : }
313 : : }
314 : :
315 : : static
316 : 0 : struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
317 : : u16 pio_mmio_base)
318 : : {
319 : 0 : struct b43legacy_pioqueue *queue;
320 : 0 : u32 value;
321 : 0 : u16 qsize;
322 : :
323 : 0 : queue = kzalloc(sizeof(*queue), GFP_KERNEL);
324 [ # # ]: 0 : if (!queue)
325 : 0 : goto out;
326 : :
327 : 0 : queue->dev = dev;
328 : 0 : queue->mmio_base = pio_mmio_base;
329 : 0 : queue->need_workarounds = (dev->dev->id.revision < 3);
330 : :
331 : 0 : INIT_LIST_HEAD(&queue->txfree);
332 : 0 : INIT_LIST_HEAD(&queue->txqueue);
333 : 0 : INIT_LIST_HEAD(&queue->txrunning);
334 : 0 : tasklet_init(&queue->txtask, tx_tasklet,
335 : : (unsigned long)queue);
336 : :
337 : 0 : value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
338 : 0 : value &= ~B43legacy_MACCTL_BE;
339 : 0 : b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value);
340 : :
341 : 0 : qsize = b43legacy_read16(dev, queue->mmio_base
342 : 0 : + B43legacy_PIO_TXQBUFSIZE);
343 [ # # ]: 0 : if (qsize == 0) {
344 : 0 : b43legacyerr(dev->wl, "This card does not support PIO "
345 : : "operation mode. Please use DMA mode "
346 : : "(module parameter pio=0).\n");
347 : 0 : goto err_freequeue;
348 : : }
349 [ # # ]: 0 : if (qsize <= B43legacy_PIO_TXQADJUST) {
350 : 0 : b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n",
351 : : qsize);
352 : 0 : goto err_freequeue;
353 : : }
354 : 0 : qsize -= B43legacy_PIO_TXQADJUST;
355 : 0 : queue->tx_devq_size = qsize;
356 : :
357 : 0 : setup_txqueues(queue);
358 : :
359 : 0 : out:
360 : 0 : return queue;
361 : :
362 : 0 : err_freequeue:
363 : 0 : kfree(queue);
364 : 0 : queue = NULL;
365 : 0 : goto out;
366 : : }
367 : :
368 : 0 : static void cancel_transfers(struct b43legacy_pioqueue *queue)
369 : : {
370 : 0 : struct b43legacy_pio_txpacket *packet, *tmp_packet;
371 : :
372 : 0 : tasklet_kill(&queue->txtask);
373 : :
374 [ # # ]: 0 : list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
375 : 0 : free_txpacket(packet, 0);
376 [ # # ]: 0 : list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
377 : 0 : free_txpacket(packet, 0);
378 : 0 : }
379 : :
380 : 0 : static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue)
381 : : {
382 : 0 : if (!queue)
383 : : return;
384 : :
385 : 0 : cancel_transfers(queue);
386 : 0 : kfree(queue);
387 : : }
388 : :
389 : 0 : void b43legacy_pio_free(struct b43legacy_wldev *dev)
390 : : {
391 : 0 : struct b43legacy_pio *pio;
392 : :
393 [ # # ]: 0 : if (!b43legacy_using_pio(dev))
394 : : return;
395 : 0 : pio = &dev->pio;
396 : :
397 [ # # ]: 0 : b43legacy_destroy_pioqueue(pio->queue3);
398 : 0 : pio->queue3 = NULL;
399 [ # # ]: 0 : b43legacy_destroy_pioqueue(pio->queue2);
400 : 0 : pio->queue2 = NULL;
401 [ # # ]: 0 : b43legacy_destroy_pioqueue(pio->queue1);
402 : 0 : pio->queue1 = NULL;
403 [ # # ]: 0 : b43legacy_destroy_pioqueue(pio->queue0);
404 : 0 : pio->queue0 = NULL;
405 : : }
406 : :
407 : 0 : int b43legacy_pio_init(struct b43legacy_wldev *dev)
408 : : {
409 : 0 : struct b43legacy_pio *pio = &dev->pio;
410 : 0 : struct b43legacy_pioqueue *queue;
411 : 0 : int err = -ENOMEM;
412 : :
413 : 0 : queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE);
414 [ # # ]: 0 : if (!queue)
415 : 0 : goto out;
416 : 0 : pio->queue0 = queue;
417 : :
418 : 0 : queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE);
419 [ # # ]: 0 : if (!queue)
420 : 0 : goto err_destroy0;
421 : 0 : pio->queue1 = queue;
422 : :
423 : 0 : queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE);
424 [ # # ]: 0 : if (!queue)
425 : 0 : goto err_destroy1;
426 : 0 : pio->queue2 = queue;
427 : :
428 : 0 : queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE);
429 [ # # ]: 0 : if (!queue)
430 : 0 : goto err_destroy2;
431 : 0 : pio->queue3 = queue;
432 : :
433 [ # # ]: 0 : if (dev->dev->id.revision < 3)
434 : 0 : dev->irq_mask |= B43legacy_IRQ_PIO_WORKAROUND;
435 : :
436 : 0 : b43legacydbg(dev->wl, "PIO initialized\n");
437 : 0 : err = 0;
438 : 0 : out:
439 : 0 : return err;
440 : :
441 : : err_destroy2:
442 [ # # ]: 0 : b43legacy_destroy_pioqueue(pio->queue2);
443 : 0 : pio->queue2 = NULL;
444 : 0 : err_destroy1:
445 [ # # ]: 0 : b43legacy_destroy_pioqueue(pio->queue1);
446 : 0 : pio->queue1 = NULL;
447 : 0 : err_destroy0:
448 [ # # ]: 0 : b43legacy_destroy_pioqueue(pio->queue0);
449 : 0 : pio->queue0 = NULL;
450 : 0 : goto out;
451 : : }
452 : :
453 : 0 : int b43legacy_pio_tx(struct b43legacy_wldev *dev,
454 : : struct sk_buff *skb)
455 : : {
456 : 0 : struct b43legacy_pioqueue *queue = dev->pio.queue1;
457 : 0 : struct b43legacy_pio_txpacket *packet;
458 : :
459 [ # # ]: 0 : B43legacy_WARN_ON(queue->tx_suspended);
460 [ # # ]: 0 : B43legacy_WARN_ON(list_empty(&queue->txfree));
461 : :
462 : 0 : packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket,
463 : : list);
464 : 0 : packet->skb = skb;
465 : :
466 [ # # ]: 0 : list_move_tail(&packet->list, &queue->txqueue);
467 : 0 : queue->nr_txfree--;
468 [ # # ]: 0 : B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
469 : :
470 : 0 : tasklet_schedule(&queue->txtask);
471 : :
472 : 0 : return 0;
473 : : }
474 : :
475 : 0 : void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
476 : : const struct b43legacy_txstatus *status)
477 : : {
478 : 0 : struct b43legacy_pioqueue *queue;
479 : 0 : struct b43legacy_pio_txpacket *packet;
480 : 0 : struct ieee80211_tx_info *info;
481 : 0 : int retry_limit;
482 : :
483 : 0 : queue = parse_cookie(dev, status->cookie, &packet);
484 [ # # ]: 0 : B43legacy_WARN_ON(!queue);
485 : :
486 [ # # ]: 0 : if (!packet->skb)
487 : 0 : return;
488 : :
489 : 0 : queue->tx_devq_packets--;
490 : 0 : queue->tx_devq_used -= (packet->skb->len +
491 : : sizeof(struct b43legacy_txhdr_fw3));
492 : :
493 : 0 : info = IEEE80211_SKB_CB(packet->skb);
494 : :
495 : : /* preserve the confiured retry limit before clearing the status
496 : : * The xmit function has overwritten the rc's value with the actual
497 : : * retry limit done by the hardware */
498 : 0 : retry_limit = info->status.rates[0].count;
499 : 0 : ieee80211_tx_info_clear_status(info);
500 : :
501 [ # # ]: 0 : if (status->acked)
502 : 0 : info->flags |= IEEE80211_TX_STAT_ACK;
503 : :
504 [ # # ]: 0 : if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
505 : : /*
506 : : * If the short retries (RTS, not data frame) have exceeded
507 : : * the limit, the hw will not have tried the selected rate,
508 : : * but will have used the fallback rate instead.
509 : : * Don't let the rate control count attempts for the selected
510 : : * rate in this case, otherwise the statistics will be off.
511 : : */
512 : 0 : info->status.rates[0].count = 0;
513 : 0 : info->status.rates[1].count = status->frame_count;
514 : : } else {
515 [ # # ]: 0 : if (status->frame_count > retry_limit) {
516 : 0 : info->status.rates[0].count = retry_limit;
517 : 0 : info->status.rates[1].count = status->frame_count -
518 : : retry_limit;
519 : :
520 : : } else {
521 : 0 : info->status.rates[0].count = status->frame_count;
522 : 0 : info->status.rates[1].idx = -1;
523 : : }
524 : : }
525 : 0 : ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
526 : 0 : packet->skb = NULL;
527 : :
528 : 0 : free_txpacket(packet, 1);
529 : : /* If there are packets on the txqueue, poke the tasklet
530 : : * to transmit them.
531 : : */
532 [ # # ]: 0 : if (!list_empty(&queue->txqueue))
533 : 0 : tasklet_schedule(&queue->txtask);
534 : : }
535 : :
536 : : static void pio_rx_error(struct b43legacy_pioqueue *queue,
537 : : int clear_buffers,
538 : : const char *error)
539 : : {
540 : : int i;
541 : :
542 : : b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error);
543 : : b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
544 : : B43legacy_PIO_RXCTL_READY);
545 : : if (clear_buffers) {
546 : : B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE);
547 : : for (i = 0; i < 15; i++) {
548 : : /* Dummy read. */
549 : : b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
550 : : }
551 : : }
552 : : }
553 : :
554 : 0 : void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
555 : : {
556 : 0 : __le16 preamble[21] = { 0 };
557 : 0 : struct b43legacy_rxhdr_fw3 *rxhdr;
558 : 0 : u16 tmp;
559 : 0 : u16 len;
560 : 0 : u16 macstat;
561 : 0 : int i;
562 : 0 : int preamble_readwords;
563 : 0 : struct sk_buff *skb;
564 : :
565 : 0 : tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
566 [ # # ]: 0 : if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE))
567 : 0 : return;
568 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
569 : : B43legacy_PIO_RXCTL_DATAAVAILABLE);
570 : :
571 [ # # ]: 0 : for (i = 0; i < 10; i++) {
572 : 0 : tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
573 [ # # ]: 0 : if (tmp & B43legacy_PIO_RXCTL_READY)
574 : 0 : goto data_ready;
575 : 0 : udelay(10);
576 : : }
577 : 0 : b43legacydbg(queue->dev->wl, "PIO RX timed out\n");
578 : 0 : return;
579 : : data_ready:
580 : :
581 : 0 : len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
582 [ # # ]: 0 : if (unlikely(len > 0x700)) {
583 : 0 : pio_rx_error(queue, 0, "len > 0x700");
584 : 0 : return;
585 : : }
586 [ # # # # ]: 0 : if (unlikely(len == 0 && queue->mmio_base !=
587 : : B43legacy_MMIO_PIO4_BASE)) {
588 : 0 : pio_rx_error(queue, 0, "len == 0");
589 : 0 : return;
590 : : }
591 : 0 : preamble[0] = cpu_to_le16(len);
592 [ # # ]: 0 : if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE)
593 : : preamble_readwords = 14 / sizeof(u16);
594 : : else
595 : 0 : preamble_readwords = 18 / sizeof(u16);
596 [ # # ]: 0 : for (i = 0; i < preamble_readwords; i++) {
597 : 0 : tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
598 : 0 : preamble[i + 1] = cpu_to_le16(tmp);
599 : : }
600 : 0 : rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble;
601 : 0 : macstat = le16_to_cpu(rxhdr->mac_status);
602 [ # # ]: 0 : if (macstat & B43legacy_RX_MAC_FCSERR) {
603 : 0 : pio_rx_error(queue,
604 : 0 : (queue->mmio_base == B43legacy_MMIO_PIO1_BASE),
605 : : "Frame FCS error");
606 : 0 : return;
607 : : }
608 [ # # ]: 0 : if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) {
609 : : /* We received an xmit status. */
610 : 0 : struct b43legacy_hwtxstatus *hw;
611 : :
612 : 0 : hw = (struct b43legacy_hwtxstatus *)(preamble + 1);
613 : 0 : b43legacy_handle_hwtxstatus(queue->dev, hw);
614 : :
615 : 0 : return;
616 : : }
617 : :
618 : 0 : skb = dev_alloc_skb(len);
619 [ # # ]: 0 : if (unlikely(!skb)) {
620 : 0 : pio_rx_error(queue, 1, "OOM");
621 : 0 : return;
622 : : }
623 : 0 : skb_put(skb, len);
624 [ # # ]: 0 : for (i = 0; i < len - 1; i += 2) {
625 : 0 : tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
626 : 0 : *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
627 : : }
628 [ # # ]: 0 : if (len % 2) {
629 : 0 : tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
630 : 0 : skb->data[len - 1] = (tmp & 0x00FF);
631 : : }
632 : 0 : b43legacy_rx(queue->dev, skb, rxhdr);
633 : : }
634 : :
635 : 0 : void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
636 : : {
637 : 0 : b43legacy_power_saving_ctl_bits(queue->dev, -1, 1);
638 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
639 : : b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
640 : : | B43legacy_PIO_TXCTL_SUSPEND);
641 : 0 : }
642 : :
643 : 0 : void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
644 : : {
645 : 0 : b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
646 : : b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
647 : : & ~B43legacy_PIO_TXCTL_SUSPEND);
648 : 0 : b43legacy_power_saving_ctl_bits(queue->dev, -1, -1);
649 : 0 : tasklet_schedule(&queue->txtask);
650 : 0 : }
651 : :
652 : 0 : void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
653 : : {
654 : 0 : struct b43legacy_pio *pio;
655 : :
656 [ # # ]: 0 : B43legacy_WARN_ON(!b43legacy_using_pio(dev));
657 : 0 : pio = &dev->pio;
658 : 0 : pio->queue0->tx_frozen = 1;
659 : 0 : pio->queue1->tx_frozen = 1;
660 : 0 : pio->queue2->tx_frozen = 1;
661 : 0 : pio->queue3->tx_frozen = 1;
662 : 0 : }
663 : :
664 : 0 : void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
665 : : {
666 : 0 : struct b43legacy_pio *pio;
667 : :
668 [ # # ]: 0 : B43legacy_WARN_ON(!b43legacy_using_pio(dev));
669 : 0 : pio = &dev->pio;
670 : 0 : pio->queue0->tx_frozen = 0;
671 : 0 : pio->queue1->tx_frozen = 0;
672 : 0 : pio->queue2->tx_frozen = 0;
673 : 0 : pio->queue3->tx_frozen = 0;
674 [ # # ]: 0 : if (!list_empty(&pio->queue0->txqueue))
675 : 0 : tasklet_schedule(&pio->queue0->txtask);
676 [ # # ]: 0 : if (!list_empty(&pio->queue1->txqueue))
677 : 0 : tasklet_schedule(&pio->queue1->txtask);
678 [ # # ]: 0 : if (!list_empty(&pio->queue2->txqueue))
679 : 0 : tasklet_schedule(&pio->queue2->txtask);
680 [ # # ]: 0 : if (!list_empty(&pio->queue3->txqueue))
681 : 0 : tasklet_schedule(&pio->queue3->txtask);
682 : 0 : }
|