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