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