aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/main.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2008-03-29 16:01:16 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-08 15:05:56 -0400
commit5100d5ac81b9330dc57e35adbe50923ba6107b8f (patch)
tree48224236b50703606c97c05ec077fde4880fc3b9 /drivers/net/wireless/b43/main.c
parent3109ece1114293b8201d9c140d02d7ce9a9fa387 (diff)
b43: Add PIO support for PCMCIA devices
This adds PIO support back (D'oh!) for PCMCIA devices. This is a complete rewrite of the old PIO code. It does actually work and we get reasonable performance out of it on a modern machine. On a PowerBook G4 I get a few MBit for TX and a few more for RX. So it doesn't work as well as DMA (of course), but it's a _lot_ faster than the old PIO code (only got a few kBit with that). The limiting factor is the host CPU speed. So it will generate 100% CPU usage when the network interface is heavily loaded. A voluntary preemption point in the RX path makes sure Desktop Latency isn't hurt. PIO is needed for 16bit PCMCIA devices, as we really don't want to poke with the braindead DMA mechanisms on PCMCIA sockets. Additionally, not all PCMCIA sockets do actually support DMA in 16bit mode (mine doesn't). Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r--drivers/net/wireless/b43/main.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index a4e6a59ccac8..355f28a2f7f5 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -47,6 +47,7 @@
47#include "debugfs.h" 47#include "debugfs.h"
48#include "phy.h" 48#include "phy.h"
49#include "dma.h" 49#include "dma.h"
50#include "pio.h"
50#include "sysfs.h" 51#include "sysfs.h"
51#include "xmit.h" 52#include "xmit.h"
52#include "lo.h" 53#include "lo.h"
@@ -1593,8 +1594,12 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
1593 handle_irq_noise(dev); 1594 handle_irq_noise(dev);
1594 1595
1595 /* Check the DMA reason registers for received data. */ 1596 /* Check the DMA reason registers for received data. */
1596 if (dma_reason[0] & B43_DMAIRQ_RX_DONE) 1597 if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
1597 b43_dma_rx(dev->dma.rx_ring); 1598 if (b43_using_pio_transfers(dev))
1599 b43_pio_rx(dev->pio.rx_queue);
1600 else
1601 b43_dma_rx(dev->dma.rx_ring);
1602 }
1598 B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); 1603 B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
1599 B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); 1604 B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
1600 B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE); 1605 B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
@@ -2698,12 +2703,21 @@ static int b43_op_tx(struct ieee80211_hw *hw,
2698 struct b43_wldev *dev = wl->current_dev; 2703 struct b43_wldev *dev = wl->current_dev;
2699 int err = -ENODEV; 2704 int err = -ENODEV;
2700 2705
2706 if (unlikely(skb->len < 2 + 2 + 6)) {
2707 /* Too short, this can't be a valid frame. */
2708 return -EINVAL;
2709 }
2710 B43_WARN_ON(skb_shinfo(skb)->nr_frags);
2711
2701 if (unlikely(!dev)) 2712 if (unlikely(!dev))
2702 goto out; 2713 goto out;
2703 if (unlikely(b43_status(dev) < B43_STAT_STARTED)) 2714 if (unlikely(b43_status(dev) < B43_STAT_STARTED))
2704 goto out; 2715 goto out;
2705 /* DMA-TX is done without a global lock. */ 2716 /* TX is done without a global lock. */
2706 err = b43_dma_tx(dev, skb, ctl); 2717 if (b43_using_pio_transfers(dev))
2718 err = b43_pio_tx(dev, skb, ctl);
2719 else
2720 err = b43_dma_tx(dev, skb, ctl);
2707out: 2721out:
2708 if (unlikely(err)) 2722 if (unlikely(err))
2709 return NETDEV_TX_BUSY; 2723 return NETDEV_TX_BUSY;
@@ -2897,7 +2911,10 @@ static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
2897 goto out; 2911 goto out;
2898 spin_lock_irqsave(&wl->irq_lock, flags); 2912 spin_lock_irqsave(&wl->irq_lock, flags);
2899 if (likely(b43_status(dev) >= B43_STAT_STARTED)) { 2913 if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
2900 b43_dma_get_tx_stats(dev, stats); 2914 if (b43_using_pio_transfers(dev))
2915 b43_pio_get_tx_stats(dev, stats);
2916 else
2917 b43_dma_get_tx_stats(dev, stats);
2901 err = 0; 2918 err = 0;
2902 } 2919 }
2903 spin_unlock_irqrestore(&wl->irq_lock, flags); 2920 spin_unlock_irqrestore(&wl->irq_lock, flags);
@@ -3366,6 +3383,7 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
3366 3383
3367 b43_set_status(dev, B43_STAT_INITIALIZED); 3384 b43_set_status(dev, B43_STAT_INITIALIZED);
3368 3385
3386 b43_pio_stop(dev);
3369 mutex_unlock(&wl->mutex); 3387 mutex_unlock(&wl->mutex);
3370 /* Must unlock as it would otherwise deadlock. No races here. 3388 /* Must unlock as it would otherwise deadlock. No races here.
3371 * Cancel the possibly running self-rearming periodic work. */ 3389 * Cancel the possibly running self-rearming periodic work. */
@@ -3683,6 +3701,7 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
3683 b43_rng_exit(dev->wl, false); 3701 b43_rng_exit(dev->wl, false);
3684 } 3702 }
3685 b43_dma_free(dev); 3703 b43_dma_free(dev);
3704 b43_pio_free(dev);
3686 b43_chip_exit(dev); 3705 b43_chip_exit(dev);
3687 b43_radio_turn_off(dev, 1); 3706 b43_radio_turn_off(dev, 1);
3688 b43_switch_analog(dev, 0); 3707 b43_switch_analog(dev, 0);
@@ -3780,7 +3799,13 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
3780 /* Maximum Contention Window */ 3799 /* Maximum Contention Window */
3781 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); 3800 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
3782 3801
3783 err = b43_dma_init(dev); 3802 if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) {
3803 dev->__using_pio_transfers = 1;
3804 err = b43_pio_init(dev);
3805 } else {
3806 dev->__using_pio_transfers = 0;
3807 err = b43_dma_init(dev);
3808 }
3784 if (err) 3809 if (err)
3785 goto err_chip_exit; 3810 goto err_chip_exit;
3786 b43_qos_init(dev); 3811 b43_qos_init(dev);