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