175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger/*
275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Broadcom B43legacy wireless driver
475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  PIO Transmission
675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
7eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch  Copyright (c) 2005 Michael Buesch <m@bues.ch>
875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  This program is free software; you can redistribute it and/or modify
1075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  it under the terms of the GNU General Public License as published by
1175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  the Free Software Foundation; either version 2 of the License, or
1275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  (at your option) any later version.
1375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
1475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  This program is distributed in the hope that it will be useful,
1575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  but WITHOUT ANY WARRANTY; without even the implied warranty of
1675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  GNU General Public License for more details.
1875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
1975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  You should have received a copy of the GNU General Public License
2075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  along with this program; see the file COPYING.  If not, write to
2175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
2275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger  Boston, MA 02110-1301, USA.
2375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
2475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger*/
2575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
2675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include "b43legacy.h"
2775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include "pio.h"
2875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include "main.h"
2975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include "xmit.h"
3075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
3175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger#include <linux/delay.h>
325a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
3375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
3475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
3575388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void tx_start(struct b43legacy_pioqueue *queue)
3675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
3775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
3875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    B43legacy_PIO_TXCTL_INIT);
3975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
4075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
4175388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void tx_octet(struct b43legacy_pioqueue *queue,
4275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		     u8 octet)
4375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
4475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->need_workarounds) {
4575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
4675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
4775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    B43legacy_PIO_TXCTL_WRITELO);
4875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	} else {
4975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
5075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    B43legacy_PIO_TXCTL_WRITELO);
5175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
5275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
5375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
5475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
5575388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic u16 tx_get_next_word(const u8 *txhdr,
5675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    const u8 *packet,
5775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    size_t txhdr_size,
5875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    unsigned int *pos)
5975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
6075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	const u8 *source;
6175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	unsigned int i = *pos;
6275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 ret;
6375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
6475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (i < txhdr_size)
6575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		source = txhdr;
6675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	else {
6775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		source = packet;
6875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		i -= txhdr_size;
6975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
7075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	ret = le16_to_cpu(*((__le16 *)(source + i)));
7175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	*pos += 2;
7275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
7375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return ret;
7475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
7575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
7675388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void tx_data(struct b43legacy_pioqueue *queue,
7775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		    u8 *txhdr,
7875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		    const u8 *packet,
7975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		    unsigned int octets)
8075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
8175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 data;
8275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	unsigned int i = 0;
8375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
8475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->need_workarounds) {
8575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		data = tx_get_next_word(txhdr, packet,
8675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					sizeof(struct b43legacy_txhdr_fw3), &i);
8775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
8875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
8975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
9075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    B43legacy_PIO_TXCTL_WRITELO |
9175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    B43legacy_PIO_TXCTL_WRITEHI);
9275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	while (i < octets - 1) {
9375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		data = tx_get_next_word(txhdr, packet,
9475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					sizeof(struct b43legacy_txhdr_fw3), &i);
9575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
9675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
9775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (octets % 2)
9875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tx_octet(queue, packet[octets -
9975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			 sizeof(struct b43legacy_txhdr_fw3) - 1]);
10075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
10175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
10275388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void tx_complete(struct b43legacy_pioqueue *queue,
10375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			struct sk_buff *skb)
10475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
10575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->need_workarounds) {
10675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA,
10775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    skb->data[skb->len - 1]);
10875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
10975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    B43legacy_PIO_TXCTL_WRITELO |
11075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    B43legacy_PIO_TXCTL_COMPLETE);
11175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	} else
11275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
11375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				    B43legacy_PIO_TXCTL_COMPLETE);
11475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
11575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
11675388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic u16 generate_cookie(struct b43legacy_pioqueue *queue,
11775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			   struct b43legacy_pio_txpacket *packet)
11875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
11975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 cookie = 0x0000;
12075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int packetindex;
12175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
12275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* We use the upper 4 bits for the PIO
12375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 * controller ID and the lower 12 bits
12475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 * for the packet index (in the cache).
12575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 */
12675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (queue->mmio_base) {
12775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_MMIO_PIO1_BASE:
12875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
12975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_MMIO_PIO2_BASE:
13075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		cookie = 0x1000;
13175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
13275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_MMIO_PIO3_BASE:
13375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		cookie = 0x2000;
13475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
13575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case B43legacy_MMIO_PIO4_BASE:
13675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		cookie = 0x3000;
13775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
13875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	default:
13975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		B43legacy_WARN_ON(1);
14075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
14175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	packetindex = pio_txpacket_getindex(packet);
14275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000));
14375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	cookie |= (u16)packetindex;
14475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
14575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return cookie;
14675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
14775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
14875388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic
14975388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstruct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev,
15075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					u16 cookie,
15175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger					struct b43legacy_pio_txpacket **packet)
15275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
15375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio *pio = &dev->pio;
15475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pioqueue *queue = NULL;
15575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int packetindex;
15675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
15775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	switch (cookie & 0xF000) {
15875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x0000:
15975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		queue = pio->queue0;
16075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
16175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x1000:
16275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		queue = pio->queue1;
16375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
16475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x2000:
16575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		queue = pio->queue2;
16675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
16775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	case 0x3000:
16875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		queue = pio->queue3;
16975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		break;
17075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	default:
17175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		B43legacy_WARN_ON(1);
17275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
17375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	packetindex = (cookie & 0x0FFF);
17475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(!(packetindex >= 0 && packetindex
17575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			  < B43legacy_PIO_MAXTXPACKETS));
17675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	*packet = &(queue->tx_packets_cache[packetindex]);
17775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
17875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return queue;
17975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
18075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
18175388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerunion txhdr_union {
18275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_txhdr_fw3 txhdr_fw3;
18375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger};
18475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
1859eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Briviostatic int pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
18675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				  struct sk_buff *skb,
18775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				  struct b43legacy_pio_txpacket *packet,
18875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				  size_t txhdr_size)
18975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
19075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	union txhdr_union txhdr_data;
19175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u8 *txhdr = NULL;
19275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	unsigned int octets;
1939eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio	int err;
19475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
19575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
19675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
19775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
1989eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio	err = b43legacy_generate_txhdr(queue->dev,
19975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				 txhdr, skb->data, skb->len,
200e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg				 IEEE80211_SKB_CB(skb),
20175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				 generate_cookie(queue, packet));
2029eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio	if (err)
2039eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio		return err;
20475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
20575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tx_start(queue);
20675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	octets = skb->len + txhdr_size;
20775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->need_workarounds)
20875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		octets--;
20975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tx_data(queue, txhdr, (u8 *)skb->data, octets);
21075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tx_complete(queue, skb);
2119eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio
2129eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio	return 0;
21375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
21475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
21575388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void free_txpacket(struct b43legacy_pio_txpacket *packet,
21675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			  int irq_context)
21775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
21875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pioqueue *queue = packet->queue;
21975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
22075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (packet->skb) {
22175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (irq_context)
22275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			dev_kfree_skb_irq(packet->skb);
22375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		else
22475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			dev_kfree_skb(packet->skb);
22575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
22675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	list_move(&packet->list, &queue->txfree);
22775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->nr_txfree++;
22875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
22975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
23075388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
23175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
23275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pioqueue *queue = packet->queue;
23375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct sk_buff *skb = packet->skb;
23475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 octets;
2359eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio	int err;
23675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
23775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
23875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->tx_devq_size < octets) {
23975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacywarn(queue->dev->wl, "PIO queue too small. "
24075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			"Dropping packet.\n");
24175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		/* Drop it silently (return success) */
24275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		free_txpacket(packet, 1);
24375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return 0;
24475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
24575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(queue->tx_devq_packets >
24675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			  B43legacy_PIO_MAXTXDEVQPACKETS);
24775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
24875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Check if there is sufficient free space on the device
24975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 * TX queue. If not, return and let the TX tasklet
25075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 * retry later.
25175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 */
25275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS)
25375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return -EBUSY;
25475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->tx_devq_used + octets > queue->tx_devq_size)
25575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return -EBUSY;
25675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Now poke the device. */
2579eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio	err = pio_tx_write_fragment(queue, skb, packet,
25875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			      sizeof(struct b43legacy_txhdr_fw3));
2599eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio	if (unlikely(err == -ENOKEY)) {
2609eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio		/* Drop this packet, as we don't have the encryption key
2619eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio		 * anymore and must not transmit it unencrypted. */
2629eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio		free_txpacket(packet, 1);
2639eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio		return 0;
2649eca9a8e81928685b4de00ecef83a7c13c340fc9Stefano Brivio	}
26575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
26675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Account for the packet size.
26775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 * (We must not overflow the device TX queue)
26875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 */
26975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->tx_devq_packets++;
27075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->tx_devq_used += octets;
27175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
27275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* Transmission started, everything ok, move the
27375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 * packet to the txrunning list.
27475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 */
27575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	list_move_tail(&packet->list, &queue->txrunning);
27675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
27775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return 0;
27875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
27975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
28075388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void tx_tasklet(unsigned long d)
28175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
28275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pioqueue *queue = (struct b43legacy_pioqueue *)d;
28375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_wldev *dev = queue->dev;
28475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	unsigned long flags;
28575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio_txpacket *packet, *tmp_packet;
28675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int err;
28775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 txctl;
28875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
28975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	spin_lock_irqsave(&dev->wl->irq_lock, flags);
29075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->tx_frozen)
29175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto out_unlock;
29275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL);
29375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (txctl & B43legacy_PIO_TXCTL_SUSPEND)
29475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto out_unlock;
29575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
29675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
29775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		/* Try to transmit the packet. This can fail, if
29875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 * the device queue is full. In case of failure, the
29975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 * packet is left in the txqueue.
30075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 * If transmission succeed, the packet is moved to txrunning.
30175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 * If it is impossible to transmit the packet, it
30275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 * is dropped.
30375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		 */
30475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		err = pio_tx_packet(packet);
30575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (err)
30675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			break;
30775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
30875388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerout_unlock:
30975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
31075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
31175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
31275388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void setup_txqueues(struct b43legacy_pioqueue *queue)
31375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
31475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio_txpacket *packet;
31575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int i;
31675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
31775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS;
31875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) {
31975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		packet = &(queue->tx_packets_cache[i]);
32075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
32175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		packet->queue = queue;
32275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		INIT_LIST_HEAD(&packet->list);
32375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
32475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		list_add(&packet->list, &queue->txfree);
32575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
32675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
32775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
32875388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic
32975388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstruct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
33075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger						    u16 pio_mmio_base)
33175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
33275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pioqueue *queue;
33375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u32 value;
33475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 qsize;
33575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
33675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
33775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!queue)
33875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto out;
33975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
34075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->dev = dev;
34175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->mmio_base = pio_mmio_base;
34275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->need_workarounds = (dev->dev->id.revision < 3);
34375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
34475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	INIT_LIST_HEAD(&queue->txfree);
34575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	INIT_LIST_HEAD(&queue->txqueue);
34675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	INIT_LIST_HEAD(&queue->txrunning);
34775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tasklet_init(&queue->txtask, tx_tasklet,
34875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		     (unsigned long)queue);
34975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
350e78c9d285709f535caae405f1da5b2936f51f0b5Stefano Brivio	value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
351e78c9d285709f535caae405f1da5b2936f51f0b5Stefano Brivio	value &= ~B43legacy_MACCTL_BE;
352e78c9d285709f535caae405f1da5b2936f51f0b5Stefano Brivio	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value);
35375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
35475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	qsize = b43legacy_read16(dev, queue->mmio_base
35575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				 + B43legacy_PIO_TXQBUFSIZE);
35675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (qsize == 0) {
35775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacyerr(dev->wl, "This card does not support PIO "
35875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		       "operation mode. Please use DMA mode "
35975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		       "(module parameter pio=0).\n");
36075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto err_freequeue;
36175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
36275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (qsize <= B43legacy_PIO_TXQADJUST) {
36375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n",
36475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		       qsize);
36575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto err_freequeue;
36675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
36775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	qsize -= B43legacy_PIO_TXQADJUST;
36875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->tx_devq_size = qsize;
36975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
37075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	setup_txqueues(queue);
37175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
37275388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerout:
37375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return queue;
37475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
37575388acd0cd827dc1498043daa7d1c760902cd67Larry Fingererr_freequeue:
37675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	kfree(queue);
37775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue = NULL;
37875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	goto out;
37975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
38075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
38175388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void cancel_transfers(struct b43legacy_pioqueue *queue)
38275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
38375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio_txpacket *packet, *tmp_packet;
38475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
38575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tasklet_disable(&queue->txtask);
38675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
38775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
38875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		free_txpacket(packet, 0);
38975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
39075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		free_txpacket(packet, 0);
39175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
39275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
39375388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue)
39475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
39575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!queue)
39675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
39775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
39875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	cancel_transfers(queue);
39975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	kfree(queue);
40075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
40175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
40275388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_pio_free(struct b43legacy_wldev *dev)
40375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
40475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio *pio;
40575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
40675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!b43legacy_using_pio(dev))
40775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
40875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio = &dev->pio;
40975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
41075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_destroy_pioqueue(pio->queue3);
41175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue3 = NULL;
41275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_destroy_pioqueue(pio->queue2);
41375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue2 = NULL;
41475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_destroy_pioqueue(pio->queue1);
41575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue1 = NULL;
41675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_destroy_pioqueue(pio->queue0);
41775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue0 = NULL;
41875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
41975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
42075388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerint b43legacy_pio_init(struct b43legacy_wldev *dev)
42175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
42275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio *pio = &dev->pio;
42375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pioqueue *queue;
42475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int err = -ENOMEM;
42575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
42675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE);
42775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!queue)
42875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto out;
42975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue0 = queue;
43075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
43175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE);
43275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!queue)
43375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto err_destroy0;
43475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue1 = queue;
43575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
43675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE);
43775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!queue)
43875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto err_destroy1;
43975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue2 = queue;
44075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
44175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE);
44275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!queue)
44375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		goto err_destroy2;
44475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue3 = queue;
44575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
44675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (dev->dev->id.revision < 3)
44744710bbc073b2e7ea269cf716b817297cd35ae10Stefano Brivio		dev->irq_mask |= B43legacy_IRQ_PIO_WORKAROUND;
44875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
44975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacydbg(dev->wl, "PIO initialized\n");
45075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	err = 0;
45175388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerout:
45275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return err;
45375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
45475388acd0cd827dc1498043daa7d1c760902cd67Larry Fingererr_destroy2:
45575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_destroy_pioqueue(pio->queue2);
45675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue2 = NULL;
45775388acd0cd827dc1498043daa7d1c760902cd67Larry Fingererr_destroy1:
45875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_destroy_pioqueue(pio->queue1);
45975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue1 = NULL;
46075388acd0cd827dc1498043daa7d1c760902cd67Larry Fingererr_destroy0:
46175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_destroy_pioqueue(pio->queue0);
46275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue0 = NULL;
46375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	goto out;
46475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
46575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
46675388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerint b43legacy_pio_tx(struct b43legacy_wldev *dev,
467e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg		     struct sk_buff *skb)
46875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
46975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pioqueue *queue = dev->pio.queue1;
47075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio_txpacket *packet;
47175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
47275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(queue->tx_suspended);
47375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(list_empty(&queue->txfree));
47475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
47575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket,
47675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    list);
47775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	packet->skb = skb;
47875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
47975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	list_move_tail(&packet->list, &queue->txqueue);
48075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->nr_txfree--;
48175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
48275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
48375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tasklet_schedule(&queue->txtask);
48475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
48575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return 0;
48675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
48775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
48875388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
48975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				   const struct b43legacy_txstatus *status)
49075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
49175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pioqueue *queue;
49275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio_txpacket *packet;
493e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	struct ieee80211_tx_info *info;
494e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	int retry_limit;
49575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
49675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue = parse_cookie(dev, status->cookie, &packet);
49775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(!queue);
49875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
4990cd67d48b519c3d8d89d238fab1cf68a5289638aStefano Brivio	if (!packet->skb)
5000cd67d48b519c3d8d89d238fab1cf68a5289638aStefano Brivio		return;
5010cd67d48b519c3d8d89d238fab1cf68a5289638aStefano Brivio
50275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->tx_devq_packets--;
50375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	queue->tx_devq_used -= (packet->skb->len +
50475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger				sizeof(struct b43legacy_txhdr_fw3));
50575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
506e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	info = IEEE80211_SKB_CB(packet->skb);
507e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg
508e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	/* preserve the confiured retry limit before clearing the status
509e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	 * The xmit function has overwritten the rc's value with the actual
510e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	 * retry limit done by the hardware */
511e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	retry_limit = info->status.rates[0].count;
512e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	ieee80211_tx_info_clear_status(info);
513e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg
51475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (status->acked)
515e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg		info->flags |= IEEE80211_TX_STAT_ACK;
516e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg
517e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
518e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		/*
519e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		 * If the short retries (RTS, not data frame) have exceeded
520e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		 * the limit, the hw will not have tried the selected rate,
521e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		 * but will have used the fallback rate instead.
522e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		 * Don't let the rate control count attempts for the selected
523e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		 * rate in this case, otherwise the statistics will be off.
524e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		 */
525e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		info->status.rates[0].count = 0;
526e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		info->status.rates[1].count = status->frame_count;
527e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	} else {
528e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		if (status->frame_count > retry_limit) {
529e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg			info->status.rates[0].count = retry_limit;
530e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg			info->status.rates[1].count = status->frame_count -
531e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg					retry_limit;
532e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg
533e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		} else {
534e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg			info->status.rates[0].count = status->frame_count;
535e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg			info->status.rates[1].idx = -1;
536e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg		}
537e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	}
538e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
53975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	packet->skb = NULL;
54075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
54175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	free_txpacket(packet, 1);
54275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	/* If there are packets on the txqueue, poke the tasklet
54375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 * to transmit them.
54475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	 */
54575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!list_empty(&queue->txqueue))
54675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tasklet_schedule(&queue->txtask);
54775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
54875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
54975388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerstatic void pio_rx_error(struct b43legacy_pioqueue *queue,
55075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			 int clear_buffers,
55175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			 const char *error)
55275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
55375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int i;
55475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
55575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error);
55675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
55775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    B43legacy_PIO_RXCTL_READY);
55875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (clear_buffers) {
55975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE);
56075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		for (i = 0; i < 15; i++) {
56175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			/* Dummy read. */
56275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
56375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		}
56475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
56575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
56675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
56775388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
56875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
56975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	__le16 preamble[21] = { 0 };
57075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_rxhdr_fw3 *rxhdr;
57175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 tmp;
57275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 len;
57375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	u16 macstat;
57475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int i;
57575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	int preamble_readwords;
57675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct sk_buff *skb;
57775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
57875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
57975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE))
58075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
58175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
58275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    B43legacy_PIO_RXCTL_DATAAVAILABLE);
58375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
58475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	for (i = 0; i < 10; i++) {
58575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
58675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		if (tmp & B43legacy_PIO_RXCTL_READY)
58775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			goto data_ready;
58875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		udelay(10);
58975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
59075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacydbg(queue->dev->wl, "PIO RX timed out\n");
59175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	return;
59275388acd0cd827dc1498043daa7d1c760902cd67Larry Fingerdata_ready:
59375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
59475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
59575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (unlikely(len > 0x700)) {
59675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		pio_rx_error(queue, 0, "len > 0x700");
59775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
59875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
59975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (unlikely(len == 0 && queue->mmio_base !=
60075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		     B43legacy_MMIO_PIO4_BASE)) {
60175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		pio_rx_error(queue, 0, "len == 0");
60275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
60375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
60475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	preamble[0] = cpu_to_le16(len);
60575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE)
60675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		preamble_readwords = 14 / sizeof(u16);
60775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	else
60875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		preamble_readwords = 18 / sizeof(u16);
60975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	for (i = 0; i < preamble_readwords; i++) {
61075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
61175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		preamble[i + 1] = cpu_to_le16(tmp);
61275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
61375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble;
61475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	macstat = le16_to_cpu(rxhdr->mac_status);
61575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (macstat & B43legacy_RX_MAC_FCSERR) {
61675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		pio_rx_error(queue,
61775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			     (queue->mmio_base == B43legacy_MMIO_PIO1_BASE),
61875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			     "Frame FCS error");
61975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
62075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
62175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) {
62275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		/* We received an xmit status. */
62375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		struct b43legacy_hwtxstatus *hw;
62475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
62575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		hw = (struct b43legacy_hwtxstatus *)(preamble + 1);
62675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		b43legacy_handle_hwtxstatus(queue->dev, hw);
62775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
62875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
62975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
63075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
63175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	skb = dev_alloc_skb(len);
63275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (unlikely(!skb)) {
63375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		pio_rx_error(queue, 1, "OOM");
63475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		return;
63575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
63675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	skb_put(skb, len);
63775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	for (i = 0; i < len - 1; i += 2) {
63875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
63975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		*((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
64075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
64175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (len % 2) {
64275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
64375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		skb->data[len - 1] = (tmp & 0x00FF);
64475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	}
64575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_rx(queue->dev, skb, rxhdr);
64675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
64775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
64875388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
64975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
65075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_power_saving_ctl_bits(queue->dev, -1, 1);
65175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
65275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
65375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    | B43legacy_PIO_TXCTL_SUSPEND);
65475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
65575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
65675388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
65775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
65875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
65975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
66075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger			    & ~B43legacy_PIO_TXCTL_SUSPEND);
66175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	b43legacy_power_saving_ctl_bits(queue->dev, -1, -1);
66275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	tasklet_schedule(&queue->txtask);
66375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
66475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
66575388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
66675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
66775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio *pio;
66875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
66975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(!b43legacy_using_pio(dev));
67075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio = &dev->pio;
67175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue0->tx_frozen = 1;
67275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue1->tx_frozen = 1;
67375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue2->tx_frozen = 1;
67475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue3->tx_frozen = 1;
67575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
67675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
67775388acd0cd827dc1498043daa7d1c760902cd67Larry Fingervoid b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
67875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger{
67975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	struct b43legacy_pio *pio;
68075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger
68175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	B43legacy_WARN_ON(!b43legacy_using_pio(dev));
68275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio = &dev->pio;
68375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue0->tx_frozen = 0;
68475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue1->tx_frozen = 0;
68575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue2->tx_frozen = 0;
68675388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	pio->queue3->tx_frozen = 0;
68775388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!list_empty(&pio->queue0->txqueue))
68875388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tasklet_schedule(&pio->queue0->txtask);
68975388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!list_empty(&pio->queue1->txqueue))
69075388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tasklet_schedule(&pio->queue1->txtask);
69175388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!list_empty(&pio->queue2->txqueue))
69275388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tasklet_schedule(&pio->queue2->txtask);
69375388acd0cd827dc1498043daa7d1c760902cd67Larry Finger	if (!list_empty(&pio->queue3->txqueue))
69475388acd0cd827dc1498043daa7d1c760902cd67Larry Finger		tasklet_schedule(&pio->queue3->txtask);
69575388acd0cd827dc1498043daa7d1c760902cd67Larry Finger}
696