[PATCH] bcm43xx: make PIO mode usable
This patch fixes PIO mode on the softmac bcm43xx
driver. (A dscape patch will follow).
It mainly fixes endianess issues.
This patch is tested on PowerPC32 and i386.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
index 2d520e4..b7d7763 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
@@ -213,6 +213,14 @@
void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
{
}
+static inline
+void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
+{
+}
+static inline
+void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
+{
+}
#endif /* CONFIG_BCM43XX_DMA */
#endif /* BCM43xx_DMA_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index c59ddd4..0aa1bd2 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -27,6 +27,7 @@
#include "bcm43xx_pio.h"
#include "bcm43xx_main.h"
#include "bcm43xx_xmit.h"
+#include "bcm43xx_power.h"
#include <linux/delay.h>
@@ -44,10 +45,10 @@
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
octet);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_WRITEHI);
+ BCM43xx_PIO_TXCTL_WRITELO);
} else {
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_WRITEHI);
+ BCM43xx_PIO_TXCTL_WRITELO);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
octet);
}
@@ -103,7 +104,7 @@
bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
skb->data[skb->len - 1]);
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
- BCM43xx_PIO_TXCTL_WRITEHI |
+ BCM43xx_PIO_TXCTL_WRITELO |
BCM43xx_PIO_TXCTL_COMPLETE);
} else {
bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
@@ -112,9 +113,10 @@
}
static u16 generate_cookie(struct bcm43xx_pioqueue *queue,
- int packetindex)
+ struct bcm43xx_pio_txpacket *packet)
{
u16 cookie = 0x0000;
+ int packetindex;
/* We use the upper 4 bits for the PIO
* controller ID and the lower 12 bits
@@ -135,6 +137,7 @@
default:
assert(0);
}
+ packetindex = pio_txpacket_getindex(packet);
assert(((u16)packetindex & 0xF000) == 0x0000);
cookie |= (u16)packetindex;
@@ -184,7 +187,7 @@
bcm43xx_generate_txhdr(queue->bcm,
&txhdr, skb->data, skb->len,
(packet->xmitted_frags == 0),
- generate_cookie(queue, pio_txpacket_getindex(packet)));
+ generate_cookie(queue, packet));
tx_start(queue);
octets = skb->len + sizeof(txhdr);
@@ -241,7 +244,7 @@
queue->tx_devq_packets++;
queue->tx_devq_used += octets;
- assert(packet->xmitted_frags <= packet->txb->nr_frags);
+ assert(packet->xmitted_frags < packet->txb->nr_frags);
packet->xmitted_frags++;
packet->xmitted_octets += octets;
}
@@ -257,8 +260,14 @@
unsigned long flags;
struct bcm43xx_pio_txpacket *packet, *tmp_packet;
int err;
+ u16 txctl;
bcm43xx_lock_mmio(bcm, flags);
+
+ txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
+ if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)
+ goto out_unlock;
+
list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
assert(packet->xmitted_frags < packet->txb->nr_frags);
if (packet->xmitted_frags == 0) {
@@ -288,6 +297,7 @@
next_packet:
continue;
}
+out_unlock:
bcm43xx_unlock_mmio(bcm, flags);
}
@@ -330,12 +340,19 @@
(unsigned long)queue);
value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
- value |= BCM43xx_SBF_XFER_REG_BYTESWAP;
+ value &= ~BCM43xx_SBF_XFER_REG_BYTESWAP;
bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE);
+ if (qsize == 0) {
+ printk(KERN_ERR PFX "ERROR: This card does not support PIO "
+ "operation mode. Please use DMA mode "
+ "(module parameter pio=0).\n");
+ goto err_freequeue;
+ }
if (qsize <= BCM43xx_PIO_TXQADJUST) {
- printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize);
+ printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n",
+ qsize);
goto err_freequeue;
}
qsize -= BCM43xx_PIO_TXQADJUST;
@@ -444,15 +461,10 @@
{
struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1;
struct bcm43xx_pio_txpacket *packet;
- u16 tmp;
assert(!queue->tx_suspended);
assert(!list_empty(&queue->txfree));
- tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
- if (tmp & BCM43xx_PIO_TXCTL_SUSPEND)
- return -EBUSY;
-
packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list);
packet->txb = txb;
packet->xmitted_frags = 0;
@@ -462,7 +474,7 @@
assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS);
/* Suspend TX, if we are out of packets in the "free" queue. */
- if (unlikely(list_empty(&queue->txfree))) {
+ if (list_empty(&queue->txfree)) {
netif_stop_queue(queue->bcm->net_dev);
queue->tx_suspended = 1;
}
@@ -480,15 +492,15 @@
queue = parse_cookie(bcm, status->cookie, &packet);
assert(queue);
-//TODO
-if (!queue)
-return;
+
free_txpacket(packet, 1);
- if (unlikely(queue->tx_suspended)) {
+ if (queue->tx_suspended) {
queue->tx_suspended = 0;
netif_wake_queue(queue->bcm->net_dev);
}
- /* If there are packets on the txqueue, poke the tasklet. */
+ /* If there are packets on the txqueue, poke the tasklet
+ * to transmit them.
+ */
if (!list_empty(&queue->txqueue))
tasklet_schedule(&queue->txtask);
}
@@ -519,12 +531,9 @@
int i, preamble_readwords;
struct sk_buff *skb;
-return;
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
- if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) {
- dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk.
+ if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE))
return;
- }
bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
BCM43xx_PIO_RXCTL_DATAAVAILABLE);
@@ -538,8 +547,7 @@
return;
data_ready:
-//FIXME: endianess in this function.
- len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
+ len = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
if (unlikely(len > 0x700)) {
pio_rx_error(queue, 0, "len > 0x700");
return;
@@ -555,7 +563,7 @@
preamble_readwords = 18 / sizeof(u16);
for (i = 0; i < preamble_readwords; i++) {
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
- preamble[i + 1] = cpu_to_be16(tmp);//FIXME?
+ preamble[i + 1] = cpu_to_le16(tmp);
}
rxhdr = (struct bcm43xx_rxhdr *)preamble;
rxflags2 = le16_to_cpu(rxhdr->flags2);
@@ -591,16 +599,40 @@
}
skb_put(skb, len);
for (i = 0; i < len - 1; i += 2) {
- tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
- *((u16 *)(skb->data + i)) = tmp;
+ tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
+ *((u16 *)(skb->data + i)) = cpu_to_le16(tmp);
}
if (len % 2) {
tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
skb->data[len - 1] = (tmp & 0x00FF);
+/* The specs say the following is required, but
+ * it is wrong and corrupts the PLCP. If we don't do
+ * this, the PLCP seems to be correct. So ifdef it out for now.
+ */
+#if 0
if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME)
- skb->data[0x20] = (tmp & 0xFF00) >> 8;
+ skb->data[2] = (tmp & 0xFF00) >> 8;
else
- skb->data[0x1E] = (tmp & 0xFF00) >> 8;
+ skb->data[0] = (tmp & 0xFF00) >> 8;
+#endif
}
+ skb_trim(skb, len - IEEE80211_FCS_LEN);
bcm43xx_rx(queue->bcm, skb, rxhdr);
}
+
+void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue)
+{
+ bcm43xx_power_saving_ctl_bits(queue->bcm, -1, 1);
+ bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+ bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
+ | BCM43xx_PIO_TXCTL_SUSPEND);
+}
+
+void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
+{
+ bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+ bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
+ & ~BCM43xx_PIO_TXCTL_SUSPEND);
+ bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1);
+ tasklet_schedule(&queue->txtask);
+}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
index 970627b..dfc7820 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
@@ -14,8 +14,8 @@
#define BCM43xx_PIO_RXCTL 0x08
#define BCM43xx_PIO_RXDATA 0x0A
-#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 0)
-#define BCM43xx_PIO_TXCTL_WRITELO (1 << 1)
+#define BCM43xx_PIO_TXCTL_WRITELO (1 << 0)
+#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 1)
#define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2)
#define BCM43xx_PIO_TXCTL_INIT (1 << 3)
#define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7)
@@ -95,6 +95,7 @@
u16 offset, u16 value)
{
bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value);
+ mmiowb();
}
@@ -107,6 +108,9 @@
struct bcm43xx_xmitstatus *status);
void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
+void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue);
+void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue);
+
#else /* CONFIG_BCM43XX_PIO */
static inline
@@ -133,6 +137,14 @@
void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
{
}
+static inline
+void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue)
+{
+}
+static inline
+void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
+{
+}
#endif /* CONFIG_BCM43XX_PIO */
#endif /* BCM43xx_PIO_H_ */