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 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 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 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 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 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 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 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 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 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 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 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 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. */ 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); 29758619b14SKalle Valo /* 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 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 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 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 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 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 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; 52858619b14SKalle Valo ieee80211_stop_queue(dev->wl->hw, 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. */ 55558619b14SKalle Valo ieee80211_stop_queue(dev->wl->hw, 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 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 58558619b14SKalle Valo ieee80211_tx_status(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) { 59058619b14SKalle Valo ieee80211_wake_queue(dev->wl->hw, q->queue_prio); 59158619b14SKalle Valo q->stopped = false; 59258619b14SKalle Valo } 59358619b14SKalle Valo } 59458619b14SKalle Valo 59558619b14SKalle Valo /* Returns whether we should fetch another frame. */ 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 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) { 768*f8f24eceSJason 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 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 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 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 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