]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
[PATCH] bcm43xx: Partially fix PIO code. Add Kconfig option for PIO or DMA mode ...
authorMichael Buesch <mbuesch@freenet.de>
Sun, 12 Feb 2006 15:47:44 +0000 (16:47 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 27 Mar 2006 16:18:32 +0000 (11:18 -0500)
Signed-off-by: Michael Buesch <mbuesch@freenet.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/Kconfig
drivers/net/wireless/bcm43xx/Kconfig [new file with mode: 0644]
drivers/net/wireless/bcm43xx/Makefile
drivers/net/wireless/bcm43xx/bcm43xx.h
drivers/net/wireless/bcm43xx/bcm43xx_dma.h
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/bcm43xx/bcm43xx_pio.c
drivers/net/wireless/bcm43xx/bcm43xx_pio.h

index 3b1363c9719197752eeac89005c8723682948e49..5c4d7b4ece5e9627522080c2677d6778bc04a0a3 100644 (file)
@@ -500,23 +500,7 @@ config PRISM54
          will be called prism54.ko.
 
 source "drivers/net/wireless/hostap/Kconfig"
-
-config BCM43XX
-       tristate "Broadcom BCM43xx wireless support"
-       depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL
-       select FW_LOADER
-       ---help---
-         This is an experimental driver for the Broadcom 43xx wireless chip,
-         found in the Apple Airport Extreme and various other devices.
-
-config BCM43XX_DEBUG
-       bool "Broadcom BCM43xx debugging (RECOMMENDED)"
-       depends on BCM43XX
-       default y
-       ---help---
-         Broadcom 43xx debugging messages.
-         Say Y, because the driver is still very experimental and
-         this will help you get it running.
+source "drivers/net/wireless/bcm43xx/Kconfig"
 
 # yes, this works even when no drivers are selected
 config NET_WIRELESS
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig
new file mode 100644 (file)
index 0000000..d8d2315
--- /dev/null
@@ -0,0 +1,57 @@
+config BCM43XX
+       tristate "Broadcom BCM43xx wireless support"
+       depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
+       select FW_LOADER
+       ---help---
+         This is an experimental driver for the Broadcom 43xx wireless chip,
+         found in the Apple Airport Extreme and various other devices.
+
+config BCM43XX_DEBUG
+       bool "Broadcom BCM43xx debugging (RECOMMENDED)"
+       depends on BCM43XX
+       default y
+       ---help---
+         Broadcom 43xx debugging messages.
+         Say Y, because the driver is still very experimental and
+         this will help you get it running.
+
+config BCM43XX_DMA
+       bool
+config BCM43XX_PIO
+       bool
+
+choice
+       prompt "BCM43xx data transfer mode"
+       depends on BCM43XX
+       default BCM43XX_DMA_AND_PIO
+
+config BCM43XX_DMA_AND_PIO_MODE
+       bool "DMA + PIO"
+       select BCM43XX_DMA
+       select BCM43XX_PIO
+       ---help---
+         Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
+         data transfer modes.
+         The actually used mode is selectable through the module
+         parameter "pio". If the module parameter is pio=0, DMA is used.
+         Otherwise PIO is used. DMA is default.
+
+         If unsure, choose this option.
+
+config BCM43XX_DMA_MODE
+       bool "DMA (Direct Memory Access) only"
+       select BCM43XX_DMA
+       ---help---
+         Only include Direct Memory Access (DMA).
+         This reduces the size of the driver module, by omitting the PIO code.
+
+config BCM43XX_PIO_MODE
+       bool "PIO (Programmed I/O) only"
+       select BCM43XX_PIO
+       ---help---
+         Only include Programmed I/O (PIO).
+         This reduces the size of the driver module, by omitting the DMA code.
+         Please note that PIO transfers are slow (compared to DMA).
+         Only use PIO, if DMA does not work for you.
+
+endchoice
index e025e9f052b24824ff2831fac16f744ee13e71dc..c87c1525b39fb7687ab054102305d55d64bd9119 100644 (file)
@@ -1,9 +1,11 @@
 obj-$(CONFIG_BCM43XX) += bcm43xx.o
 bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o
 
-bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o \
+bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o
+bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o
+
+bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \
                bcm43xx_radio.o bcm43xx_phy.o \
                bcm43xx_power.o bcm43xx_wx.o \
-               bcm43xx_pio.o bcm43xx_ilt.o \
                bcm43xx_leds.o bcm43xx_ethtool.o \
                $(bcm43xx-obj-y)
index 981d563f57382fe0132a19ff4c31af8c8d00f78f..3d8ac7e952cc3d7fae195e98455637f9c9ff8bd4 100644 (file)
@@ -639,7 +639,7 @@ struct bcm43xx_private {
        u32 initialized:1,              /* init_board() succeed */
            was_initialized:1,          /* for PCI suspend/resume. */
            shutting_down:1,            /* free_board() in progress */
-           pio_mode:1,                 /* PIO (if true), or DMA (if false) used. */
+           __using_pio:1,              /* Internal, use bcm43xx_using_pio(). */
            bad_frames_preempt:1,       /* Use "Bad Frames Preemption" (default off) */
            reg124_set_0x4:1,           /* Some variable to keep track of IRQ stuff. */
            powersaving:1,              /* TRUE if we are in PowerSaving mode. FALSE otherwise. */
@@ -749,6 +749,33 @@ struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
        return ieee80211softmac_priv(dev);
 }
 
+
+/* Helper function, which returns a boolean.
+ * TRUE, if PIO is used; FALSE, if DMA is used.
+ */
+#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
+static inline
+int bcm43xx_using_pio(struct bcm43xx_private *bcm)
+{
+       return bcm->__using_pio;
+}
+#elif defined(CONFIG_BCM43XX_DMA)
+static inline
+int bcm43xx_using_pio(struct bcm43xx_private *bcm)
+{
+       return 0;
+}
+#elif defined(CONFIG_BCM43XX_PIO)
+static inline
+int bcm43xx_using_pio(struct bcm43xx_private *bcm)
+{
+       return 1;
+}
+#else
+# error "Using neither DMA nor PIO? Confused..."
+#endif
+
+
 static inline
 int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm)
 {
index 93e99d61f2e18930de48b0c6cf2da0235bed5191..88ad34dff2f23b07b30e6accd18ecdc8be0ba208 100644 (file)
 #define BCM43xx_TXRESUME_PERCENT       50
 
 
+
+#ifdef CONFIG_BCM43XX_DMA
+
+
 struct sk_buff;
 struct bcm43xx_private;
 struct bcm43xx_xmitstatus;
@@ -172,4 +176,46 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
                   struct ieee80211_txb *txb);
 void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
 
+
+#else /* CONFIG_BCM43XX_DMA */
+
+
+static inline
+int bcm43xx_dma_init(struct bcm43xx_private *bcm)
+{
+       return 0;
+}
+static inline
+void bcm43xx_dma_free(struct bcm43xx_private *bcm)
+{
+}
+static inline
+int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
+                                  u16 dmacontroller_mmio_base)
+{
+       return 0;
+}
+static inline
+int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
+                                  u16 dmacontroller_mmio_base)
+{
+       return 0;
+}
+static inline
+int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
+                  struct ieee80211_txb *txb)
+{
+       return 0;
+}
+static inline
+void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
+                                  struct bcm43xx_xmitstatus *status)
+{
+}
+static inline
+void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
+{
+}
+
+#endif /* CONFIG_BCM43XX_DMA */
 #endif /* BCM43xx_DMA_H_ */
index 4c4a2d71ca04176c7aaac511c7efe60de1c266dd..4e49da99818d1acedfec3ed17430cacc2b44f20b 100644 (file)
@@ -62,10 +62,15 @@ MODULE_LICENSE("GPL");
 extern char *nvram_get(char *name);
 #endif
 
-/* Module parameters */
+#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
 static int modparam_pio;
 module_param_named(pio, modparam_pio, int, 0444);
 MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
+#elif defined(CONFIG_BCM43XX_DMA)
+# define modparam_pio  0
+#elif defined(CONFIG_BCM43XX_PIO)
+# define modparam_pio  1
+#endif
 
 static int modparam_bad_frames_preempt;
 module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
@@ -1528,7 +1533,8 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
 {
        u32 flags = 0x00040000;
 
-       if ((bcm43xx_core_enabled(bcm)) && (!bcm->pio_mode)) {
+       if ((bcm43xx_core_enabled(bcm)) &&
+           !bcm43xx_using_pio(bcm)) {
 //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
 #ifndef CONFIG_BCM947XX
                /* reset all used DMA controllers. */
@@ -1635,7 +1641,7 @@ static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm)
                }
                //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
 
-               if (bcm->pio_mode)
+               if (bcm43xx_using_pio(bcm))
                        bcm43xx_pio_handle_xmitstatus(bcm, &stat);
                else
                        bcm43xx_dma_handle_xmitstatus(bcm, &stat);
@@ -1933,7 +1939,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
        assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
        assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
        if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
-               if (bcm->pio_mode)
+               if (bcm43xx_using_pio(bcm))
                        bcm43xx_pio_rx(bcm->current_core->pio->queue0);
                else
                        bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0);
@@ -1941,7 +1947,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
        }
        if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
                if (likely(bcm->current_core->rev < 5)) {
-                       if (bcm->pio_mode)
+                       if (bcm43xx_using_pio(bcm))
                                bcm43xx_pio_rx(bcm->current_core->pio->queue3);
                        else
                                bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1);
@@ -1999,7 +2005,7 @@ void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm,
        bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
                             & 0x0001dc00;
 
-       if ((bcm->pio_mode) &&
+       if (bcm43xx_using_pio(bcm) &&
            (bcm->current_core->rev < 3) &&
            (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
                /* Apply a PIO specific workaround to the dma_reasons */
@@ -2624,7 +2630,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
        value32 |= 0x100000; //FIXME: What's this? Is this correct?
        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
 
-       if (bcm->pio_mode) {
+       if (bcm43xx_using_pio(bcm)) {
                bcm43xx_write32(bcm, 0x0210, 0x00000100);
                bcm43xx_write32(bcm, 0x0230, 0x00000100);
                bcm43xx_write32(bcm, 0x0250, 0x00000100);
@@ -3123,15 +3129,12 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
        if (bcm->current_core->rev >= 5)
                bcm43xx_write16(bcm, 0x043C, 0x000C);
 
-       if (!bcm->pio_mode) {
-               err = bcm43xx_dma_init(bcm);
-               if (err)
-                       goto err_chip_cleanup;
-       } else {
+       if (bcm43xx_using_pio(bcm))
                err = bcm43xx_pio_init(bcm);
-               if (err)
-                       goto err_chip_cleanup;
-       }
+       else
+               err = bcm43xx_dma_init(bcm);
+       if (err)
+               goto err_chip_cleanup;
        bcm43xx_write16(bcm, 0x0612, 0x0050);
        bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
        bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
@@ -4001,8 +4004,8 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
 {
        int err = -ENODEV;
 
-       if (bcm->pio_mode)
-               err = bcm43xx_pio_transfer_txb(bcm, txb);
+       if (bcm43xx_using_pio(bcm))
+               err = bcm43xx_pio_tx(bcm, txb);
        else
                err = bcm43xx_dma_tx(bcm, txb);
 
@@ -4158,10 +4161,10 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
        return 0;
 }
 
-static void bcm43xx_init_private(struct bcm43xx_private *bcm,
-                                struct net_device *net_dev,
-                                struct pci_dev *pci_dev,
-                                struct workqueue_struct *wq)
+static int bcm43xx_init_private(struct bcm43xx_private *bcm,
+                               struct net_device *net_dev,
+                               struct pci_dev *pci_dev,
+                               struct workqueue_struct *wq)
 {
        bcm->ieee = netdev_priv(net_dev);
        bcm->softmac = ieee80211_priv(net_dev);
@@ -4190,13 +4193,17 @@ static void bcm43xx_init_private(struct bcm43xx_private *bcm,
                     (unsigned long)bcm);
        tasklet_disable_nosync(&bcm->isr_tasklet);
        if (modparam_pio) {
-               bcm->pio_mode = 1;
+               bcm->__using_pio = 1;
        } else {
-               if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK) == 0) {
-                       bcm->pio_mode = 0;
-               } else {
+               if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK)) {
+#ifdef CONFIG_BCM43XX_PIO
                        printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
-                       bcm->pio_mode = 1;
+                       bcm->__using_pio = 1;
+#else
+                       printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+                                           "Recompile the driver with PIO support, please.\n");
+                       return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
                }
        }
        bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
@@ -4210,6 +4217,8 @@ static void bcm43xx_init_private(struct bcm43xx_private *bcm,
        bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
        bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
        bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
+
+       return 0;
 }
 
 static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
@@ -4261,7 +4270,9 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
                err = -ENOMEM;
                goto err_free_netdev;
        }
-       bcm43xx_init_private(bcm, net_dev, pdev, wq);
+       err = bcm43xx_init_private(bcm, net_dev, pdev, wq);
+       if (err)
+               goto err_destroy_wq;
 
        pci_set_drvdata(pdev, net_dev);
 
@@ -4325,7 +4336,9 @@ static void bcm43xx_chip_reset(void *_bcm)
                bcm43xx_free_board(bcm);
        bcm->firmware_norelease = 0;
        bcm43xx_detach_board(bcm);
-       bcm43xx_init_private(bcm, net_dev, pci_dev, wq);
+       err = bcm43xx_init_private(bcm, net_dev, pci_dev, wq);
+       if (err)
+               goto failure;
        err = bcm43xx_attach_board(bcm);
        if (err)
                goto failure;
index 9a55e9d0052844ee9571d9d40e2517be31a401dd..0bf4b3e26f9dbf68486e52750b18ee15e0ebaf23 100644 (file)
 #include <linux/delay.h>
 
 
-static inline
-u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue,
-                    u16 offset)
+static void tx_start(struct bcm43xx_pioqueue *queue)
 {
-       return bcm43xx_read16(queue->bcm, queue->mmio_base + offset);
+       bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+                         BCM43xx_PIO_TXCTL_INIT);
 }
 
-static inline
-void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue,
-                      u16 offset, u16 value)
+static void tx_octet(struct bcm43xx_pioqueue *queue,
+                    u8 octet)
 {
-       bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value);
+       if (queue->need_workarounds) {
+               bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
+                                 octet);
+               bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+                                 BCM43xx_PIO_TXCTL_WRITEHI);
+       } else {
+               bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+                                 BCM43xx_PIO_TXCTL_WRITEHI);
+               bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA,
+                                 octet);
+       }
 }
 
-static inline
-void tx_start(struct bcm43xx_pioqueue *queue)
+static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr,
+                           const u8 *packet,
+                           unsigned int *pos)
 {
-       bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_INIT);
-}
+       const u8 *source;
+       unsigned int i = *pos;
+       u16 ret;
 
-static inline
-void tx_octet(struct bcm43xx_pioqueue *queue,
-             u8 octet)
-{
-       if (queue->bcm->current_core->rev < 3) {
-               bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet);
-               bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI);
+       if (i < sizeof(*txhdr)) {
+               source = (const u8 *)txhdr;
        } else {
-               bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI);
-               bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet);
+               source = packet;
+               i -= sizeof(*txhdr);
        }
+       ret = le16_to_cpu( *((u16 *)(source + i)) );
+       *pos += 2;
+
+       return ret;
 }
 
-static inline
-void tx_data(struct bcm43xx_pioqueue *queue,
-            u8 *packet,
-            unsigned int octets)
+static void tx_data(struct bcm43xx_pioqueue *queue,
+                   struct bcm43xx_txhdr *txhdr,
+                   const u8 *packet,
+                   unsigned int octets)
 {
        u16 data;
        unsigned int i = 0;
 
-       if (queue->bcm->current_core->rev < 3) {
-               data = be16_to_cpu( *((u16 *)packet) );
+       if (queue->need_workarounds) {
+               data = tx_get_next_word(txhdr, packet, &i);
                bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
-               i += 2;
        }
        bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
-                         BCM43xx_PIO_TXCTL_WRITELO | BCM43xx_PIO_TXCTL_WRITEHI);
-       for ( ; i < octets - 1; i += 2) {
-               data = be16_to_cpu( *((u16 *)(packet + i)) );
+                         BCM43xx_PIO_TXCTL_WRITELO |
+                         BCM43xx_PIO_TXCTL_WRITEHI);
+       while (i < octets - 1) {
+               data = tx_get_next_word(txhdr, packet, &i);
                bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
        }
        if (octets % 2)
-               tx_octet(queue, packet[octets - 1]);
+               tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]);
 }
 
-static inline
-void tx_complete(struct bcm43xx_pioqueue *queue,
-                struct sk_buff *skb)
+static void tx_complete(struct bcm43xx_pioqueue *queue,
+                       struct sk_buff *skb)
 {
-       u16 data;
-
-       if (queue->bcm->current_core->rev < 3) {
-               data = be16_to_cpu( *((u16 *)(skb->data + skb->len - 2)) );
-               bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data);
+       if (queue->need_workarounds) {
+               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_COMPLETE);
+                                 BCM43xx_PIO_TXCTL_WRITEHI |
+                                 BCM43xx_PIO_TXCTL_COMPLETE);
        } else {
-               bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_COMPLETE);
+               bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL,
+                                 BCM43xx_PIO_TXCTL_COMPLETE);
        }
 }
 
-static inline
-u16 generate_cookie(struct bcm43xx_pioqueue *queue,
-                   int packetindex)
+static u16 generate_cookie(struct bcm43xx_pioqueue *queue,
+                          int packetindex)
 {
        u16 cookie = 0x0000;
 
@@ -113,8 +120,6 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue,
         * for the packet index (in the cache).
         */
        switch (queue->mmio_base) {
-       default:
-               assert(0);
        case BCM43xx_MMIO_PIO1_BASE:
                break;
        case BCM43xx_MMIO_PIO2_BASE:
@@ -126,6 +131,8 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue,
        case BCM43xx_MMIO_PIO4_BASE:
                cookie = 0x3000;
                break;
+       default:
+               assert(0);
        }
        assert(((u16)packetindex & 0xF000) == 0x0000);
        cookie |= (u16)packetindex;
@@ -133,66 +140,75 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue,
        return cookie;
 }
 
-static inline
+static
 struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm,
                                       u16 cookie,
                                       struct bcm43xx_pio_txpacket **packet)
 {
+       struct bcm43xx_pio *pio = bcm->current_core->pio;
        struct bcm43xx_pioqueue *queue = NULL;
        int packetindex;
 
        switch (cookie & 0xF000) {
        case 0x0000:
-               queue = bcm->current_core->pio->queue0;
+               queue = pio->queue0;
                break;
        case 0x1000:
-               queue = bcm->current_core->pio->queue1;
+               queue = pio->queue1;
                break;
        case 0x2000:
-               queue = bcm->current_core->pio->queue2;
+               queue = pio->queue2;
                break;
        case 0x3000:
-               queue = bcm->current_core->pio->queue3;
+               queue = pio->queue3;
                break;
        default:
                assert(0);
        }
-
        packetindex = (cookie & 0x0FFF);
        assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS);
-       *packet = queue->__tx_packets_cache + packetindex;
+       *packet = &(queue->tx_packets_cache[packetindex]);
 
        return queue;
 }
 
-static inline
-void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue,
-                          struct sk_buff *skb,
-                          struct bcm43xx_pio_txpacket *packet)
+static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue,
+                                 struct sk_buff *skb,
+                                 struct bcm43xx_pio_txpacket *packet)
 {
+       struct bcm43xx_txhdr txhdr;
        unsigned int octets;
 
        assert(skb_shinfo(skb)->nr_frags == 0);
-       assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
-
-       __skb_push(skb, sizeof(struct bcm43xx_txhdr));
        bcm43xx_generate_txhdr(queue->bcm,
-                              (struct bcm43xx_txhdr *)skb->data,
-                              skb->data + sizeof(struct bcm43xx_txhdr),
-                              skb->len - sizeof(struct bcm43xx_txhdr),
+                              &txhdr, skb->data, skb->len,
                               (packet->xmitted_frags == 0),
                               generate_cookie(queue, pio_txpacket_getindex(packet)));
 
        tx_start(queue);
-       octets = skb->len;
-       if (queue->bcm->current_core->rev < 3) //FIXME: && this is the last packet in the queue.
-               octets -= 2;
-       tx_data(queue, (u8 *)skb->data, octets);
+       octets = skb->len + sizeof(txhdr);
+       if (queue->need_workarounds)
+               octets--;
+       tx_data(queue, &txhdr, (u8 *)skb->data, octets);
        tx_complete(queue, skb);
 }
 
-static inline
-int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
+static void free_txpacket(struct bcm43xx_pio_txpacket *packet,
+                         int irq_context)
+{
+       struct bcm43xx_pioqueue *queue = packet->queue;
+
+       ieee80211_txb_free(packet->txb);
+       list_move(&packet->list, &queue->txfree);
+       queue->nr_txfree++;
+
+       assert(queue->tx_devq_used >= packet->xmitted_octets);
+       assert(queue->tx_devq_packets >= packet->xmitted_frags);
+       queue->tx_devq_used -= packet->xmitted_octets;
+       queue->tx_devq_packets -= packet->xmitted_frags;
+}
+
+static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
 {
        struct bcm43xx_pioqueue *queue = packet->queue;
        struct ieee80211_txb *txb = packet->txb;
@@ -204,12 +220,11 @@ int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
                skb = txb->fragments[i];
 
                octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr);
-
                assert(queue->tx_devq_size >= octets);
                assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS);
                assert(queue->tx_devq_used <= queue->tx_devq_size);
                /* Check if there is sufficient free space on the device
-                * TX queue. If not, return and let the TX-work-handler
+                * TX queue. If not, return and let the TX tasklet
                 * retry later.
                 */
                if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS)
@@ -234,28 +249,15 @@ int pio_tx_packet(struct bcm43xx_pio_txpacket *packet)
        return 0;
 }
 
-static void free_txpacket(struct bcm43xx_pio_txpacket *packet)
+static void tx_tasklet(unsigned long d)
 {
-       struct bcm43xx_pioqueue *queue = packet->queue;
-
-       ieee80211_txb_free(packet->txb);
-
-       list_move(&packet->list, &packet->queue->txfree);
-
-       assert(queue->tx_devq_used >= packet->xmitted_octets);
-       queue->tx_devq_used -= packet->xmitted_octets;
-       assert(queue->tx_devq_packets >= packet->xmitted_frags);
-       queue->tx_devq_packets -= packet->xmitted_frags;
-}
-
-static void txwork_handler(void *d)
-{
-       struct bcm43xx_pioqueue *queue = d;
+       struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d;
+       struct bcm43xx_private *bcm = queue->bcm;
        unsigned long flags;
        struct bcm43xx_pio_txpacket *packet, *tmp_packet;
        int err;
 
-       spin_lock_irqsave(&queue->txlock, flags);
+       spin_lock_irqsave(&bcm->lock, flags);
        list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
                assert(packet->xmitted_frags < packet->txb->nr_frags);
                if (packet->xmitted_frags == 0) {
@@ -270,22 +272,22 @@ static void txwork_handler(void *d)
                                skb = packet->txb->fragments[i];
                                if (unlikely(skb->len > queue->tx_devq_size)) {
                                        dprintkl(KERN_ERR PFX "PIO TX device queue too small. "
-                                                             "Dropping packet...\n");
-                                       free_txpacket(packet);
+                                                             "Dropping packet.\n");
+                                       free_txpacket(packet, 1);
                                        goto next_packet;
                                }
                        }
                }
-               /* Now try to transmit the packet.
+               /* Try to transmit the packet.
                 * This may not completely succeed.
                 */
                err = pio_tx_packet(packet);
                if (err)
                        break;
-next_packet:
+       next_packet:
                continue;
        }
-       spin_unlock_irqrestore(&queue->txlock, flags);
+       spin_unlock_irqrestore(&bcm->lock, flags);
 }
 
 static void setup_txqueues(struct bcm43xx_pioqueue *queue)
@@ -293,8 +295,9 @@ static void setup_txqueues(struct bcm43xx_pioqueue *queue)
        struct bcm43xx_pio_txpacket *packet;
        int i;
 
+       queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS;
        for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) {
-               packet = queue->__tx_packets_cache + i;
+               packet = &(queue->tx_packets_cache[i]);
 
                packet->queue = queue;
                INIT_LIST_HEAD(&packet->list);
@@ -311,19 +314,19 @@ struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm,
        u32 value;
        u16 qsize;
 
-       queue = kmalloc(sizeof(*queue), GFP_KERNEL);
+       queue = kzalloc(sizeof(*queue), GFP_KERNEL);
        if (!queue)
                goto out;
-       memset(queue, 0, sizeof(*queue));
 
        queue->bcm = bcm;
        queue->mmio_base = pio_mmio_base;
+       queue->need_workarounds = (bcm->current_core->rev < 3);
 
        INIT_LIST_HEAD(&queue->txfree);
        INIT_LIST_HEAD(&queue->txqueue);
        INIT_LIST_HEAD(&queue->txrunning);
-       spin_lock_init(&queue->txlock);
-       INIT_WORK(&queue->txwork, txwork_handler, queue);
+       tasklet_init(&queue->txtask, tx_tasklet,
+                    (unsigned long)queue);
 
        value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
        value |= BCM43xx_SBF_XFER_REG_BYTESWAP;
@@ -331,7 +334,7 @@ struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm,
 
        qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE);
        if (qsize <= BCM43xx_PIO_TXQADJUST) {
-               printk(KERN_ERR PFX "PIO tx 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;
@@ -354,13 +357,12 @@ static void cancel_transfers(struct bcm43xx_pioqueue *queue)
 
        netif_tx_disable(queue->bcm->net_dev);
        assert(queue->bcm->shutting_down);
-       cancel_delayed_work(&queue->txwork);
-       flush_workqueue(queue->bcm->workqueue);
+       tasklet_disable(&queue->txtask);
 
        list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
-               free_txpacket(packet);
+               free_txpacket(packet, 0);
        list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
-               free_txpacket(packet);
+               free_txpacket(packet, 0);
 }
 
 static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue)
@@ -374,40 +376,43 @@ static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue)
 
 void bcm43xx_pio_free(struct bcm43xx_private *bcm)
 {
-       bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue3);
-       bcm->current_core->pio->queue3 = NULL;
-       bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2);
-       bcm->current_core->pio->queue2 = NULL;
-       bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1);
-       bcm->current_core->pio->queue1 = NULL;
-       bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0);
-       bcm->current_core->pio->queue0 = NULL;
+       struct bcm43xx_pio *pio = bcm->current_core->pio;
+
+       bcm43xx_destroy_pioqueue(pio->queue3);
+       pio->queue3 = NULL;
+       bcm43xx_destroy_pioqueue(pio->queue2);
+       pio->queue2 = NULL;
+       bcm43xx_destroy_pioqueue(pio->queue1);
+       pio->queue1 = NULL;
+       bcm43xx_destroy_pioqueue(pio->queue0);
+       pio->queue0 = NULL;
 }
 
 int bcm43xx_pio_init(struct bcm43xx_private *bcm)
 {
+       struct bcm43xx_pio *pio = bcm->current_core->pio;
        struct bcm43xx_pioqueue *queue;
        int err = -ENOMEM;
 
        queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE);
        if (!queue)
                goto out;
-       bcm->current_core->pio->queue0 = queue;
+       pio->queue0 = queue;
 
        queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE);
        if (!queue)
                goto err_destroy0;
-       bcm->current_core->pio->queue1 = queue;
+       pio->queue1 = queue;
 
        queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE);
        if (!queue)
                goto err_destroy1;
-       bcm->current_core->pio->queue2 = queue;
+       pio->queue2 = queue;
 
        queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE);
        if (!queue)
                goto err_destroy2;
-       bcm->current_core->pio->queue3 = queue;
+       pio->queue3 = queue;
 
        if (bcm->current_core->rev < 3)
                bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND;
@@ -418,41 +423,38 @@ out:
        return err;
 
 err_destroy2:
-       bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2);
-       bcm->current_core->pio->queue2 = NULL;
+       bcm43xx_destroy_pioqueue(pio->queue2);
+       pio->queue2 = NULL;
 err_destroy1:
-       bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1);
-       bcm->current_core->pio->queue1 = NULL;
+       bcm43xx_destroy_pioqueue(pio->queue1);
+       pio->queue1 = NULL;
 err_destroy0:
-       bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0);
-       bcm->current_core->pio->queue0 = NULL;
+       bcm43xx_destroy_pioqueue(pio->queue0);
+       pio->queue0 = NULL;
        goto out;
 }
 
-static inline
-int pio_transfer_txb(struct bcm43xx_pioqueue *queue,
-                    struct ieee80211_txb *txb)
+int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
+                  struct ieee80211_txb *txb)
 {
+       struct bcm43xx_pioqueue *queue = bcm->current_core->pio->queue1;
        struct bcm43xx_pio_txpacket *packet;
-       unsigned long flags;
        u16 tmp;
 
-       spin_lock_irqsave(&queue->txlock, flags);
        assert(!queue->tx_suspended);
        assert(!list_empty(&queue->txfree));
 
        tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
-       if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) {
-               spin_unlock_irqrestore(&queue->txlock, flags);
+       if (tmp & BCM43xx_PIO_TXCTL_SUSPEND)
                return -EBUSY;
-       }
 
        packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list);
-
        packet->txb = txb;
-       list_move_tail(&packet->list, &queue->txqueue);
-       packet->xmitted_octets = 0;
        packet->xmitted_frags = 0;
+       packet->xmitted_octets = 0;
+       list_move_tail(&packet->list, &queue->txqueue);
+       queue->nr_txfree--;
+       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))) {
@@ -460,69 +462,66 @@ int pio_transfer_txb(struct bcm43xx_pioqueue *queue,
                queue->tx_suspended = 1;
        }
 
-       spin_unlock_irqrestore(&queue->txlock, flags);
-       queue_work(queue->bcm->workqueue, &queue->txwork);
+       tasklet_schedule(&queue->txtask);
 
        return 0;
 }
 
-int fastcall bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm,
-                                     struct ieee80211_txb *txb)
-{
-       return pio_transfer_txb(bcm->current_core->pio->queue1, txb);
-}
-
-void fastcall
-bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
-                             struct bcm43xx_xmitstatus *status)
+void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
+                                  struct bcm43xx_xmitstatus *status)
 {
        struct bcm43xx_pioqueue *queue;
        struct bcm43xx_pio_txpacket *packet;
-       unsigned long flags;
 
        queue = parse_cookie(bcm, status->cookie, &packet);
        assert(queue);
-       spin_lock_irqsave(&queue->txlock, flags);
-       free_txpacket(packet);
+//TODO
+if (!queue)
+return;
+       free_txpacket(packet, 1);
        if (unlikely(queue->tx_suspended)) {
                queue->tx_suspended = 0;
                netif_wake_queue(queue->bcm->net_dev);
        }
-
-       /* If there are packets on the txqueue,
-        * start the work handler again.
-        */
-       if (!list_empty(&queue->txqueue)) {
-               queue_work(queue->bcm->workqueue,
-                          &queue->txwork);
-       }
-       spin_unlock_irqrestore(&queue->txlock, flags);
+       /* If there are packets on the txqueue, poke the tasklet. */
+       if (!list_empty(&queue->txqueue))
+               tasklet_schedule(&queue->txtask);
 }
 
 static void pio_rx_error(struct bcm43xx_pioqueue *queue,
+                        int clear_buffers,
                         const char *error)
 {
-       printk("PIO RX error: %s\n", error);
-       bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_READY);
+       int i;
+
+       printkl("PIO RX error: %s\n", error);
+       bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
+                         BCM43xx_PIO_RXCTL_READY);
+       if (clear_buffers) {
+               assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE);
+               for (i = 0; i < 15; i++) {
+                       /* Dummy read. */
+                       bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
+               }
+       }
 }
 
-void fastcall
-bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
+void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
 {
        u16 preamble[21] = { 0 };
        struct bcm43xx_rxhdr *rxhdr;
-       u16 tmp;
-       u16 len;
-       int i, err;
-       int preamble_readwords;
+       u16 tmp, len, rxflags2;
+       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");
+               dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk.
                return;
        }
-       bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_DATAAVAILABLE);
+       bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL,
+                         BCM43xx_PIO_RXCTL_DATAAVAILABLE);
 
        for (i = 0; i < 10; i++) {
                tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL);
@@ -534,13 +533,14 @@ bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
        return;
 data_ready:
 
+//FIXME: endianess in this function.
        len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
        if (unlikely(len > 0x700)) {
-               pio_rx_error(queue, "len > 0x700");
+               pio_rx_error(queue, 0, "len > 0x700");
                return;
        }
        if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) {
-               pio_rx_error(queue, "len == 0");
+               pio_rx_error(queue, 0, "len == 0");
                return;
        }
        preamble[0] = cpu_to_le16(len);
@@ -550,28 +550,38 @@ data_ready:
                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);
+               preamble[i + 1] = cpu_to_be16(tmp);//FIXME?
        }
        rxhdr = (struct bcm43xx_rxhdr *)preamble;
-       if (unlikely(rxhdr->flags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) {
-               pio_rx_error(queue, "invalid frame");
-               if (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE) {
-                       for (i = 0; i < 15; i++)
-                               bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); /* dummy read. */
-               }
+       rxflags2 = le16_to_cpu(rxhdr->flags2);
+       if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) {
+               pio_rx_error(queue,
+                            (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE),
+                            "invalid frame");
                return;
        }
-//FIXME
-#if 0
        if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) {
-               bcm43xx_rx_transmitstatus(queue->bcm,
-                                         (const struct bcm43xx_hwxmitstatus *)(preamble + 1));
+               /* We received an xmit status. */
+               struct bcm43xx_hwxmitstatus *hw;
+               struct bcm43xx_xmitstatus stat;
+
+               hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1);
+               stat.cookie = le16_to_cpu(hw->cookie);
+               stat.flags = hw->flags;
+               stat.cnt1 = hw->cnt1;
+               stat.cnt2 = hw->cnt2;
+               stat.seq = le16_to_cpu(hw->seq);
+               stat.unknown = le16_to_cpu(hw->unknown);
+
+               bcm43xx_debugfs_log_txstat(queue->bcm, &stat);
+               bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat);
+
                return;
        }
-#endif
+
        skb = dev_alloc_skb(len);
        if (unlikely(!skb)) {
-               pio_rx_error(queue, "out of memory");
+               pio_rx_error(queue, 1, "OOM");
                return;
        }
        skb_put(skb, len);
@@ -580,13 +590,14 @@ data_ready:
                *((u16 *)(skb->data + i)) = tmp;
        }
        if (len % 2) {
-               tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA));
+               tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
                skb->data[len - 1] = (tmp & 0x00FF);
-               skb->data[0] = (tmp & 0xFF00) >> 8;
+               if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME)
+                       skb->data[0x20] = (tmp & 0xFF00) >> 8;
+               else
+                       skb->data[0x1E] = (tmp & 0xFF00) >> 8;
        }
-       err = bcm43xx_rx(queue->bcm, skb, rxhdr);
-       if (unlikely(err))
-               dev_kfree_skb_irq(skb);
+       bcm43xx_rx(queue->bcm, skb, rxhdr);
 }
 
 /* vim: set ts=8 sw=8 sts=8: */
index 71b92ee341691d09faaf27fbe4598447866511a6..970627bc1769acc285adc0ee04f33dcf6b2f6d94 100644 (file)
@@ -3,9 +3,8 @@
 
 #include "bcm43xx.h"
 
+#include <linux/interrupt.h>
 #include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
 #include <linux/skbuff.h>
 
 
 #define BCM43xx_PIO_MAXTXPACKETS       256
 
 
+
+#ifdef CONFIG_BCM43XX_PIO
+
+
 struct bcm43xx_pioqueue;
 struct bcm43xx_xmitstatus;
 
@@ -44,13 +47,14 @@ struct bcm43xx_pio_txpacket {
        u16 xmitted_octets;
 };
 
-#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->__tx_packets_cache)) 
+#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) 
 
 struct bcm43xx_pioqueue {
        struct bcm43xx_private *bcm;
        u16 mmio_base;
 
-       u8 tx_suspended:1;
+       u8 tx_suspended:1,
+          need_workarounds:1; /* Workarounds needed for core.rev < 3 */
 
        /* Adjusted size of the device internal TX buffer. */
        u16 tx_devq_size;
@@ -62,6 +66,7 @@ struct bcm43xx_pioqueue {
         * be taken on incoming TX requests.
         */
        struct list_head txfree;
+       unsigned int nr_txfree;
        /* Packets on the txqueue are queued,
         * but not completely written to the chip, yet.
         */
@@ -70,19 +75,64 @@ struct bcm43xx_pioqueue {
         * posted to the device. We are waiting for the txstatus.
         */
        struct list_head txrunning;
-       /* Locking of the TX queues and the accounting. */
-       spinlock_t txlock;
-       struct work_struct txwork;
-       struct bcm43xx_pio_txpacket __tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS];
+       /* Total number or packets sent.
+        * (This counter can obviously wrap).
+        */
+       unsigned int nr_tx_packets;
+       struct tasklet_struct txtask;
+       struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS];
 };
 
+static inline
+u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue,
+                    u16 offset)
+{
+       return bcm43xx_read16(queue->bcm, queue->mmio_base + offset);
+}
+
+static inline
+void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue,
+                      u16 offset, u16 value)
+{
+       bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value);
+}
+
+
 int bcm43xx_pio_init(struct bcm43xx_private *bcm);
 void bcm43xx_pio_free(struct bcm43xx_private *bcm);
 
-int FASTCALL(bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm,
-                                     struct ieee80211_txb *txb));
-void FASTCALL(bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
-                                           struct bcm43xx_xmitstatus *status));
-
-void FASTCALL(bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue));
+int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
+                  struct ieee80211_txb *txb);
+void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
+                                  struct bcm43xx_xmitstatus *status);
+void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
+
+#else /* CONFIG_BCM43XX_PIO */
+
+static inline
+int bcm43xx_pio_init(struct bcm43xx_private *bcm)
+{
+       return 0;
+}
+static inline
+void bcm43xx_pio_free(struct bcm43xx_private *bcm)
+{
+}
+static inline
+int bcm43xx_pio_tx(struct bcm43xx_private *bcm,
+                  struct ieee80211_txb *txb)
+{
+       return 0;
+}
+static inline
+void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
+                                  struct bcm43xx_xmitstatus *status)
+{
+}
+static inline
+void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
+{
+}
+
+#endif /* CONFIG_BCM43XX_PIO */
 #endif /* BCM43xx_PIO_H_ */