Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003 
0004   Broadcom B43legacy wireless driver
0005 
0006   PIO Transmission
0007 
0008   Copyright (c) 2005 Michael Buesch <m@bues.ch>
0009 
0010 
0011 */
0012 
0013 #include "b43legacy.h"
0014 #include "pio.h"
0015 #include "main.h"
0016 #include "xmit.h"
0017 
0018 #include <linux/delay.h>
0019 #include <linux/slab.h>
0020 
0021 
0022 static void tx_start(struct b43legacy_pioqueue *queue)
0023 {
0024     b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
0025                 B43legacy_PIO_TXCTL_INIT);
0026 }
0027 
0028 static void tx_octet(struct b43legacy_pioqueue *queue,
0029              u8 octet)
0030 {
0031     if (queue->need_workarounds) {
0032         b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
0033         b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
0034                     B43legacy_PIO_TXCTL_WRITELO);
0035     } else {
0036         b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
0037                     B43legacy_PIO_TXCTL_WRITELO);
0038         b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
0039     }
0040 }
0041 
0042 static u16 tx_get_next_word(const u8 *txhdr,
0043                 const u8 *packet,
0044                 size_t txhdr_size,
0045                 unsigned int *pos)
0046 {
0047     const u8 *source;
0048     unsigned int i = *pos;
0049     u16 ret;
0050 
0051     if (i < txhdr_size)
0052         source = txhdr;
0053     else {
0054         source = packet;
0055         i -= txhdr_size;
0056     }
0057     ret = le16_to_cpu(*((__le16 *)(source + i)));
0058     *pos += 2;
0059 
0060     return ret;
0061 }
0062 
0063 static void tx_data(struct b43legacy_pioqueue *queue,
0064             u8 *txhdr,
0065             const u8 *packet,
0066             unsigned int octets)
0067 {
0068     u16 data;
0069     unsigned int i = 0;
0070 
0071     if (queue->need_workarounds) {
0072         data = tx_get_next_word(txhdr, packet,
0073                     sizeof(struct b43legacy_txhdr_fw3), &i);
0074         b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
0075     }
0076     b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
0077                 B43legacy_PIO_TXCTL_WRITELO |
0078                 B43legacy_PIO_TXCTL_WRITEHI);
0079     while (i < octets - 1) {
0080         data = tx_get_next_word(txhdr, packet,
0081                     sizeof(struct b43legacy_txhdr_fw3), &i);
0082         b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
0083     }
0084     if (octets % 2)
0085         tx_octet(queue, packet[octets -
0086              sizeof(struct b43legacy_txhdr_fw3) - 1]);
0087 }
0088 
0089 static void tx_complete(struct b43legacy_pioqueue *queue,
0090             struct sk_buff *skb)
0091 {
0092     if (queue->need_workarounds) {
0093         b43legacy_pio_write(queue, B43legacy_PIO_TXDATA,
0094                     skb->data[skb->len - 1]);
0095         b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
0096                     B43legacy_PIO_TXCTL_WRITELO |
0097                     B43legacy_PIO_TXCTL_COMPLETE);
0098     } else
0099         b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
0100                     B43legacy_PIO_TXCTL_COMPLETE);
0101 }
0102 
0103 static u16 generate_cookie(struct b43legacy_pioqueue *queue,
0104                struct b43legacy_pio_txpacket *packet)
0105 {
0106     u16 cookie = 0x0000;
0107     int packetindex;
0108 
0109     /* We use the upper 4 bits for the PIO
0110      * controller ID and the lower 12 bits
0111      * for the packet index (in the cache).
0112      */
0113     switch (queue->mmio_base) {
0114     case B43legacy_MMIO_PIO1_BASE:
0115         break;
0116     case B43legacy_MMIO_PIO2_BASE:
0117         cookie = 0x1000;
0118         break;
0119     case B43legacy_MMIO_PIO3_BASE:
0120         cookie = 0x2000;
0121         break;
0122     case B43legacy_MMIO_PIO4_BASE:
0123         cookie = 0x3000;
0124         break;
0125     default:
0126         B43legacy_WARN_ON(1);
0127     }
0128     packetindex = pio_txpacket_getindex(packet);
0129     B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000));
0130     cookie |= (u16)packetindex;
0131 
0132     return cookie;
0133 }
0134 
0135 static
0136 struct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev,
0137                     u16 cookie,
0138                     struct b43legacy_pio_txpacket **packet)
0139 {
0140     struct b43legacy_pio *pio = &dev->pio;
0141     struct b43legacy_pioqueue *queue = NULL;
0142     int packetindex;
0143 
0144     switch (cookie & 0xF000) {
0145     case 0x0000:
0146         queue = pio->queue0;
0147         break;
0148     case 0x1000:
0149         queue = pio->queue1;
0150         break;
0151     case 0x2000:
0152         queue = pio->queue2;
0153         break;
0154     case 0x3000:
0155         queue = pio->queue3;
0156         break;
0157     default:
0158         B43legacy_WARN_ON(1);
0159     }
0160     packetindex = (cookie & 0x0FFF);
0161     B43legacy_WARN_ON(!(packetindex >= 0 && packetindex
0162               < B43legacy_PIO_MAXTXPACKETS));
0163     *packet = &(queue->tx_packets_cache[packetindex]);
0164 
0165     return queue;
0166 }
0167 
0168 union txhdr_union {
0169     struct b43legacy_txhdr_fw3 txhdr_fw3;
0170 };
0171 
0172 static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
0173                   struct sk_buff *skb,
0174                   struct b43legacy_pio_txpacket *packet,
0175                   size_t txhdr_size)
0176 {
0177     union txhdr_union txhdr_data;
0178     u8 *txhdr = NULL;
0179     unsigned int octets;
0180     int err;
0181 
0182     txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
0183 
0184     B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
0185     err = b43legacy_generate_txhdr(queue->dev,
0186                  txhdr, skb->data, skb->len,
0187                  IEEE80211_SKB_CB(skb),
0188                  generate_cookie(queue, packet));
0189     if (err)
0190         return err;
0191 
0192     tx_start(queue);
0193     octets = skb->len + txhdr_size;
0194     if (queue->need_workarounds)
0195         octets--;
0196     tx_data(queue, txhdr, (u8 *)skb->data, octets);
0197     tx_complete(queue, skb);
0198 
0199     return 0;
0200 }
0201 
0202 static void free_txpacket(struct b43legacy_pio_txpacket *packet,
0203               int irq_context)
0204 {
0205     struct b43legacy_pioqueue *queue = packet->queue;
0206 
0207     if (packet->skb) {
0208         if (irq_context)
0209             dev_kfree_skb_irq(packet->skb);
0210         else
0211             dev_kfree_skb(packet->skb);
0212     }
0213     list_move(&packet->list, &queue->txfree);
0214     queue->nr_txfree++;
0215 }
0216 
0217 static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
0218 {
0219     struct b43legacy_pioqueue *queue = packet->queue;
0220     struct sk_buff *skb = packet->skb;
0221     u16 octets;
0222     int err;
0223 
0224     octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
0225     if (queue->tx_devq_size < octets) {
0226         b43legacywarn(queue->dev->wl, "PIO queue too small. "
0227             "Dropping packet.\n");
0228         /* Drop it silently (return success) */
0229         free_txpacket(packet, 1);
0230         return 0;
0231     }
0232     B43legacy_WARN_ON(queue->tx_devq_packets >
0233               B43legacy_PIO_MAXTXDEVQPACKETS);
0234     B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
0235     /* Check if there is sufficient free space on the device
0236      * TX queue. If not, return and let the TX tasklet
0237      * retry later.
0238      */
0239     if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS)
0240         return -EBUSY;
0241     if (queue->tx_devq_used + octets > queue->tx_devq_size)
0242         return -EBUSY;
0243     /* Now poke the device. */
0244     err = pio_tx_write_fragment(queue, skb, packet,
0245                   sizeof(struct b43legacy_txhdr_fw3));
0246     if (unlikely(err == -ENOKEY)) {
0247         /* Drop this packet, as we don't have the encryption key
0248          * anymore and must not transmit it unencrypted. */
0249         free_txpacket(packet, 1);
0250         return 0;
0251     }
0252 
0253     /* Account for the packet size.
0254      * (We must not overflow the device TX queue)
0255      */
0256     queue->tx_devq_packets++;
0257     queue->tx_devq_used += octets;
0258 
0259     /* Transmission started, everything ok, move the
0260      * packet to the txrunning list.
0261      */
0262     list_move_tail(&packet->list, &queue->txrunning);
0263 
0264     return 0;
0265 }
0266 
0267 static void tx_tasklet(struct tasklet_struct *t)
0268 {
0269     struct b43legacy_pioqueue *queue = from_tasklet(queue, t, txtask);
0270     struct b43legacy_wldev *dev = queue->dev;
0271     unsigned long flags;
0272     struct b43legacy_pio_txpacket *packet, *tmp_packet;
0273     int err;
0274     u16 txctl;
0275 
0276     spin_lock_irqsave(&dev->wl->irq_lock, flags);
0277     if (queue->tx_frozen)
0278         goto out_unlock;
0279     txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL);
0280     if (txctl & B43legacy_PIO_TXCTL_SUSPEND)
0281         goto out_unlock;
0282 
0283     list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
0284         /* Try to transmit the packet. This can fail, if
0285          * the device queue is full. In case of failure, the
0286          * packet is left in the txqueue.
0287          * If transmission succeed, the packet is moved to txrunning.
0288          * If it is impossible to transmit the packet, it
0289          * is dropped.
0290          */
0291         err = pio_tx_packet(packet);
0292         if (err)
0293             break;
0294     }
0295 out_unlock:
0296     spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
0297 }
0298 
0299 static void setup_txqueues(struct b43legacy_pioqueue *queue)
0300 {
0301     struct b43legacy_pio_txpacket *packet;
0302     int i;
0303 
0304     queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS;
0305     for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) {
0306         packet = &(queue->tx_packets_cache[i]);
0307 
0308         packet->queue = queue;
0309         INIT_LIST_HEAD(&packet->list);
0310 
0311         list_add(&packet->list, &queue->txfree);
0312     }
0313 }
0314 
0315 static
0316 struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
0317                             u16 pio_mmio_base)
0318 {
0319     struct b43legacy_pioqueue *queue;
0320     u32 value;
0321     u16 qsize;
0322 
0323     queue = kzalloc(sizeof(*queue), GFP_KERNEL);
0324     if (!queue)
0325         goto out;
0326 
0327     queue->dev = dev;
0328     queue->mmio_base = pio_mmio_base;
0329     queue->need_workarounds = (dev->dev->id.revision < 3);
0330 
0331     INIT_LIST_HEAD(&queue->txfree);
0332     INIT_LIST_HEAD(&queue->txqueue);
0333     INIT_LIST_HEAD(&queue->txrunning);
0334     tasklet_setup(&queue->txtask, tx_tasklet);
0335 
0336     value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
0337     value &= ~B43legacy_MACCTL_BE;
0338     b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value);
0339 
0340     qsize = b43legacy_read16(dev, queue->mmio_base
0341                  + B43legacy_PIO_TXQBUFSIZE);
0342     if (qsize == 0) {
0343         b43legacyerr(dev->wl, "This card does not support PIO "
0344                "operation mode. Please use DMA mode "
0345                "(module parameter pio=0).\n");
0346         goto err_freequeue;
0347     }
0348     if (qsize <= B43legacy_PIO_TXQADJUST) {
0349         b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n",
0350                qsize);
0351         goto err_freequeue;
0352     }
0353     qsize -= B43legacy_PIO_TXQADJUST;
0354     queue->tx_devq_size = qsize;
0355 
0356     setup_txqueues(queue);
0357 
0358 out:
0359     return queue;
0360 
0361 err_freequeue:
0362     kfree(queue);
0363     queue = NULL;
0364     goto out;
0365 }
0366 
0367 static void cancel_transfers(struct b43legacy_pioqueue *queue)
0368 {
0369     struct b43legacy_pio_txpacket *packet, *tmp_packet;
0370 
0371     tasklet_kill(&queue->txtask);
0372 
0373     list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
0374         free_txpacket(packet, 0);
0375     list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
0376         free_txpacket(packet, 0);
0377 }
0378 
0379 static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue)
0380 {
0381     if (!queue)
0382         return;
0383 
0384     cancel_transfers(queue);
0385     kfree(queue);
0386 }
0387 
0388 void b43legacy_pio_free(struct b43legacy_wldev *dev)
0389 {
0390     struct b43legacy_pio *pio;
0391 
0392     if (!b43legacy_using_pio(dev))
0393         return;
0394     pio = &dev->pio;
0395 
0396     b43legacy_destroy_pioqueue(pio->queue3);
0397     pio->queue3 = NULL;
0398     b43legacy_destroy_pioqueue(pio->queue2);
0399     pio->queue2 = NULL;
0400     b43legacy_destroy_pioqueue(pio->queue1);
0401     pio->queue1 = NULL;
0402     b43legacy_destroy_pioqueue(pio->queue0);
0403     pio->queue0 = NULL;
0404 }
0405 
0406 int b43legacy_pio_init(struct b43legacy_wldev *dev)
0407 {
0408     struct b43legacy_pio *pio = &dev->pio;
0409     struct b43legacy_pioqueue *queue;
0410     int err = -ENOMEM;
0411 
0412     queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE);
0413     if (!queue)
0414         goto out;
0415     pio->queue0 = queue;
0416 
0417     queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE);
0418     if (!queue)
0419         goto err_destroy0;
0420     pio->queue1 = queue;
0421 
0422     queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE);
0423     if (!queue)
0424         goto err_destroy1;
0425     pio->queue2 = queue;
0426 
0427     queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE);
0428     if (!queue)
0429         goto err_destroy2;
0430     pio->queue3 = queue;
0431 
0432     if (dev->dev->id.revision < 3)
0433         dev->irq_mask |= B43legacy_IRQ_PIO_WORKAROUND;
0434 
0435     b43legacydbg(dev->wl, "PIO initialized\n");
0436     err = 0;
0437 out:
0438     return err;
0439 
0440 err_destroy2:
0441     b43legacy_destroy_pioqueue(pio->queue2);
0442     pio->queue2 = NULL;
0443 err_destroy1:
0444     b43legacy_destroy_pioqueue(pio->queue1);
0445     pio->queue1 = NULL;
0446 err_destroy0:
0447     b43legacy_destroy_pioqueue(pio->queue0);
0448     pio->queue0 = NULL;
0449     goto out;
0450 }
0451 
0452 int b43legacy_pio_tx(struct b43legacy_wldev *dev,
0453              struct sk_buff *skb)
0454 {
0455     struct b43legacy_pioqueue *queue = dev->pio.queue1;
0456     struct b43legacy_pio_txpacket *packet;
0457 
0458     B43legacy_WARN_ON(queue->tx_suspended);
0459     B43legacy_WARN_ON(list_empty(&queue->txfree));
0460 
0461     packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket,
0462                 list);
0463     packet->skb = skb;
0464 
0465     list_move_tail(&packet->list, &queue->txqueue);
0466     queue->nr_txfree--;
0467     B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
0468 
0469     tasklet_schedule(&queue->txtask);
0470 
0471     return 0;
0472 }
0473 
0474 void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
0475                    const struct b43legacy_txstatus *status)
0476 {
0477     struct b43legacy_pioqueue *queue;
0478     struct b43legacy_pio_txpacket *packet;
0479     struct ieee80211_tx_info *info;
0480     int retry_limit;
0481 
0482     queue = parse_cookie(dev, status->cookie, &packet);
0483     B43legacy_WARN_ON(!queue);
0484 
0485     if (!packet->skb)
0486         return;
0487 
0488     queue->tx_devq_packets--;
0489     queue->tx_devq_used -= (packet->skb->len +
0490                 sizeof(struct b43legacy_txhdr_fw3));
0491 
0492     info = IEEE80211_SKB_CB(packet->skb);
0493 
0494     /* preserve the confiured retry limit before clearing the status
0495      * The xmit function has overwritten the rc's value with the actual
0496      * retry limit done by the hardware */
0497     retry_limit = info->status.rates[0].count;
0498     ieee80211_tx_info_clear_status(info);
0499 
0500     if (status->acked)
0501         info->flags |= IEEE80211_TX_STAT_ACK;
0502 
0503     if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
0504         /*
0505          * If the short retries (RTS, not data frame) have exceeded
0506          * the limit, the hw will not have tried the selected rate,
0507          * but will have used the fallback rate instead.
0508          * Don't let the rate control count attempts for the selected
0509          * rate in this case, otherwise the statistics will be off.
0510          */
0511         info->status.rates[0].count = 0;
0512         info->status.rates[1].count = status->frame_count;
0513     } else {
0514         if (status->frame_count > retry_limit) {
0515             info->status.rates[0].count = retry_limit;
0516             info->status.rates[1].count = status->frame_count -
0517                     retry_limit;
0518 
0519         } else {
0520             info->status.rates[0].count = status->frame_count;
0521             info->status.rates[1].idx = -1;
0522         }
0523     }
0524     ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
0525     packet->skb = NULL;
0526 
0527     free_txpacket(packet, 1);
0528     /* If there are packets on the txqueue, poke the tasklet
0529      * to transmit them.
0530      */
0531     if (!list_empty(&queue->txqueue))
0532         tasklet_schedule(&queue->txtask);
0533 }
0534 
0535 static void pio_rx_error(struct b43legacy_pioqueue *queue,
0536              int clear_buffers,
0537              const char *error)
0538 {
0539     int i;
0540 
0541     b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error);
0542     b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
0543                 B43legacy_PIO_RXCTL_READY);
0544     if (clear_buffers) {
0545         B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE);
0546         for (i = 0; i < 15; i++) {
0547             /* Dummy read. */
0548             b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
0549         }
0550     }
0551 }
0552 
0553 void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
0554 {
0555     __le16 preamble[21] = { 0 };
0556     struct b43legacy_rxhdr_fw3 *rxhdr;
0557     u16 tmp;
0558     u16 len;
0559     u16 macstat;
0560     int i;
0561     int preamble_readwords;
0562     struct sk_buff *skb;
0563 
0564     tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
0565     if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE))
0566         return;
0567     b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
0568                 B43legacy_PIO_RXCTL_DATAAVAILABLE);
0569 
0570     for (i = 0; i < 10; i++) {
0571         tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
0572         if (tmp & B43legacy_PIO_RXCTL_READY)
0573             goto data_ready;
0574         udelay(10);
0575     }
0576     b43legacydbg(queue->dev->wl, "PIO RX timed out\n");
0577     return;
0578 data_ready:
0579 
0580     len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
0581     if (unlikely(len > 0x700)) {
0582         pio_rx_error(queue, 0, "len > 0x700");
0583         return;
0584     }
0585     if (unlikely(len == 0 && queue->mmio_base !=
0586              B43legacy_MMIO_PIO4_BASE)) {
0587         pio_rx_error(queue, 0, "len == 0");
0588         return;
0589     }
0590     preamble[0] = cpu_to_le16(len);
0591     if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE)
0592         preamble_readwords = 14 / sizeof(u16);
0593     else
0594         preamble_readwords = 18 / sizeof(u16);
0595     for (i = 0; i < preamble_readwords; i++) {
0596         tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
0597         preamble[i + 1] = cpu_to_le16(tmp);
0598     }
0599     rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble;
0600     macstat = le16_to_cpu(rxhdr->mac_status);
0601     if (macstat & B43legacy_RX_MAC_FCSERR) {
0602         pio_rx_error(queue,
0603                  (queue->mmio_base == B43legacy_MMIO_PIO1_BASE),
0604                  "Frame FCS error");
0605         return;
0606     }
0607     if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) {
0608         /* We received an xmit status. */
0609         struct b43legacy_hwtxstatus *hw;
0610 
0611         hw = (struct b43legacy_hwtxstatus *)(preamble + 1);
0612         b43legacy_handle_hwtxstatus(queue->dev, hw);
0613 
0614         return;
0615     }
0616 
0617     skb = dev_alloc_skb(len);
0618     if (unlikely(!skb)) {
0619         pio_rx_error(queue, 1, "OOM");
0620         return;
0621     }
0622     skb_put(skb, len);
0623     for (i = 0; i < len - 1; i += 2) {
0624         tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
0625         *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
0626     }
0627     if (len % 2) {
0628         tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
0629         skb->data[len - 1] = (tmp & 0x00FF);
0630     }
0631     b43legacy_rx(queue->dev, skb, rxhdr);
0632 }
0633 
0634 void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
0635 {
0636     b43legacy_power_saving_ctl_bits(queue->dev, -1, 1);
0637     b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
0638                 b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
0639                 | B43legacy_PIO_TXCTL_SUSPEND);
0640 }
0641 
0642 void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
0643 {
0644     b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
0645                 b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
0646                 & ~B43legacy_PIO_TXCTL_SUSPEND);
0647     b43legacy_power_saving_ctl_bits(queue->dev, -1, -1);
0648     tasklet_schedule(&queue->txtask);
0649 }
0650 
0651 void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
0652 {
0653     struct b43legacy_pio *pio;
0654 
0655     B43legacy_WARN_ON(!b43legacy_using_pio(dev));
0656     pio = &dev->pio;
0657     pio->queue0->tx_frozen = 1;
0658     pio->queue1->tx_frozen = 1;
0659     pio->queue2->tx_frozen = 1;
0660     pio->queue3->tx_frozen = 1;
0661 }
0662 
0663 void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
0664 {
0665     struct b43legacy_pio *pio;
0666 
0667     B43legacy_WARN_ON(!b43legacy_using_pio(dev));
0668     pio = &dev->pio;
0669     pio->queue0->tx_frozen = 0;
0670     pio->queue1->tx_frozen = 0;
0671     pio->queue2->tx_frozen = 0;
0672     pio->queue3->tx_frozen = 0;
0673     if (!list_empty(&pio->queue0->txqueue))
0674         tasklet_schedule(&pio->queue0->txtask);
0675     if (!list_empty(&pio->queue1->txqueue))
0676         tasklet_schedule(&pio->queue1->txtask);
0677     if (!list_empty(&pio->queue2->txqueue))
0678         tasklet_schedule(&pio->queue2->txtask);
0679     if (!list_empty(&pio->queue3->txqueue))
0680         tasklet_schedule(&pio->queue3->txtask);
0681 }