Commit 77db31ea authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville

[PATCH] bcm43xx: Partially fix PIO code. Add Kconfig option for PIO or DMA mode (or both).

Signed-off-by: default avatarMichael Buesch <mbuesch@freenet.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5c57807a
......@@ -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
......
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
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)
......@@ -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)
{
......
......@@ -94,6 +94,10 @@
#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_ */
......@@ -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;
......
This diff is collapsed.
......@@ -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>
......@@ -32,6 +31,10 @@
#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_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment