15100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch/*
25100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
35100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  Broadcom B43 wireless driver
45100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
55100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  PIO data transfer
65100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
7eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch  Copyright (c) 2005-2008 Michael Buesch <m@bues.ch>
85100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
95100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  This program is free software; you can redistribute it and/or modify
105100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  it under the terms of the GNU General Public License as published by
115100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  the Free Software Foundation; either version 2 of the License, or
125100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  (at your option) any later version.
135100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
145100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  This program is distributed in the hope that it will be useful,
155100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  but WITHOUT ANY WARRANTY; without even the implied warranty of
165100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
175100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  GNU General Public License for more details.
185100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
195100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  You should have received a copy of the GNU General Public License
205100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  along with this program; see the file COPYING.  If not, write to
215100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
225100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  Boston, MA 02110-1301, USA.
235100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
245100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch*/
255100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
265100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch#include "b43.h"
275100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch#include "pio.h"
285100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch#include "dma.h"
295100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch#include "main.h"
305100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch#include "xmit.h"
315100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
325100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch#include <linux/delay.h>
33d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h>
345a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
355100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
365100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
375100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic u16 generate_cookie(struct b43_pio_txqueue *q,
385100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			   struct b43_pio_txpacket *pack)
395100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
405100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	u16 cookie;
415100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
425100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Use the upper 4 bits of the cookie as
435100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * PIO controller ID and store the packet index number
445100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * in the lower 12 bits.
455100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * Note that the cookie must never be 0, as this
465100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * is a special value used in RX path.
475100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * It can also not be 0xFFFF because that is special
485100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * for multicast frames.
495100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 */
505100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	cookie = (((u16)q->index + 1) << 12);
515100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	cookie |= pack->index;
525100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
535100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return cookie;
545100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
555100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
565100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic
5799da185a72ba685a5aaf49dff6a5fe83885112e4John Daikerstruct b43_pio_txqueue *parse_cookie(struct b43_wldev *dev,
5899da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker				     u16 cookie,
595100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				      struct b43_pio_txpacket **pack)
605100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
615100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio *pio = &dev->pio;
625100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txqueue *q = NULL;
635100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	unsigned int pack_index;
645100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
655100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	switch (cookie & 0xF000) {
665100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	case 0x1000:
675100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q = pio->tx_queue_AC_BK;
685100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		break;
695100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	case 0x2000:
705100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q = pio->tx_queue_AC_BE;
715100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		break;
725100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	case 0x3000:
735100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q = pio->tx_queue_AC_VI;
745100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		break;
755100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	case 0x4000:
765100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q = pio->tx_queue_AC_VO;
775100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		break;
785100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	case 0x5000:
795100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q = pio->tx_queue_mcast;
805100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		break;
815100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
825100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (B43_WARN_ON(!q))
835100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return NULL;
845100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pack_index = (cookie & 0x0FFF);
855100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (B43_WARN_ON(pack_index >= ARRAY_SIZE(q->packets)))
865100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return NULL;
875100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	*pack = &q->packets[pack_index];
885100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
895100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return q;
905100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
915100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
925100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic u16 index_to_pioqueue_base(struct b43_wldev *dev,
935100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  unsigned int index)
945100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
955100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	static const u16 bases[] = {
965100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO_BASE0,
975100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO_BASE1,
985100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO_BASE2,
995100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO_BASE3,
1005100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO_BASE4,
1015100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO_BASE5,
1025100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO_BASE6,
1035100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO_BASE7,
1045100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	};
1055100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	static const u16 bases_rev11[] = {
1065100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO11_BASE0,
1075100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO11_BASE1,
1085100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO11_BASE2,
1095100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO11_BASE3,
1105100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO11_BASE4,
1115100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_MMIO_PIO11_BASE5,
1125100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	};
1135100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
11421d889d433eb962b70ad88d554a4a7658067596fRafał Miłecki	if (dev->dev->core_rev >= 11) {
1155100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11));
1165100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return bases_rev11[index];
1175100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
1185100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	B43_WARN_ON(index >= ARRAY_SIZE(bases));
1195100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return bases[index];
1205100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
1215100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1225100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic u16 pio_txqueue_offset(struct b43_wldev *dev)
1235100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
12421d889d433eb962b70ad88d554a4a7658067596fRafał Miłecki	if (dev->dev->core_rev >= 11)
1255100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return 0x18;
1265100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return 0;
1275100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
1285100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1295100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic u16 pio_rxqueue_offset(struct b43_wldev *dev)
1305100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
13121d889d433eb962b70ad88d554a4a7658067596fRafał Miłecki	if (dev->dev->core_rev >= 11)
1325100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return 0x38;
1335100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return 8;
1345100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
1355100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
13699da185a72ba685a5aaf49dff6a5fe83885112e4John Daikerstatic struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev,
13799da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker						     unsigned int index)
1385100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
1395100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txqueue *q;
1405100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txpacket *p;
1415100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	unsigned int i;
1425100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1435100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q = kzalloc(sizeof(*q), GFP_KERNEL);
1445100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!q)
1455100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return NULL;
1465100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->dev = dev;
14721d889d433eb962b70ad88d554a4a7658067596fRafał Miłecki	q->rev = dev->dev->core_rev;
1485100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->mmio_base = index_to_pioqueue_base(dev, index) +
1495100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		       pio_txqueue_offset(dev);
1505100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->index = index;
1515100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1525100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->free_packet_slots = B43_PIO_MAX_NR_TXPACKETS;
1535100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (q->rev >= 8) {
1545100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q->buffer_size = 1920; //FIXME this constant is wrong.
1555100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	} else {
1565100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q->buffer_size = b43_piotx_read16(q, B43_PIO_TXQBUFSIZE);
1575100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q->buffer_size -= 80;
1585100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
1595100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1605100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	INIT_LIST_HEAD(&q->packets_list);
1615100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	for (i = 0; i < ARRAY_SIZE(q->packets); i++) {
1625100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		p = &(q->packets[i]);
1635100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		INIT_LIST_HEAD(&p->list);
1645100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		p->index = i;
1655100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		p->queue = q;
1665100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		list_add(&p->list, &q->packets_list);
1675100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
1685100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1695100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return q;
1705100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
1715100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
17299da185a72ba685a5aaf49dff6a5fe83885112e4John Daikerstatic struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev,
17399da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker						     unsigned int index)
1745100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
1755100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_rxqueue *q;
1765100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1775100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q = kzalloc(sizeof(*q), GFP_KERNEL);
1785100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!q)
1795100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return NULL;
1805100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->dev = dev;
18121d889d433eb962b70ad88d554a4a7658067596fRafał Miłecki	q->rev = dev->dev->core_rev;
1825100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->mmio_base = index_to_pioqueue_base(dev, index) +
1835100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		       pio_rxqueue_offset(dev);
1845100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1855100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Enable Direct FIFO RX (PIO) on the engine. */
1865100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_dma_direct_fifo_rx(dev, index, 1);
1875100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1885100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return q;
1895100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
1905100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1915100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic void b43_pio_cancel_tx_packets(struct b43_pio_txqueue *q)
1925100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
1935100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txpacket *pack;
1945100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	unsigned int i;
1955100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
1965100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	for (i = 0; i < ARRAY_SIZE(q->packets); i++) {
1975100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		pack = &(q->packets[i]);
1985100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		if (pack->skb) {
1995100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			dev_kfree_skb_any(pack->skb);
2005100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			pack->skb = NULL;
2015100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		}
2025100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
2035100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
2045100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2055100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic void b43_destroy_pioqueue_tx(struct b43_pio_txqueue *q,
2065100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				    const char *name)
2075100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
2085100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!q)
2095100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return;
2105100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_cancel_tx_packets(q);
2115100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	kfree(q);
2125100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
2135100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2145100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic void b43_destroy_pioqueue_rx(struct b43_pio_rxqueue *q,
2155100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				    const char *name)
2165100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
2175100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!q)
2185100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return;
2195100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	kfree(q);
2205100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
2215100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2225100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch#define destroy_queue_tx(pio, queue) do {				\
2235100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_destroy_pioqueue_tx((pio)->queue, __stringify(queue));	\
2245100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	(pio)->queue = NULL;						\
2255100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  } while (0)
2265100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2275100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch#define destroy_queue_rx(pio, queue) do {				\
2285100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_destroy_pioqueue_rx((pio)->queue, __stringify(queue));	\
2295100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	(pio)->queue = NULL;						\
2305100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch  } while (0)
2315100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2325100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschvoid b43_pio_free(struct b43_wldev *dev)
2335100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
2345100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio *pio;
2355100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2365100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!b43_using_pio_transfers(dev))
2375100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return;
2385100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pio = &dev->pio;
2395100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2405100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_rx(pio, rx_queue);
2415100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_mcast);
2425100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_AC_VO);
2435100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_AC_VI);
2445100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_AC_BE);
2455100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_AC_BK);
2465100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
2475100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2485100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschint b43_pio_init(struct b43_wldev *dev)
2495100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
2505100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio *pio = &dev->pio;
2515100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	int err = -ENOMEM;
2525100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2535100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
2545100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		    & ~B43_MACCTL_BE);
2555100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RXPADOFF, 0);
2565100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2575100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pio->tx_queue_AC_BK = b43_setup_pioqueue_tx(dev, 0);
2585100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!pio->tx_queue_AC_BK)
2595100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		goto out;
2605100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2615100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pio->tx_queue_AC_BE = b43_setup_pioqueue_tx(dev, 1);
2625100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!pio->tx_queue_AC_BE)
2635100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		goto err_destroy_bk;
2645100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2655100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pio->tx_queue_AC_VI = b43_setup_pioqueue_tx(dev, 2);
2665100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!pio->tx_queue_AC_VI)
2675100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		goto err_destroy_be;
2685100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2695100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pio->tx_queue_AC_VO = b43_setup_pioqueue_tx(dev, 3);
2705100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!pio->tx_queue_AC_VO)
2715100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		goto err_destroy_vi;
2725100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2735100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pio->tx_queue_mcast = b43_setup_pioqueue_tx(dev, 4);
2745100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!pio->tx_queue_mcast)
2755100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		goto err_destroy_vo;
2765100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2775100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pio->rx_queue = b43_setup_pioqueue_rx(dev, 0);
2785100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (!pio->rx_queue)
2795100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		goto err_destroy_mcast;
2805100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2815100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43dbg(dev->wl, "PIO initialized\n");
2825100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	err = 0;
2835100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschout:
2845100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return err;
2855100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2865100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buescherr_destroy_mcast:
2875100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_mcast);
2885100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buescherr_destroy_vo:
2895100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_AC_VO);
2905100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buescherr_destroy_vi:
2915100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_AC_VI);
2925100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buescherr_destroy_be:
2935100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_AC_BE);
2945100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buescherr_destroy_bk:
2955100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	destroy_queue_tx(pio, tx_queue_AC_BK);
2965100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return err;
2975100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
2985100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
2995100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch/* Static mapping of mac80211's queues (priorities) to b43 PIO queues. */
30099da185a72ba685a5aaf49dff6a5fe83885112e4John Daikerstatic struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev,
30199da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker							u8 queue_prio)
3025100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
3035100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txqueue *q;
3045100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
305403a3a136122457165321e90b7569a321cc9ac12Michael Buesch	if (dev->qos_enabled) {
3065100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		/* 0 = highest priority */
3075100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		switch (queue_prio) {
3085100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		default:
3095100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			B43_WARN_ON(1);
3105100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			/* fallthrough */
3115100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		case 0:
3125100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			q = dev->pio.tx_queue_AC_VO;
3135100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			break;
3145100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		case 1:
3155100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			q = dev->pio.tx_queue_AC_VI;
3165100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			break;
3175100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		case 2:
3185100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			q = dev->pio.tx_queue_AC_BE;
3195100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			break;
3205100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		case 3:
3215100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			q = dev->pio.tx_queue_AC_BK;
3225100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			break;
3235100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		}
3245100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	} else
3255100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q = dev->pio.tx_queue_AC_BE;
3265100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
3275100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return q;
3285100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
3295100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
330d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Bueschstatic u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
331d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch				u16 ctl,
332d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch				const void *_data,
333d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch				unsigned int data_len)
3345100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
335d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	struct b43_wldev *dev = q->dev;
3367e937c633f718e0916a294db7282c922c1bf3ce3Albert Herranz	struct b43_wl *wl = dev->wl;
3375100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	const u8 *data = _data;
338d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch
339d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	ctl |= B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI;
340d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
341d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch
342620d785ba9066d5436857ec8e7c104c7b1c467e1Rafał Miłecki	b43_block_write(dev, data, (data_len & ~1),
343d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			q->mmio_base + B43_PIO_TXDATA,
344d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			sizeof(u16));
345d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	if (data_len & 1) {
34688499ab3d8dbbf9c080416952603742666c71262Michael Buesch		u8 *tail = wl->pio_tailspace;
34788499ab3d8dbbf9c080416952603742666c71262Michael Buesch		BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
34888499ab3d8dbbf9c080416952603742666c71262Michael Buesch
349d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		/* Write the last byte. */
350d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		ctl &= ~B43_PIO_TXCTL_WRITEHI;
351d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
35288499ab3d8dbbf9c080416952603742666c71262Michael Buesch		tail[0] = data[data_len - 1];
35388499ab3d8dbbf9c080416952603742666c71262Michael Buesch		tail[1] = 0;
354620d785ba9066d5436857ec8e7c104c7b1c467e1Rafał Miłecki		b43_block_write(dev, tail, 2,
355b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				q->mmio_base + B43_PIO_TXDATA,
356b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				sizeof(u16));
3575100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
358d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch
359d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	return ctl;
3605100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
3615100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
3625100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic void pio_tx_frame_2byte_queue(struct b43_pio_txpacket *pack,
3635100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				     const u8 *hdr, unsigned int hdrlen)
3645100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
3655100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txqueue *q = pack->queue;
3665100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	const char *frame = pack->skb->data;
3675100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	unsigned int frame_len = pack->skb->len;
3685100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	u16 ctl;
3695100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
3705100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	ctl = b43_piotx_read16(q, B43_PIO_TXCTL);
3715100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	ctl |= B43_PIO_TXCTL_FREADY;
3725100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	ctl &= ~B43_PIO_TXCTL_EOF;
3735100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
3745100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Transfer the header data. */
375d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	ctl = tx_write_2byte_queue(q, ctl, hdr, hdrlen);
3765100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Transfer the frame data. */
377d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	ctl = tx_write_2byte_queue(q, ctl, frame, frame_len);
3785100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
3795100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	ctl |= B43_PIO_TXCTL_EOF;
3805100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
3815100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
3825100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
383d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Bueschstatic u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
384d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch				u32 ctl,
385d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch				const void *_data,
386d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch				unsigned int data_len)
3875100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
388d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	struct b43_wldev *dev = q->dev;
3897e937c633f718e0916a294db7282c922c1bf3ce3Albert Herranz	struct b43_wl *wl = dev->wl;
3905100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	const u8 *data = _data;
391d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch
392d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	ctl |= B43_PIO8_TXCTL_0_7 | B43_PIO8_TXCTL_8_15 |
393d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	       B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31;
394d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
395d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch
396620d785ba9066d5436857ec8e7c104c7b1c467e1Rafał Miłecki	b43_block_write(dev, data, (data_len & ~3),
397d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			q->mmio_base + B43_PIO8_TXDATA,
398d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			sizeof(u32));
399d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	if (data_len & 3) {
40088499ab3d8dbbf9c080416952603742666c71262Michael Buesch		u8 *tail = wl->pio_tailspace;
40188499ab3d8dbbf9c080416952603742666c71262Michael Buesch		BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
40288499ab3d8dbbf9c080416952603742666c71262Michael Buesch
40388499ab3d8dbbf9c080416952603742666c71262Michael Buesch		memset(tail, 0, 4);
404d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		/* Write the last few bytes. */
405d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 |
406d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			 B43_PIO8_TXCTL_24_31);
407d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		switch (data_len & 3) {
408d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		case 3:
409b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch			ctl |= B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_8_15;
41088499ab3d8dbbf9c080416952603742666c71262Michael Buesch			tail[0] = data[data_len - 3];
41188499ab3d8dbbf9c080416952603742666c71262Michael Buesch			tail[1] = data[data_len - 2];
41288499ab3d8dbbf9c080416952603742666c71262Michael Buesch			tail[2] = data[data_len - 1];
413b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch			break;
414d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		case 2:
415d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			ctl |= B43_PIO8_TXCTL_8_15;
41688499ab3d8dbbf9c080416952603742666c71262Michael Buesch			tail[0] = data[data_len - 2];
41788499ab3d8dbbf9c080416952603742666c71262Michael Buesch			tail[1] = data[data_len - 1];
418b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch			break;
419d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		case 1:
42088499ab3d8dbbf9c080416952603742666c71262Michael Buesch			tail[0] = data[data_len - 1];
421b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch			break;
4225100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		}
423d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
424620d785ba9066d5436857ec8e7c104c7b1c467e1Rafał Miłecki		b43_block_write(dev, tail, 4,
425b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				q->mmio_base + B43_PIO8_TXDATA,
426b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				sizeof(u32));
4275100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
428d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch
429d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	return ctl;
4305100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
4315100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4325100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack,
4335100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				     const u8 *hdr, unsigned int hdrlen)
4345100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
4355100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txqueue *q = pack->queue;
4365100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	const char *frame = pack->skb->data;
4375100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	unsigned int frame_len = pack->skb->len;
4385100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	u32 ctl;
4395100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4405100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	ctl = b43_piotx_read32(q, B43_PIO8_TXCTL);
4415100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	ctl |= B43_PIO8_TXCTL_FREADY;
4425100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	ctl &= ~B43_PIO8_TXCTL_EOF;
4435100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4445100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Transfer the header data. */
445d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	ctl = tx_write_4byte_queue(q, ctl, hdr, hdrlen);
4465100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Transfer the frame data. */
447d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	ctl = tx_write_4byte_queue(q, ctl, frame, frame_len);
4485100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4495100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	ctl |= B43_PIO8_TXCTL_EOF;
4505100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_piotx_write32(q, B43_PIO_TXCTL, ctl);
4515100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
4525100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4535100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic int pio_tx_frame(struct b43_pio_txqueue *q,
454e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg			struct sk_buff *skb)
4555100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
4567e937c633f718e0916a294db7282c922c1bf3ce3Albert Herranz	struct b43_wldev *dev = q->dev;
4577e937c633f718e0916a294db7282c922c1bf3ce3Albert Herranz	struct b43_wl *wl = dev->wl;
4585100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txpacket *pack;
4595100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	u16 cookie;
4605100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	int err;
4615100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	unsigned int hdrlen;
462e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
46388499ab3d8dbbf9c080416952603742666c71262Michael Buesch	struct b43_txhdr *txhdr = (struct b43_txhdr *)wl->pio_scratchspace;
4645100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4655100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	B43_WARN_ON(list_empty(&q->packets_list));
4665100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pack = list_entry(q->packets_list.next,
4675100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			  struct b43_pio_txpacket, list);
4685100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4695100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	cookie = generate_cookie(q, pack);
4707e937c633f718e0916a294db7282c922c1bf3ce3Albert Herranz	hdrlen = b43_txhdr_size(dev);
47188499ab3d8dbbf9c080416952603742666c71262Michael Buesch	BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(struct b43_txhdr));
47288499ab3d8dbbf9c080416952603742666c71262Michael Buesch	B43_WARN_ON(sizeof(wl->pio_scratchspace) < hdrlen);
47388499ab3d8dbbf9c080416952603742666c71262Michael Buesch	err = b43_generate_txhdr(dev, (u8 *)txhdr, skb,
474035d0243ebbdbd5f8f07d6ce378c9a9b36415bc9gregor kowski				 info, cookie);
4755100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (err)
4765100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return err;
4775100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
478e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
4795100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		/* Tell the firmware about the cookie of the last
4805100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		 * mcast frame, so it can clear the more-data bit in it. */
4817e937c633f718e0916a294db7282c922c1bf3ce3Albert Herranz		b43_shm_write16(dev, B43_SHM_SHARED,
4825100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				B43_SHM_SH_MCASTCOOKIE, cookie);
4835100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
4845100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4855100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pack->skb = skb;
4865100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (q->rev >= 8)
48788499ab3d8dbbf9c080416952603742666c71262Michael Buesch		pio_tx_frame_4byte_queue(pack, (const u8 *)txhdr, hdrlen);
4885100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	else
48988499ab3d8dbbf9c080416952603742666c71262Michael Buesch		pio_tx_frame_2byte_queue(pack, (const u8 *)txhdr, hdrlen);
4905100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4915100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Remove it from the list of available packet slots.
4925100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * It will be put back when we receive the status report. */
4935100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	list_del(&pack->list);
4945100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4955100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Update the queue statistics. */
4965100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->buffer_used += roundup(skb->len + hdrlen, 4);
4975100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->free_packet_slots -= 1;
4985100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
4995100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return 0;
5005100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
5015100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
502e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Bergint b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
5035100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
5045100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txqueue *q;
5055100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct ieee80211_hdr *hdr;
5065100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	unsigned int hdrlen, total_len;
5075100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	int err = 0;
508e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
5095100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
5105100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	hdr = (struct ieee80211_hdr *)skb->data;
511e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg
512e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
5135100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		/* The multicast queue will be sent after the DTIM. */
5145100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		q = dev->pio.tx_queue_mcast;
5155100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		/* Set the frame More-Data bit. Ucode will clear it
5165100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		 * for us on the last frame. */
5175100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
5185100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	} else {
5195100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		/* Decide by priority where to put this frame. */
520e2530083609148a7835b54c431f6b8956407c1f6Johannes Berg		q = select_queue_by_priority(dev, skb_get_queue_mapping(skb));
5215100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
5225100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
5235100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	hdrlen = b43_txhdr_size(dev);
5245100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	total_len = roundup(skb->len + hdrlen, 4);
5255100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
5265100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (unlikely(total_len > q->buffer_size)) {
5275100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		err = -ENOBUFS;
5285100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43dbg(dev->wl, "PIO: TX packet longer than queue.\n");
529637dae3f637eb7dab447e74362e0dfeded775c7cMichael Buesch		goto out;
5305100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
5315100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (unlikely(q->free_packet_slots == 0)) {
5325100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		err = -ENOBUFS;
5335100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43warn(dev->wl, "PIO: TX packet overflow.\n");
534637dae3f637eb7dab447e74362e0dfeded775c7cMichael Buesch		goto out;
5355100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
5365100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	B43_WARN_ON(q->buffer_used > q->buffer_size);
5375100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
5385100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (total_len > (q->buffer_size - q->buffer_used)) {
5395100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		/* Not enough memory on the queue. */
5405100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		err = -EBUSY;
541e2530083609148a7835b54c431f6b8956407c1f6Johannes Berg		ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
5423db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell		q->stopped = true;
543637dae3f637eb7dab447e74362e0dfeded775c7cMichael Buesch		goto out;
5445100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
5455100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
5465100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Assign the queue number to the ring (if not already done before)
5475100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * so TX status handling can use it. The mac80211-queue to b43-queue
5485100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * mapping is static, so we don't need to store it per frame. */
549e2530083609148a7835b54c431f6b8956407c1f6Johannes Berg	q->queue_prio = skb_get_queue_mapping(skb);
5505100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
551e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	err = pio_tx_frame(q, skb);
5525100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (unlikely(err == -ENOKEY)) {
5535100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		/* Drop this packet, as we don't have the encryption key
5545100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		 * anymore and must not transmit it unencrypted. */
5555100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		dev_kfree_skb_any(skb);
5565100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		err = 0;
557637dae3f637eb7dab447e74362e0dfeded775c7cMichael Buesch		goto out;
5585100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
5595100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (unlikely(err)) {
5605100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43err(dev->wl, "PIO transmission failure\n");
561637dae3f637eb7dab447e74362e0dfeded775c7cMichael Buesch		goto out;
5625100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
5635100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
5645100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	B43_WARN_ON(q->buffer_used > q->buffer_size);
5655100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) ||
5665100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	    (q->free_packet_slots == 0)) {
5675100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		/* The queue is full. */
568e2530083609148a7835b54c431f6b8956407c1f6Johannes Berg		ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
5693db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell		q->stopped = true;
5705100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
5715100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
572637dae3f637eb7dab447e74362e0dfeded775c7cMichael Bueschout:
5735100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return err;
5745100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
5755100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
5765100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschvoid b43_pio_handle_txstatus(struct b43_wldev *dev,
5775100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			     const struct b43_txstatus *status)
5785100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
5795100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txqueue *q;
5805100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct b43_pio_txpacket *pack = NULL;
5815100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	unsigned int total_len;
582e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg	struct ieee80211_tx_info *info;
5835100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
5845100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q = parse_cookie(dev, status->cookie, &pack);
5855100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (unlikely(!q))
5865100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		return;
5875100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	B43_WARN_ON(!pack);
5885100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
58914a7dd6f6c1e0b361a37b6df52d4dc2ea36757d2Michael Buesch	info = IEEE80211_SKB_CB(pack->skb);
590e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg
591e6a9854b05c1a6af1308fe2b8c68f35abf28a3eeJohannes Berg	b43_fill_txstatus_report(dev, info, status);
5925100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
5935100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	total_len = pack->skb->len + b43_txhdr_size(dev);
5945100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	total_len = roundup(total_len, 4);
5955100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->buffer_used -= total_len;
5965100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	q->free_packet_slots += 1;
5975100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
598ce6c4a13927bc0418169fe543c6614abfab051ebMichael Buesch	ieee80211_tx_status(dev->wl->hw, pack->skb);
5995100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	pack->skb = NULL;
6005100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	list_add(&pack->list, &q->packets_list);
6015100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
6025100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (q->stopped) {
6035100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		ieee80211_wake_queue(dev->wl->hw, q->queue_prio);
6043db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell		q->stopped = false;
6055100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
6065100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
6075100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
6085100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch/* Returns whether we should fetch another frame. */
6095100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic bool pio_rx_frame(struct b43_pio_rxqueue *q)
6105100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
611d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch	struct b43_wldev *dev = q->dev;
6127e937c633f718e0916a294db7282c922c1bf3ce3Albert Herranz	struct b43_wl *wl = dev->wl;
6135100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	u16 len;
614c3e5fac8e54591d2e4585d3329ead61ba059eb1dJohn W. Linville	u32 macstat = 0;
6155100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	unsigned int i, padding;
6165100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	struct sk_buff *skb;
6175100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	const char *err_msg = NULL;
61888499ab3d8dbbf9c080416952603742666c71262Michael Buesch	struct b43_rxhdr_fw4 *rxhdr =
61988499ab3d8dbbf9c080416952603742666c71262Michael Buesch		(struct b43_rxhdr_fw4 *)wl->pio_scratchspace;
62009009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski	size_t rxhdr_size = sizeof(*rxhdr);
6215100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
62288499ab3d8dbbf9c080416952603742666c71262Michael Buesch	BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(*rxhdr));
62309009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski	switch (dev->fw.hdr_format) {
62409009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski	case B43_FW_HDR_410:
62509009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski	case B43_FW_HDR_351:
62609009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski		rxhdr_size -= sizeof(rxhdr->format_598) -
62709009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski			sizeof(rxhdr->format_351);
62809009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski		break;
62909009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski	case B43_FW_HDR_598:
63009009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski		break;
63109009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski	}
63209009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski	memset(rxhdr, 0, rxhdr_size);
6335100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
6345100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Check if we have data and wait for it to get ready. */
6355100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (q->rev >= 8) {
6365100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		u32 ctl;
6375100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
6385100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
6395100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		if (!(ctl & B43_PIO8_RXCTL_FRAMERDY))
6405100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			return 0;
6415100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43_piorx_write32(q, B43_PIO8_RXCTL,
6425100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  B43_PIO8_RXCTL_FRAMERDY);
6435100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		for (i = 0; i < 10; i++) {
6445100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
6455100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			if (ctl & B43_PIO8_RXCTL_DATARDY)
6465100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				goto data_ready;
6475100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			udelay(10);
6485100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		}
6495100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	} else {
6505100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		u16 ctl;
6515100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
6525100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
6535100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		if (!(ctl & B43_PIO_RXCTL_FRAMERDY))
6545100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			return 0;
6555100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43_piorx_write16(q, B43_PIO_RXCTL,
6565100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  B43_PIO_RXCTL_FRAMERDY);
6575100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		for (i = 0; i < 10; i++) {
6585100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
6595100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			if (ctl & B43_PIO_RXCTL_DATARDY)
6605100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				goto data_ready;
6615100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			udelay(10);
6625100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		}
6635100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
6645100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43dbg(q->dev->wl, "PIO RX timed out\n");
6655100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return 1;
6665100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschdata_ready:
6675100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
6685100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Get the preamble (RX header) */
6695100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (q->rev >= 8) {
67009009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski		b43_block_read(dev, rxhdr, rxhdr_size,
671d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			       q->mmio_base + B43_PIO8_RXDATA,
672d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			       sizeof(u32));
6735100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	} else {
67409009512e5e7ab341b1554a256f81dd512c1f4bfGuennadi Liakhovetski		b43_block_read(dev, rxhdr, rxhdr_size,
675d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			       q->mmio_base + B43_PIO_RXDATA,
676d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			       sizeof(u16));
6775100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
6785100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* Sanity checks. */
67988499ab3d8dbbf9c080416952603742666c71262Michael Buesch	len = le16_to_cpu(rxhdr->frame_len);
6805100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (unlikely(len > 0x700)) {
6815100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		err_msg = "len > 0x700";
6825100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		goto rx_error;
6835100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
6845100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (unlikely(len == 0)) {
6855100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		err_msg = "len == 0";
6865100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		goto rx_error;
6875100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
6885100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
68917030f48e31adde5b043741c91ba143f5f7db0fdRafał Miłecki	switch (dev->fw.hdr_format) {
69017030f48e31adde5b043741c91ba143f5f7db0fdRafał Miłecki	case B43_FW_HDR_598:
69117030f48e31adde5b043741c91ba143f5f7db0fdRafał Miłecki		macstat = le32_to_cpu(rxhdr->format_598.mac_status);
69217030f48e31adde5b043741c91ba143f5f7db0fdRafał Miłecki		break;
69317030f48e31adde5b043741c91ba143f5f7db0fdRafał Miłecki	case B43_FW_HDR_410:
69417030f48e31adde5b043741c91ba143f5f7db0fdRafał Miłecki	case B43_FW_HDR_351:
69517030f48e31adde5b043741c91ba143f5f7db0fdRafał Miłecki		macstat = le32_to_cpu(rxhdr->format_351.mac_status);
69617030f48e31adde5b043741c91ba143f5f7db0fdRafał Miłecki		break;
69717030f48e31adde5b043741c91ba143f5f7db0fdRafał Miłecki	}
6985100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (macstat & B43_RX_MAC_FCSERR) {
6995100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
7005100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			/* Drop frames with failed FCS. */
7015100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			err_msg = "Frame FCS error";
7025100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			goto rx_error;
7035100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		}
7045100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
7055100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
7065100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	/* We always pad 2 bytes, as that's what upstream code expects
7075100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * due to the RX-header being 30 bytes. In case the frame is
7085100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	 * unaligned, we pad another 2 bytes. */
7095100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0;
7105100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	skb = dev_alloc_skb(len + padding + 2);
7115100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (unlikely(!skb)) {
7125100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		err_msg = "Out of memory";
7135100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		goto rx_error;
7145100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
7155100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	skb_reserve(skb, 2);
7165100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	skb_put(skb, len + padding);
7175100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (q->rev >= 8) {
718620d785ba9066d5436857ec8e7c104c7b1c467e1Rafał Miłecki		b43_block_read(dev, skb->data + padding, (len & ~3),
719d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			       q->mmio_base + B43_PIO8_RXDATA,
720d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			       sizeof(u32));
721d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		if (len & 3) {
72288499ab3d8dbbf9c080416952603742666c71262Michael Buesch			u8 *tail = wl->pio_tailspace;
72388499ab3d8dbbf9c080416952603742666c71262Michael Buesch			BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
72488499ab3d8dbbf9c080416952603742666c71262Michael Buesch
725d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			/* Read the last few bytes. */
726620d785ba9066d5436857ec8e7c104c7b1c467e1Rafał Miłecki			b43_block_read(dev, tail, 4,
727b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				       q->mmio_base + B43_PIO8_RXDATA,
728b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				       sizeof(u32));
729d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			switch (len & 3) {
730d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			case 3:
73188499ab3d8dbbf9c080416952603742666c71262Michael Buesch				skb->data[len + padding - 3] = tail[0];
73288499ab3d8dbbf9c080416952603742666c71262Michael Buesch				skb->data[len + padding - 2] = tail[1];
73388499ab3d8dbbf9c080416952603742666c71262Michael Buesch				skb->data[len + padding - 1] = tail[2];
734b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				break;
735d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			case 2:
73688499ab3d8dbbf9c080416952603742666c71262Michael Buesch				skb->data[len + padding - 2] = tail[0];
73788499ab3d8dbbf9c080416952603742666c71262Michael Buesch				skb->data[len + padding - 1] = tail[1];
738b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				break;
739d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			case 1:
74088499ab3d8dbbf9c080416952603742666c71262Michael Buesch				skb->data[len + padding - 1] = tail[0];
741b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				break;
742d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			}
7435100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		}
7445100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	} else {
745620d785ba9066d5436857ec8e7c104c7b1c467e1Rafał Miłecki		b43_block_read(dev, skb->data + padding, (len & ~1),
746d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			       q->mmio_base + B43_PIO_RXDATA,
747d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			       sizeof(u16));
748d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch		if (len & 1) {
74988499ab3d8dbbf9c080416952603742666c71262Michael Buesch			u8 *tail = wl->pio_tailspace;
75088499ab3d8dbbf9c080416952603742666c71262Michael Buesch			BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
75188499ab3d8dbbf9c080416952603742666c71262Michael Buesch
752d8c17e159758c2a4f8c3319fe8a6cf313f7a6733Michael Buesch			/* Read the last byte. */
753620d785ba9066d5436857ec8e7c104c7b1c467e1Rafał Miłecki			b43_block_read(dev, tail, 2,
754b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				       q->mmio_base + B43_PIO_RXDATA,
755b96ab540c1deac17238c4902c328ee08c3130370Michael Buesch				       sizeof(u16));
75688499ab3d8dbbf9c080416952603742666c71262Michael Buesch			skb->data[len + padding - 1] = tail[0];
7575100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		}
7585100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
7595100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
76088499ab3d8dbbf9c080416952603742666c71262Michael Buesch	b43_rx(q->dev, skb, rxhdr);
7615100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
7625100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return 1;
7635100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
7645100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschrx_error:
7655100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (err_msg)
7665100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43dbg(q->dev->wl, "PIO RX error: %s\n", err_msg);
767c286181d5bfd8703219b954284143cfadff60b9bMichael Buesch	if (q->rev >= 8)
768c286181d5bfd8703219b954284143cfadff60b9bMichael Buesch		b43_piorx_write32(q, B43_PIO8_RXCTL, B43_PIO8_RXCTL_DATARDY);
769c286181d5bfd8703219b954284143cfadff60b9bMichael Buesch	else
770c286181d5bfd8703219b954284143cfadff60b9bMichael Buesch		b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY);
771c286181d5bfd8703219b954284143cfadff60b9bMichael Buesch
7725100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	return 1;
7735100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
7745100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
77577ca07ffe1797a0f2f41aa4997c9a5ae433a0be8Michael Bueschvoid b43_pio_rx(struct b43_pio_rxqueue *q)
7765100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
77777ca07ffe1797a0f2f41aa4997c9a5ae433a0be8Michael Buesch	unsigned int count = 0;
7785100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	bool stop;
7795100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
78077ca07ffe1797a0f2f41aa4997c9a5ae433a0be8Michael Buesch	while (1) {
7815100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		stop = (pio_rx_frame(q) == 0);
7825100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		if (stop)
7835100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch			break;
78477ca07ffe1797a0f2f41aa4997c9a5ae433a0be8Michael Buesch		cond_resched();
78577ca07ffe1797a0f2f41aa4997c9a5ae433a0be8Michael Buesch		if (WARN_ON_ONCE(++count > 10000))
78677ca07ffe1797a0f2f41aa4997c9a5ae433a0be8Michael Buesch			break;
78777ca07ffe1797a0f2f41aa4997c9a5ae433a0be8Michael Buesch	}
7885100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
7895100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
7905100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q)
7915100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
7925100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (q->rev >= 8) {
7935100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43_piotx_write32(q, B43_PIO8_TXCTL,
7945100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  b43_piotx_read32(q, B43_PIO8_TXCTL)
7955100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  | B43_PIO8_TXCTL_SUSPREQ);
7965100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	} else {
7975100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43_piotx_write16(q, B43_PIO_TXCTL,
7985100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  b43_piotx_read16(q, B43_PIO_TXCTL)
7995100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  | B43_PIO_TXCTL_SUSPREQ);
8005100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
8015100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
8025100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
8035100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschstatic void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q)
8045100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
8055100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	if (q->rev >= 8) {
8065100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43_piotx_write32(q, B43_PIO8_TXCTL,
8075100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  b43_piotx_read32(q, B43_PIO8_TXCTL)
8085100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  & ~B43_PIO8_TXCTL_SUSPREQ);
8095100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	} else {
8105100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch		b43_piotx_write16(q, B43_PIO_TXCTL,
8115100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  b43_piotx_read16(q, B43_PIO_TXCTL)
8125100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch				  & ~B43_PIO_TXCTL_SUSPREQ);
8135100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	}
8145100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
8155100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
8165100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschvoid b43_pio_tx_suspend(struct b43_wldev *dev)
8175100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
8185100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
8195100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BK);
8205100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BE);
8215100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VI);
8225100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VO);
8235100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_suspend_queue(dev->pio.tx_queue_mcast);
8245100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
8255100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch
8265100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Bueschvoid b43_pio_tx_resume(struct b43_wldev *dev)
8275100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch{
8285100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_resume_queue(dev->pio.tx_queue_mcast);
8295100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VO);
8305100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VI);
8315100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BE);
8325100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BK);
8335100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch	b43_power_saving_ctl_bits(dev, 0);
8345100d5ac81b9330dc57e35adbe50923ba6107b8fMichael Buesch}
835