1ca47d344SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
258619b14SKalle Valo /*
358619b14SKalle Valo
458619b14SKalle Valo Broadcom B43 wireless driver
558619b14SKalle Valo
658619b14SKalle Valo PIO data transfer
758619b14SKalle Valo
858619b14SKalle Valo Copyright (c) 2005-2008 Michael Buesch <m@bues.ch>
958619b14SKalle Valo
1058619b14SKalle Valo
1158619b14SKalle Valo */
1258619b14SKalle Valo
1358619b14SKalle Valo #include "b43.h"
1458619b14SKalle Valo #include "pio.h"
1558619b14SKalle Valo #include "dma.h"
1658619b14SKalle Valo #include "main.h"
1758619b14SKalle Valo #include "xmit.h"
1858619b14SKalle Valo
1958619b14SKalle Valo #include <linux/delay.h>
2058619b14SKalle Valo #include <linux/sched.h>
2158619b14SKalle Valo #include <linux/slab.h>
2258619b14SKalle Valo
2358619b14SKalle Valo
generate_cookie(struct b43_pio_txqueue * q,struct b43_pio_txpacket * pack)2458619b14SKalle Valo static u16 generate_cookie(struct b43_pio_txqueue *q,
2558619b14SKalle Valo struct b43_pio_txpacket *pack)
2658619b14SKalle Valo {
2758619b14SKalle Valo u16 cookie;
2858619b14SKalle Valo
2958619b14SKalle Valo /* Use the upper 4 bits of the cookie as
3058619b14SKalle Valo * PIO controller ID and store the packet index number
3158619b14SKalle Valo * in the lower 12 bits.
3258619b14SKalle Valo * Note that the cookie must never be 0, as this
3358619b14SKalle Valo * is a special value used in RX path.
3458619b14SKalle Valo * It can also not be 0xFFFF because that is special
3558619b14SKalle Valo * for multicast frames.
3658619b14SKalle Valo */
3758619b14SKalle Valo cookie = (((u16)q->index + 1) << 12);
3858619b14SKalle Valo cookie |= pack->index;
3958619b14SKalle Valo
4058619b14SKalle Valo return cookie;
4158619b14SKalle Valo }
4258619b14SKalle Valo
4358619b14SKalle Valo static
parse_cookie(struct b43_wldev * dev,u16 cookie,struct b43_pio_txpacket ** pack)4458619b14SKalle Valo struct b43_pio_txqueue *parse_cookie(struct b43_wldev *dev,
4558619b14SKalle Valo u16 cookie,
4658619b14SKalle Valo struct b43_pio_txpacket **pack)
4758619b14SKalle Valo {
4858619b14SKalle Valo struct b43_pio *pio = &dev->pio;
4958619b14SKalle Valo struct b43_pio_txqueue *q = NULL;
5058619b14SKalle Valo unsigned int pack_index;
5158619b14SKalle Valo
5258619b14SKalle Valo switch (cookie & 0xF000) {
5358619b14SKalle Valo case 0x1000:
5458619b14SKalle Valo q = pio->tx_queue_AC_BK;
5558619b14SKalle Valo break;
5658619b14SKalle Valo case 0x2000:
5758619b14SKalle Valo q = pio->tx_queue_AC_BE;
5858619b14SKalle Valo break;
5958619b14SKalle Valo case 0x3000:
6058619b14SKalle Valo q = pio->tx_queue_AC_VI;
6158619b14SKalle Valo break;
6258619b14SKalle Valo case 0x4000:
6358619b14SKalle Valo q = pio->tx_queue_AC_VO;
6458619b14SKalle Valo break;
6558619b14SKalle Valo case 0x5000:
6658619b14SKalle Valo q = pio->tx_queue_mcast;
6758619b14SKalle Valo break;
6858619b14SKalle Valo }
6958619b14SKalle Valo if (B43_WARN_ON(!q))
7058619b14SKalle Valo return NULL;
7158619b14SKalle Valo pack_index = (cookie & 0x0FFF);
7258619b14SKalle Valo if (B43_WARN_ON(pack_index >= ARRAY_SIZE(q->packets)))
7358619b14SKalle Valo return NULL;
7458619b14SKalle Valo *pack = &q->packets[pack_index];
7558619b14SKalle Valo
7658619b14SKalle Valo return q;
7758619b14SKalle Valo }
7858619b14SKalle Valo
index_to_pioqueue_base(struct b43_wldev * dev,unsigned int index)7958619b14SKalle Valo static u16 index_to_pioqueue_base(struct b43_wldev *dev,
8058619b14SKalle Valo unsigned int index)
8158619b14SKalle Valo {
8258619b14SKalle Valo static const u16 bases[] = {
8358619b14SKalle Valo B43_MMIO_PIO_BASE0,
8458619b14SKalle Valo B43_MMIO_PIO_BASE1,
8558619b14SKalle Valo B43_MMIO_PIO_BASE2,
8658619b14SKalle Valo B43_MMIO_PIO_BASE3,
8758619b14SKalle Valo B43_MMIO_PIO_BASE4,
8858619b14SKalle Valo B43_MMIO_PIO_BASE5,
8958619b14SKalle Valo B43_MMIO_PIO_BASE6,
9058619b14SKalle Valo B43_MMIO_PIO_BASE7,
9158619b14SKalle Valo };
9258619b14SKalle Valo static const u16 bases_rev11[] = {
9358619b14SKalle Valo B43_MMIO_PIO11_BASE0,
9458619b14SKalle Valo B43_MMIO_PIO11_BASE1,
9558619b14SKalle Valo B43_MMIO_PIO11_BASE2,
9658619b14SKalle Valo B43_MMIO_PIO11_BASE3,
9758619b14SKalle Valo B43_MMIO_PIO11_BASE4,
9858619b14SKalle Valo B43_MMIO_PIO11_BASE5,
9958619b14SKalle Valo };
10058619b14SKalle Valo
10158619b14SKalle Valo if (dev->dev->core_rev >= 11) {
10258619b14SKalle Valo B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11));
10358619b14SKalle Valo return bases_rev11[index];
10458619b14SKalle Valo }
10558619b14SKalle Valo B43_WARN_ON(index >= ARRAY_SIZE(bases));
10658619b14SKalle Valo return bases[index];
10758619b14SKalle Valo }
10858619b14SKalle Valo
pio_txqueue_offset(struct b43_wldev * dev)10958619b14SKalle Valo static u16 pio_txqueue_offset(struct b43_wldev *dev)
11058619b14SKalle Valo {
11158619b14SKalle Valo if (dev->dev->core_rev >= 11)
11258619b14SKalle Valo return 0x18;
11358619b14SKalle Valo return 0;
11458619b14SKalle Valo }
11558619b14SKalle Valo
pio_rxqueue_offset(struct b43_wldev * dev)11658619b14SKalle Valo static u16 pio_rxqueue_offset(struct b43_wldev *dev)
11758619b14SKalle Valo {
11858619b14SKalle Valo if (dev->dev->core_rev >= 11)
11958619b14SKalle Valo return 0x38;
12058619b14SKalle Valo return 8;
12158619b14SKalle Valo }
12258619b14SKalle Valo
b43_setup_pioqueue_tx(struct b43_wldev * dev,unsigned int index)12358619b14SKalle Valo static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev,
12458619b14SKalle Valo unsigned int index)
12558619b14SKalle Valo {
12658619b14SKalle Valo struct b43_pio_txqueue *q;
12758619b14SKalle Valo struct b43_pio_txpacket *p;
12858619b14SKalle Valo unsigned int i;
12958619b14SKalle Valo
13058619b14SKalle Valo q = kzalloc(sizeof(*q), GFP_KERNEL);
13158619b14SKalle Valo if (!q)
13258619b14SKalle Valo return NULL;
13358619b14SKalle Valo q->dev = dev;
13458619b14SKalle Valo q->rev = dev->dev->core_rev;
13558619b14SKalle Valo q->mmio_base = index_to_pioqueue_base(dev, index) +
13658619b14SKalle Valo pio_txqueue_offset(dev);
13758619b14SKalle Valo q->index = index;
13858619b14SKalle Valo
13958619b14SKalle Valo q->free_packet_slots = B43_PIO_MAX_NR_TXPACKETS;
14058619b14SKalle Valo if (q->rev >= 8) {
14158619b14SKalle Valo q->buffer_size = 1920; //FIXME this constant is wrong.
14258619b14SKalle Valo } else {
14358619b14SKalle Valo q->buffer_size = b43_piotx_read16(q, B43_PIO_TXQBUFSIZE);
14458619b14SKalle Valo q->buffer_size -= 80;
14558619b14SKalle Valo }
14658619b14SKalle Valo
14758619b14SKalle Valo INIT_LIST_HEAD(&q->packets_list);
14858619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(q->packets); i++) {
14958619b14SKalle Valo p = &(q->packets[i]);
15058619b14SKalle Valo INIT_LIST_HEAD(&p->list);
15158619b14SKalle Valo p->index = i;
15258619b14SKalle Valo p->queue = q;
15358619b14SKalle Valo list_add(&p->list, &q->packets_list);
15458619b14SKalle Valo }
15558619b14SKalle Valo
15658619b14SKalle Valo return q;
15758619b14SKalle Valo }
15858619b14SKalle Valo
b43_setup_pioqueue_rx(struct b43_wldev * dev,unsigned int index)15958619b14SKalle Valo static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev,
16058619b14SKalle Valo unsigned int index)
16158619b14SKalle Valo {
16258619b14SKalle Valo struct b43_pio_rxqueue *q;
16358619b14SKalle Valo
16458619b14SKalle Valo q = kzalloc(sizeof(*q), GFP_KERNEL);
16558619b14SKalle Valo if (!q)
16658619b14SKalle Valo return NULL;
16758619b14SKalle Valo q->dev = dev;
16858619b14SKalle Valo q->rev = dev->dev->core_rev;
16958619b14SKalle Valo q->mmio_base = index_to_pioqueue_base(dev, index) +
17058619b14SKalle Valo pio_rxqueue_offset(dev);
17158619b14SKalle Valo
17258619b14SKalle Valo /* Enable Direct FIFO RX (PIO) on the engine. */
17358619b14SKalle Valo b43_dma_direct_fifo_rx(dev, index, 1);
17458619b14SKalle Valo
17558619b14SKalle Valo return q;
17658619b14SKalle Valo }
17758619b14SKalle Valo
b43_pio_cancel_tx_packets(struct b43_pio_txqueue * q)17858619b14SKalle Valo static void b43_pio_cancel_tx_packets(struct b43_pio_txqueue *q)
17958619b14SKalle Valo {
18058619b14SKalle Valo struct b43_pio_txpacket *pack;
18158619b14SKalle Valo unsigned int i;
18258619b14SKalle Valo
18358619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(q->packets); i++) {
18458619b14SKalle Valo pack = &(q->packets[i]);
18558619b14SKalle Valo if (pack->skb) {
18658619b14SKalle Valo ieee80211_free_txskb(q->dev->wl->hw, pack->skb);
18758619b14SKalle Valo pack->skb = NULL;
18858619b14SKalle Valo }
18958619b14SKalle Valo }
19058619b14SKalle Valo }
19158619b14SKalle Valo
b43_destroy_pioqueue_tx(struct b43_pio_txqueue * q,const char * name)19258619b14SKalle Valo static void b43_destroy_pioqueue_tx(struct b43_pio_txqueue *q,
19358619b14SKalle Valo const char *name)
19458619b14SKalle Valo {
19558619b14SKalle Valo if (!q)
19658619b14SKalle Valo return;
19758619b14SKalle Valo b43_pio_cancel_tx_packets(q);
19858619b14SKalle Valo kfree(q);
19958619b14SKalle Valo }
20058619b14SKalle Valo
b43_destroy_pioqueue_rx(struct b43_pio_rxqueue * q,const char * name)20158619b14SKalle Valo static void b43_destroy_pioqueue_rx(struct b43_pio_rxqueue *q,
20258619b14SKalle Valo const char *name)
20358619b14SKalle Valo {
20458619b14SKalle Valo if (!q)
20558619b14SKalle Valo return;
20658619b14SKalle Valo kfree(q);
20758619b14SKalle Valo }
20858619b14SKalle Valo
20958619b14SKalle Valo #define destroy_queue_tx(pio, queue) do { \
21058619b14SKalle Valo b43_destroy_pioqueue_tx((pio)->queue, __stringify(queue)); \
21158619b14SKalle Valo (pio)->queue = NULL; \
21258619b14SKalle Valo } while (0)
21358619b14SKalle Valo
21458619b14SKalle Valo #define destroy_queue_rx(pio, queue) do { \
21558619b14SKalle Valo b43_destroy_pioqueue_rx((pio)->queue, __stringify(queue)); \
21658619b14SKalle Valo (pio)->queue = NULL; \
21758619b14SKalle Valo } while (0)
21858619b14SKalle Valo
b43_pio_free(struct b43_wldev * dev)21958619b14SKalle Valo void b43_pio_free(struct b43_wldev *dev)
22058619b14SKalle Valo {
22158619b14SKalle Valo struct b43_pio *pio;
22258619b14SKalle Valo
22358619b14SKalle Valo if (!b43_using_pio_transfers(dev))
22458619b14SKalle Valo return;
22558619b14SKalle Valo pio = &dev->pio;
22658619b14SKalle Valo
22758619b14SKalle Valo destroy_queue_rx(pio, rx_queue);
22858619b14SKalle Valo destroy_queue_tx(pio, tx_queue_mcast);
22958619b14SKalle Valo destroy_queue_tx(pio, tx_queue_AC_VO);
23058619b14SKalle Valo destroy_queue_tx(pio, tx_queue_AC_VI);
23158619b14SKalle Valo destroy_queue_tx(pio, tx_queue_AC_BE);
23258619b14SKalle Valo destroy_queue_tx(pio, tx_queue_AC_BK);
23358619b14SKalle Valo }
23458619b14SKalle Valo
b43_pio_init(struct b43_wldev * dev)23558619b14SKalle Valo int b43_pio_init(struct b43_wldev *dev)
23658619b14SKalle Valo {
23758619b14SKalle Valo struct b43_pio *pio = &dev->pio;
23858619b14SKalle Valo int err = -ENOMEM;
23958619b14SKalle Valo
24058619b14SKalle Valo b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
24158619b14SKalle Valo & ~B43_MACCTL_BE);
24258619b14SKalle Valo b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RXPADOFF, 0);
24358619b14SKalle Valo
24458619b14SKalle Valo pio->tx_queue_AC_BK = b43_setup_pioqueue_tx(dev, 0);
24558619b14SKalle Valo if (!pio->tx_queue_AC_BK)
24658619b14SKalle Valo goto out;
24758619b14SKalle Valo
24858619b14SKalle Valo pio->tx_queue_AC_BE = b43_setup_pioqueue_tx(dev, 1);
24958619b14SKalle Valo if (!pio->tx_queue_AC_BE)
25058619b14SKalle Valo goto err_destroy_bk;
25158619b14SKalle Valo
25258619b14SKalle Valo pio->tx_queue_AC_VI = b43_setup_pioqueue_tx(dev, 2);
25358619b14SKalle Valo if (!pio->tx_queue_AC_VI)
25458619b14SKalle Valo goto err_destroy_be;
25558619b14SKalle Valo
25658619b14SKalle Valo pio->tx_queue_AC_VO = b43_setup_pioqueue_tx(dev, 3);
25758619b14SKalle Valo if (!pio->tx_queue_AC_VO)
25858619b14SKalle Valo goto err_destroy_vi;
25958619b14SKalle Valo
26058619b14SKalle Valo pio->tx_queue_mcast = b43_setup_pioqueue_tx(dev, 4);
26158619b14SKalle Valo if (!pio->tx_queue_mcast)
26258619b14SKalle Valo goto err_destroy_vo;
26358619b14SKalle Valo
26458619b14SKalle Valo pio->rx_queue = b43_setup_pioqueue_rx(dev, 0);
26558619b14SKalle Valo if (!pio->rx_queue)
26658619b14SKalle Valo goto err_destroy_mcast;
26758619b14SKalle Valo
26858619b14SKalle Valo b43dbg(dev->wl, "PIO initialized\n");
26958619b14SKalle Valo err = 0;
27058619b14SKalle Valo out:
27158619b14SKalle Valo return err;
27258619b14SKalle Valo
27358619b14SKalle Valo err_destroy_mcast:
27458619b14SKalle Valo destroy_queue_tx(pio, tx_queue_mcast);
27558619b14SKalle Valo err_destroy_vo:
27658619b14SKalle Valo destroy_queue_tx(pio, tx_queue_AC_VO);
27758619b14SKalle Valo err_destroy_vi:
27858619b14SKalle Valo destroy_queue_tx(pio, tx_queue_AC_VI);
27958619b14SKalle Valo err_destroy_be:
28058619b14SKalle Valo destroy_queue_tx(pio, tx_queue_AC_BE);
28158619b14SKalle Valo err_destroy_bk:
28258619b14SKalle Valo destroy_queue_tx(pio, tx_queue_AC_BK);
28358619b14SKalle Valo return err;
28458619b14SKalle Valo }
28558619b14SKalle Valo
28658619b14SKalle Valo /* Static mapping of mac80211's queues (priorities) to b43 PIO queues. */
select_queue_by_priority(struct b43_wldev * dev,u8 queue_prio)28758619b14SKalle Valo static struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev,
28858619b14SKalle Valo u8 queue_prio)
28958619b14SKalle Valo {
29058619b14SKalle Valo struct b43_pio_txqueue *q;
29158619b14SKalle Valo
29258619b14SKalle Valo if (dev->qos_enabled) {
29358619b14SKalle Valo /* 0 = highest priority */
29458619b14SKalle Valo switch (queue_prio) {
29558619b14SKalle Valo default:
29658619b14SKalle Valo B43_WARN_ON(1);
2977b54281cSGustavo A. R. Silva fallthrough;
29858619b14SKalle Valo case 0:
29958619b14SKalle Valo q = dev->pio.tx_queue_AC_VO;
30058619b14SKalle Valo break;
30158619b14SKalle Valo case 1:
30258619b14SKalle Valo q = dev->pio.tx_queue_AC_VI;
30358619b14SKalle Valo break;
30458619b14SKalle Valo case 2:
30558619b14SKalle Valo q = dev->pio.tx_queue_AC_BE;
30658619b14SKalle Valo break;
30758619b14SKalle Valo case 3:
30858619b14SKalle Valo q = dev->pio.tx_queue_AC_BK;
30958619b14SKalle Valo break;
31058619b14SKalle Valo }
31158619b14SKalle Valo } else
31258619b14SKalle Valo q = dev->pio.tx_queue_AC_BE;
31358619b14SKalle Valo
31458619b14SKalle Valo return q;
31558619b14SKalle Valo }
31658619b14SKalle Valo
tx_write_2byte_queue(struct b43_pio_txqueue * q,u16 ctl,const void * _data,unsigned int data_len)31758619b14SKalle Valo static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
31858619b14SKalle Valo u16 ctl,
31958619b14SKalle Valo const void *_data,
32058619b14SKalle Valo unsigned int data_len)
32158619b14SKalle Valo {
32258619b14SKalle Valo struct b43_wldev *dev = q->dev;
32358619b14SKalle Valo struct b43_wl *wl = dev->wl;
32458619b14SKalle Valo const u8 *data = _data;
32558619b14SKalle Valo
32658619b14SKalle Valo ctl |= B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI;
32758619b14SKalle Valo b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
32858619b14SKalle Valo
32958619b14SKalle Valo b43_block_write(dev, data, (data_len & ~1),
33058619b14SKalle Valo q->mmio_base + B43_PIO_TXDATA,
33158619b14SKalle Valo sizeof(u16));
33258619b14SKalle Valo if (data_len & 1) {
33358619b14SKalle Valo u8 *tail = wl->pio_tailspace;
33458619b14SKalle Valo BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
33558619b14SKalle Valo
33658619b14SKalle Valo /* Write the last byte. */
33758619b14SKalle Valo ctl &= ~B43_PIO_TXCTL_WRITEHI;
33858619b14SKalle Valo b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
33958619b14SKalle Valo tail[0] = data[data_len - 1];
34058619b14SKalle Valo tail[1] = 0;
34158619b14SKalle Valo b43_block_write(dev, tail, 2,
34258619b14SKalle Valo q->mmio_base + B43_PIO_TXDATA,
34358619b14SKalle Valo sizeof(u16));
34458619b14SKalle Valo }
34558619b14SKalle Valo
34658619b14SKalle Valo return ctl;
34758619b14SKalle Valo }
34858619b14SKalle Valo
pio_tx_frame_2byte_queue(struct b43_pio_txpacket * pack,const u8 * hdr,unsigned int hdrlen)34958619b14SKalle Valo static void pio_tx_frame_2byte_queue(struct b43_pio_txpacket *pack,
35058619b14SKalle Valo const u8 *hdr, unsigned int hdrlen)
35158619b14SKalle Valo {
35258619b14SKalle Valo struct b43_pio_txqueue *q = pack->queue;
35358619b14SKalle Valo const char *frame = pack->skb->data;
35458619b14SKalle Valo unsigned int frame_len = pack->skb->len;
35558619b14SKalle Valo u16 ctl;
35658619b14SKalle Valo
35758619b14SKalle Valo ctl = b43_piotx_read16(q, B43_PIO_TXCTL);
35858619b14SKalle Valo ctl |= B43_PIO_TXCTL_FREADY;
35958619b14SKalle Valo ctl &= ~B43_PIO_TXCTL_EOF;
36058619b14SKalle Valo
36158619b14SKalle Valo /* Transfer the header data. */
36258619b14SKalle Valo ctl = tx_write_2byte_queue(q, ctl, hdr, hdrlen);
36358619b14SKalle Valo /* Transfer the frame data. */
36458619b14SKalle Valo ctl = tx_write_2byte_queue(q, ctl, frame, frame_len);
36558619b14SKalle Valo
36658619b14SKalle Valo ctl |= B43_PIO_TXCTL_EOF;
36758619b14SKalle Valo b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
36858619b14SKalle Valo }
36958619b14SKalle Valo
tx_write_4byte_queue(struct b43_pio_txqueue * q,u32 ctl,const void * _data,unsigned int data_len)37058619b14SKalle Valo static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
37158619b14SKalle Valo u32 ctl,
37258619b14SKalle Valo const void *_data,
37358619b14SKalle Valo unsigned int data_len)
37458619b14SKalle Valo {
37558619b14SKalle Valo struct b43_wldev *dev = q->dev;
37658619b14SKalle Valo struct b43_wl *wl = dev->wl;
37758619b14SKalle Valo const u8 *data = _data;
37858619b14SKalle Valo
37958619b14SKalle Valo ctl |= B43_PIO8_TXCTL_0_7 | B43_PIO8_TXCTL_8_15 |
38058619b14SKalle Valo B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31;
38158619b14SKalle Valo b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
38258619b14SKalle Valo
38358619b14SKalle Valo b43_block_write(dev, data, (data_len & ~3),
38458619b14SKalle Valo q->mmio_base + B43_PIO8_TXDATA,
38558619b14SKalle Valo sizeof(u32));
38658619b14SKalle Valo if (data_len & 3) {
38758619b14SKalle Valo u8 *tail = wl->pio_tailspace;
38858619b14SKalle Valo BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
38958619b14SKalle Valo
39058619b14SKalle Valo memset(tail, 0, 4);
39158619b14SKalle Valo /* Write the last few bytes. */
39258619b14SKalle Valo ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 |
39358619b14SKalle Valo B43_PIO8_TXCTL_24_31);
39458619b14SKalle Valo switch (data_len & 3) {
39558619b14SKalle Valo case 3:
39658619b14SKalle Valo ctl |= B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_8_15;
39758619b14SKalle Valo tail[0] = data[data_len - 3];
39858619b14SKalle Valo tail[1] = data[data_len - 2];
39958619b14SKalle Valo tail[2] = data[data_len - 1];
40058619b14SKalle Valo break;
40158619b14SKalle Valo case 2:
40258619b14SKalle Valo ctl |= B43_PIO8_TXCTL_8_15;
40358619b14SKalle Valo tail[0] = data[data_len - 2];
40458619b14SKalle Valo tail[1] = data[data_len - 1];
40558619b14SKalle Valo break;
40658619b14SKalle Valo case 1:
40758619b14SKalle Valo tail[0] = data[data_len - 1];
40858619b14SKalle Valo break;
40958619b14SKalle Valo }
41058619b14SKalle Valo b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
41158619b14SKalle Valo b43_block_write(dev, tail, 4,
41258619b14SKalle Valo q->mmio_base + B43_PIO8_TXDATA,
41358619b14SKalle Valo sizeof(u32));
41458619b14SKalle Valo }
41558619b14SKalle Valo
41658619b14SKalle Valo return ctl;
41758619b14SKalle Valo }
41858619b14SKalle Valo
pio_tx_frame_4byte_queue(struct b43_pio_txpacket * pack,const u8 * hdr,unsigned int hdrlen)41958619b14SKalle Valo static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack,
42058619b14SKalle Valo const u8 *hdr, unsigned int hdrlen)
42158619b14SKalle Valo {
42258619b14SKalle Valo struct b43_pio_txqueue *q = pack->queue;
42358619b14SKalle Valo const char *frame = pack->skb->data;
42458619b14SKalle Valo unsigned int frame_len = pack->skb->len;
42558619b14SKalle Valo u32 ctl;
42658619b14SKalle Valo
42758619b14SKalle Valo ctl = b43_piotx_read32(q, B43_PIO8_TXCTL);
42858619b14SKalle Valo ctl |= B43_PIO8_TXCTL_FREADY;
42958619b14SKalle Valo ctl &= ~B43_PIO8_TXCTL_EOF;
43058619b14SKalle Valo
43158619b14SKalle Valo /* Transfer the header data. */
43258619b14SKalle Valo ctl = tx_write_4byte_queue(q, ctl, hdr, hdrlen);
43358619b14SKalle Valo /* Transfer the frame data. */
43458619b14SKalle Valo ctl = tx_write_4byte_queue(q, ctl, frame, frame_len);
43558619b14SKalle Valo
43658619b14SKalle Valo ctl |= B43_PIO8_TXCTL_EOF;
43758619b14SKalle Valo b43_piotx_write32(q, B43_PIO_TXCTL, ctl);
43858619b14SKalle Valo }
43958619b14SKalle Valo
pio_tx_frame(struct b43_pio_txqueue * q,struct sk_buff * skb)44058619b14SKalle Valo static int pio_tx_frame(struct b43_pio_txqueue *q,
44158619b14SKalle Valo struct sk_buff *skb)
44258619b14SKalle Valo {
44358619b14SKalle Valo struct b43_wldev *dev = q->dev;
44458619b14SKalle Valo struct b43_wl *wl = dev->wl;
44558619b14SKalle Valo struct b43_pio_txpacket *pack;
44658619b14SKalle Valo u16 cookie;
44758619b14SKalle Valo int err;
44858619b14SKalle Valo unsigned int hdrlen;
44958619b14SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
45058619b14SKalle Valo struct b43_txhdr *txhdr = (struct b43_txhdr *)wl->pio_scratchspace;
45158619b14SKalle Valo
45258619b14SKalle Valo B43_WARN_ON(list_empty(&q->packets_list));
45358619b14SKalle Valo pack = list_entry(q->packets_list.next,
45458619b14SKalle Valo struct b43_pio_txpacket, list);
45558619b14SKalle Valo
45658619b14SKalle Valo cookie = generate_cookie(q, pack);
45758619b14SKalle Valo hdrlen = b43_txhdr_size(dev);
45858619b14SKalle Valo BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(struct b43_txhdr));
45958619b14SKalle Valo B43_WARN_ON(sizeof(wl->pio_scratchspace) < hdrlen);
46058619b14SKalle Valo err = b43_generate_txhdr(dev, (u8 *)txhdr, skb,
46158619b14SKalle Valo info, cookie);
46258619b14SKalle Valo if (err)
46358619b14SKalle Valo return err;
46458619b14SKalle Valo
46558619b14SKalle Valo if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
46658619b14SKalle Valo /* Tell the firmware about the cookie of the last
46758619b14SKalle Valo * mcast frame, so it can clear the more-data bit in it. */
46858619b14SKalle Valo b43_shm_write16(dev, B43_SHM_SHARED,
46958619b14SKalle Valo B43_SHM_SH_MCASTCOOKIE, cookie);
47058619b14SKalle Valo }
47158619b14SKalle Valo
47258619b14SKalle Valo pack->skb = skb;
47358619b14SKalle Valo if (q->rev >= 8)
47458619b14SKalle Valo pio_tx_frame_4byte_queue(pack, (const u8 *)txhdr, hdrlen);
47558619b14SKalle Valo else
47658619b14SKalle Valo pio_tx_frame_2byte_queue(pack, (const u8 *)txhdr, hdrlen);
47758619b14SKalle Valo
47858619b14SKalle Valo /* Remove it from the list of available packet slots.
47958619b14SKalle Valo * It will be put back when we receive the status report. */
48058619b14SKalle Valo list_del(&pack->list);
48158619b14SKalle Valo
48258619b14SKalle Valo /* Update the queue statistics. */
48358619b14SKalle Valo q->buffer_used += roundup(skb->len + hdrlen, 4);
48458619b14SKalle Valo q->free_packet_slots -= 1;
48558619b14SKalle Valo
48658619b14SKalle Valo return 0;
48758619b14SKalle Valo }
48858619b14SKalle Valo
b43_pio_tx(struct b43_wldev * dev,struct sk_buff * skb)48958619b14SKalle Valo int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
49058619b14SKalle Valo {
49158619b14SKalle Valo struct b43_pio_txqueue *q;
49258619b14SKalle Valo struct ieee80211_hdr *hdr;
49358619b14SKalle Valo unsigned int hdrlen, total_len;
49458619b14SKalle Valo int err = 0;
49558619b14SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
49658619b14SKalle Valo
49758619b14SKalle Valo hdr = (struct ieee80211_hdr *)skb->data;
49858619b14SKalle Valo
49958619b14SKalle Valo if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
50058619b14SKalle Valo /* The multicast queue will be sent after the DTIM. */
50158619b14SKalle Valo q = dev->pio.tx_queue_mcast;
50258619b14SKalle Valo /* Set the frame More-Data bit. Ucode will clear it
50358619b14SKalle Valo * for us on the last frame. */
50458619b14SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
50558619b14SKalle Valo } else {
50658619b14SKalle Valo /* Decide by priority where to put this frame. */
50758619b14SKalle Valo q = select_queue_by_priority(dev, skb_get_queue_mapping(skb));
50858619b14SKalle Valo }
50958619b14SKalle Valo
51058619b14SKalle Valo hdrlen = b43_txhdr_size(dev);
51158619b14SKalle Valo total_len = roundup(skb->len + hdrlen, 4);
51258619b14SKalle Valo
51358619b14SKalle Valo if (unlikely(total_len > q->buffer_size)) {
51458619b14SKalle Valo err = -ENOBUFS;
51558619b14SKalle Valo b43dbg(dev->wl, "PIO: TX packet longer than queue.\n");
51658619b14SKalle Valo goto out;
51758619b14SKalle Valo }
51858619b14SKalle Valo if (unlikely(q->free_packet_slots == 0)) {
51958619b14SKalle Valo err = -ENOBUFS;
52058619b14SKalle Valo b43warn(dev->wl, "PIO: TX packet overflow.\n");
52158619b14SKalle Valo goto out;
52258619b14SKalle Valo }
52358619b14SKalle Valo B43_WARN_ON(q->buffer_used > q->buffer_size);
52458619b14SKalle Valo
52558619b14SKalle Valo if (total_len > (q->buffer_size - q->buffer_used)) {
52658619b14SKalle Valo /* Not enough memory on the queue. */
52758619b14SKalle Valo err = -EBUSY;
528*77135a38SRahul Rameshbabu b43_stop_queue(dev, skb_get_queue_mapping(skb));
52958619b14SKalle Valo q->stopped = true;
53058619b14SKalle Valo goto out;
53158619b14SKalle Valo }
53258619b14SKalle Valo
53358619b14SKalle Valo /* Assign the queue number to the ring (if not already done before)
53458619b14SKalle Valo * so TX status handling can use it. The mac80211-queue to b43-queue
53558619b14SKalle Valo * mapping is static, so we don't need to store it per frame. */
53658619b14SKalle Valo q->queue_prio = skb_get_queue_mapping(skb);
53758619b14SKalle Valo
53858619b14SKalle Valo err = pio_tx_frame(q, skb);
53958619b14SKalle Valo if (unlikely(err == -ENOKEY)) {
54058619b14SKalle Valo /* Drop this packet, as we don't have the encryption key
54158619b14SKalle Valo * anymore and must not transmit it unencrypted. */
54258619b14SKalle Valo ieee80211_free_txskb(dev->wl->hw, skb);
54358619b14SKalle Valo err = 0;
54458619b14SKalle Valo goto out;
54558619b14SKalle Valo }
54658619b14SKalle Valo if (unlikely(err)) {
54758619b14SKalle Valo b43err(dev->wl, "PIO transmission failure\n");
54858619b14SKalle Valo goto out;
54958619b14SKalle Valo }
55058619b14SKalle Valo
55158619b14SKalle Valo B43_WARN_ON(q->buffer_used > q->buffer_size);
55258619b14SKalle Valo if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) ||
55358619b14SKalle Valo (q->free_packet_slots == 0)) {
55458619b14SKalle Valo /* The queue is full. */
555*77135a38SRahul Rameshbabu b43_stop_queue(dev, skb_get_queue_mapping(skb));
55658619b14SKalle Valo q->stopped = true;
55758619b14SKalle Valo }
55858619b14SKalle Valo
55958619b14SKalle Valo out:
56058619b14SKalle Valo return err;
56158619b14SKalle Valo }
56258619b14SKalle Valo
b43_pio_handle_txstatus(struct b43_wldev * dev,const struct b43_txstatus * status)56358619b14SKalle Valo void b43_pio_handle_txstatus(struct b43_wldev *dev,
56458619b14SKalle Valo const struct b43_txstatus *status)
56558619b14SKalle Valo {
56658619b14SKalle Valo struct b43_pio_txqueue *q;
56758619b14SKalle Valo struct b43_pio_txpacket *pack = NULL;
56858619b14SKalle Valo unsigned int total_len;
56958619b14SKalle Valo struct ieee80211_tx_info *info;
57058619b14SKalle Valo
57158619b14SKalle Valo q = parse_cookie(dev, status->cookie, &pack);
57258619b14SKalle Valo if (unlikely(!q))
57358619b14SKalle Valo return;
57458619b14SKalle Valo B43_WARN_ON(!pack);
57558619b14SKalle Valo
57658619b14SKalle Valo info = IEEE80211_SKB_CB(pack->skb);
57758619b14SKalle Valo
57858619b14SKalle Valo b43_fill_txstatus_report(dev, info, status);
57958619b14SKalle Valo
58058619b14SKalle Valo total_len = pack->skb->len + b43_txhdr_size(dev);
58158619b14SKalle Valo total_len = roundup(total_len, 4);
58258619b14SKalle Valo q->buffer_used -= total_len;
58358619b14SKalle Valo q->free_packet_slots += 1;
58458619b14SKalle Valo
5852703bc85SKalle Valo ieee80211_tx_status_skb(dev->wl->hw, pack->skb);
58658619b14SKalle Valo pack->skb = NULL;
58758619b14SKalle Valo list_add(&pack->list, &q->packets_list);
58858619b14SKalle Valo
58958619b14SKalle Valo if (q->stopped) {
590*77135a38SRahul Rameshbabu b43_wake_queue(dev, q->queue_prio);
59158619b14SKalle Valo q->stopped = false;
59258619b14SKalle Valo }
59358619b14SKalle Valo }
59458619b14SKalle Valo
59558619b14SKalle Valo /* Returns whether we should fetch another frame. */
pio_rx_frame(struct b43_pio_rxqueue * q)59658619b14SKalle Valo static bool pio_rx_frame(struct b43_pio_rxqueue *q)
59758619b14SKalle Valo {
59858619b14SKalle Valo struct b43_wldev *dev = q->dev;
59958619b14SKalle Valo struct b43_wl *wl = dev->wl;
60058619b14SKalle Valo u16 len;
60158619b14SKalle Valo u32 macstat = 0;
60258619b14SKalle Valo unsigned int i, padding;
60358619b14SKalle Valo struct sk_buff *skb;
60458619b14SKalle Valo const char *err_msg = NULL;
60558619b14SKalle Valo struct b43_rxhdr_fw4 *rxhdr =
60658619b14SKalle Valo (struct b43_rxhdr_fw4 *)wl->pio_scratchspace;
60758619b14SKalle Valo size_t rxhdr_size = sizeof(*rxhdr);
60858619b14SKalle Valo
60958619b14SKalle Valo BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(*rxhdr));
61058619b14SKalle Valo switch (dev->fw.hdr_format) {
61158619b14SKalle Valo case B43_FW_HDR_410:
61258619b14SKalle Valo case B43_FW_HDR_351:
61358619b14SKalle Valo rxhdr_size -= sizeof(rxhdr->format_598) -
61458619b14SKalle Valo sizeof(rxhdr->format_351);
61558619b14SKalle Valo break;
61658619b14SKalle Valo case B43_FW_HDR_598:
61758619b14SKalle Valo break;
61858619b14SKalle Valo }
61958619b14SKalle Valo memset(rxhdr, 0, rxhdr_size);
62058619b14SKalle Valo
62158619b14SKalle Valo /* Check if we have data and wait for it to get ready. */
62258619b14SKalle Valo if (q->rev >= 8) {
62358619b14SKalle Valo u32 ctl;
62458619b14SKalle Valo
62558619b14SKalle Valo ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
62658619b14SKalle Valo if (!(ctl & B43_PIO8_RXCTL_FRAMERDY))
62758619b14SKalle Valo return false;
62858619b14SKalle Valo b43_piorx_write32(q, B43_PIO8_RXCTL,
62958619b14SKalle Valo B43_PIO8_RXCTL_FRAMERDY);
63058619b14SKalle Valo for (i = 0; i < 10; i++) {
63158619b14SKalle Valo ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
63258619b14SKalle Valo if (ctl & B43_PIO8_RXCTL_DATARDY)
63358619b14SKalle Valo goto data_ready;
63458619b14SKalle Valo udelay(10);
63558619b14SKalle Valo }
63658619b14SKalle Valo } else {
63758619b14SKalle Valo u16 ctl;
63858619b14SKalle Valo
63958619b14SKalle Valo ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
64058619b14SKalle Valo if (!(ctl & B43_PIO_RXCTL_FRAMERDY))
64158619b14SKalle Valo return false;
64258619b14SKalle Valo b43_piorx_write16(q, B43_PIO_RXCTL,
64358619b14SKalle Valo B43_PIO_RXCTL_FRAMERDY);
64458619b14SKalle Valo for (i = 0; i < 10; i++) {
64558619b14SKalle Valo ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
64658619b14SKalle Valo if (ctl & B43_PIO_RXCTL_DATARDY)
64758619b14SKalle Valo goto data_ready;
64858619b14SKalle Valo udelay(10);
64958619b14SKalle Valo }
65058619b14SKalle Valo }
65158619b14SKalle Valo b43dbg(q->dev->wl, "PIO RX timed out\n");
65258619b14SKalle Valo return true;
65358619b14SKalle Valo data_ready:
65458619b14SKalle Valo
65558619b14SKalle Valo /* Get the preamble (RX header) */
65658619b14SKalle Valo if (q->rev >= 8) {
65758619b14SKalle Valo b43_block_read(dev, rxhdr, rxhdr_size,
65858619b14SKalle Valo q->mmio_base + B43_PIO8_RXDATA,
65958619b14SKalle Valo sizeof(u32));
66058619b14SKalle Valo } else {
66158619b14SKalle Valo b43_block_read(dev, rxhdr, rxhdr_size,
66258619b14SKalle Valo q->mmio_base + B43_PIO_RXDATA,
66358619b14SKalle Valo sizeof(u16));
66458619b14SKalle Valo }
66558619b14SKalle Valo /* Sanity checks. */
66658619b14SKalle Valo len = le16_to_cpu(rxhdr->frame_len);
66758619b14SKalle Valo if (unlikely(len > 0x700)) {
66858619b14SKalle Valo err_msg = "len > 0x700";
66958619b14SKalle Valo goto rx_error;
67058619b14SKalle Valo }
67158619b14SKalle Valo if (unlikely(len == 0)) {
67258619b14SKalle Valo err_msg = "len == 0";
67358619b14SKalle Valo goto rx_error;
67458619b14SKalle Valo }
67558619b14SKalle Valo
67658619b14SKalle Valo switch (dev->fw.hdr_format) {
67758619b14SKalle Valo case B43_FW_HDR_598:
67858619b14SKalle Valo macstat = le32_to_cpu(rxhdr->format_598.mac_status);
67958619b14SKalle Valo break;
68058619b14SKalle Valo case B43_FW_HDR_410:
68158619b14SKalle Valo case B43_FW_HDR_351:
68258619b14SKalle Valo macstat = le32_to_cpu(rxhdr->format_351.mac_status);
68358619b14SKalle Valo break;
68458619b14SKalle Valo }
68558619b14SKalle Valo if (macstat & B43_RX_MAC_FCSERR) {
68658619b14SKalle Valo if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
68758619b14SKalle Valo /* Drop frames with failed FCS. */
68858619b14SKalle Valo err_msg = "Frame FCS error";
68958619b14SKalle Valo goto rx_error;
69058619b14SKalle Valo }
69158619b14SKalle Valo }
69258619b14SKalle Valo
69358619b14SKalle Valo /* We always pad 2 bytes, as that's what upstream code expects
69458619b14SKalle Valo * due to the RX-header being 30 bytes. In case the frame is
69558619b14SKalle Valo * unaligned, we pad another 2 bytes. */
69658619b14SKalle Valo padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0;
69758619b14SKalle Valo skb = dev_alloc_skb(len + padding + 2);
69858619b14SKalle Valo if (unlikely(!skb)) {
69958619b14SKalle Valo err_msg = "Out of memory";
70058619b14SKalle Valo goto rx_error;
70158619b14SKalle Valo }
70258619b14SKalle Valo skb_reserve(skb, 2);
70358619b14SKalle Valo skb_put(skb, len + padding);
70458619b14SKalle Valo if (q->rev >= 8) {
70558619b14SKalle Valo b43_block_read(dev, skb->data + padding, (len & ~3),
70658619b14SKalle Valo q->mmio_base + B43_PIO8_RXDATA,
70758619b14SKalle Valo sizeof(u32));
70858619b14SKalle Valo if (len & 3) {
70958619b14SKalle Valo u8 *tail = wl->pio_tailspace;
71058619b14SKalle Valo BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
71158619b14SKalle Valo
71258619b14SKalle Valo /* Read the last few bytes. */
71358619b14SKalle Valo b43_block_read(dev, tail, 4,
71458619b14SKalle Valo q->mmio_base + B43_PIO8_RXDATA,
71558619b14SKalle Valo sizeof(u32));
71658619b14SKalle Valo switch (len & 3) {
71758619b14SKalle Valo case 3:
71858619b14SKalle Valo skb->data[len + padding - 3] = tail[0];
71958619b14SKalle Valo skb->data[len + padding - 2] = tail[1];
72058619b14SKalle Valo skb->data[len + padding - 1] = tail[2];
72158619b14SKalle Valo break;
72258619b14SKalle Valo case 2:
72358619b14SKalle Valo skb->data[len + padding - 2] = tail[0];
72458619b14SKalle Valo skb->data[len + padding - 1] = tail[1];
72558619b14SKalle Valo break;
72658619b14SKalle Valo case 1:
72758619b14SKalle Valo skb->data[len + padding - 1] = tail[0];
72858619b14SKalle Valo break;
72958619b14SKalle Valo }
73058619b14SKalle Valo }
73158619b14SKalle Valo } else {
73258619b14SKalle Valo b43_block_read(dev, skb->data + padding, (len & ~1),
73358619b14SKalle Valo q->mmio_base + B43_PIO_RXDATA,
73458619b14SKalle Valo sizeof(u16));
73558619b14SKalle Valo if (len & 1) {
73658619b14SKalle Valo u8 *tail = wl->pio_tailspace;
73758619b14SKalle Valo BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
73858619b14SKalle Valo
73958619b14SKalle Valo /* Read the last byte. */
74058619b14SKalle Valo b43_block_read(dev, tail, 2,
74158619b14SKalle Valo q->mmio_base + B43_PIO_RXDATA,
74258619b14SKalle Valo sizeof(u16));
74358619b14SKalle Valo skb->data[len + padding - 1] = tail[0];
74458619b14SKalle Valo }
74558619b14SKalle Valo }
74658619b14SKalle Valo
74758619b14SKalle Valo b43_rx(q->dev, skb, rxhdr);
74858619b14SKalle Valo
74958619b14SKalle Valo return true;
75058619b14SKalle Valo
75158619b14SKalle Valo rx_error:
75258619b14SKalle Valo if (err_msg)
75358619b14SKalle Valo b43dbg(q->dev->wl, "PIO RX error: %s\n", err_msg);
75458619b14SKalle Valo if (q->rev >= 8)
75558619b14SKalle Valo b43_piorx_write32(q, B43_PIO8_RXCTL, B43_PIO8_RXCTL_DATARDY);
75658619b14SKalle Valo else
75758619b14SKalle Valo b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY);
75858619b14SKalle Valo
75958619b14SKalle Valo return true;
76058619b14SKalle Valo }
76158619b14SKalle Valo
b43_pio_rx(struct b43_pio_rxqueue * q)76258619b14SKalle Valo void b43_pio_rx(struct b43_pio_rxqueue *q)
76358619b14SKalle Valo {
76458619b14SKalle Valo unsigned int count = 0;
76558619b14SKalle Valo bool stop;
76658619b14SKalle Valo
76758619b14SKalle Valo while (1) {
768f8f24eceSJason Yan stop = !pio_rx_frame(q);
76958619b14SKalle Valo if (stop)
77058619b14SKalle Valo break;
77158619b14SKalle Valo cond_resched();
77258619b14SKalle Valo if (WARN_ON_ONCE(++count > 10000))
77358619b14SKalle Valo break;
77458619b14SKalle Valo }
77558619b14SKalle Valo }
77658619b14SKalle Valo
b43_pio_tx_suspend_queue(struct b43_pio_txqueue * q)77758619b14SKalle Valo static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q)
77858619b14SKalle Valo {
77958619b14SKalle Valo if (q->rev >= 8) {
78058619b14SKalle Valo b43_piotx_write32(q, B43_PIO8_TXCTL,
78158619b14SKalle Valo b43_piotx_read32(q, B43_PIO8_TXCTL)
78258619b14SKalle Valo | B43_PIO8_TXCTL_SUSPREQ);
78358619b14SKalle Valo } else {
78458619b14SKalle Valo b43_piotx_write16(q, B43_PIO_TXCTL,
78558619b14SKalle Valo b43_piotx_read16(q, B43_PIO_TXCTL)
78658619b14SKalle Valo | B43_PIO_TXCTL_SUSPREQ);
78758619b14SKalle Valo }
78858619b14SKalle Valo }
78958619b14SKalle Valo
b43_pio_tx_resume_queue(struct b43_pio_txqueue * q)79058619b14SKalle Valo static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q)
79158619b14SKalle Valo {
79258619b14SKalle Valo if (q->rev >= 8) {
79358619b14SKalle Valo b43_piotx_write32(q, B43_PIO8_TXCTL,
79458619b14SKalle Valo b43_piotx_read32(q, B43_PIO8_TXCTL)
79558619b14SKalle Valo & ~B43_PIO8_TXCTL_SUSPREQ);
79658619b14SKalle Valo } else {
79758619b14SKalle Valo b43_piotx_write16(q, B43_PIO_TXCTL,
79858619b14SKalle Valo b43_piotx_read16(q, B43_PIO_TXCTL)
79958619b14SKalle Valo & ~B43_PIO_TXCTL_SUSPREQ);
80058619b14SKalle Valo }
80158619b14SKalle Valo }
80258619b14SKalle Valo
b43_pio_tx_suspend(struct b43_wldev * dev)80358619b14SKalle Valo void b43_pio_tx_suspend(struct b43_wldev *dev)
80458619b14SKalle Valo {
80558619b14SKalle Valo b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
80658619b14SKalle Valo b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BK);
80758619b14SKalle Valo b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BE);
80858619b14SKalle Valo b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VI);
80958619b14SKalle Valo b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VO);
81058619b14SKalle Valo b43_pio_tx_suspend_queue(dev->pio.tx_queue_mcast);
81158619b14SKalle Valo }
81258619b14SKalle Valo
b43_pio_tx_resume(struct b43_wldev * dev)81358619b14SKalle Valo void b43_pio_tx_resume(struct b43_wldev *dev)
81458619b14SKalle Valo {
81558619b14SKalle Valo b43_pio_tx_resume_queue(dev->pio.tx_queue_mcast);
81658619b14SKalle Valo b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VO);
81758619b14SKalle Valo b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VI);
81858619b14SKalle Valo b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BE);
81958619b14SKalle Valo b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BK);
82058619b14SKalle Valo b43_power_saving_ctl_bits(dev, 0);
82158619b14SKalle Valo }
822