Skip to contentSkip to conversation

b43: Add PIO support for PCMCIA devices

PATCH In review Michael Buesch 3 participants 6 messages Mar 29, 2008 – Apr 3, 2008 Networking drivers (wireless)

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 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).

---

John, please queue for 2.6.26
With this patch (and the others I sent earlier) we can finally get 16bit PCMCIA and Compact Flash cards working.

drivers/net/wireless/b43/Kconfig +17 -0
Index: wireless-testing/drivers/net/wireless/b43/Kconfig
===================================================================
@@ -59,12 +59,19 @@ config B43_PCMCIA
 	  CF b43 cards can sometimes be found in handheld PCs.
 
 	  It's safe to select Y here, even if you don't have a B43 PCMCIA device.
 
 	  If unsure, say N.
 
+# Data transfers to the device via PIO
+# This is only needed on PCMCIA devices. All others can do DMA properly.
+config B43_PIO
+	bool
+	depends on B43 && (B43_PCMCIA || B43_FORCE_PIO)
+	default y
+
 config B43_NPHY
 	bool "Pre IEEE 802.11n support (BROKEN)"
 	depends on B43 && EXPERIMENTAL
 	---help---
 	  Support for the IEEE 802.11n draft.
 
@@ -91,6 +98,16 @@ config B43_DEBUG
 	depends on B43
 	---help---
 	  Broadcom 43xx debugging messages.
 
 	  Say Y, if you want to find out why the driver does not
 	  work for you.
+
+config B43_FORCE_PIO
+	bool "Force usage of PIO instead of DMA"
+	depends on B43 && B43_DEBUG
+	---help---
+	  This will disable DMA and always enable PIO instead.
+
+	  Say N!
+	  This is only for debugging the PIO engine code. You do
+	  _NOT_ want to enable this.
drivers/net/wireless/b43/pio.c new file +835 -0

835 lines not on this page · raw message

drivers/net/wireless/b43/pio.h new file +220 -0

220 lines not on this page · raw message

drivers/net/wireless/b43/Makefile +1 -0
Index: wireless-testing/drivers/net/wireless/b43/Makefile
===================================================================
@@ -5,12 +5,13 @@ b43-y				+= phy.o
 b43-$(CONFIG_B43_NPHY)		+= nphy.o
 b43-y				+= sysfs.o
 b43-y				+= xmit.o
 b43-y				+= lo.o
 b43-y				+= wa.o
 b43-y				+= dma.o
+b43-$(CONFIG_B43_PIO)		+= pio.o
 b43-$(CONFIG_B43_RFKILL)	+= rfkill.o
 b43-$(CONFIG_B43_LEDS)		+= leds.o
 b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o
 b43-$(CONFIG_B43_DEBUG)		+= debugfs.o
 
 obj-$(CONFIG_B43)		+= b43.o
drivers/net/wireless/b43/b43.h +56 -3

119 lines not on this page · raw message

drivers/net/wireless/b43/dma.c +64 -56

243 lines not on this page · raw message

drivers/net/wireless/b43/dma.h +3 -0
Index: wireless-testing/drivers/net/wireless/b43/dma.h
===================================================================
@@ -288,7 +288,10 @@ int b43_dma_tx(struct b43_wldev *dev,
 	       struct sk_buff *skb, struct ieee80211_tx_control *ctl);
 void b43_dma_handle_txstatus(struct b43_wldev *dev,
 			     const struct b43_txstatus *status);
 
 void b43_dma_rx(struct b43_dmaring *ring);
 
+void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
+			    unsigned int engine_index, bool enable);
+
 #endif /* B43_DMA_H_ */
drivers/net/wireless/b43/main.c +31 -6
Index: wireless-testing/drivers/net/wireless/b43/main.c
===================================================================
@@ -44,12 +44,13 @@
 
 #include "b43.h"
 #include "main.h"
 #include "debugfs.h"
 #include "phy.h"
 #include "dma.h"
+#include "pio.h"
 #include "sysfs.h"
 #include "xmit.h"
 #include "lo.h"
 #include "pcmcia.h"
 
 MODULE_DESCRIPTION("Broadcom B43 wireless driver");
@@ -1590,14 +1591,18 @@ static void b43_interrupt_tasklet(struct
 	if (reason & B43_IRQ_TXFIFO_FLUSH_OK)
 		;/* TODO */
 	if (reason & B43_IRQ_NOISESAMPLE_OK)
 		handle_irq_noise(dev);
 
 	/* Check the DMA reason registers for received data. */
-	if (dma_reason[0] & B43_DMAIRQ_RX_DONE)
-		b43_dma_rx(dev->dma.rx_ring);
+	if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
+		if (b43_using_pio_transfers(dev))
+			b43_pio_rx(dev->pio.rx_queue);
+		else
+			b43_dma_rx(dev->dma.rx_ring);
+	}
 	B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
 	B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
 	B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
 	B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
 	B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
 
@@ -2695,18 +2700,27 @@ static int b43_op_tx(struct ieee80211_hw
 		     struct ieee80211_tx_control *ctl)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
 	int err = -ENODEV;
 
+	if (unlikely(skb->len < 2 + 2 + 6)) {
+		/* Too short, this can't be a valid frame. */
+		return -EINVAL;
+	}
+	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+
 	if (unlikely(!dev))
 		goto out;
 	if (unlikely(b43_status(dev) < B43_STAT_STARTED))
 		goto out;
-	/* DMA-TX is done without a global lock. */
-	err = b43_dma_tx(dev, skb, ctl);
+	/* TX is done without a global lock. */
+	if (b43_using_pio_transfers(dev))
+		err = b43_pio_tx(dev, skb, ctl);
+	else
+		err = b43_dma_tx(dev, skb, ctl);
 out:
 	if (unlikely(err))
 		return NETDEV_TX_BUSY;
 	return NETDEV_TX_OK;
 }
 
@@ -2894,13 +2908,16 @@ static int b43_op_get_tx_stats(struct ie
 	int err = -ENODEV;
 
 	if (!dev)
 		goto out;
 	spin_lock_irqsave(&wl->irq_lock, flags);
 	if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
-		b43_dma_get_tx_stats(dev, stats);
+		if (b43_using_pio_transfers(dev))
+			b43_pio_get_tx_stats(dev, stats);
+		else
+			b43_dma_get_tx_stats(dev, stats);
 		err = 0;
 	}
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 out:
 	return err;
 }
@@ -3363,12 +3380,13 @@ static void b43_wireless_core_stop(struc
 	b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);	/* flush */
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 	b43_synchronize_irq(dev);
 
 	b43_set_status(dev, B43_STAT_INITIALIZED);
 
+	b43_pio_stop(dev);
 	mutex_unlock(&wl->mutex);
 	/* Must unlock as it would otherwise deadlock. No races here.
 	 * Cancel the possibly running self-rearming periodic work. */
 	cancel_delayed_work_sync(&dev->periodic_work);
 	mutex_lock(&wl->mutex);
 
@@ -3680,12 +3698,13 @@ static void b43_wireless_core_exit(struc
 
 	if (!dev->suspend_in_progress) {
 		b43_leds_exit(dev);
 		b43_rng_exit(dev->wl, false);
 	}
 	b43_dma_free(dev);
+	b43_pio_free(dev);
 	b43_chip_exit(dev);
 	b43_radio_turn_off(dev, 1);
 	b43_switch_analog(dev, 0);
 	if (phy->dyn_tssi_tbl)
 		kfree(phy->tssi2dbm);
 	kfree(phy->lo_control);
@@ -3777,13 +3796,19 @@ static int b43_wireless_core_init(struct
 	} else {
 		b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF);
 	}
 	/* Maximum Contention Window */
 	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-	err = b43_dma_init(dev);
+	if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) {
+		dev->__using_pio_transfers = 1;
+		err = b43_pio_init(dev);
+	} else {
+		dev->__using_pio_transfers = 0;
+		err = b43_dma_init(dev);
+	}
 	if (err)
 		goto err_chip_exit;
 	b43_qos_init(dev);
 
 //FIXME
 #if 1
drivers/net/wireless/b43/xmit.c +38 -23

93 lines not on this page · raw message

drivers/net/wireless/b43/xmit.h +2 -15
Index: wireless-testing/drivers/net/wireless/b43/xmit.h
===================================================================
@@ -204,24 +204,12 @@ enum {
 	B43_TXST_SUPP_CHAN,	/* Channel mismatch */
 	B43_TXST_SUPP_LIFE,	/* Lifetime expired */
 	B43_TXST_SUPP_UNDER,	/* Buffer underflow */
 	B43_TXST_SUPP_ABNACK,	/* Afterburner NACK */
 };
 
-/* Transmit Status as received through DMA/PIO on old chips */
-struct b43_hwtxstatus {
-	PAD_BYTES(4);
-	__le16 cookie;
-	u8 flags;
-	u8 count;
-	 PAD_BYTES(2);
-	__le16 seq;
-	u8 phy_stat;
-	 PAD_BYTES(1);
-} __attribute__ ((__packed__));
-
 /* Receive header for v4 firmware. */
 struct b43_rxhdr_fw4 {
 	__le16 frame_len;	/* Frame length */
 	 PAD_BYTES(2);
 	__le16 phy_status0;	/* PHY RX Status 0 */
 	__u8 jssi;		/* PHY RX Status 1: JSSI */
@@ -292,15 +280,14 @@ void b43_generate_plcp_hdr(struct b43_pl
 			   const u16 octets, const u8 bitrate);
 
 void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
 
 void b43_handle_txstatus(struct b43_wldev *dev,
 			 const struct b43_txstatus *status);
-
-void b43_handle_hwtxstatus(struct b43_wldev *dev,
-			   const struct b43_hwtxstatus *hw);
+bool b43_fill_txstatus_report(struct ieee80211_tx_status *report,
+			      const struct b43_txstatus *status);
 
 void b43_tx_suspend(struct b43_wldev *dev);
 void b43_tx_resume(struct b43_wldev *dev);
 
 
 /* Helper functions for converting the key-table index from "firmware-format"
#1 lore raw

drivers/net/wireless/b43/Kconfig config B43_PCMCIA · line 74

Quoted 10 lines · Michael Buesch
drivers/net/wireless/b43/Kconfig +7 -0
+# Data transfers to the device via PIO
+# This is only needed on PCMCIA devices. All others can do DMA properly.
+config B43_PIO
+	bool
+	depends on B43 && (B43_PCMCIA || B43_FORCE_PIO)
+	default y
+
 config B43_NPHY
 	bool "Pre IEEE 802.11n support (BROKEN)"
 	depends on B43 && EXPERIMENTAL

Oh, this generates a tiny fuzz here, as I locally removed the && BROKEN from B43_NPHY. I guess that's trivial to fix for you and I don't need to rediff without that local patch applied before. :)

Quoted 3 lines
drivers/net/wireless/b43/Kconfig +0 -0
 	---help---
 	  Support for the IEEE 802.11n draft.
#2 lore raw
In reply to Michael Buesch
Quoted 4 lines

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).

Does this mean there are b43 based compact flash cards available?

maintainer
#3 lore raw
Quoted 6 lines · Holger Schurig
Quoted 4 lines

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).

Does this mean there are b43 based compact flash cards available?

Yes, for example this one which we have a few
of: http://www.summitdatacom.com/specifications.htm#SDC-CF10G_802.11g_Compact_Flash_Module_with_Antenna_Connectors

johannes

maintainer
#4 lore raw
In reply to Michael Buesch
Quoted 4 lines

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).

Oddly, my CF card still doesn't work. Is there anything else I need in a current wireless-testing tree?

johannes

#5 lore raw
Quoted 7 lines · On Thursday 03 April 2008 12:36:48 Johannes Berg wrote:
Quoted 4 lines

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).

Oddly, my CF card still doesn't work. Is there anything else I need in a current wireless-testing tree?

Yeah, see my wireless-testing patches directory. There are still a few patches that john did not apply, yet.

Signature · 1 line
Greetings Michael.