aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/b43legacy/pio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/b43legacy/pio.c')
-rw-r--r--drivers/net/wireless/b43legacy/pio.c95
1 files changed, 61 insertions, 34 deletions
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
index de843ac147a..282eedec675 100644
--- a/drivers/net/wireless/b43legacy/pio.c
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -4,7 +4,7 @@
PIO Transmission
- Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005 Michael Buesch <m@bues.ch>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@
#include "xmit.h"
#include <linux/delay.h>
+#include <linux/slab.h>
static void tx_start(struct b43legacy_pioqueue *queue)
@@ -181,7 +182,7 @@ union txhdr_union {
struct b43legacy_txhdr_fw3 txhdr_fw3;
};
-static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
+static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
struct sk_buff *skb,
struct b43legacy_pio_txpacket *packet,
size_t txhdr_size)
@@ -189,14 +190,17 @@ static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
union txhdr_union txhdr_data;
u8 *txhdr = NULL;
unsigned int octets;
+ int err;
txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
- b43legacy_generate_txhdr(queue->dev,
+ err = b43legacy_generate_txhdr(queue->dev,
txhdr, skb->data, skb->len,
- &packet->txstat.control,
+ IEEE80211_SKB_CB(skb),
generate_cookie(queue, packet));
+ if (err)
+ return err;
tx_start(queue);
octets = skb->len + txhdr_size;
@@ -204,6 +208,8 @@ static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
octets--;
tx_data(queue, txhdr, (u8 *)skb->data, octets);
tx_complete(queue, skb);
+
+ return 0;
}
static void free_txpacket(struct b43legacy_pio_txpacket *packet,
@@ -226,6 +232,7 @@ static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
struct b43legacy_pioqueue *queue = packet->queue;
struct sk_buff *skb = packet->skb;
u16 octets;
+ int err;
octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
if (queue->tx_devq_size < octets) {
@@ -247,8 +254,14 @@ static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
if (queue->tx_devq_used + octets > queue->tx_devq_size)
return -EBUSY;
/* Now poke the device. */
- pio_tx_write_fragment(queue, skb, packet,
+ err = pio_tx_write_fragment(queue, skb, packet,
sizeof(struct b43legacy_txhdr_fw3));
+ if (unlikely(err == -ENOKEY)) {
+ /* Drop this packet, as we don't have the encryption key
+ * anymore and must not transmit it unencrypted. */
+ free_txpacket(packet, 1);
+ return 0;
+ }
/* Account for the packet size.
* (We must not overflow the device TX queue)
@@ -334,9 +347,9 @@ struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
tasklet_init(&queue->txtask, tx_tasklet,
(unsigned long)queue);
- value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
- value &= ~B43legacy_SBF_XFER_REG_BYTESWAP;
- b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value);
+ value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+ value &= ~B43legacy_MACCTL_BE;
+ b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value);
qsize = b43legacy_read16(dev, queue->mmio_base
+ B43legacy_PIO_TXQBUFSIZE);
@@ -369,7 +382,7 @@ static void cancel_transfers(struct b43legacy_pioqueue *queue)
{
struct b43legacy_pio_txpacket *packet, *tmp_packet;
- tasklet_disable(&queue->txtask);
+ tasklet_kill(&queue->txtask);
list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
free_txpacket(packet, 0);
@@ -431,7 +444,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev)
pio->queue3 = queue;
if (dev->dev->id.revision < 3)
- dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND;
+ dev->irq_mask |= B43legacy_IRQ_PIO_WORKAROUND;
b43legacydbg(dev->wl, "PIO initialized\n");
err = 0;
@@ -451,8 +464,7 @@ err_destroy0:
}
int b43legacy_pio_tx(struct b43legacy_wldev *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
struct b43legacy_pioqueue *queue = dev->pio.queue1;
struct b43legacy_pio_txpacket *packet;
@@ -464,12 +476,8 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev,
list);
packet->skb = skb;
- memset(&packet->txstat, 0, sizeof(packet->txstat));
- memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
-
list_move_tail(&packet->list, &queue->txqueue);
queue->nr_txfree--;
- queue->nr_tx_packets++;
B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
tasklet_schedule(&queue->txtask);
@@ -482,19 +490,52 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
{
struct b43legacy_pioqueue *queue;
struct b43legacy_pio_txpacket *packet;
+ struct ieee80211_tx_info *info;
+ int retry_limit;
queue = parse_cookie(dev, status->cookie, &packet);
B43legacy_WARN_ON(!queue);
+ if (!packet->skb)
+ return;
+
queue->tx_devq_packets--;
queue->tx_devq_used -= (packet->skb->len +
sizeof(struct b43legacy_txhdr_fw3));
+ info = IEEE80211_SKB_CB(packet->skb);
+
+ /* preserve the confiured retry limit before clearing the status
+ * The xmit function has overwritten the rc's value with the actual
+ * retry limit done by the hardware */
+ retry_limit = info->status.rates[0].count;
+ ieee80211_tx_info_clear_status(info);
+
if (status->acked)
- packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
- packet->txstat.retry_count = status->frame_count - 1;
- ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
- &(packet->txstat));
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
+ if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+ /*
+ * If the short retries (RTS, not data frame) have exceeded
+ * the limit, the hw will not have tried the selected rate,
+ * but will have used the fallback rate instead.
+ * Don't let the rate control count attempts for the selected
+ * rate in this case, otherwise the statistics will be off.
+ */
+ info->status.rates[0].count = 0;
+ info->status.rates[1].count = status->frame_count;
+ } else {
+ if (status->frame_count > retry_limit) {
+ info->status.rates[0].count = retry_limit;
+ info->status.rates[1].count = status->frame_count -
+ retry_limit;
+
+ } else {
+ info->status.rates[0].count = status->frame_count;
+ info->status.rates[1].idx = -1;
+ }
+ }
+ ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
packet->skb = NULL;
free_txpacket(packet, 1);
@@ -505,20 +546,6 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
tasklet_schedule(&queue->txtask);
}
-void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct b43legacy_pio *pio = &dev->pio;
- struct b43legacy_pioqueue *queue;
- struct ieee80211_tx_queue_stats_data *data;
-
- queue = pio->queue1;
- data = &(stats->data[0]);
- data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree;
- data->limit = B43legacy_PIO_MAXTXPACKETS;
- data->count = queue->nr_tx_packets;
-}
-
static void pio_rx_error(struct b43legacy_pioqueue *queue,
int clear_buffers,
const char *error)