Commit 650b3b29 authored by Larry Finger's avatar Larry Finger Committed by Greg Kroah-Hartman

bcm43xx: fix regressions in 2.6.18

The bcm43xx code in 2.6.18 has a serious problems not found in 2.6.17, due to
a change in the locking mechanism introduced to reduce latency. The following patch
fixes the problems in locking, reduces the latency associated with the periodic
work tasklet, and contains code needed for those cards that use 64-bit DMA.
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 7752e010
...@@ -33,14 +33,18 @@ ...@@ -33,14 +33,18 @@
#define BCM43xx_PCICFG_ICR 0x94 #define BCM43xx_PCICFG_ICR 0x94
/* MMIO offsets */ /* MMIO offsets */
#define BCM43xx_MMIO_DMA1_REASON 0x20 #define BCM43xx_MMIO_DMA0_REASON 0x20
#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x24 #define BCM43xx_MMIO_DMA0_IRQ_MASK 0x24
#define BCM43xx_MMIO_DMA2_REASON 0x28 #define BCM43xx_MMIO_DMA1_REASON 0x28
#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x2C #define BCM43xx_MMIO_DMA1_IRQ_MASK 0x2C
#define BCM43xx_MMIO_DMA3_REASON 0x30 #define BCM43xx_MMIO_DMA2_REASON 0x30
#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x34 #define BCM43xx_MMIO_DMA2_IRQ_MASK 0x34
#define BCM43xx_MMIO_DMA4_REASON 0x38 #define BCM43xx_MMIO_DMA3_REASON 0x38
#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x3C #define BCM43xx_MMIO_DMA3_IRQ_MASK 0x3C
#define BCM43xx_MMIO_DMA4_REASON 0x40
#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x44
#define BCM43xx_MMIO_DMA5_REASON 0x48
#define BCM43xx_MMIO_DMA5_IRQ_MASK 0x4C
#define BCM43xx_MMIO_STATUS_BITFIELD 0x120 #define BCM43xx_MMIO_STATUS_BITFIELD 0x120
#define BCM43xx_MMIO_STATUS2_BITFIELD 0x124 #define BCM43xx_MMIO_STATUS2_BITFIELD 0x124
#define BCM43xx_MMIO_GEN_IRQ_REASON 0x128 #define BCM43xx_MMIO_GEN_IRQ_REASON 0x128
...@@ -56,14 +60,27 @@ ...@@ -56,14 +60,27 @@
#define BCM43xx_MMIO_XMITSTAT_1 0x174 #define BCM43xx_MMIO_XMITSTAT_1 0x174
#define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ #define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ #define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
#define BCM43xx_MMIO_DMA1_BASE 0x200
#define BCM43xx_MMIO_DMA2_BASE 0x220 /* 32-bit DMA */
#define BCM43xx_MMIO_DMA3_BASE 0x240 #define BCM43xx_MMIO_DMA32_BASE0 0x200
#define BCM43xx_MMIO_DMA4_BASE 0x260 #define BCM43xx_MMIO_DMA32_BASE1 0x220
#define BCM43xx_MMIO_DMA32_BASE2 0x240
#define BCM43xx_MMIO_DMA32_BASE3 0x260
#define BCM43xx_MMIO_DMA32_BASE4 0x280
#define BCM43xx_MMIO_DMA32_BASE5 0x2A0
/* 64-bit DMA */
#define BCM43xx_MMIO_DMA64_BASE0 0x200
#define BCM43xx_MMIO_DMA64_BASE1 0x240
#define BCM43xx_MMIO_DMA64_BASE2 0x280
#define BCM43xx_MMIO_DMA64_BASE3 0x2C0
#define BCM43xx_MMIO_DMA64_BASE4 0x300
#define BCM43xx_MMIO_DMA64_BASE5 0x340
/* PIO */
#define BCM43xx_MMIO_PIO1_BASE 0x300 #define BCM43xx_MMIO_PIO1_BASE 0x300
#define BCM43xx_MMIO_PIO2_BASE 0x310 #define BCM43xx_MMIO_PIO2_BASE 0x310
#define BCM43xx_MMIO_PIO3_BASE 0x320 #define BCM43xx_MMIO_PIO3_BASE 0x320
#define BCM43xx_MMIO_PIO4_BASE 0x330 #define BCM43xx_MMIO_PIO4_BASE 0x330
#define BCM43xx_MMIO_PHY_VER 0x3E0 #define BCM43xx_MMIO_PHY_VER 0x3E0
#define BCM43xx_MMIO_PHY_RADIO 0x3E2 #define BCM43xx_MMIO_PHY_RADIO 0x3E2
#define BCM43xx_MMIO_ANTENNA 0x3E8 #define BCM43xx_MMIO_ANTENNA 0x3E8
...@@ -233,8 +250,14 @@ ...@@ -233,8 +250,14 @@
#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000
/* sbtmstatehigh state flags */ /* sbtmstatehigh state flags */
#define BCM43xx_SBTMSTATEHIGH_SERROR 0x1 #define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001
#define BCM43xx_SBTMSTATEHIGH_BUSY 0x4 #define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004
#define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020
#define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000
#define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000
#define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000
#define BCM43xx_SBTMSTATEHIGH_BISTFAILED 0x40000000
#define BCM43xx_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000
/* sbimstate flags */ /* sbimstate flags */
#define BCM43xx_SBIMSTATE_IB_ERROR 0x20000 #define BCM43xx_SBIMSTATE_IB_ERROR 0x20000
...@@ -283,6 +306,13 @@ ...@@ -283,6 +306,13 @@
#define BCM43xx_SBF_TIME_UPDATE 0x10000000 #define BCM43xx_SBF_TIME_UPDATE 0x10000000
#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/ #define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/
/* Microcode */
#define BCM43xx_UCODE_REVISION 0x0000
#define BCM43xx_UCODE_PATCHLEVEL 0x0002
#define BCM43xx_UCODE_DATE 0x0004
#define BCM43xx_UCODE_TIME 0x0006
#define BCM43xx_UCODE_STATUS 0x0040
/* MicrocodeFlagsBitfield (addr + lo-word values?)*/ /* MicrocodeFlagsBitfield (addr + lo-word values?)*/
#define BCM43xx_UCODEFLAGS_OFFSET 0x005E #define BCM43xx_UCODEFLAGS_OFFSET 0x005E
...@@ -504,6 +534,12 @@ struct bcm43xx_phyinfo { ...@@ -504,6 +534,12 @@ struct bcm43xx_phyinfo {
* This lock is only used by bcm43xx_phy_{un}lock() * This lock is only used by bcm43xx_phy_{un}lock()
*/ */
spinlock_t lock; spinlock_t lock;
/* Firmware. */
const struct firmware *ucode;
const struct firmware *pcm;
const struct firmware *initvals0;
const struct firmware *initvals1;
}; };
...@@ -568,8 +604,11 @@ struct bcm43xx_dma { ...@@ -568,8 +604,11 @@ struct bcm43xx_dma {
struct bcm43xx_dmaring *tx_ring1; struct bcm43xx_dmaring *tx_ring1;
struct bcm43xx_dmaring *tx_ring2; struct bcm43xx_dmaring *tx_ring2;
struct bcm43xx_dmaring *tx_ring3; struct bcm43xx_dmaring *tx_ring3;
struct bcm43xx_dmaring *tx_ring4;
struct bcm43xx_dmaring *tx_ring5;
struct bcm43xx_dmaring *rx_ring0; struct bcm43xx_dmaring *rx_ring0;
struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */ struct bcm43xx_dmaring *rx_ring3; /* only available on core.rev < 5 */
}; };
/* Data structures for PIO transmission, per 80211 core. */ /* Data structures for PIO transmission, per 80211 core. */
...@@ -593,12 +632,14 @@ struct bcm43xx_coreinfo { ...@@ -593,12 +632,14 @@ struct bcm43xx_coreinfo {
u8 available:1, u8 available:1,
enabled:1, enabled:1,
initialized:1; initialized:1;
/** core_id ID number */
u16 id;
/** core_rev revision number */ /** core_rev revision number */
u8 rev; u8 rev;
/** Index number for _switch_core() */ /** Index number for _switch_core() */
u8 index; u8 index;
/** core_id ID number */
u16 id;
/** Core-specific data. */
void *priv;
}; };
/* Additional information for each 80211 core. */ /* Additional information for each 80211 core. */
...@@ -647,7 +688,23 @@ enum { ...@@ -647,7 +688,23 @@ enum {
BCM43xx_STAT_RESTARTING, /* controller_restart() called. */ BCM43xx_STAT_RESTARTING, /* controller_restart() called. */
}; };
#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status) #define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status)
#define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat)) #define bcm43xx_set_status(bcm, stat) do { \
atomic_set(&(bcm)->init_status, (stat)); \
smp_wmb(); \
} while (0)
/* *** THEORY OF LOCKING ***
*
* We have two different locks in the bcm43xx driver.
* => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
* and the device registers. This mutex does _not_ protect
* against concurrency from the IRQ handler.
* => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
*
* Please note that, if you only take the irq_lock, you are not protected
* against concurrency from the periodic work handlers.
* Most times you want to take _both_ locks.
*/
struct bcm43xx_private { struct bcm43xx_private {
struct ieee80211_device *ieee; struct ieee80211_device *ieee;
...@@ -659,7 +716,6 @@ struct bcm43xx_private { ...@@ -659,7 +716,6 @@ struct bcm43xx_private {
void __iomem *mmio_addr; void __iomem *mmio_addr;
/* Locking, see "theory of locking" text below. */
spinlock_t irq_lock; spinlock_t irq_lock;
struct mutex mutex; struct mutex mutex;
...@@ -691,6 +747,7 @@ struct bcm43xx_private { ...@@ -691,6 +747,7 @@ struct bcm43xx_private {
struct bcm43xx_sprominfo sprom; struct bcm43xx_sprominfo sprom;
#define BCM43xx_NR_LEDS 4 #define BCM43xx_NR_LEDS 4
struct bcm43xx_led leds[BCM43xx_NR_LEDS]; struct bcm43xx_led leds[BCM43xx_NR_LEDS];
spinlock_t leds_lock;
/* The currently active core. */ /* The currently active core. */
struct bcm43xx_coreinfo *current_core; struct bcm43xx_coreinfo *current_core;
...@@ -708,10 +765,6 @@ struct bcm43xx_private { ...@@ -708,10 +765,6 @@ struct bcm43xx_private {
struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
/* Additional information, specific to the 80211 cores. */ /* Additional information, specific to the 80211 cores. */
struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
/* Index of the current 80211 core. If current_core is not
* an 80211 core, this is -1.
*/
int current_80211_core_idx;
/* Number of available 80211 cores. */ /* Number of available 80211 cores. */
int nr_80211_available; int nr_80211_available;
...@@ -719,11 +772,13 @@ struct bcm43xx_private { ...@@ -719,11 +772,13 @@ struct bcm43xx_private {
/* Reason code of the last interrupt. */ /* Reason code of the last interrupt. */
u32 irq_reason; u32 irq_reason;
u32 dma_reason[4]; u32 dma_reason[6];
/* saved irq enable/disable state bitfield. */ /* saved irq enable/disable state bitfield. */
u32 irq_savedstate; u32 irq_savedstate;
/* Link Quality calculation context. */ /* Link Quality calculation context. */
struct bcm43xx_noise_calculation noisecalc; struct bcm43xx_noise_calculation noisecalc;
/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
int mac_suspended;
/* Threshold values. */ /* Threshold values. */
//TODO: The RTS thr has to be _used_. Currently, it is only set via WX. //TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
...@@ -746,12 +801,6 @@ struct bcm43xx_private { ...@@ -746,12 +801,6 @@ struct bcm43xx_private {
struct bcm43xx_key key[54]; struct bcm43xx_key key[54];
u8 default_key_idx; u8 default_key_idx;
/* Firmware. */
const struct firmware *ucode;
const struct firmware *pcm;
const struct firmware *initvals0;
const struct firmware *initvals1;
/* Random Number Generator. */ /* Random Number Generator. */
struct hwrng rng; struct hwrng rng;
char rng_name[20 + 1]; char rng_name[20 + 1];
...@@ -763,55 +812,6 @@ struct bcm43xx_private { ...@@ -763,55 +812,6 @@ struct bcm43xx_private {
}; };
/* *** THEORY OF LOCKING ***
*
* We have two different locks in the bcm43xx driver.
* => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
* and the device registers.
* => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
*
* We have three types of helper function pairs to utilize these locks.
* (Always use the helper functions.)
* 1) bcm43xx_{un}lock_noirq():
* Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
* so it is almost always unsafe, if device IRQs are enabled.
* So only use this, if device IRQs are masked.
* Locking may sleep.
* You can sleep within the critical section.
* 2) bcm43xx_{un}lock_irqonly():
* Takes bcm->irq_lock. Does _not_ protect against
* bcm43xx_lock_noirq() critical sections.
* Does only protect against the IRQ handler path and other
* irqonly() critical sections.
* Locking does not sleep.
* You must not sleep within the critical section.
* 3) bcm43xx_{un}lock_irqsafe():
* This is the cummulative lock and takes both, mutex and irq_lock.
* Protects against noirq() and irqonly() critical sections (and
* the IRQ handler path).
* Locking may sleep.
* You must not sleep within the critical section.
*/
/* Lock type 1 */
#define bcm43xx_lock_noirq(bcm) mutex_lock(&(bcm)->mutex)
#define bcm43xx_unlock_noirq(bcm) mutex_unlock(&(bcm)->mutex)
/* Lock type 2 */
#define bcm43xx_lock_irqonly(bcm, flags) \
spin_lock_irqsave(&(bcm)->irq_lock, flags)
#define bcm43xx_unlock_irqonly(bcm, flags) \
spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
/* Lock type 3 */
#define bcm43xx_lock_irqsafe(bcm, flags) do { \
bcm43xx_lock_noirq(bcm); \
bcm43xx_lock_irqonly(bcm, flags); \
} while (0)
#define bcm43xx_unlock_irqsafe(bcm, flags) do { \
bcm43xx_unlock_irqonly(bcm, flags); \
bcm43xx_unlock_noirq(bcm); \
} while (0)
static inline static inline
struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
{ {
...@@ -863,34 +863,33 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm) ...@@ -863,34 +863,33 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm)
* any of these functions. * any of these functions.
*/ */
static inline static inline
struct bcm43xx_coreinfo_80211 *
bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
{
assert(bcm->current_core->id == BCM43xx_COREID_80211);
return bcm->current_core->priv;
}
static inline
struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
{ {
assert(bcm43xx_using_pio(bcm)); assert(bcm43xx_using_pio(bcm));
assert(bcm->current_80211_core_idx >= 0); return &(bcm43xx_current_80211_priv(bcm)->pio);
assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
} }
static inline static inline
struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
{ {
assert(!bcm43xx_using_pio(bcm)); assert(!bcm43xx_using_pio(bcm));
assert(bcm->current_80211_core_idx >= 0); return &(bcm43xx_current_80211_priv(bcm)->dma);
assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
} }
static inline static inline
struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
{ {
assert(bcm->current_80211_core_idx >= 0); return &(bcm43xx_current_80211_priv(bcm)->phy);
assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
} }
static inline static inline
struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
{ {
assert(bcm->current_80211_core_idx >= 0); return &(bcm43xx_current_80211_priv(bcm)->radio);
assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
} }
......
...@@ -77,7 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, ...@@ -77,7 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
down(&big_buffer_sem); down(&big_buffer_sem);
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n"); fappend("Board not initialized.\n");
goto out; goto out;
...@@ -121,7 +122,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, ...@@ -121,7 +122,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
fappend("\n"); fappend("\n");
out: out:
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem); up(&big_buffer_sem);
return res; return res;
...@@ -159,7 +161,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, ...@@ -159,7 +161,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
unsigned long flags; unsigned long flags;
down(&big_buffer_sem); down(&big_buffer_sem);
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n"); fappend("Board not initialized.\n");
goto out; goto out;
...@@ -169,7 +172,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, ...@@ -169,7 +172,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
out: out:
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem); up(&big_buffer_sem);
return res; return res;
...@@ -188,7 +192,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, ...@@ -188,7 +192,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
u64 tsf; u64 tsf;
down(&big_buffer_sem); down(&big_buffer_sem);
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n"); fappend("Board not initialized.\n");
goto out; goto out;
...@@ -199,7 +204,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, ...@@ -199,7 +204,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
(unsigned int)(tsf & 0xFFFFFFFFULL)); (unsigned int)(tsf & 0xFFFFFFFFULL));
out: out:
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem); up(&big_buffer_sem);
return res; return res;
...@@ -221,7 +227,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, ...@@ -221,7 +227,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = -EFAULT; res = -EFAULT;
goto out_up; goto out_up;
} }
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT; res = -EFAULT;
...@@ -237,7 +244,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, ...@@ -237,7 +244,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = buf_size; res = buf_size;
out_unlock: out_unlock:
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
out_up: out_up:
up(&big_buffer_sem); up(&big_buffer_sem);
return res; return res;
...@@ -258,7 +266,8 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, ...@@ -258,7 +266,8 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
int i, cnt, j = 0; int i, cnt, j = 0;
down(&big_buffer_sem); down(&big_buffer_sem);
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
BCM43xx_NR_LOGGED_XMITSTATUS); BCM43xx_NR_LOGGED_XMITSTATUS);
...@@ -294,14 +303,51 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, ...@@ -294,14 +303,51 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
} }
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
bcm43xx_lock_irqsafe(bcm, flags); spin_lock_irqsave(&bcm->irq_lock, flags);
if (*ppos == pos) { if (*ppos == pos) {
/* Done. Drop the copied data. */ /* Done. Drop the copied data. */
e->xmitstatus_printing = 0; e->xmitstatus_printing = 0;
} }
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
up(&big_buffer_sem);
return res;
}
static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct bcm43xx_private *bcm = file->private_data;
char *buf = really_big_buffer;
ssize_t buf_size;
ssize_t res;
unsigned long flags;
buf_size = min(count, sizeof (really_big_buffer) - 1);
down(&big_buffer_sem);
if (copy_from_user(buf, user_buf, buf_size)) {
res = -EFAULT;
goto out_up;
}
mutex_lock(&(bcm)->mutex);
spin_lock_irqsave(&(bcm)->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT;
goto out_unlock;
}
if (count > 0 && buf[0] == '1') {
bcm43xx_controller_restart(bcm, "manually restarted");
res = count;
} else
res = -EINVAL;
out_unlock:
spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
mutex_unlock(&(bcm)->mutex);
out_up:
up(&big_buffer_sem); up(&big_buffer_sem);
return res; return res;
} }
...@@ -339,6 +385,11 @@ static struct file_operations txstat_fops = { ...@@ -339,6 +385,11 @@ static struct file_operations txstat_fops = {
.open = open_file_generic, .open = open_file_generic,
}; };
static struct file_operations restart_fops = {
.write = restart_write_file,
.open = open_file_generic,
};
void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
{ {
...@@ -390,6 +441,10 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) ...@@ -390,6 +441,10 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
bcm, &txstat_fops); bcm, &txstat_fops);
if (!e->dentry_txstat) if (!e->dentry_txstat)
printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
bcm, &restart_fops);
if (!e->dentry_restart)
printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
} }
void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
...@@ -405,6 +460,7 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) ...@@ -405,6 +460,7 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
debugfs_remove(e->dentry_devinfo); debugfs_remove(e->dentry_devinfo);
debugfs_remove(e->dentry_tsf); debugfs_remove(e->dentry_tsf);
debugfs_remove(e->dentry_txstat); debugfs_remove(e->dentry_txstat);
debugfs_remove(e->dentry_restart);
debugfs_remove(e->subdir); debugfs_remove(e->subdir);
kfree(e->xmitstatus_buffer); kfree(e->xmitstatus_buffer);
kfree(e->xmitstatus_print_buffer); kfree(e->xmitstatus_print_buffer);
......
...@@ -20,6 +20,7 @@ struct bcm43xx_dfsentry { ...@@ -20,6 +20,7 @@ struct bcm43xx_dfsentry {
struct dentry *dentry_spromdump; struct dentry *dentry_spromdump;
struct dentry *dentry_tsf; struct dentry *dentry_tsf;
struct dentry *dentry_txstat; struct dentry *dentry_txstat;
struct dentry *dentry_restart;
struct bcm43xx_private *bcm; struct bcm43xx_private *bcm;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
DMA ringbuffer and descriptor allocation/management DMA ringbuffer and descriptor allocation/management
Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de> Copyright (c) 2005, 2006 Michael Buesch <mbuesch@freenet.de>
Some code in this file is derived from the b44.c driver Some code in this file is derived from the b44.c driver
Copyright (C) 2002 David S. Miller Copyright (C) 2002 David S. Miller
...@@ -109,6 +109,35 @@ void return_slot(struct bcm43xx_dmaring *ring, int slot) ...@@ -109,6 +109,35 @@ void return_slot(struct bcm43xx_dmaring *ring, int slot)
} }
} }
u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
{
static const u16 map64[] = {
BCM43xx_MMIO_DMA64_BASE0,
BCM43xx_MMIO_DMA64_BASE1,
BCM43xx_MMIO_DMA64_BASE2,
BCM43xx_MMIO_DMA64_BASE3,
BCM43xx_MMIO_DMA64_BASE4,
BCM43xx_MMIO_DMA64_BASE5,
};
static const u16 map32[] = {
BCM43xx_MMIO_DMA32_BASE0,
BCM43xx_MMIO_DMA32_BASE1,
BCM43xx_MMIO_DMA32_BASE2,
BCM43xx_MMIO_DMA32_BASE3,
BCM43xx_MMIO_DMA32_BASE4,
BCM43xx_MMIO_DMA32_BASE5,
};
if (dma64bit) {
assert(controller_idx >= 0 &&
controller_idx < ARRAY_SIZE(map64));
return map64[controller_idx];
}
assert(controller_idx >= 0 &&
controller_idx < ARRAY_SIZE(map32));
return map32[controller_idx];
}
static inline static inline
dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring, dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
unsigned char *buf, unsigned char *buf,
...@@ -172,7 +201,6 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, ...@@ -172,7 +201,6 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
/* Unmap and free a descriptor buffer. */ /* Unmap and free a descriptor buffer. */
static inline static inline
void free_descriptor_buffer(struct bcm43xx_dmaring *ring, void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
struct bcm43xx_dmadesc *desc,
struct bcm43xx_dmadesc_meta *meta, struct bcm43xx_dmadesc_meta *meta,
int irq_context) int irq_context)
{ {
...@@ -188,23 +216,13 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring) ...@@ -188,23 +216,13 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
{ {
struct device *dev = &(ring->bcm->pci_dev->dev); struct device *dev = &(ring->bcm->pci_dev->dev);
ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
&(ring->dmabase), GFP_KERNEL); &(ring->dmabase), GFP_KERNEL);
if (!ring->vbase) { if (!ring->descbase) {
printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
return -ENOMEM; return -ENOMEM;
} }
if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G "
"(0x%llx, len: %lu)\n",
(unsigned long long)ring->dmabase,
BCM43xx_DMA_RINGMEMSIZE);
dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
ring->vbase, ring->dmabase);
return -ENOMEM;
}
assert(!(ring->dmabase & 0x000003FF));
memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE);
return 0; return 0;
} }
...@@ -214,26 +232,34 @@ static void free_ringmemory(struct bcm43xx_dmaring *ring) ...@@ -214,26 +232,34 @@ static void free_ringmemory(struct bcm43xx_dmaring *ring)
struct device *dev = &(ring->bcm->pci_dev->dev); struct device *dev = &(ring->bcm->pci_dev->dev);
dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
ring->vbase, ring->dmabase); ring->descbase, ring->dmabase);
} }
/* Reset the RX DMA channel */ /* Reset the RX DMA channel */
int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
u16 mmio_base) u16 mmio_base, int dma64)
{ {
int i; int i;
u32 value; u32 value;
u16 offset;
bcm43xx_write32(bcm, offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL;
mmio_base + BCM43xx_DMA_RX_CONTROL, bcm43xx_write32(bcm, mmio_base + offset, 0);
0x00000000);
for (i = 0; i < 1000; i++) { for (i = 0; i < 1000; i++) {
value = bcm43xx_read32(bcm, offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS;
mmio_base + BCM43xx_DMA_RX_STATUS); value = bcm43xx_read32(bcm, mmio_base + offset);
value &= BCM43xx_DMA_RXSTAT_STAT_MASK; if (dma64) {
if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) { value &= BCM43xx_DMA64_RXSTAT;
i = -1; if (value == BCM43xx_DMA64_RXSTAT_DISABLED) {
break; i = -1;
break;
}
} else {
value &= BCM43xx_DMA32_RXSTATE;
if (value == BCM43xx_DMA32_RXSTAT_DISABLED) {
i = -1;
break;
}
} }
udelay(10); udelay(10);
} }
...@@ -247,31 +273,47 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, ...@@ -247,31 +273,47 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
/* Reset the RX DMA channel */ /* Reset the RX DMA channel */
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
u16 mmio_base) u16 mmio_base, int dma64)
{ {
int i; int i;
u32 value; u32 value;
u16 offset;
for (i = 0; i < 1000; i++) { for (i = 0; i < 1000; i++) {
value = bcm43xx_read32(bcm, offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
mmio_base + BCM43xx_DMA_TX_STATUS); value = bcm43xx_read32(bcm, mmio_base + offset);
value &= BCM43xx_DMA_TXSTAT_STAT_MASK; if (dma64) {
if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED || value &= BCM43xx_DMA64_TXSTAT;
value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT || if (value == BCM43xx_DMA64_TXSTAT_DISABLED ||
value == BCM43xx_DMA_TXSTAT_STAT_STOPPED) value == BCM43xx_DMA64_TXSTAT_IDLEWAIT ||
break; value == BCM43xx_DMA64_TXSTAT_STOPPED)
break;
} else {
value &= BCM43xx_DMA32_TXSTATE;
if (value == BCM43xx_DMA32_TXSTAT_DISABLED ||
value == BCM43xx_DMA32_TXSTAT_IDLEWAIT ||
value == BCM43xx_DMA32_TXSTAT_STOPPED)
break;
}
udelay(10); udelay(10);
} }
bcm43xx_write32(bcm, offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL;
mmio_base + BCM43xx_DMA_TX_CONTROL, bcm43xx_write32(bcm, mmio_base + offset, 0);
0x00000000);
for (i = 0; i < 1000; i++) { for (i = 0; i < 1000; i++) {
value = bcm43xx_read32(bcm, offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
mmio_base + BCM43xx_DMA_TX_STATUS); value = bcm43xx_read32(bcm, mmio_base + offset);
value &= BCM43xx_DMA_TXSTAT_STAT_MASK; if (dma64) {
if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) { value &= BCM43xx_DMA64_TXSTAT;
i = -1; if (value == BCM43xx_DMA64_TXSTAT_DISABLED) {
break; i = -1;
break;
}
} else {
value &= BCM43xx_DMA32_TXSTATE;
if (value == BCM43xx_DMA32_TXSTAT_DISABLED) {
i = -1;
break;
}
} }
udelay(10); udelay(10);
} }
...@@ -285,47 +327,98 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, ...@@ -285,47 +327,98 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
return 0; return 0;
} }
static void fill_descriptor(struct bcm43xx_dmaring *ring,
struct bcm43xx_dmadesc_generic *desc,
dma_addr_t dmaaddr,
u16 bufsize,
int start, int end, int irq)
{
int slot;
slot = bcm43xx_dma_desc2idx(ring, desc);
assert(slot >= 0 && slot < ring->nr_slots);
if (ring->dma64) {
u32 ctl0 = 0, ctl1 = 0;
u32 addrlo, addrhi;
u32 addrext;
addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
addrhi = (((u64)dmaaddr >> 32) & ~BCM43xx_DMA64_ROUTING);
addrext = (((u64)dmaaddr >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
addrhi |= ring->routing;
if (slot == ring->nr_slots - 1)
ctl0 |= BCM43xx_DMA64_DCTL0_DTABLEEND;
if (start)
ctl0 |= BCM43xx_DMA64_DCTL0_FRAMESTART;
if (end)
ctl0 |= BCM43xx_DMA64_DCTL0_FRAMEEND;
if (irq)
ctl0 |= BCM43xx_DMA64_DCTL0_IRQ;
ctl1 |= (bufsize - ring->frameoffset)
& BCM43xx_DMA64_DCTL1_BYTECNT;
ctl1 |= (addrext << BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT)
& BCM43xx_DMA64_DCTL1_ADDREXT_MASK;
desc->dma64.control0 = cpu_to_le32(ctl0);
desc->dma64.control1 = cpu_to_le32(ctl1);
desc->dma64.address_low = cpu_to_le32(addrlo);
desc->dma64.address_high = cpu_to_le32(addrhi);
} else {
u32 ctl;
u32 addr;
u32 addrext;
addr = (u32)(dmaaddr & ~BCM43xx_DMA32_ROUTING);
addrext = (u32)(dmaaddr & BCM43xx_DMA32_ROUTING)
>> BCM43xx_DMA32_ROUTING_SHIFT;
addr |= ring->routing;
ctl = (bufsize - ring->frameoffset)
& BCM43xx_DMA32_DCTL_BYTECNT;
if (slot == ring->nr_slots - 1)
ctl |= BCM43xx_DMA32_DCTL_DTABLEEND;
if (start)
ctl |= BCM43xx_DMA32_DCTL_FRAMESTART;
if (end)
ctl |= BCM43xx_DMA32_DCTL_FRAMEEND;
if (irq)
ctl |= BCM43xx_DMA32_DCTL_IRQ;
ctl |= (addrext << BCM43xx_DMA32_DCTL_ADDREXT_SHIFT)
& BCM43xx_DMA32_DCTL_ADDREXT_MASK;
desc->dma32.control = cpu_to_le32(ctl);
desc->dma32.address = cpu_to_le32(addr);
}
}
static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
struct bcm43xx_dmadesc *desc, struct bcm43xx_dmadesc_generic *desc,
struct bcm43xx_dmadesc_meta *meta, struct bcm43xx_dmadesc_meta *meta,
gfp_t gfp_flags) gfp_t gfp_flags)
{ {
struct bcm43xx_rxhdr *rxhdr; struct bcm43xx_rxhdr *rxhdr;
struct bcm43xx_hwxmitstatus *xmitstat;
dma_addr_t dmaaddr; dma_addr_t dmaaddr;
u32 desc_addr;
u32 desc_ctl;
const int slot = (int)(desc - ring->vbase);
struct sk_buff *skb; struct sk_buff *skb;
assert(slot >= 0 && slot < ring->nr_slots);
assert(!ring->tx); assert(!ring->tx);
skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
if (unlikely(!skb)) if (unlikely(!skb))
return -ENOMEM; return -ENOMEM;
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) {
unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
dev_kfree_skb_any(skb);
printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G "
"(0x%llx, len: %u)\n",
(unsigned long long)dmaaddr, ring->rx_buffersize);
return -ENOMEM;
}
meta->skb = skb; meta->skb = skb;
meta->dmaaddr = dmaaddr; meta->dmaaddr = dmaaddr;
skb->dev = ring->bcm->net_dev; skb->dev = ring->bcm->net_dev;
desc_addr = (u32)(dmaaddr + ring->memoffset);
desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK & fill_descriptor(ring, desc, dmaaddr,
(u32)(ring->rx_buffersize - ring->frameoffset)); ring->rx_buffersize, 0, 0, 0);
if (slot == ring->nr_slots - 1)
desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
set_desc_addr(desc, desc_addr);
set_desc_ctl(desc, desc_ctl);
rxhdr = (struct bcm43xx_rxhdr *)(skb->data); rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
rxhdr->frame_length = 0; rxhdr->frame_length = 0;
rxhdr->flags1 = 0; rxhdr->flags1 = 0;
xmitstat = (struct bcm43xx_hwxmitstatus *)(skb->data);
xmitstat->cookie = 0;
return 0; return 0;
} }
...@@ -336,17 +429,17 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, ...@@ -336,17 +429,17 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
{ {
int i, err = -ENOMEM; int i, err = -ENOMEM;
struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta; struct bcm43xx_dmadesc_meta *meta;
for (i = 0; i < ring->nr_slots; i++) { for (i = 0; i < ring->nr_slots; i++) {
desc = ring->vbase + i; desc = bcm43xx_dma_idx2desc(ring, i, &meta);
meta = ring->meta + i;
err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
if (err) if (err)
goto err_unwind; goto err_unwind;
} }
mb();
ring->used_slots = ring->nr_slots; ring->used_slots = ring->nr_slots;
err = 0; err = 0;
out: out:
...@@ -354,8 +447,7 @@ static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) ...@@ -354,8 +447,7 @@ static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
err_unwind: err_unwind:
for (i--; i >= 0; i--) { for (i--; i >= 0; i--) {
desc = ring->vbase + i; desc = bcm43xx_dma_idx2desc(ring, i, &meta);
meta = ring->meta + i;
unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
dev_kfree_skb(meta->skb); dev_kfree_skb(meta->skb);
...@@ -371,27 +463,67 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring) ...@@ -371,27 +463,67 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring)
{ {
int err = 0; int err = 0;
u32 value; u32 value;
u32 addrext;
if (ring->tx) { if (ring->tx) {
/* Set Transmit Control register to "transmit enable" */ if (ring->dma64) {
bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, u64 ringbase = (u64)(ring->dmabase);
BCM43xx_DMA_TXCTRL_ENABLE);
/* Set Transmit Descriptor ring address. */ addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, value = BCM43xx_DMA64_TXENABLE;
ring->dmabase + ring->memoffset); value |= (addrext << BCM43xx_DMA64_TXADDREXT_SHIFT)
& BCM43xx_DMA64_TXADDREXT_MASK;
bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, value);
bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO,
(ringbase & 0xFFFFFFFF));
bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI,
((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
| ring->routing);
} else {
u32 ringbase = (u32)(ring->dmabase);
addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
value = BCM43xx_DMA32_TXENABLE;
value |= (addrext << BCM43xx_DMA32_TXADDREXT_SHIFT)
& BCM43xx_DMA32_TXADDREXT_MASK;
bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, value);
bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING,
(ringbase & ~BCM43xx_DMA32_ROUTING)
| ring->routing);
}
} else { } else {
err = alloc_initial_descbuffers(ring); err = alloc_initial_descbuffers(ring);
if (err) if (err)
goto out; goto out;
/* Set Receive Control "receive enable" and frame offset */ if (ring->dma64) {
value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT); u64 ringbase = (u64)(ring->dmabase);
value |= BCM43xx_DMA_RXCTRL_ENABLE;
bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value); addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
/* Set Receive Descriptor ring address. */ value = (ring->frameoffset << BCM43xx_DMA64_RXFROFF_SHIFT);
bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, value |= BCM43xx_DMA64_RXENABLE;
ring->dmabase + ring->memoffset); value |= (addrext << BCM43xx_DMA64_RXADDREXT_SHIFT)
/* Init the descriptor pointer. */ & BCM43xx_DMA64_RXADDREXT_MASK;
bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200); bcm43xx_dma_write(ring, BCM43xx_DMA64_RXCTL, value);
bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO,
(ringbase & 0xFFFFFFFF));
bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI,
((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
| ring->routing);
bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, 200);
} else {
u32 ringbase = (u32)(ring->dmabase);
addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
value = (ring->frameoffset << BCM43xx_DMA32_RXFROFF_SHIFT);
value |= BCM43xx_DMA32_RXENABLE;
value |= (addrext << BCM43xx_DMA32_RXADDREXT_SHIFT)
& BCM43xx_DMA32_RXADDREXT_MASK;
bcm43xx_dma_write(ring, BCM43xx_DMA32_RXCTL, value);
bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING,
(ringbase & ~BCM43xx_DMA32_ROUTING)
| ring->routing);
bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, 200);
}
} }
out: out:
...@@ -402,27 +534,32 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring) ...@@ -402,27 +534,32 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring)
static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
{ {
if (ring->tx) { if (ring->tx) {
bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base, ring->dma64);
/* Zero out Transmit Descriptor ring address. */ if (ring->dma64) {
bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0); bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, 0);
bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, 0);
} else
bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, 0);
} else { } else {
bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base, ring->dma64);
/* Zero out Receive Descriptor ring address. */ if (ring->dma64) {
bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0); bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, 0);
bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, 0);
} else
bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, 0);
} }
} }
static void free_all_descbuffers(struct bcm43xx_dmaring *ring) static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
{ {
struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta; struct bcm43xx_dmadesc_meta *meta;
int i; int i;
if (!ring->used_slots) if (!ring->used_slots)
return; return;
for (i = 0; i < ring->nr_slots; i++) { for (i = 0; i < ring->nr_slots; i++) {
desc = ring->vbase + i; desc = bcm43xx_dma_idx2desc(ring, i, &meta);
meta = ring->meta + i;
if (!meta->skb) { if (!meta->skb) {
assert(ring->tx); assert(ring->tx);
...@@ -430,62 +567,67 @@ static void free_all_descbuffers(struct bcm43xx_dmaring *ring) ...@@ -430,62 +567,67 @@ static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
} }
if (ring->tx) { if (ring->tx) {
unmap_descbuffer(ring, meta->dmaaddr, unmap_descbuffer(ring, meta->dmaaddr,
meta->skb->len, 1); meta->skb->len, 1);
} else { } else {
unmap_descbuffer(ring, meta->dmaaddr, unmap_descbuffer(ring, meta->dmaaddr,
ring->rx_buffersize, 0); ring->rx_buffersize, 0);
} }
free_descriptor_buffer(ring, desc, meta, 0); free_descriptor_buffer(ring, meta, 0);
} }
} }
/* Main initialization function. */ /* Main initialization function. */
static static
struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
u16 dma_controller_base, int controller_index,
int nr_descriptor_slots, int for_tx,
int tx) int dma64)
{ {
struct bcm43xx_dmaring *ring; struct bcm43xx_dmaring *ring;
int err; int err;
int nr_slots;
ring = kzalloc(sizeof(*ring), GFP_KERNEL); ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring) if (!ring)
goto out; goto out;
ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots, nr_slots = BCM43xx_RXRING_SLOTS;
if (for_tx)
nr_slots = BCM43xx_TXRING_SLOTS;
ring->meta = kcalloc(nr_slots, sizeof(struct bcm43xx_dmadesc_meta),
GFP_KERNEL); GFP_KERNEL);
if (!ring->meta) if (!ring->meta)
goto err_kfree_ring; goto err_kfree_ring;
ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET; ring->routing = BCM43xx_DMA32_CLIENTTRANS;
if (dma64)
ring->routing = BCM43xx_DMA64_CLIENTTRANS;
#ifdef CONFIG_BCM947XX #ifdef CONFIG_BCM947XX
if (bcm->pci_dev->bus->number == 0) if (bcm->pci_dev->bus->number == 0)
ring->memoffset = 0; ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
#endif #endif
ring->bcm = bcm; ring->bcm = bcm;
ring->nr_slots = nr_descriptor_slots; ring->nr_slots = nr_slots;
ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100; ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100; ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
assert(ring->suspend_mark < ring->resume_mark); assert(ring->suspend_mark < ring->resume_mark);
ring->mmio_base = dma_controller_base; ring->mmio_base = bcm43xx_dmacontroller_base(dma64, controller_index);
if (tx) { ring->index = controller_index;
ring->dma64 = !!dma64;
if (for_tx) {
ring->tx = 1; ring->tx = 1;
ring->current_slot = -1; ring->current_slot = -1;
} else { } else {
switch (dma_controller_base) { if (ring->index == 0) {
case BCM43xx_MMIO_DMA1_BASE: ring->rx_buffersize = BCM43xx_DMA0_RX_BUFFERSIZE;
ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE; ring->frameoffset = BCM43xx_DMA0_RX_FRAMEOFFSET;
ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET; } else if (ring->index == 3) {
break; ring->rx_buffersize = BCM43xx_DMA3_RX_BUFFERSIZE;
case BCM43xx_MMIO_DMA4_BASE: ring->frameoffset = BCM43xx_DMA3_RX_FRAMEOFFSET;
ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE; } else
ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET;
break;
default:
assert(0); assert(0);
}
} }
err = alloc_ringmemory(ring); err = alloc_ringmemory(ring);
...@@ -514,7 +656,8 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) ...@@ -514,7 +656,8 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring)
if (!ring) if (!ring)
return; return;
dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n", dprintk(KERN_INFO PFX "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
(ring->dma64) ? "64" : "32",
ring->mmio_base, ring->mmio_base,
(ring->tx) ? "TX" : "RX", (ring->tx) ? "TX" : "RX",
ring->max_used_slots, ring->nr_slots); ring->max_used_slots, ring->nr_slots);
...@@ -537,10 +680,15 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm) ...@@ -537,10 +680,15 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm)
return; return;
dma = bcm43xx_current_dma(bcm); dma = bcm43xx_current_dma(bcm);
bcm43xx_destroy_dmaring(dma->rx_ring1); bcm43xx_destroy_dmaring(dma->rx_ring3);
dma->rx_ring1 = NULL; dma->rx_ring3 = NULL;
bcm43xx_destroy_dmaring(dma->rx_ring0); bcm43xx_destroy_dmaring(dma->rx_ring0);
dma->rx_ring0 = NULL; dma->rx_ring0 = NULL;
bcm43xx_destroy_dmaring(dma->tx_ring5);
dma->tx_ring5 = NULL;
bcm43xx_destroy_dmaring(dma->tx_ring4);
dma->tx_ring4 = NULL;
bcm43xx_destroy_dmaring(dma->tx_ring3); bcm43xx_destroy_dmaring(dma->tx_ring3);
dma->tx_ring3 = NULL; dma->tx_ring3 = NULL;
bcm43xx_destroy_dmaring(dma->tx_ring2); bcm43xx_destroy_dmaring(dma->tx_ring2);
...@@ -556,48 +704,59 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) ...@@ -556,48 +704,59 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
struct bcm43xx_dmaring *ring; struct bcm43xx_dmaring *ring;
int err = -ENOMEM; int err = -ENOMEM;
int dma64 = 0;
u32 sbtmstatehi;
sbtmstatehi = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
if (sbtmstatehi & BCM43xx_SBTMSTATEHIGH_DMA64BIT)
dma64 = 1;
/* setup TX DMA channels. */ /* setup TX DMA channels. */
ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
BCM43xx_TXRING_SLOTS, 1);
if (!ring) if (!ring)
goto out; goto out;
dma->tx_ring0 = ring; dma->tx_ring0 = ring;
ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE, ring = bcm43xx_setup_dmaring(bcm, 1, 1, dma64);
BCM43xx_TXRING_SLOTS, 1);
if (!ring) if (!ring)
goto err_destroy_tx0; goto err_destroy_tx0;
dma->tx_ring1 = ring; dma->tx_ring1 = ring;
ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE, ring = bcm43xx_setup_dmaring(bcm, 2, 1, dma64);
BCM43xx_TXRING_SLOTS, 1);
if (!ring) if (!ring)
goto err_destroy_tx1; goto err_destroy_tx1;
dma->tx_ring2 = ring; dma->tx_ring2 = ring;
ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, ring = bcm43xx_setup_dmaring(bcm, 3, 1, dma64);
BCM43xx_TXRING_SLOTS, 1);
if (!ring) if (!ring)
goto err_destroy_tx2; goto err_destroy_tx2;
dma->tx_ring3 = ring; dma->tx_ring3 = ring;
/* setup RX DMA channels. */ ring = bcm43xx_setup_dmaring(bcm, 4, 1, dma64);
ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
BCM43xx_RXRING_SLOTS, 0);
if (!ring) if (!ring)
goto err_destroy_tx3; goto err_destroy_tx3;
dma->tx_ring4 = ring;
ring = bcm43xx_setup_dmaring(bcm, 5, 1, dma64);
if (!ring)
goto err_destroy_tx4;
dma->tx_ring5 = ring;
/* setup RX DMA channels. */
ring = bcm43xx_setup_dmaring(bcm, 0, 0, dma64);
if (!ring)
goto err_destroy_tx5;
dma->rx_ring0 = ring; dma->rx_ring0 = ring;
if (bcm->current_core->rev < 5) { if (bcm->current_core->rev < 5) {
ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64);
BCM43xx_RXRING_SLOTS, 0);
if (!ring) if (!ring)
goto err_destroy_rx0; goto err_destroy_rx0;
dma->rx_ring1 = ring; dma->rx_ring3 = ring;
} }
dprintk(KERN_INFO PFX "DMA initialized\n"); dprintk(KERN_INFO PFX "%s DMA initialized\n",
dma64 ? "64-bit" : "32-bit");
err = 0; err = 0;
out: out:
return err; return err;
...@@ -605,6 +764,12 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) ...@@ -605,6 +764,12 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
err_destroy_rx0: err_destroy_rx0:
bcm43xx_destroy_dmaring(dma->rx_ring0); bcm43xx_destroy_dmaring(dma->rx_ring0);
dma->rx_ring0 = NULL; dma->rx_ring0 = NULL;
err_destroy_tx5:
bcm43xx_destroy_dmaring(dma->tx_ring5);
dma->tx_ring5 = NULL;
err_destroy_tx4:
bcm43xx_destroy_dmaring(dma->tx_ring4);
dma->tx_ring4 = NULL;
err_destroy_tx3: err_destroy_tx3:
bcm43xx_destroy_dmaring(dma->tx_ring3); bcm43xx_destroy_dmaring(dma->tx_ring3);
dma->tx_ring3 = NULL; dma->tx_ring3 = NULL;
...@@ -624,7 +789,7 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) ...@@ -624,7 +789,7 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
static u16 generate_cookie(struct bcm43xx_dmaring *ring, static u16 generate_cookie(struct bcm43xx_dmaring *ring,
int slot) int slot)
{ {
u16 cookie = 0xF000; u16 cookie = 0x1000;
/* Use the upper 4 bits of the cookie as /* Use the upper 4 bits of the cookie as
* DMA controller ID and store the slot number * DMA controller ID and store the slot number
...@@ -632,21 +797,25 @@ static u16 generate_cookie(struct bcm43xx_dmaring *ring, ...@@ -632,21 +797,25 @@ static u16 generate_cookie(struct bcm43xx_dmaring *ring,
* Note that the cookie must never be 0, as this * Note that the cookie must never be 0, as this
* is a special value used in RX path. * is a special value used in RX path.
*/ */
switch (ring->mmio_base) { switch (ring->index) {
default: case 0:
assert(0);
case BCM43xx_MMIO_DMA1_BASE:
cookie = 0xA000; cookie = 0xA000;
break; break;
case BCM43xx_MMIO_DMA2_BASE: case 1:
cookie = 0xB000; cookie = 0xB000;
break; break;
case BCM43xx_MMIO_DMA3_BASE: case 2:
cookie = 0xC000; cookie = 0xC000;
break; break;
case BCM43xx_MMIO_DMA4_BASE: case 3:
cookie = 0xD000; cookie = 0xD000;
break; break;
case 4:
cookie = 0xE000;
break;
case 5:
cookie = 0xF000;
break;
} }
assert(((u16)slot & 0xF000) == 0x0000); assert(((u16)slot & 0xF000) == 0x0000);
cookie |= (u16)slot; cookie |= (u16)slot;
...@@ -675,6 +844,12 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, ...@@ -675,6 +844,12 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
case 0xD000: case 0xD000:
ring = dma->tx_ring3; ring = dma->tx_ring3;
break; break;
case 0xE000:
ring = dma->tx_ring4;
break;
case 0xF000:
ring = dma->tx_ring5;
break;
default: default:
assert(0); assert(0);
} }
...@@ -687,6 +862,9 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, ...@@ -687,6 +862,9 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
int slot) int slot)
{ {
u16 offset;
int descsize;
/* Everything is ready to start. Buffers are DMA mapped and /* Everything is ready to start. Buffers are DMA mapped and
* associated with slots. * associated with slots.
* "slot" is the last slot of the new frame we want to transmit. * "slot" is the last slot of the new frame we want to transmit.
...@@ -694,25 +872,26 @@ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, ...@@ -694,25 +872,26 @@ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
*/ */
wmb(); wmb();
slot = next_slot(ring, slot); slot = next_slot(ring, slot);
bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX, offset = (ring->dma64) ? BCM43xx_DMA64_TXINDEX : BCM43xx_DMA32_TXINDEX;
(u32)(slot * sizeof(struct bcm43xx_dmadesc))); descsize = (ring->dma64) ? sizeof(struct bcm43xx_dmadesc64)
: sizeof(struct bcm43xx_dmadesc32);
bcm43xx_dma_write(ring, offset,
(u32)(slot * descsize));
} }
static int dma_tx_fragment(struct bcm43xx_dmaring *ring, static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
struct sk_buff *skb, struct sk_buff *skb,
u8 cur_frag) u8 cur_frag)
{ {
int slot; int slot;
struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta; struct bcm43xx_dmadesc_meta *meta;
u32 desc_ctl; dma_addr_t dmaaddr;
u32 desc_addr;
assert(skb_shinfo(skb)->nr_frags == 0); assert(skb_shinfo(skb)->nr_frags == 0);
slot = request_slot(ring); slot = request_slot(ring);
desc = ring->vbase + slot; desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
meta = ring->meta + slot;
/* Add a device specific TX header. */ /* Add a device specific TX header. */
assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
...@@ -729,29 +908,14 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring, ...@@ -729,29 +908,14 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
generate_cookie(ring, slot)); generate_cookie(ring, slot));
meta->skb = skb; meta->skb = skb;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { meta->dmaaddr = dmaaddr;
return_slot(ring, slot);
printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G "
"(0x%llx, len: %u)\n",
(unsigned long long)meta->dmaaddr, skb->len);
return -ENOMEM;
}
desc_addr = (u32)(meta->dmaaddr + ring->memoffset); fill_descriptor(ring, desc, dmaaddr,
desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND; skb->len, 1, 1, 1);
desc_ctl |= BCM43xx_DMADTOR_COMPIRQ;
desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK &
(u32)(meta->skb->len - ring->frameoffset));
if (slot == ring->nr_slots - 1)
desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
set_desc_ctl(desc, desc_ctl);
set_desc_addr(desc, desc_addr);
/* Now transfer the whole frame. */ /* Now transfer the whole frame. */
dmacontroller_poke_tx(ring, slot); dmacontroller_poke_tx(ring, slot);
return 0;
} }
int bcm43xx_dma_tx(struct bcm43xx_private *bcm, int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
...@@ -781,7 +945,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, ...@@ -781,7 +945,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
/* Take skb from ieee80211_txb_free */ /* Take skb from ieee80211_txb_free */
txb->fragments[i] = NULL; txb->fragments[i] = NULL;
dma_tx_fragment(ring, skb, i); dma_tx_fragment(ring, skb, i);
//TODO: handle failure of dma_tx_fragment
} }
ieee80211_txb_free(txb); ieee80211_txb_free(txb);
...@@ -792,23 +955,28 @@ void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, ...@@ -792,23 +955,28 @@ void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
struct bcm43xx_xmitstatus *status) struct bcm43xx_xmitstatus *status)
{ {
struct bcm43xx_dmaring *ring; struct bcm43xx_dmaring *ring;
struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta; struct bcm43xx_dmadesc_meta *meta;
int is_last_fragment; int is_last_fragment;
int slot; int slot;
u32 tmp;
ring = parse_cookie(bcm, status->cookie, &slot); ring = parse_cookie(bcm, status->cookie, &slot);
assert(ring); assert(ring);
assert(ring->tx); assert(ring->tx);
assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART);
while (1) { while (1) {
assert(slot >= 0 && slot < ring->nr_slots); assert(slot >= 0 && slot < ring->nr_slots);
desc = ring->vbase + slot; desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
meta = ring->meta + slot;
is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND); if (ring->dma64) {
tmp = le32_to_cpu(desc->dma64.control0);
is_last_fragment = !!(tmp & BCM43xx_DMA64_DCTL0_FRAMEEND);
} else {
tmp = le32_to_cpu(desc->dma32.control);
is_last_fragment = !!(tmp & BCM43xx_DMA32_DCTL_FRAMEEND);
}
unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
free_descriptor_buffer(ring, desc, meta, 1); free_descriptor_buffer(ring, meta, 1);
/* Everything belonging to the slot is unmapped /* Everything belonging to the slot is unmapped
* and freed, so we can return it. * and freed, so we can return it.
*/ */
...@@ -824,7 +992,7 @@ void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, ...@@ -824,7 +992,7 @@ void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
static void dma_rx(struct bcm43xx_dmaring *ring, static void dma_rx(struct bcm43xx_dmaring *ring,
int *slot) int *slot)
{ {
struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta; struct bcm43xx_dmadesc_meta *meta;
struct bcm43xx_rxhdr *rxhdr; struct bcm43xx_rxhdr *rxhdr;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -832,13 +1000,12 @@ static void dma_rx(struct bcm43xx_dmaring *ring, ...@@ -832,13 +1000,12 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
int err; int err;
dma_addr_t dmaaddr; dma_addr_t dmaaddr;
desc = ring->vbase + *slot; desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
meta = ring->meta + *slot;
sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
skb = meta->skb; skb = meta->skb;
if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) { if (ring->index == 3) {
/* We received an xmit status. */ /* We received an xmit status. */
struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data; struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
struct bcm43xx_xmitstatus stat; struct bcm43xx_xmitstatus stat;
...@@ -894,8 +1061,7 @@ static void dma_rx(struct bcm43xx_dmaring *ring, ...@@ -894,8 +1061,7 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
s32 tmp = len; s32 tmp = len;
while (1) { while (1) {
desc = ring->vbase + *slot; desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
meta = ring->meta + *slot;
/* recycle the descriptor buffer. */ /* recycle the descriptor buffer. */
sync_descbuffer_for_device(ring, meta->dmaaddr, sync_descbuffer_for_device(ring, meta->dmaaddr,
ring->rx_buffersize); ring->rx_buffersize);
...@@ -906,8 +1072,8 @@ static void dma_rx(struct bcm43xx_dmaring *ring, ...@@ -906,8 +1072,8 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
break; break;
} }
printkl(KERN_ERR PFX "DMA RX buffer too small " printkl(KERN_ERR PFX "DMA RX buffer too small "
"(len: %u, buffer: %u, nr-dropped: %d)\n", "(len: %u, buffer: %u, nr-dropped: %d)\n",
len, ring->rx_buffersize, cnt); len, ring->rx_buffersize, cnt);
goto drop; goto drop;
} }
len -= IEEE80211_FCS_LEN; len -= IEEE80211_FCS_LEN;
...@@ -945,9 +1111,15 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) ...@@ -945,9 +1111,15 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
#endif #endif
assert(!ring->tx); assert(!ring->tx);
status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS); if (ring->dma64) {
descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK); status = bcm43xx_dma_read(ring, BCM43xx_DMA64_RXSTATUS);
current_slot = descptr / sizeof(struct bcm43xx_dmadesc); descptr = (status & BCM43xx_DMA64_RXSTATDPTR);
current_slot = descptr / sizeof(struct bcm43xx_dmadesc64);
} else {
status = bcm43xx_dma_read(ring, BCM43xx_DMA32_RXSTATUS);
descptr = (status & BCM43xx_DMA32_RXDPTR);
current_slot = descptr / sizeof(struct bcm43xx_dmadesc32);
}
assert(current_slot >= 0 && current_slot < ring->nr_slots); assert(current_slot >= 0 && current_slot < ring->nr_slots);
slot = ring->current_slot; slot = ring->current_slot;
...@@ -958,8 +1130,13 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) ...@@ -958,8 +1130,13 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
ring->max_used_slots = used_slots; ring->max_used_slots = used_slots;
#endif #endif
} }
bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, if (ring->dma64) {
(u32)(slot * sizeof(struct bcm43xx_dmadesc))); bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX,
(u32)(slot * sizeof(struct bcm43xx_dmadesc64)));
} else {
bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX,
(u32)(slot * sizeof(struct bcm43xx_dmadesc32)));
}
ring->current_slot = slot; ring->current_slot = slot;
} }
...@@ -967,16 +1144,28 @@ void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring) ...@@ -967,16 +1144,28 @@ void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
{ {
assert(ring->tx); assert(ring->tx);
bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1); bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1);
bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, if (ring->dma64) {
bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
| BCM43xx_DMA_TXCTRL_SUSPEND); bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
| BCM43xx_DMA64_TXSUSPEND);
} else {
bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
| BCM43xx_DMA32_TXSUSPEND);
}
} }
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
{ {
assert(ring->tx); assert(ring->tx);
bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, if (ring->dma64) {
bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
& ~BCM43xx_DMA_TXCTRL_SUSPEND); bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
& ~BCM43xx_DMA64_TXSUSPEND);
} else {
bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
& ~BCM43xx_DMA32_TXSUSPEND);
}
bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1); bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1);
} }
...@@ -14,63 +14,179 @@ ...@@ -14,63 +14,179 @@
#define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13) #define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13)
#define BCM43xx_DMAIRQ_RX_DONE (1 << 16) #define BCM43xx_DMAIRQ_RX_DONE (1 << 16)
/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
#define BCM43xx_DMA_TX_CONTROL 0x00 /*** 32-bit DMA Engine. ***/
#define BCM43xx_DMA_TX_DESC_RING 0x04
#define BCM43xx_DMA_TX_DESC_INDEX 0x08 /* 32-bit DMA controller registers. */
#define BCM43xx_DMA_TX_STATUS 0x0c #define BCM43xx_DMA32_TXCTL 0x00
#define BCM43xx_DMA_RX_CONTROL 0x10 #define BCM43xx_DMA32_TXENABLE 0x00000001
#define BCM43xx_DMA_RX_DESC_RING 0x14 #define BCM43xx_DMA32_TXSUSPEND 0x00000002
#define BCM43xx_DMA_RX_DESC_INDEX 0x18 #define BCM43xx_DMA32_TXLOOPBACK 0x00000004
#define BCM43xx_DMA_RX_STATUS 0x1c #define BCM43xx_DMA32_TXFLUSH 0x00000010
#define BCM43xx_DMA32_TXADDREXT_MASK 0x00030000
/* DMA controller channel control word values. */ #define BCM43xx_DMA32_TXADDREXT_SHIFT 16
#define BCM43xx_DMA_TXCTRL_ENABLE (1 << 0) #define BCM43xx_DMA32_TXRING 0x04
#define BCM43xx_DMA_TXCTRL_SUSPEND (1 << 1) #define BCM43xx_DMA32_TXINDEX 0x08
#define BCM43xx_DMA_TXCTRL_LOOPBACK (1 << 2) #define BCM43xx_DMA32_TXSTATUS 0x0C
#define BCM43xx_DMA_TXCTRL_FLUSH (1 << 4) #define BCM43xx_DMA32_TXDPTR 0x00000FFF
#define BCM43xx_DMA_RXCTRL_ENABLE (1 << 0) #define BCM43xx_DMA32_TXSTATE 0x0000F000
#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK 0x000000fe #define BCM43xx_DMA32_TXSTAT_DISABLED 0x00000000
#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT 1 #define BCM43xx_DMA32_TXSTAT_ACTIVE 0x00001000
#define BCM43xx_DMA_RXCTRL_PIO (1 << 8) #define BCM43xx_DMA32_TXSTAT_IDLEWAIT 0x00002000
/* DMA controller channel status word values. */ #define BCM43xx_DMA32_TXSTAT_STOPPED 0x00003000
#define BCM43xx_DMA_TXSTAT_DPTR_MASK 0x00000fff #define BCM43xx_DMA32_TXSTAT_SUSP 0x00004000
#define BCM43xx_DMA_TXSTAT_STAT_MASK 0x0000f000 #define BCM43xx_DMA32_TXERROR 0x000F0000
#define BCM43xx_DMA_TXSTAT_STAT_DISABLED 0x00000000 #define BCM43xx_DMA32_TXERR_NOERR 0x00000000
#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE 0x00001000 #define BCM43xx_DMA32_TXERR_PROT 0x00010000
#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT 0x00002000 #define BCM43xx_DMA32_TXERR_UNDERRUN 0x00020000
#define BCM43xx_DMA_TXSTAT_STAT_STOPPED 0x00003000 #define BCM43xx_DMA32_TXERR_BUFREAD 0x00030000
#define BCM43xx_DMA_TXSTAT_STAT_SUSP 0x00004000 #define BCM43xx_DMA32_TXERR_DESCREAD 0x00040000
#define BCM43xx_DMA_TXSTAT_ERROR_MASK 0x000f0000 #define BCM43xx_DMA32_TXACTIVE 0xFFF00000
#define BCM43xx_DMA_TXSTAT_FLUSHED (1 << 20) #define BCM43xx_DMA32_RXCTL 0x10
#define BCM43xx_DMA_RXSTAT_DPTR_MASK 0x00000fff #define BCM43xx_DMA32_RXENABLE 0x00000001
#define BCM43xx_DMA_RXSTAT_STAT_MASK 0x0000f000 #define BCM43xx_DMA32_RXFROFF_MASK 0x000000FE
#define BCM43xx_DMA_RXSTAT_STAT_DISABLED 0x00000000 #define BCM43xx_DMA32_RXFROFF_SHIFT 1
#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE 0x00001000 #define BCM43xx_DMA32_RXDIRECTFIFO 0x00000100
#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT 0x00002000 #define BCM43xx_DMA32_RXADDREXT_MASK 0x00030000
#define BCM43xx_DMA_RXSTAT_STAT_RESERVED 0x00003000 #define BCM43xx_DMA32_RXADDREXT_SHIFT 16
#define BCM43xx_DMA_RXSTAT_STAT_ERRORS 0x00004000 #define BCM43xx_DMA32_RXRING 0x14
#define BCM43xx_DMA_RXSTAT_ERROR_MASK 0x000f0000 #define BCM43xx_DMA32_RXINDEX 0x18
#define BCM43xx_DMA32_RXSTATUS 0x1C
/* DMA descriptor control field values. */ #define BCM43xx_DMA32_RXDPTR 0x00000FFF
#define BCM43xx_DMADTOR_BYTECNT_MASK 0x00001fff #define BCM43xx_DMA32_RXSTATE 0x0000F000
#define BCM43xx_DMADTOR_DTABLEEND (1 << 28) /* End of descriptor table */ #define BCM43xx_DMA32_RXSTAT_DISABLED 0x00000000
#define BCM43xx_DMADTOR_COMPIRQ (1 << 29) /* IRQ on completion request */ #define BCM43xx_DMA32_RXSTAT_ACTIVE 0x00001000
#define BCM43xx_DMADTOR_FRAMEEND (1 << 30) #define BCM43xx_DMA32_RXSTAT_IDLEWAIT 0x00002000
#define BCM43xx_DMADTOR_FRAMESTART (1 << 31) #define BCM43xx_DMA32_RXSTAT_STOPPED 0x00003000
#define BCM43xx_DMA32_RXERROR 0x000F0000
#define BCM43xx_DMA32_RXERR_NOERR 0x00000000
#define BCM43xx_DMA32_RXERR_PROT 0x00010000
#define BCM43xx_DMA32_RXERR_OVERFLOW 0x00020000
#define BCM43xx_DMA32_RXERR_BUFWRITE 0x00030000
#define BCM43xx_DMA32_RXERR_DESCREAD 0x00040000
#define BCM43xx_DMA32_RXACTIVE 0xFFF00000
/* 32-bit DMA descriptor. */
struct bcm43xx_dmadesc32 {
__le32 control;
__le32 address;
} __attribute__((__packed__));
#define BCM43xx_DMA32_DCTL_BYTECNT 0x00001FFF
#define BCM43xx_DMA32_DCTL_ADDREXT_MASK 0x00030000
#define BCM43xx_DMA32_DCTL_ADDREXT_SHIFT 16
#define BCM43xx_DMA32_DCTL_DTABLEEND 0x10000000
#define BCM43xx_DMA32_DCTL_IRQ 0x20000000
#define BCM43xx_DMA32_DCTL_FRAMEEND 0x40000000
#define BCM43xx_DMA32_DCTL_FRAMESTART 0x80000000
/* Address field Routing value. */
#define BCM43xx_DMA32_ROUTING 0xC0000000
#define BCM43xx_DMA32_ROUTING_SHIFT 30
#define BCM43xx_DMA32_NOTRANS 0x00000000
#define BCM43xx_DMA32_CLIENTTRANS 0x40000000
/*** 64-bit DMA Engine. ***/
/* 64-bit DMA controller registers. */
#define BCM43xx_DMA64_TXCTL 0x00
#define BCM43xx_DMA64_TXENABLE 0x00000001
#define BCM43xx_DMA64_TXSUSPEND 0x00000002
#define BCM43xx_DMA64_TXLOOPBACK 0x00000004
#define BCM43xx_DMA64_TXFLUSH 0x00000010
#define BCM43xx_DMA64_TXADDREXT_MASK 0x00030000
#define BCM43xx_DMA64_TXADDREXT_SHIFT 16
#define BCM43xx_DMA64_TXINDEX 0x04
#define BCM43xx_DMA64_TXRINGLO 0x08
#define BCM43xx_DMA64_TXRINGHI 0x0C
#define BCM43xx_DMA64_TXSTATUS 0x10
#define BCM43xx_DMA64_TXSTATDPTR 0x00001FFF
#define BCM43xx_DMA64_TXSTAT 0xF0000000
#define BCM43xx_DMA64_TXSTAT_DISABLED 0x00000000
#define BCM43xx_DMA64_TXSTAT_ACTIVE 0x10000000
#define BCM43xx_DMA64_TXSTAT_IDLEWAIT 0x20000000
#define BCM43xx_DMA64_TXSTAT_STOPPED 0x30000000
#define BCM43xx_DMA64_TXSTAT_SUSP 0x40000000
#define BCM43xx_DMA64_TXERROR 0x14
#define BCM43xx_DMA64_TXERRDPTR 0x0001FFFF
#define BCM43xx_DMA64_TXERR 0xF0000000
#define BCM43xx_DMA64_TXERR_NOERR 0x00000000
#define BCM43xx_DMA64_TXERR_PROT 0x10000000
#define BCM43xx_DMA64_TXERR_UNDERRUN 0x20000000
#define BCM43xx_DMA64_TXERR_TRANSFER 0x30000000
#define BCM43xx_DMA64_TXERR_DESCREAD 0x40000000
#define BCM43xx_DMA64_TXERR_CORE 0x50000000
#define BCM43xx_DMA64_RXCTL 0x20
#define BCM43xx_DMA64_RXENABLE 0x00000001
#define BCM43xx_DMA64_RXFROFF_MASK 0x000000FE
#define BCM43xx_DMA64_RXFROFF_SHIFT 1
#define BCM43xx_DMA64_RXDIRECTFIFO 0x00000100
#define BCM43xx_DMA64_RXADDREXT_MASK 0x00030000
#define BCM43xx_DMA64_RXADDREXT_SHIFT 16
#define BCM43xx_DMA64_RXINDEX 0x24
#define BCM43xx_DMA64_RXRINGLO 0x28
#define BCM43xx_DMA64_RXRINGHI 0x2C
#define BCM43xx_DMA64_RXSTATUS 0x30
#define BCM43xx_DMA64_RXSTATDPTR 0x00001FFF
#define BCM43xx_DMA64_RXSTAT 0xF0000000
#define BCM43xx_DMA64_RXSTAT_DISABLED 0x00000000
#define BCM43xx_DMA64_RXSTAT_ACTIVE 0x10000000
#define BCM43xx_DMA64_RXSTAT_IDLEWAIT 0x20000000
#define BCM43xx_DMA64_RXSTAT_STOPPED 0x30000000
#define BCM43xx_DMA64_RXSTAT_SUSP 0x40000000
#define BCM43xx_DMA64_RXERROR 0x34
#define BCM43xx_DMA64_RXERRDPTR 0x0001FFFF
#define BCM43xx_DMA64_RXERR 0xF0000000
#define BCM43xx_DMA64_RXERR_NOERR 0x00000000
#define BCM43xx_DMA64_RXERR_PROT 0x10000000
#define BCM43xx_DMA64_RXERR_UNDERRUN 0x20000000
#define BCM43xx_DMA64_RXERR_TRANSFER 0x30000000
#define BCM43xx_DMA64_RXERR_DESCREAD 0x40000000
#define BCM43xx_DMA64_RXERR_CORE 0x50000000
/* 64-bit DMA descriptor. */
struct bcm43xx_dmadesc64 {
__le32 control0;
__le32 control1;
__le32 address_low;
__le32 address_high;
} __attribute__((__packed__));
#define BCM43xx_DMA64_DCTL0_DTABLEEND 0x10000000
#define BCM43xx_DMA64_DCTL0_IRQ 0x20000000
#define BCM43xx_DMA64_DCTL0_FRAMEEND 0x40000000
#define BCM43xx_DMA64_DCTL0_FRAMESTART 0x80000000
#define BCM43xx_DMA64_DCTL1_BYTECNT 0x00001FFF
#define BCM43xx_DMA64_DCTL1_ADDREXT_MASK 0x00030000
#define BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT 16
/* Address field Routing value. */
#define BCM43xx_DMA64_ROUTING 0xC0000000
#define BCM43xx_DMA64_ROUTING_SHIFT 30
#define BCM43xx_DMA64_NOTRANS 0x00000000
#define BCM43xx_DMA64_CLIENTTRANS 0x80000000
struct bcm43xx_dmadesc_generic {
union {
struct bcm43xx_dmadesc32 dma32;
struct bcm43xx_dmadesc64 dma64;
} __attribute__((__packed__));
} __attribute__((__packed__));
/* Misc DMA constants */ /* Misc DMA constants */
#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE #define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE
#define BCM43xx_DMA_BUSADDRMAX 0x3FFFFFFF #define BCM43xx_DMA0_RX_FRAMEOFFSET 30
#define BCM43xx_DMA_DMABUSADDROFFSET (1 << 30) #define BCM43xx_DMA3_RX_FRAMEOFFSET 0
#define BCM43xx_DMA1_RX_FRAMEOFFSET 30
#define BCM43xx_DMA4_RX_FRAMEOFFSET 0
/* DMA engine tuning knobs */ /* DMA engine tuning knobs */
#define BCM43xx_TXRING_SLOTS 512 #define BCM43xx_TXRING_SLOTS 512
#define BCM43xx_RXRING_SLOTS 64 #define BCM43xx_RXRING_SLOTS 64
#define BCM43xx_DMA1_RXBUFFERSIZE (2304 + 100) #define BCM43xx_DMA0_RX_BUFFERSIZE (2304 + 100)
#define BCM43xx_DMA4_RXBUFFERSIZE 16 #define BCM43xx_DMA3_RX_BUFFERSIZE 16
/* Suspend the tx queue, if less than this percent slots are free. */ /* Suspend the tx queue, if less than this percent slots are free. */
#define BCM43xx_TXSUSPEND_PERCENT 20 #define BCM43xx_TXSUSPEND_PERCENT 20
/* Resume the tx queue, if more than this percent slots are free. */ /* Resume the tx queue, if more than this percent slots are free. */
...@@ -86,17 +202,6 @@ struct bcm43xx_private; ...@@ -86,17 +202,6 @@ struct bcm43xx_private;
struct bcm43xx_xmitstatus; struct bcm43xx_xmitstatus;
struct bcm43xx_dmadesc {
__le32 _control;
__le32 _address;
} __attribute__((__packed__));
/* Macros to access the bcm43xx_dmadesc struct */
#define get_desc_ctl(desc) le32_to_cpu((desc)->_control)
#define set_desc_ctl(desc, ctl) do { (desc)->_control = cpu_to_le32(ctl); } while (0)
#define get_desc_addr(desc) le32_to_cpu((desc)->_address)
#define set_desc_addr(desc, addr) do { (desc)->_address = cpu_to_le32(addr); } while (0)
struct bcm43xx_dmadesc_meta { struct bcm43xx_dmadesc_meta {
/* The kernel DMA-able buffer. */ /* The kernel DMA-able buffer. */
struct sk_buff *skb; struct sk_buff *skb;
...@@ -105,15 +210,14 @@ struct bcm43xx_dmadesc_meta { ...@@ -105,15 +210,14 @@ struct bcm43xx_dmadesc_meta {
}; };
struct bcm43xx_dmaring { struct bcm43xx_dmaring {
struct bcm43xx_private *bcm;
/* Kernel virtual base address of the ring memory. */ /* Kernel virtual base address of the ring memory. */
struct bcm43xx_dmadesc *vbase; void *descbase;
/* DMA memory offset */
dma_addr_t memoffset;
/* (Unadjusted) DMA base bus-address of the ring memory. */
dma_addr_t dmabase;
/* Meta data about all descriptors. */ /* Meta data about all descriptors. */
struct bcm43xx_dmadesc_meta *meta; struct bcm43xx_dmadesc_meta *meta;
/* DMA Routing value. */
u32 routing;
/* (Unadjusted) DMA base bus-address of the ring memory. */
dma_addr_t dmabase;
/* Number of descriptor slots in the ring. */ /* Number of descriptor slots in the ring. */
int nr_slots; int nr_slots;
/* Number of used descriptor slots. */ /* Number of used descriptor slots. */
...@@ -127,12 +231,17 @@ struct bcm43xx_dmaring { ...@@ -127,12 +231,17 @@ struct bcm43xx_dmaring {
u32 frameoffset; u32 frameoffset;
/* Descriptor buffer size. */ /* Descriptor buffer size. */
u16 rx_buffersize; u16 rx_buffersize;
/* The MMIO base register of the DMA controller, this /* The MMIO base register of the DMA controller. */
* ring is posted to.
*/
u16 mmio_base; u16 mmio_base;
u8 tx:1, /* TRUE, if this is a TX ring. */ /* DMA controller index number (0-5). */
suspended:1; /* TRUE, if transfers are suspended on this ring. */ int index;
/* Boolean. Is this a TX ring? */
u8 tx;
/* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
u8 dma64;
/* Boolean. Are transfers suspended on this ring? */
u8 suspended;
struct bcm43xx_private *bcm;
#ifdef CONFIG_BCM43XX_DEBUG #ifdef CONFIG_BCM43XX_DEBUG
/* Maximum number of used slots. */ /* Maximum number of used slots. */
int max_used_slots; int max_used_slots;
...@@ -140,6 +249,34 @@ struct bcm43xx_dmaring { ...@@ -140,6 +249,34 @@ struct bcm43xx_dmaring {
}; };
static inline
int bcm43xx_dma_desc2idx(struct bcm43xx_dmaring *ring,
struct bcm43xx_dmadesc_generic *desc)
{
if (ring->dma64) {
struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
return (int)(&(desc->dma64) - dd64);
} else {
struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
return (int)(&(desc->dma32) - dd32);
}
}
static inline
struct bcm43xx_dmadesc_generic * bcm43xx_dma_idx2desc(struct bcm43xx_dmaring *ring,
int slot,
struct bcm43xx_dmadesc_meta **meta)
{
*meta = &(ring->meta[slot]);
if (ring->dma64) {
struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
return (struct bcm43xx_dmadesc_generic *)(&(dd64[slot]));
} else {
struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
return (struct bcm43xx_dmadesc_generic *)(&(dd32[slot]));
}
}
static inline static inline
u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring, u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
u16 offset) u16 offset)
...@@ -159,9 +296,13 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm); ...@@ -159,9 +296,13 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm);
void bcm43xx_dma_free(struct bcm43xx_private *bcm); void bcm43xx_dma_free(struct bcm43xx_private *bcm);
int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
u16 dmacontroller_mmio_base); u16 dmacontroller_mmio_base,
int dma64);
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
u16 dmacontroller_mmio_base); u16 dmacontroller_mmio_base,
int dma64);
u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx);
void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring); void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring); void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
...@@ -173,7 +314,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, ...@@ -173,7 +314,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
struct ieee80211_txb *txb); struct ieee80211_txb *txb);
void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
#else /* CONFIG_BCM43XX_DMA */ #else /* CONFIG_BCM43XX_DMA */
...@@ -188,13 +328,15 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm) ...@@ -188,13 +328,15 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm)
} }
static inline static inline
int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
u16 dmacontroller_mmio_base) u16 dmacontroller_mmio_base,
int dma64)
{ {
return 0; return 0;
} }
static inline static inline
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
u16 dmacontroller_mmio_base) u16 dmacontroller_mmio_base,
int dma64)
{ {
return 0; return 0;
} }
......
...@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d) ...@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d)
struct bcm43xx_private *bcm = led->bcm; struct bcm43xx_private *bcm = led->bcm;
unsigned long flags; unsigned long flags;
bcm43xx_lock_irqonly(bcm, flags); spin_lock_irqsave(&bcm->leds_lock, flags);
if (led->blink_interval) { if (led->blink_interval) {
bcm43xx_led_changestate(led); bcm43xx_led_changestate(led);
mod_timer(&led->blink_timer, jiffies + led->blink_interval); mod_timer(&led->blink_timer, jiffies + led->blink_interval);
} }
bcm43xx_unlock_irqonly(bcm, flags); spin_unlock_irqrestore(&bcm->leds_lock, flags);
} }
static void bcm43xx_led_blink_start(struct bcm43xx_led *led, static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
...@@ -177,7 +177,9 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) ...@@ -177,7 +177,9 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
int i, turn_on; int i, turn_on;
unsigned long interval = 0; unsigned long interval = 0;
u16 ledctl; u16 ledctl;
unsigned long flags;
spin_lock_irqsave(&bcm->leds_lock, flags);
ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
for (i = 0; i < BCM43xx_NR_LEDS; i++) { for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(bcm->leds[i]); led = &(bcm->leds[i]);
...@@ -266,6 +268,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) ...@@ -266,6 +268,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
ledctl &= ~(1 << i); ledctl &= ~(1 << i);
} }
bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
spin_unlock_irqrestore(&bcm->leds_lock, flags);
} }
void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
...@@ -274,7 +277,9 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) ...@@ -274,7 +277,9 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
u16 ledctl; u16 ledctl;
int i; int i;
int bit_on; int bit_on;
unsigned long flags;
spin_lock_irqsave(&bcm->leds_lock, flags);
ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
for (i = 0; i < BCM43xx_NR_LEDS; i++) { for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(bcm->leds[i]); led = &(bcm->leds[i]);
...@@ -290,4 +295,5 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) ...@@ -290,4 +295,5 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
ledctl &= ~(1 << i); ledctl &= ~(1 << i);
} }
bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
spin_unlock_irqrestore(&bcm->leds_lock, flags);
} }
...@@ -509,23 +509,20 @@ static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm) ...@@ -509,23 +509,20 @@ static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
} }
/* Make sure we don't receive more data from the device. */ /* Make sure we don't receive more data from the device. */
static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
{ {
unsigned long flags; unsigned long flags;
u32 old;
bcm43xx_lock_irqonly(bcm, flags); spin_lock_irqsave(&bcm->irq_lock, flags);
if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
bcm43xx_unlock_irqonly(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
return -EBUSY; return -EBUSY;
} }
old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
bcm43xx_unlock_irqonly(bcm, flags); bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); /* flush */
spin_unlock_irqrestore(&bcm->irq_lock, flags);
bcm43xx_synchronize_irq(bcm); bcm43xx_synchronize_irq(bcm);
if (oldstate)
*oldstate = old;
return 0; return 0;
} }
...@@ -537,7 +534,6 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) ...@@ -537,7 +534,6 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
u16 manufact; u16 manufact;
u16 version; u16 version;
u8 revision; u8 revision;
s8 i;
if (bcm->chip_id == 0x4317) { if (bcm->chip_id == 0x4317) {
if (bcm->chip_rev == 0x00) if (bcm->chip_rev == 0x00)
...@@ -580,20 +576,11 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) ...@@ -580,20 +576,11 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
radio->version = version; radio->version = version;
radio->revision = revision; radio->revision = revision;
/* Set default attenuation values. */
radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
radio->txctl1 = bcm43xx_default_txctl1(bcm);
radio->txctl2 = 0xFFFF;
if (phy->type == BCM43xx_PHYTYPE_A) if (phy->type == BCM43xx_PHYTYPE_A)
radio->txpower_desired = bcm->sprom.maxpower_aphy; radio->txpower_desired = bcm->sprom.maxpower_aphy;
else else
radio->txpower_desired = bcm->sprom.maxpower_bgphy; radio->txpower_desired = bcm->sprom.maxpower_bgphy;
/* Initialize the in-memory nrssi Lookup Table. */
for (i = 0; i < 64; i++)
radio->nrssi_lt[i] = i;
return 0; return 0;
err_unsupported_radio: err_unsupported_radio:
...@@ -1250,10 +1237,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne ...@@ -1250,10 +1237,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne
goto out; goto out;
bcm->current_core = new_core; bcm->current_core = new_core;
bcm->current_80211_core_idx = -1;
if (new_core->id == BCM43xx_COREID_80211)
bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
out: out:
return err; return err;
} }
...@@ -1389,6 +1372,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) ...@@ -1389,6 +1372,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
if ((bcm43xx_core_enabled(bcm)) && if ((bcm43xx_core_enabled(bcm)) &&
!bcm43xx_using_pio(bcm)) { !bcm43xx_using_pio(bcm)) {
//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here? //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
#if 0
#ifndef CONFIG_BCM947XX #ifndef CONFIG_BCM947XX
/* reset all used DMA controllers. */ /* reset all used DMA controllers. */
bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
...@@ -1398,6 +1382,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) ...@@ -1398,6 +1382,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
if (bcm->current_core->rev < 5) if (bcm->current_core->rev < 5)
bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
#endif
#endif #endif
} }
if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) { if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
...@@ -1423,43 +1408,23 @@ static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm) ...@@ -1423,43 +1408,23 @@ static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
bcm43xx_core_disable(bcm, 0); bcm43xx_core_disable(bcm, 0);
} }
/* Mark the current 80211 core inactive. /* Mark the current 80211 core inactive. */
* "active_80211_core" is the other 80211 core, which is used. static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm)
*/
static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
struct bcm43xx_coreinfo *active_80211_core)
{ {
u32 sbtmstatelow; u32 sbtmstatelow;
struct bcm43xx_coreinfo *old_core;
int err = 0;
bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
bcm43xx_radio_turn_off(bcm); bcm43xx_radio_turn_off(bcm);
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
sbtmstatelow &= ~0x200a0000; sbtmstatelow &= 0xDFF5FFFF;
sbtmstatelow |= 0xa0000; sbtmstatelow |= 0x000A0000;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
udelay(1); udelay(1);
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
sbtmstatelow &= ~0xa0000; sbtmstatelow &= 0xFFF5FFFF;
sbtmstatelow |= 0x80000; sbtmstatelow |= 0x00080000;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
udelay(1); udelay(1);
if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
old_core = bcm->current_core;
err = bcm43xx_switch_core(bcm, active_80211_core);
if (err)
goto out;
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
sbtmstatelow &= ~0x20000000;
sbtmstatelow |= 0x20000000;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
err = bcm43xx_switch_core(bcm, old_core);
}
out:
return err;
} }
static void handle_irq_transmit_status(struct bcm43xx_private *bcm) static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
...@@ -1581,17 +1546,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm) ...@@ -1581,17 +1546,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm)
else else
average -= 48; average -= 48;
/* FIXME: This is wrong, but people want fancy stats. well... */ bcm->stats.noise = average;
bcm->stats.noise = average;
if (average > -65)
bcm->stats.link_quality = 0;
else if (average > -75)
bcm->stats.link_quality = 1;
else if (average > -85)
bcm->stats.link_quality = 2;
else
bcm->stats.link_quality = 3;
// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
drop_calculation: drop_calculation:
bcm->noisecalc.calculation_running = 0; bcm->noisecalc.calculation_running = 0;
return; return;
...@@ -1709,8 +1664,9 @@ static void handle_irq_beacon(struct bcm43xx_private *bcm) ...@@ -1709,8 +1664,9 @@ static void handle_irq_beacon(struct bcm43xx_private *bcm)
static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
{ {
u32 reason; u32 reason;
u32 dma_reason[4]; u32 dma_reason[6];
int activity = 0; u32 merged_dma_reason = 0;
int i, activity = 0;
unsigned long flags; unsigned long flags;
#ifdef CONFIG_BCM43XX_DEBUG #ifdef CONFIG_BCM43XX_DEBUG
...@@ -1720,12 +1676,12 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) ...@@ -1720,12 +1676,12 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
# define bcmirq_handled(irq) do { /* nothing */ } while (0) # define bcmirq_handled(irq) do { /* nothing */ } while (0)
#endif /* CONFIG_BCM43XX_DEBUG*/ #endif /* CONFIG_BCM43XX_DEBUG*/
bcm43xx_lock_irqonly(bcm, flags); spin_lock_irqsave(&bcm->irq_lock, flags);
reason = bcm->irq_reason; reason = bcm->irq_reason;
dma_reason[0] = bcm->dma_reason[0]; for (i = 5; i >= 0; i--) {
dma_reason[1] = bcm->dma_reason[1]; dma_reason[i] = bcm->dma_reason[i];
dma_reason[2] = bcm->dma_reason[2]; merged_dma_reason |= dma_reason[i];
dma_reason[3] = bcm->dma_reason[3]; }
if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) { if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
/* TX error. We get this when Template Ram is written in wrong endianess /* TX error. We get this when Template Ram is written in wrong endianess
...@@ -1736,27 +1692,25 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) ...@@ -1736,27 +1692,25 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n"); printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR); bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
} }
if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) | if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_FATALMASK)) {
(dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
(dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
(dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: " printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
"0x%08X, 0x%08X, 0x%08X, 0x%08X\n", "0x%08X, 0x%08X, 0x%08X, "
"0x%08X, 0x%08X, 0x%08X\n",
dma_reason[0], dma_reason[1], dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3]); dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);
bcm43xx_controller_restart(bcm, "DMA error"); bcm43xx_controller_restart(bcm, "DMA error");
mmiowb(); mmiowb();
bcm43xx_unlock_irqonly(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
return; return;
} }
if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_NONFATALMASK)) {
(dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
(dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
(dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
printkl(KERN_ERR PFX "DMA error: " printkl(KERN_ERR PFX "DMA error: "
"0x%08X, 0x%08X, 0x%08X, 0x%08X\n", "0x%08X, 0x%08X, 0x%08X, "
"0x%08X, 0x%08X, 0x%08X\n",
dma_reason[0], dma_reason[1], dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3]); dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);
} }
if (reason & BCM43xx_IRQ_PS) { if (reason & BCM43xx_IRQ_PS) {
...@@ -1791,8 +1745,6 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) ...@@ -1791,8 +1745,6 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
} }
/* Check the DMA reason registers for received data. */ /* Check the DMA reason registers for received data. */
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 (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
if (bcm43xx_using_pio(bcm)) if (bcm43xx_using_pio(bcm))
bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0); bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
...@@ -1800,13 +1752,17 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) ...@@ -1800,13 +1752,17 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0); bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
/* We intentionally don't set "activity" to 1, here. */ /* We intentionally don't set "activity" to 1, here. */
} }
assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
if (bcm43xx_using_pio(bcm)) if (bcm43xx_using_pio(bcm))
bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3); bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
else else
bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1); bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring3);
activity = 1; activity = 1;
} }
assert(!(dma_reason[4] & BCM43xx_DMAIRQ_RX_DONE));
assert(!(dma_reason[5] & BCM43xx_DMAIRQ_RX_DONE));
bcmirq_handled(BCM43xx_IRQ_RX); bcmirq_handled(BCM43xx_IRQ_RX);
if (reason & BCM43xx_IRQ_XMIT_STATUS) { if (reason & BCM43xx_IRQ_XMIT_STATUS) {
...@@ -1834,7 +1790,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) ...@@ -1834,7 +1790,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
bcm43xx_leds_update(bcm, activity); bcm43xx_leds_update(bcm, activity);
bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
mmiowb(); mmiowb();
bcm43xx_unlock_irqonly(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
} }
static void pio_irq_workaround(struct bcm43xx_private *bcm, static void pio_irq_workaround(struct bcm43xx_private *bcm,
...@@ -1863,14 +1819,18 @@ static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason) ...@@ -1863,14 +1819,18 @@ static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason); bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_REASON,
bcm->dma_reason[0]); bcm->dma_reason[0]);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON, bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
bcm->dma_reason[1]); bcm->dma_reason[1]);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON, bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
bcm->dma_reason[2]); bcm->dma_reason[2]);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON, bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
bcm->dma_reason[3]); bcm->dma_reason[3]);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
bcm->dma_reason[4]);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_REASON,
bcm->dma_reason[5]);
} }
/* Interrupt handler top-half */ /* Interrupt handler top-half */
...@@ -1885,14 +1845,8 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re ...@@ -1885,14 +1845,8 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
spin_lock(&bcm->irq_lock); spin_lock(&bcm->irq_lock);
/* Only accept IRQs, if we are initialized properly. assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
* This avoids an RX race while initializing. assert(bcm->current_core->id == BCM43xx_COREID_80211);
* We should probably not enable IRQs before we are initialized
* completely, but some careful work is needed to fix this. I think it
* is best to stay with this cheap workaround for now... .
*/
if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
goto out;
reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) { if (reason == 0xffffffff) {
...@@ -1904,14 +1858,18 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re ...@@ -1904,14 +1858,18 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
if (!reason) if (!reason)
goto out; goto out;
bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON)
& 0x0001dc00; & 0x0001DC00;
bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
& 0x0000dc00; & 0x0000DC00;
bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
& 0x0000dc00; & 0x0000DC00;
bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
& 0x0001dc00; & 0x0001DC00;
bcm->dma_reason[4] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
& 0x0000DC00;
bcm->dma_reason[5] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA5_REASON)
& 0x0000DC00;
bcm43xx_interrupt_ack(bcm, reason); bcm43xx_interrupt_ack(bcm, reason);
...@@ -1930,16 +1888,18 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re ...@@ -1930,16 +1888,18 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
{ {
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
if (bcm->firmware_norelease && !force) if (bcm->firmware_norelease && !force)
return; /* Suspending or controller reset. */ return; /* Suspending or controller reset. */
release_firmware(bcm->ucode); release_firmware(phy->ucode);
bcm->ucode = NULL; phy->ucode = NULL;
release_firmware(bcm->pcm); release_firmware(phy->pcm);
bcm->pcm = NULL; phy->pcm = NULL;
release_firmware(bcm->initvals0); release_firmware(phy->initvals0);
bcm->initvals0 = NULL; phy->initvals0 = NULL;
release_firmware(bcm->initvals1); release_firmware(phy->initvals1);
bcm->initvals1 = NULL; phy->initvals1 = NULL;
} }
static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
...@@ -1950,11 +1910,11 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) ...@@ -1950,11 +1910,11 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
int nr; int nr;
char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
if (!bcm->ucode) { if (!phy->ucode) {
snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
(rev >= 5 ? 5 : rev), (rev >= 5 ? 5 : rev),
modparam_fwpostfix); modparam_fwpostfix);
err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev);
if (err) { if (err) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"Error: Microcode \"%s\" not available or load failed.\n", "Error: Microcode \"%s\" not available or load failed.\n",
...@@ -1963,12 +1923,12 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) ...@@ -1963,12 +1923,12 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
} }
} }
if (!bcm->pcm) { if (!phy->pcm) {
snprintf(buf, ARRAY_SIZE(buf), snprintf(buf, ARRAY_SIZE(buf),
"bcm43xx_pcm%d%s.fw", "bcm43xx_pcm%d%s.fw",
(rev < 5 ? 4 : 5), (rev < 5 ? 4 : 5),
modparam_fwpostfix); modparam_fwpostfix);
err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev);
if (err) { if (err) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"Error: PCM \"%s\" not available or load failed.\n", "Error: PCM \"%s\" not available or load failed.\n",
...@@ -1977,7 +1937,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) ...@@ -1977,7 +1937,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
} }
} }
if (!bcm->initvals0) { if (!phy->initvals0) {
if (rev == 2 || rev == 4) { if (rev == 2 || rev == 4) {
switch (phy->type) { switch (phy->type) {
case BCM43xx_PHYTYPE_A: case BCM43xx_PHYTYPE_A:
...@@ -2008,20 +1968,20 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) ...@@ -2008,20 +1968,20 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
nr, modparam_fwpostfix); nr, modparam_fwpostfix);
err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev);
if (err) { if (err) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"Error: InitVals \"%s\" not available or load failed.\n", "Error: InitVals \"%s\" not available or load failed.\n",
buf); buf);
goto error; goto error;
} }
if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) {
printk(KERN_ERR PFX "InitVals fileformat error.\n"); printk(KERN_ERR PFX "InitVals fileformat error.\n");
goto error; goto error;
} }
} }
if (!bcm->initvals1) { if (!phy->initvals1) {
if (rev >= 5) { if (rev >= 5) {
u32 sbtmstatehigh; u32 sbtmstatehigh;
...@@ -2043,14 +2003,14 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) ...@@ -2043,14 +2003,14 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
nr, modparam_fwpostfix); nr, modparam_fwpostfix);
err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev);
if (err) { if (err) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"Error: InitVals \"%s\" not available or load failed.\n", "Error: InitVals \"%s\" not available or load failed.\n",
buf); buf);
goto error; goto error;
} }
if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) {
printk(KERN_ERR PFX "InitVals fileformat error.\n"); printk(KERN_ERR PFX "InitVals fileformat error.\n");
goto error; goto error;
} }
...@@ -2070,12 +2030,13 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) ...@@ -2070,12 +2030,13 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
{ {
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
const u32 *data; const u32 *data;
unsigned int i, len; unsigned int i, len;
/* Upload Microcode. */ /* Upload Microcode. */
data = (u32 *)(bcm->ucode->data); data = (u32 *)(phy->ucode->data);
len = bcm->ucode->size / sizeof(u32); len = phy->ucode->size / sizeof(u32);
bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
...@@ -2084,8 +2045,8 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) ...@@ -2084,8 +2045,8 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
} }
/* Upload PCM data. */ /* Upload PCM data. */
data = (u32 *)(bcm->pcm->data); data = (u32 *)(phy->pcm->data);
len = bcm->pcm->size / sizeof(u32); len = phy->pcm->size / sizeof(u32);
bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
...@@ -2131,15 +2092,16 @@ static int bcm43xx_write_initvals(struct bcm43xx_private *bcm, ...@@ -2131,15 +2092,16 @@ static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,
static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
{ {
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
int err; int err;
err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data,
bcm->initvals0->size / sizeof(struct bcm43xx_initval)); phy->initvals0->size / sizeof(struct bcm43xx_initval));
if (err) if (err)
goto out; goto out;
if (bcm->initvals1) { if (phy->initvals1) {
err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data,
bcm->initvals1->size / sizeof(struct bcm43xx_initval)); phy->initvals1->size / sizeof(struct bcm43xx_initval));
if (err) if (err)
goto out; goto out;
} }
...@@ -2156,9 +2118,7 @@ static struct pci_device_id bcm43xx_47xx_ids[] = { ...@@ -2156,9 +2118,7 @@ static struct pci_device_id bcm43xx_47xx_ids[] = {
static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
{ {
int res; int err;
unsigned int i;
u32 data;
bcm->irq = bcm->pci_dev->irq; bcm->irq = bcm->pci_dev->irq;
#ifdef CONFIG_BCM947XX #ifdef CONFIG_BCM947XX
...@@ -2175,32 +2135,12 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) ...@@ -2175,32 +2135,12 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
} }
} }
#endif #endif
res = request_irq(bcm->irq, bcm43xx_interrupt_handler, err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
IRQF_SHARED, KBUILD_MODNAME, bcm); IRQF_SHARED, KBUILD_MODNAME, bcm);
if (res) { if (err)
printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
return -ENODEV;
}
bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
i = 0;
while (1) {
data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (data == BCM43xx_IRQ_READY)
break;
i++;
if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
printk(KERN_ERR PFX "Card IRQ register not responding. "
"Giving up.\n");
free_irq(bcm->irq, bcm);
return -ENODEV;
}
udelay(10);
}
// dummy read
bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
return 0; return err;
} }
/* Switch to the core used to write the GPIO register. /* Switch to the core used to write the GPIO register.
...@@ -2298,13 +2238,17 @@ static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm) ...@@ -2298,13 +2238,17 @@ static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
/* http://bcm-specs.sipsolutions.net/EnableMac */ /* http://bcm-specs.sipsolutions.net/EnableMac */
void bcm43xx_mac_enable(struct bcm43xx_private *bcm) void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
{ {
bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, bcm->mac_suspended--;
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) assert(bcm->mac_suspended >= 0);
| BCM43xx_SBF_MAC_ENABLED); if (bcm->mac_suspended == 0) {
bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | BCM43xx_SBF_MAC_ENABLED);
bcm43xx_power_saving_ctl_bits(bcm, -1, -1); bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
}
} }
/* http://bcm-specs.sipsolutions.net/SuspendMAC */ /* http://bcm-specs.sipsolutions.net/SuspendMAC */
...@@ -2313,18 +2257,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) ...@@ -2313,18 +2257,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
int i; int i;
u32 tmp; u32 tmp;
bcm43xx_power_saving_ctl_bits(bcm, -1, 1); assert(bcm->mac_suspended >= 0);
bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, if (bcm->mac_suspended == 0) {
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
& ~BCM43xx_SBF_MAC_ENABLED); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
for (i = 100000; i; i--) { & ~BCM43xx_SBF_MAC_ENABLED);
tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
if (tmp & BCM43xx_IRQ_READY) for (i = 10000; i; i--) {
return; tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
udelay(10); if (tmp & BCM43xx_IRQ_READY)
goto out;
udelay(1);
}
printkl(KERN_ERR PFX "MAC suspend failed\n");
} }
printkl(KERN_ERR PFX "MAC suspend failed\n"); out:
bcm->mac_suspended++;
} }
void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
...@@ -2394,7 +2343,6 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) ...@@ -2394,7 +2343,6 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
if (!modparam_noleds) if (!modparam_noleds)
bcm43xx_leds_exit(bcm); bcm43xx_leds_exit(bcm);
bcm43xx_gpio_cleanup(bcm); bcm43xx_gpio_cleanup(bcm);
free_irq(bcm->irq, bcm);
bcm43xx_release_firmware(bcm, 0); bcm43xx_release_firmware(bcm, 0);
} }
...@@ -2406,7 +2354,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) ...@@ -2406,7 +2354,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
int err; int err;
int tmp; int i, tmp;
u32 value32; u32 value32;
u16 value16; u16 value16;
...@@ -2419,13 +2367,53 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) ...@@ -2419,13 +2367,53 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
goto out; goto out;
bcm43xx_upload_microcode(bcm); bcm43xx_upload_microcode(bcm);
err = bcm43xx_initialize_irq(bcm); bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF);
if (err) bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
i = 0;
while (1) {
value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (value32 == BCM43xx_IRQ_READY)
break;
i++;
if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
printk(KERN_ERR PFX "IRQ_READY timeout\n");
err = -ENODEV;
goto err_release_fw;
}
udelay(10);
}
bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
value16 = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
BCM43xx_UCODE_REVISION);
dprintk(KERN_INFO PFX "Microcode rev 0x%x, pl 0x%x "
"(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", value16,
bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
BCM43xx_UCODE_PATCHLEVEL),
(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
BCM43xx_UCODE_DATE) >> 12) & 0xf,
(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
BCM43xx_UCODE_DATE) >> 8) & 0xf,
bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
BCM43xx_UCODE_DATE) & 0xff,
(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
BCM43xx_UCODE_TIME) >> 11) & 0x1f,
(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
BCM43xx_UCODE_TIME) >> 5) & 0x3f,
bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
BCM43xx_UCODE_TIME) & 0x1f);
if ( value16 > 0x128 ) {
dprintk(KERN_ERR PFX
"Firmware: no support for microcode rev > 0x128\n");
err = -1;
goto err_release_fw; goto err_release_fw;
}
err = bcm43xx_gpio_init(bcm); err = bcm43xx_gpio_init(bcm);
if (err) if (err)
goto err_free_irq; goto err_release_fw;
err = bcm43xx_upload_initvals(bcm); err = bcm43xx_upload_initvals(bcm);
if (err) if (err)
...@@ -2489,10 +2477,12 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) ...@@ -2489,10 +2477,12 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
bcm43xx_write32(bcm, 0x018C, 0x02000000); bcm43xx_write32(bcm, 0x018C, 0x02000000);
} }
bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000); bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
value32 |= 0x00100000; value32 |= 0x00100000;
...@@ -2509,8 +2499,6 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) ...@@ -2509,8 +2499,6 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
bcm43xx_radio_turn_off(bcm); bcm43xx_radio_turn_off(bcm);
err_gpio_cleanup: err_gpio_cleanup:
bcm43xx_gpio_cleanup(bcm); bcm43xx_gpio_cleanup(bcm);
err_free_irq:
free_irq(bcm->irq, bcm);
err_release_fw: err_release_fw:
bcm43xx_release_firmware(bcm, 1); bcm43xx_release_firmware(bcm, 1);
goto out; goto out;
...@@ -2550,11 +2538,9 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) ...@@ -2550,11 +2538,9 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
{ {
/* Initialize a "phyinfo" structure. The structure is already /* Initialize a "phyinfo" structure. The structure is already
* zeroed out. * zeroed out.
* This is called on insmod time to initialize members.
*/ */
phy->antenna_diversity = 0xFFFF;
phy->savedpctlreg = 0xFFFF; phy->savedpctlreg = 0xFFFF;
phy->minlowsig[0] = 0xFFFF;
phy->minlowsig[1] = 0xFFFF;
spin_lock_init(&phy->lock); spin_lock_init(&phy->lock);
} }
...@@ -2562,14 +2548,11 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) ...@@ -2562,14 +2548,11 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
{ {
/* Initialize a "radioinfo" structure. The structure is already /* Initialize a "radioinfo" structure. The structure is already
* zeroed out. * zeroed out.
* This is called on insmod time to initialize members.
*/ */
radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
radio->channel = 0xFF; radio->channel = 0xFF;
radio->initial_channel = 0xFF; radio->initial_channel = 0xFF;
radio->lofcal = 0xFFFF;
radio->initval = 0xFFFF;
radio->nrssi[0] = -1000;
radio->nrssi[1] = -1000;
} }
static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
...@@ -2587,7 +2570,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) ...@@ -2587,7 +2570,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
* BCM43xx_MAX_80211_CORES); * BCM43xx_MAX_80211_CORES);
memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
* BCM43xx_MAX_80211_CORES); * BCM43xx_MAX_80211_CORES);
bcm->current_80211_core_idx = -1;
bcm->nr_80211_available = 0; bcm->nr_80211_available = 0;
bcm->current_core = NULL; bcm->current_core = NULL;
bcm->active_80211_core = NULL; bcm->active_80211_core = NULL;
...@@ -2757,6 +2739,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) ...@@ -2757,6 +2739,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
goto out; goto out;
} }
bcm->nr_80211_available++; bcm->nr_80211_available++;
core->priv = ext_80211;
bcm43xx_init_struct_phyinfo(&ext_80211->phy); bcm43xx_init_struct_phyinfo(&ext_80211->phy);
bcm43xx_init_struct_radioinfo(&ext_80211->radio); bcm43xx_init_struct_radioinfo(&ext_80211->radio);
break; break;
...@@ -2857,7 +2840,8 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) ...@@ -2857,7 +2840,8 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
} }
/* http://bcm-specs.sipsolutions.net/80211Init */ /* http://bcm-specs.sipsolutions.net/80211Init */
static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
int active_wlcore)
{ {
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
...@@ -2939,19 +2923,26 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) ...@@ -2939,19 +2923,26 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
if (bcm->current_core->rev >= 5) if (bcm->current_core->rev >= 5)
bcm43xx_write16(bcm, 0x043C, 0x000C); bcm43xx_write16(bcm, 0x043C, 0x000C);
if (bcm43xx_using_pio(bcm)) if (active_wlcore) {
err = bcm43xx_pio_init(bcm); if (bcm43xx_using_pio(bcm))
else err = bcm43xx_pio_init(bcm);
err = bcm43xx_dma_init(bcm); else
if (err) err = bcm43xx_dma_init(bcm);
goto err_chip_cleanup; if (err)
goto err_chip_cleanup;
}
bcm43xx_write16(bcm, 0x0612, 0x0050); bcm43xx_write16(bcm, 0x0612, 0x0050);
bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
bcm43xx_mac_enable(bcm); if (active_wlcore) {
bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); if (radio->initial_channel != 0xFF)
bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0);
}
/* Don't enable MAC/IRQ here, as it will race with the IRQ handler.
* We enable it later.
*/
bcm->current_core->initialized = 1; bcm->current_core->initialized = 1;
out: out:
return err; return err;
...@@ -3066,11 +3057,6 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, ...@@ -3066,11 +3057,6 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm,
return err; return err;
} }
static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
{
ieee80211softmac_start(bcm->net_dev);
}
static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
{ {
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
...@@ -3178,51 +3164,43 @@ static void bcm43xx_periodic_work_handler(void *d) ...@@ -3178,51 +3164,43 @@ static void bcm43xx_periodic_work_handler(void *d)
int badness; int badness;
badness = estimate_periodic_work_badness(bcm->periodic_state); badness = estimate_periodic_work_badness(bcm->periodic_state);
mutex_lock(&bcm->mutex);
netif_tx_disable(bcm->net_dev);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (badness > BADNESS_LIMIT) { if (badness > BADNESS_LIMIT) {
/* Periodic work will take a long time, so we want it to /* Periodic work will take a long time, so we want it to
* be preemtible. * be preemtible.
*/ */
bcm43xx_lock_irqonly(bcm, flags); bcm43xx_mac_suspend(bcm);
netif_stop_queue(bcm->net_dev);
if (bcm43xx_using_pio(bcm)) if (bcm43xx_using_pio(bcm))
bcm43xx_pio_freeze_txqueues(bcm); bcm43xx_pio_freeze_txqueues(bcm);
savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
bcm43xx_unlock_irqonly(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
bcm43xx_lock_noirq(bcm);
bcm43xx_synchronize_irq(bcm); bcm43xx_synchronize_irq(bcm);
} else {
/* Periodic work should take short time, so we want low
* locking overhead.
*/
bcm43xx_lock_irqsafe(bcm, flags);
} }
do_periodic_work(bcm); do_periodic_work(bcm);
if (badness > BADNESS_LIMIT) { if (badness > BADNESS_LIMIT) {
bcm43xx_lock_irqonly(bcm, flags); spin_lock_irqsave(&bcm->irq_lock, flags);
if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) { tasklet_enable(&bcm->isr_tasklet);
tasklet_enable(&bcm->isr_tasklet); bcm43xx_interrupt_enable(bcm, savedirqs);
bcm43xx_interrupt_enable(bcm, savedirqs); if (bcm43xx_using_pio(bcm))
if (bcm43xx_using_pio(bcm)) bcm43xx_pio_thaw_txqueues(bcm);
bcm43xx_pio_thaw_txqueues(bcm); bcm43xx_mac_enable(bcm);
}
netif_wake_queue(bcm->net_dev);
mmiowb();
bcm43xx_unlock_irqonly(bcm, flags);
bcm43xx_unlock_noirq(bcm);
} else {
mmiowb();
bcm43xx_unlock_irqsafe(bcm, flags);
} }
mmiowb();
spin_unlock_irqrestore(&bcm->irq_lock, flags);
netif_wake_queue(bcm->net_dev);
mutex_unlock(&bcm->mutex);
} }
static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
{ {
cancel_rearming_delayed_work(&bcm->periodic_work); cancel_rearming_delayed_work(&bcm->periodic_work);
} }
static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
{ {
struct work_struct *work = &(bcm->periodic_work); struct work_struct *work = &(bcm->periodic_work);
...@@ -3243,9 +3221,9 @@ static int bcm43xx_rng_read(struct hwrng *rng, u32 *data) ...@@ -3243,9 +3221,9 @@ static int bcm43xx_rng_read(struct hwrng *rng, u32 *data)
struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv; struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv;
unsigned long flags; unsigned long flags;
bcm43xx_lock_irqonly(bcm, flags); spin_lock_irqsave(&(bcm)->irq_lock, flags);
*data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG); *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG);
bcm43xx_unlock_irqonly(bcm, flags); spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
return (sizeof(u16)); return (sizeof(u16));
} }
...@@ -3271,139 +3249,329 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm) ...@@ -3271,139 +3249,329 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
return err; return err;
} }
/* This is the opposite of bcm43xx_init_board() */ static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
static void bcm43xx_free_board(struct bcm43xx_private *bcm)
{ {
int ret = 0;
int i, err; int i, err;
struct bcm43xx_coreinfo *core;
bcm43xx_lock_noirq(bcm); bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
for (i = 0; i < bcm->nr_80211_available; i++) {
core = &(bcm->core_80211[i]);
assert(core->available);
if (!core->initialized)
continue;
err = bcm43xx_switch_core(bcm, core);
if (err) {
dprintk(KERN_ERR PFX "shutdown_all_wireless_cores "
"switch_core failed (%d)\n", err);
ret = err;
continue;
}
bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
bcm43xx_wireless_core_cleanup(bcm);
if (core == bcm->active_80211_core)
bcm->active_80211_core = NULL;
}
free_irq(bcm->irq, bcm);
bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
return ret;
}
/* This is the opposite of bcm43xx_init_board() */
static void bcm43xx_free_board(struct bcm43xx_private *bcm)
{
bcm43xx_rng_exit(bcm);
bcm43xx_sysfs_unregister(bcm); bcm43xx_sysfs_unregister(bcm);
bcm43xx_periodic_tasks_delete(bcm); bcm43xx_periodic_tasks_delete(bcm);
bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); mutex_lock(&(bcm)->mutex);
bcm43xx_shutdown_all_wireless_cores(bcm);
bcm43xx_pctl_set_crystal(bcm, 0);
mutex_unlock(&(bcm)->mutex);
}
bcm43xx_rng_exit(bcm); static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy)
{
phy->antenna_diversity = 0xFFFF;
memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
/* Flags */
phy->calibrated = 0;
phy->is_locked = 0;
if (phy->_lo_pairs) {
memset(phy->_lo_pairs, 0,
sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT);
}
memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
}
static void prepare_radiodata_for_init(struct bcm43xx_private *bcm,
struct bcm43xx_radioinfo *radio)
{
int i;
/* Set default attenuation values. */
radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
radio->txctl1 = bcm43xx_default_txctl1(bcm);
radio->txctl2 = 0xFFFF;
radio->txpwr_offset = 0;
/* NRSSI */
radio->nrssislope = 0;
for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++)
radio->nrssi[i] = -1000;
for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++)
radio->nrssi_lt[i] = i;
radio->lofcal = 0xFFFF;
radio->initval = 0xFFFF;
radio->aci_enable = 0;
radio->aci_wlan_automatic = 0;
radio->aci_hw_rssi = 0;
}
static void prepare_priv_for_init(struct bcm43xx_private *bcm)
{
int i;
struct bcm43xx_coreinfo *core;
struct bcm43xx_coreinfo_80211 *wlext;
assert(!bcm->active_80211_core);
bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
/* Flags */
bcm->was_initialized = 0;
bcm->reg124_set_0x4 = 0;
/* Stats */
memset(&bcm->stats, 0, sizeof(bcm->stats));
/* Wireless core data */
for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
if (!bcm->core_80211[i].available) core = &(bcm->core_80211[i]);
continue; wlext = core->priv;
if (!bcm->core_80211[i].initialized)
if (!core->available)
continue; continue;
assert(wlext == &(bcm->core_80211_ext[i]));
err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); prepare_phydata_for_init(&wlext->phy);
assert(err == 0); prepare_radiodata_for_init(bcm, &wlext->radio);
bcm43xx_wireless_core_cleanup(bcm);
} }
bcm43xx_pctl_set_crystal(bcm, 0); /* IRQ related flags */
bcm->irq_reason = 0;
memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason));
bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); bcm->mac_suspended = 1;
bcm43xx_unlock_noirq(bcm);
/* Noise calculation context */
memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc));
/* Periodic work context */
bcm->periodic_state = 0;
} }
static int bcm43xx_init_board(struct bcm43xx_private *bcm) static int wireless_core_up(struct bcm43xx_private *bcm,
int active_wlcore)
{
int err;
if (!bcm43xx_core_enabled(bcm))
bcm43xx_wireless_core_reset(bcm, 1);
if (!active_wlcore)
bcm43xx_wireless_core_mark_inactive(bcm);
err = bcm43xx_wireless_core_init(bcm, active_wlcore);
if (err)
goto out;
if (!active_wlcore)
bcm43xx_radio_turn_off(bcm);
out:
return err;
}
/* Select and enable the "to be used" wireless core.
* Locking: bcm->mutex must be aquired before calling this.
* bcm->irq_lock must not be aquired.
*/
int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
int phytype)
{ {
int i, err; int i, err;
int connect_phy; struct bcm43xx_coreinfo *active_core = NULL;
struct bcm43xx_coreinfo_80211 *active_wlext = NULL;
struct bcm43xx_coreinfo *core;
struct bcm43xx_coreinfo_80211 *wlext;
int adjust_active_sbtmstatelow = 0;
might_sleep(); might_sleep();
bcm43xx_lock_noirq(bcm); if (phytype < 0) {
bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); /* If no phytype is requested, select the first core. */
assert(bcm->core_80211[0].available);
wlext = bcm->core_80211[0].priv;
phytype = wlext->phy.type;
}
/* Find the requested core. */
for (i = 0; i < bcm->nr_80211_available; i++) {
core = &(bcm->core_80211[i]);
wlext = core->priv;
if (wlext->phy.type == phytype) {
active_core = core;
active_wlext = wlext;
break;
}
}
if (!active_core)
return -ESRCH; /* No such PHYTYPE on this board. */
if (bcm->active_80211_core) {
/* We already selected a wl core in the past.
* So first clean up everything.
*/
dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n");
ieee80211softmac_stop(bcm->net_dev);
bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
err = bcm43xx_disable_interrupts_sync(bcm);
assert(!err);
tasklet_enable(&bcm->isr_tasklet);
err = bcm43xx_shutdown_all_wireless_cores(bcm);
if (err)
goto error;
/* Ok, everything down, continue to re-initialize. */
bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
}
/* Reset all data structures. */
prepare_priv_for_init(bcm);
err = bcm43xx_pctl_set_crystal(bcm, 1);
if (err)
goto out;
err = bcm43xx_pctl_init(bcm);
if (err)
goto err_crystal_off;
err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
if (err) if (err)
goto err_crystal_off; goto error;
tasklet_enable(&bcm->isr_tasklet); /* Mark all unused cores "inactive". */
for (i = 0; i < bcm->nr_80211_available; i++) { for (i = 0; i < bcm->nr_80211_available; i++) {
err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); core = &(bcm->core_80211[i]);
assert(err != -ENODEV); wlext = core->priv;
if (err)
goto err_80211_unwind;
/* Enable the selected wireless core. if (core == active_core)
* Connect PHY only on the first core. continue;
*/ err = bcm43xx_switch_core(bcm, core);
if (!bcm43xx_core_enabled(bcm)) { if (err) {
if (bcm->nr_80211_available == 1) { dprintk(KERN_ERR PFX "Could not switch to inactive "
connect_phy = bcm43xx_current_phy(bcm)->connected; "802.11 core (%d)\n", err);
} else { goto error;
if (i == 0)
connect_phy = 1;
else
connect_phy = 0;
}
bcm43xx_wireless_core_reset(bcm, connect_phy);
} }
err = wireless_core_up(bcm, 0);
if (err) {
dprintk(KERN_ERR PFX "core_up for inactive 802.11 core "
"failed (%d)\n", err);
goto error;
}
adjust_active_sbtmstatelow = 1;
}
if (i != 0) /* Now initialize the active 802.11 core. */
bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); err = bcm43xx_switch_core(bcm, active_core);
if (err) {
err = bcm43xx_wireless_core_init(bcm); dprintk(KERN_ERR PFX "Could not switch to active "
if (err) "802.11 core (%d)\n", err);
goto err_80211_unwind; goto error;
}
if (adjust_active_sbtmstatelow &&
active_wlext->phy.type == BCM43xx_PHYTYPE_G) {
u32 sbtmstatelow;
if (i != 0) { sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
bcm43xx_mac_suspend(bcm); sbtmstatelow |= 0x20000000;
bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
bcm43xx_radio_turn_off(bcm);
}
} }
bcm->active_80211_core = &bcm->core_80211[0]; err = wireless_core_up(bcm, 1);
if (bcm->nr_80211_available >= 2) { if (err) {
bcm43xx_switch_core(bcm, &bcm->core_80211[0]); dprintk(KERN_ERR PFX "core_up for active 802.11 core "
bcm43xx_mac_enable(bcm); "failed (%d)\n", err);
goto error;
} }
err = bcm43xx_rng_init(bcm); err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
if (err) if (err)
goto err_80211_unwind; goto error;
bcm->active_80211_core = active_core;
bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
dprintk(KERN_INFO PFX "80211 cores initialized\n");
bcm43xx_security_init(bcm); bcm43xx_security_init(bcm);
bcm43xx_softmac_init(bcm); ieee80211softmac_start(bcm->net_dev);
bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); /* Let's go! Be careful after enabling the IRQs.
* Don't switch cores, for example.
*/
bcm43xx_mac_enable(bcm);
bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
err = bcm43xx_initialize_irq(bcm);
if (err)
goto error;
bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
bcm43xx_mac_suspend(bcm); active_wlext->phy.type);
bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
bcm43xx_mac_enable(bcm);
}
/* Initialization of the board is done. Flag it as such. */ return 0;
bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
error:
bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
return err;
}
static int bcm43xx_init_board(struct bcm43xx_private *bcm)
{
int err;
mutex_lock(&(bcm)->mutex);
tasklet_enable(&bcm->isr_tasklet);
err = bcm43xx_pctl_set_crystal(bcm, 1);
if (err)
goto err_tasklet;
err = bcm43xx_pctl_init(bcm);
if (err)
goto err_crystal_off;
err = bcm43xx_select_wireless_core(bcm, -1);
if (err)
goto err_crystal_off;
err = bcm43xx_sysfs_register(bcm);
if (err)
goto err_wlshutdown;
err = bcm43xx_rng_init(bcm);
if (err)
goto err_sysfs_unreg;
bcm43xx_periodic_tasks_setup(bcm); bcm43xx_periodic_tasks_setup(bcm);
bcm43xx_sysfs_register(bcm);
//FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
/*FIXME: This should be handled by softmac instead. */ /*FIXME: This should be handled by softmac instead. */
schedule_work(&bcm->softmac->associnfo.work); schedule_work(&bcm->softmac->associnfo.work);
assert(err == 0);
out: out:
bcm43xx_unlock_noirq(bcm); mutex_unlock(&(bcm)->mutex);
return err; return err;
err_80211_unwind: err_sysfs_unreg:
tasklet_disable(&bcm->isr_tasklet); bcm43xx_sysfs_unregister(bcm);
/* unwind all 80211 initialization */ err_wlshutdown:
for (i = 0; i < bcm->nr_80211_available; i++) { bcm43xx_shutdown_all_wireless_cores(bcm);
if (!bcm->core_80211[i].initialized)
continue;
bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
bcm43xx_wireless_core_cleanup(bcm);
}
err_crystal_off: err_crystal_off:
bcm43xx_pctl_set_crystal(bcm, 0); bcm43xx_pctl_set_crystal(bcm, 0);
err_tasklet:
tasklet_disable(&bcm->isr_tasklet);
goto out; goto out;
} }
...@@ -3647,7 +3815,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, ...@@ -3647,7 +3815,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
struct bcm43xx_radioinfo *radio; struct bcm43xx_radioinfo *radio;
unsigned long flags; unsigned long flags;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
bcm43xx_mac_suspend(bcm); bcm43xx_mac_suspend(bcm);
bcm43xx_radio_selectchannel(bcm, channel, 0); bcm43xx_radio_selectchannel(bcm, channel, 0);
...@@ -3656,7 +3825,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, ...@@ -3656,7 +3825,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
radio = bcm43xx_current_radio(bcm); radio = bcm43xx_current_radio(bcm);
radio->initial_channel = channel; radio->initial_channel = channel;
} }
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
} }
/* set_security() callback in struct ieee80211_device */ /* set_security() callback in struct ieee80211_device */
...@@ -3670,7 +3840,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, ...@@ -3670,7 +3840,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
dprintk(KERN_INFO PFX "set security called"); dprintk(KERN_INFO PFX "set security called");
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
if (sec->flags & (1<<keyidx)) { if (sec->flags & (1<<keyidx)) {
...@@ -3739,7 +3910,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, ...@@ -3739,7 +3910,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
} else } else
bcm43xx_clear_keys(bcm); bcm43xx_clear_keys(bcm);
} }
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
} }
/* hard_start_xmit() callback in struct ieee80211_device */ /* hard_start_xmit() callback in struct ieee80211_device */
...@@ -3751,12 +3923,14 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, ...@@ -3751,12 +3923,14 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
int err = -ENODEV; int err = -ENODEV;
unsigned long flags; unsigned long flags;
bcm43xx_lock_irqonly(bcm, flags); spin_lock_irqsave(&bcm->irq_lock, flags);
if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
err = bcm43xx_tx(bcm, txb); err = bcm43xx_tx(bcm, txb);
bcm43xx_unlock_irqonly(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
return err; if (unlikely(err))
return NETDEV_TX_BUSY;
return NETDEV_TX_OK;
} }
static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev) static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
...@@ -3769,9 +3943,9 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev) ...@@ -3769,9 +3943,9 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags; unsigned long flags;
bcm43xx_lock_irqonly(bcm, flags); spin_lock_irqsave(&bcm->irq_lock, flags);
bcm43xx_controller_restart(bcm, "TX timeout"); bcm43xx_controller_restart(bcm, "TX timeout");
bcm43xx_unlock_irqonly(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
} }
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
...@@ -3781,7 +3955,8 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev) ...@@ -3781,7 +3955,8 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev)
unsigned long flags; unsigned long flags;
local_irq_save(flags); local_irq_save(flags);
bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
local_irq_restore(flags); local_irq_restore(flags);
} }
#endif /* CONFIG_NET_POLL_CONTROLLER */ #endif /* CONFIG_NET_POLL_CONTROLLER */
...@@ -3799,9 +3974,10 @@ static int bcm43xx_net_stop(struct net_device *net_dev) ...@@ -3799,9 +3974,10 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
int err; int err;
ieee80211softmac_stop(net_dev); ieee80211softmac_stop(net_dev);
err = bcm43xx_disable_interrupts_sync(bcm, NULL); err = bcm43xx_disable_interrupts_sync(bcm);
assert(!err); assert(!err);
bcm43xx_free_board(bcm); bcm43xx_free_board(bcm);
flush_scheduled_work();
return 0; return 0;
} }
...@@ -3818,10 +3994,12 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, ...@@ -3818,10 +3994,12 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
bcm->mac_suspended = 1;
bcm->pci_dev = pci_dev; bcm->pci_dev = pci_dev;
bcm->net_dev = net_dev; bcm->net_dev = net_dev;
bcm->bad_frames_preempt = modparam_bad_frames_preempt; bcm->bad_frames_preempt = modparam_bad_frames_preempt;
spin_lock_init(&bcm->irq_lock); spin_lock_init(&bcm->irq_lock);
spin_lock_init(&bcm->leds_lock);
mutex_init(&bcm->mutex); mutex_init(&bcm->mutex);
tasklet_init(&bcm->isr_tasklet, tasklet_init(&bcm->isr_tasklet,
(void (*)(unsigned long))bcm43xx_interrupt_tasklet, (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
...@@ -3940,7 +4118,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) ...@@ -3940,7 +4118,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
bcm43xx_debugfs_remove_device(bcm); bcm43xx_debugfs_remove_device(bcm);
unregister_netdev(net_dev); unregister_netdev(net_dev);
bcm43xx_detach_board(bcm); bcm43xx_detach_board(bcm);
assert(bcm->ucode == NULL);
free_ieee80211softmac(net_dev); free_ieee80211softmac(net_dev);
} }
...@@ -3950,47 +4127,31 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) ...@@ -3950,47 +4127,31 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
static void bcm43xx_chip_reset(void *_bcm) static void bcm43xx_chip_reset(void *_bcm)
{ {
struct bcm43xx_private *bcm = _bcm; struct bcm43xx_private *bcm = _bcm;
struct net_device *net_dev = bcm->net_dev; struct bcm43xx_phyinfo *phy;
struct pci_dev *pci_dev = bcm->pci_dev; int err = -ENODEV;
int err;
int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
netif_stop_queue(bcm->net_dev);
tasklet_disable(&bcm->isr_tasklet);
bcm->firmware_norelease = 1; mutex_lock(&(bcm)->mutex);
if (was_initialized) if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
bcm43xx_free_board(bcm); bcm43xx_periodic_tasks_delete(bcm);
bcm->firmware_norelease = 0; phy = bcm43xx_current_phy(bcm);
bcm43xx_detach_board(bcm); err = bcm43xx_select_wireless_core(bcm, phy->type);
err = bcm43xx_init_private(bcm, net_dev, pci_dev); if (!err)
if (err) bcm43xx_periodic_tasks_setup(bcm);
goto failure;
err = bcm43xx_attach_board(bcm);
if (err)
goto failure;
if (was_initialized) {
err = bcm43xx_init_board(bcm);
if (err)
goto failure;
} }
netif_wake_queue(bcm->net_dev); mutex_unlock(&(bcm)->mutex);
printk(KERN_INFO PFX "Controller restarted\n");
return; printk(KERN_ERR PFX "Controller restart%s\n",
failure: (err == 0) ? "ed" : " failed");
printk(KERN_ERR PFX "Controller restart failed\n");
} }
/* Hard-reset the chip. /* Hard-reset the chip.
* This can be called from interrupt or process context. * This can be called from interrupt or process context.
* Make sure to _not_ re-enable device interrupts after this has been called. * bcm->irq_lock must be locked.
*/ */
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
{ {
bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); return;
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
schedule_work(&bcm->restart_work); schedule_work(&bcm->restart_work);
...@@ -4002,21 +4163,16 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) ...@@ -4002,21 +4163,16 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
{ {
struct net_device *net_dev = pci_get_drvdata(pdev); struct net_device *net_dev = pci_get_drvdata(pdev);
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags; int err;
int try_to_shutdown = 0, err;
dprintk(KERN_INFO PFX "Suspending...\n"); dprintk(KERN_INFO PFX "Suspending...\n");
bcm43xx_lock_irqsafe(bcm, flags);
bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
if (bcm->was_initialized)
try_to_shutdown = 1;
bcm43xx_unlock_irqsafe(bcm, flags);
netif_device_detach(net_dev); netif_device_detach(net_dev);
if (try_to_shutdown) { bcm->was_initialized = 0;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
bcm->was_initialized = 1;
ieee80211softmac_stop(net_dev); ieee80211softmac_stop(net_dev);
err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); err = bcm43xx_disable_interrupts_sync(bcm);
if (unlikely(err)) { if (unlikely(err)) {
dprintk(KERN_ERR PFX "Suspend failed.\n"); dprintk(KERN_ERR PFX "Suspend failed.\n");
return -EAGAIN; return -EAGAIN;
...@@ -4049,17 +4205,14 @@ static int bcm43xx_resume(struct pci_dev *pdev) ...@@ -4049,17 +4205,14 @@ static int bcm43xx_resume(struct pci_dev *pdev)
pci_restore_state(pdev); pci_restore_state(pdev);
bcm43xx_chipset_attach(bcm); bcm43xx_chipset_attach(bcm);
if (bcm->was_initialized) { if (bcm->was_initialized)
bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
err = bcm43xx_init_board(bcm); err = bcm43xx_init_board(bcm);
}
if (err) { if (err) {
printk(KERN_ERR PFX "Resume failed!\n"); printk(KERN_ERR PFX "Resume failed!\n");
return err; return err;
} }
netif_device_attach(net_dev); netif_device_attach(net_dev);
dprintk(KERN_INFO PFX "Device resumed.\n"); dprintk(KERN_INFO PFX "Device resumed.\n");
return 0; return 0;
......
...@@ -133,11 +133,17 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm); ...@@ -133,11 +133,17 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
int phytype);
void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
void bcm43xx_mac_enable(struct bcm43xx_private *bcm); void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom);
......
...@@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table[] = { ...@@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table[] = {
static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
static inline
void bcm43xx_voluntary_preempt(void)
{
assert(!in_atomic() && !in_irq() &&
!in_interrupt() && !irqs_disabled());
#ifndef CONFIG_PREEMPT
cond_resched();
#endif /* CONFIG_PREEMPT */
}
void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
{ {
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
...@@ -133,22 +143,14 @@ void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) ...@@ -133,22 +143,14 @@ void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
{ {
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
unsigned long flags;
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
if (phy->calibrated) if (phy->calibrated)
return; return;
if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) { if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
/* We do not want to be preempted while calibrating
* the hardware.
*/
local_irq_save(flags);
bcm43xx_wireless_core_reset(bcm, 0); bcm43xx_wireless_core_reset(bcm, 0);
bcm43xx_phy_initg(bcm); bcm43xx_phy_initg(bcm);
bcm43xx_wireless_core_reset(bcm, 1); bcm43xx_wireless_core_reset(bcm, 1);
local_irq_restore(flags);
} }
phy->calibrated = 1; phy->calibrated = 1;
} }
...@@ -359,7 +361,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) ...@@ -359,7 +361,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
if (phy->rev <= 2) if (phy->rev <= 2)
for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]);
else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) else if ((phy->rev >= 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
else else
...@@ -369,7 +371,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) ...@@ -369,7 +371,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
if (phy->rev == 2) if (phy->rev == 2)
for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
else if ((phy->rev > 2) && (phy->rev <= 7)) else if ((phy->rev > 2) && (phy->rev <= 8))
for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]);
...@@ -1195,7 +1197,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) ...@@ -1195,7 +1197,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
if (phy->rev == 1) if (phy->rev == 1)
bcm43xx_phy_initb5(bcm); bcm43xx_phy_initb5(bcm);
else if (phy->rev >= 2 && phy->rev <= 7) else
bcm43xx_phy_initb6(bcm); bcm43xx_phy_initb6(bcm);
if (phy->rev >= 2 || phy->connected) if (phy->rev >= 2 || phy->connected)
bcm43xx_phy_inita(bcm); bcm43xx_phy_inita(bcm);
...@@ -1239,23 +1241,22 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) ...@@ -1239,23 +1241,22 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
bcm43xx_phy_lo_g_measure(bcm); bcm43xx_phy_lo_g_measure(bcm);
} else { } else {
if (radio->version == 0x2050 && radio->revision == 8) { if (radio->version == 0x2050 && radio->revision == 8) {
//FIXME bcm43xx_radio_write16(bcm, 0x0052,
(radio->txctl1 << 4) | radio->txctl2);
} else { } else {
bcm43xx_radio_write16(bcm, 0x0052, bcm43xx_radio_write16(bcm, 0x0052,
(bcm43xx_radio_read16(bcm, 0x0052) (bcm43xx_radio_read16(bcm, 0x0052)
& 0xFFF0) | radio->txctl1); & 0xFFF0) | radio->txctl1);
} }
if (phy->rev >= 6) { if (phy->rev >= 6) {
/*
bcm43xx_phy_write(bcm, 0x0036, bcm43xx_phy_write(bcm, 0x0036,
(bcm43xx_phy_read(bcm, 0x0036) (bcm43xx_phy_read(bcm, 0x0036)
& 0xF000) | (FIXME << 12)); & 0xF000) | (radio->txctl2 << 12));
*/
} }
if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
bcm43xx_phy_write(bcm, 0x002E, 0x8075); bcm43xx_phy_write(bcm, 0x002E, 0x8075);
else else
bcm43xx_phy_write(bcm, 0x003E, 0x807F); bcm43xx_phy_write(bcm, 0x002E, 0x807F);
if (phy->rev < 2) if (phy->rev < 2)
bcm43xx_phy_write(bcm, 0x002F, 0x0101); bcm43xx_phy_write(bcm, 0x002F, 0x0101);
else else
...@@ -1299,7 +1300,9 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) ...@@ -1299,7 +1300,9 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
{ {
int i; int i;
u16 ret = 0; u16 ret = 0;
unsigned long flags;
local_irq_save(flags);
for (i = 0; i < 10; i++){ for (i = 0; i < 10; i++){
bcm43xx_phy_write(bcm, 0x0015, 0xAFA0); bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
udelay(1); udelay(1);
...@@ -1309,6 +1312,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) ...@@ -1309,6 +1312,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
udelay(40); udelay(40);
ret += bcm43xx_phy_read(bcm, 0x002C); ret += bcm43xx_phy_read(bcm, 0x002C);
} }
local_irq_restore(flags);
bcm43xx_voluntary_preempt();
return ret; return ret;
} }
...@@ -1435,6 +1440,7 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) ...@@ -1435,6 +1440,7 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
} }
ret = bcm43xx_phy_read(bcm, 0x002D); ret = bcm43xx_phy_read(bcm, 0x002D);
local_irq_restore(flags); local_irq_restore(flags);
bcm43xx_voluntary_preempt();
return ret; return ret;
} }
...@@ -1760,6 +1766,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) ...@@ -1760,6 +1766,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
bcm43xx_radio_write16(bcm, 0x43, i); bcm43xx_radio_write16(bcm, 0x43, i);
bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
udelay(10); udelay(10);
bcm43xx_voluntary_preempt();
bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
...@@ -1803,6 +1810,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) ...@@ -1803,6 +1810,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
radio->txctl2 radio->txctl2
| (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
udelay(10); udelay(10);
bcm43xx_voluntary_preempt();
bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
...@@ -1824,6 +1832,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) ...@@ -1824,6 +1832,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
udelay(2); udelay(2);
bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
bcm43xx_voluntary_preempt();
} else } else
bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
bcm43xx_phy_lo_adjust(bcm, is_initializing); bcm43xx_phy_lo_adjust(bcm, is_initializing);
...@@ -2188,12 +2197,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm) ...@@ -2188,12 +2197,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm)
{ {
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
int err = -ENODEV; int err = -ENODEV;
unsigned long flags;
/* We do not want to be preempted while calibrating
* the hardware.
*/
local_irq_save(flags);
switch (phy->type) { switch (phy->type) {
case BCM43xx_PHYTYPE_A: case BCM43xx_PHYTYPE_A:
...@@ -2227,7 +2230,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm) ...@@ -2227,7 +2230,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm)
err = 0; err = 0;
break; break;
} }
local_irq_restore(flags);
if (err) if (err)
printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n"); printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
......
...@@ -262,7 +262,7 @@ static void tx_tasklet(unsigned long d) ...@@ -262,7 +262,7 @@ static void tx_tasklet(unsigned long d)
int err; int err;
u16 txctl; u16 txctl;
bcm43xx_lock_irqonly(bcm, flags); spin_lock_irqsave(&bcm->irq_lock, flags);
if (queue->tx_frozen) if (queue->tx_frozen)
goto out_unlock; goto out_unlock;
...@@ -300,7 +300,7 @@ static void tx_tasklet(unsigned long d) ...@@ -300,7 +300,7 @@ static void tx_tasklet(unsigned long d)
continue; continue;
} }
out_unlock: out_unlock:
bcm43xx_unlock_irqonly(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
} }
static void setup_txqueues(struct bcm43xx_pioqueue *queue) static void setup_txqueues(struct bcm43xx_pioqueue *queue)
......
...@@ -120,12 +120,14 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, ...@@ -120,12 +120,14 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
GFP_KERNEL); GFP_KERNEL);
if (!sprom) if (!sprom)
return -ENOMEM; return -ENOMEM;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
err = bcm43xx_sprom_read(bcm, sprom); err = bcm43xx_sprom_read(bcm, sprom);
if (!err) if (!err)
err = sprom2hex(sprom, buf, PAGE_SIZE); err = sprom2hex(sprom, buf, PAGE_SIZE);
mmiowb(); mmiowb();
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
kfree(sprom); kfree(sprom);
return err; return err;
...@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev, ...@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
err = hex2sprom(sprom, buf, count); err = hex2sprom(sprom, buf, count);
if (err) if (err)
goto out_kfree; goto out_kfree;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
spin_lock(&bcm->leds_lock);
err = bcm43xx_sprom_write(bcm, sprom); err = bcm43xx_sprom_write(bcm, sprom);
mmiowb(); mmiowb();
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock(&bcm->leds_lock);
spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
out_kfree: out_kfree:
kfree(sprom); kfree(sprom);
...@@ -170,13 +176,12 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, ...@@ -170,13 +176,12 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
char *buf) char *buf)
{ {
struct bcm43xx_private *bcm = dev_to_bcm(dev); struct bcm43xx_private *bcm = dev_to_bcm(dev);
int err;
ssize_t count = 0; ssize_t count = 0;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
bcm43xx_lock_noirq(bcm); mutex_lock(&bcm->mutex);
switch (bcm43xx_current_radio(bcm)->interfmode) { switch (bcm43xx_current_radio(bcm)->interfmode) {
case BCM43xx_RADIO_INTERFMODE_NONE: case BCM43xx_RADIO_INTERFMODE_NONE:
...@@ -191,11 +196,10 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, ...@@ -191,11 +196,10 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
default: default:
assert(0); assert(0);
} }
err = 0;
bcm43xx_unlock_noirq(bcm); mutex_unlock(&bcm->mutex);
return err ? err : count; return count;
} }
...@@ -229,7 +233,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, ...@@ -229,7 +233,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
return -EINVAL; return -EINVAL;
} }
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
err = bcm43xx_radio_set_interference_mitigation(bcm, mode); err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) { if (err) {
...@@ -237,7 +242,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, ...@@ -237,7 +242,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
"supported by device\n"); "supported by device\n");
} }
mmiowb(); mmiowb();
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
return err ? err : count; return err ? err : count;
} }
...@@ -251,23 +257,21 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, ...@@ -251,23 +257,21 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
char *buf) char *buf)
{ {
struct bcm43xx_private *bcm = dev_to_bcm(dev); struct bcm43xx_private *bcm = dev_to_bcm(dev);
int err;
ssize_t count; ssize_t count;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
bcm43xx_lock_noirq(bcm); mutex_lock(&bcm->mutex);
if (bcm->short_preamble) if (bcm->short_preamble)
count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
else else
count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
err = 0; mutex_unlock(&bcm->mutex);
bcm43xx_unlock_noirq(bcm);
return err ? err : count; return count;
} }
static ssize_t bcm43xx_attr_preamble_store(struct device *dev, static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
...@@ -276,7 +280,6 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, ...@@ -276,7 +280,6 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
{ {
struct bcm43xx_private *bcm = dev_to_bcm(dev); struct bcm43xx_private *bcm = dev_to_bcm(dev);
unsigned long flags; unsigned long flags;
int err;
int value; int value;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
...@@ -285,14 +288,15 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, ...@@ -285,14 +288,15 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
value = get_boolean(buf, count); value = get_boolean(buf, count);
if (value < 0) if (value < 0)
return value; return value;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
bcm->short_preamble = !!value; bcm->short_preamble = !!value;
err = 0; spin_unlock_irqrestore(&bcm->irq_lock, flags);
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
return err ? err : count; return count;
} }
static DEVICE_ATTR(shortpreamble, 0644, static DEVICE_ATTR(shortpreamble, 0644,
......
...@@ -56,12 +56,11 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, ...@@ -56,12 +56,11 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
{ {
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
int i; int i;
unsigned long flags;
struct bcm43xx_phyinfo *phy; struct bcm43xx_phyinfo *phy;
char suffix[7] = { 0 }; char suffix[7] = { 0 };
int have_a = 0, have_b = 0, have_g = 0; int have_a = 0, have_b = 0, have_g = 0;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
for (i = 0; i < bcm->nr_80211_available; i++) { for (i = 0; i < bcm->nr_80211_available; i++) {
phy = &(bcm->core_80211_ext[i].phy); phy = &(bcm->core_80211_ext[i].phy);
switch (phy->type) { switch (phy->type) {
...@@ -77,7 +76,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, ...@@ -77,7 +76,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
assert(0); assert(0);
} }
} }
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
i = 0; i = 0;
if (have_a) { if (have_a) {
...@@ -111,7 +110,9 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, ...@@ -111,7 +110,9 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
int freq; int freq;
int err = -EINVAL; int err = -EINVAL;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
channel = data->freq.m; channel = data->freq.m;
freq = bcm43xx_channel_to_freq(bcm, channel); freq = bcm43xx_channel_to_freq(bcm, channel);
...@@ -131,7 +132,8 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, ...@@ -131,7 +132,8 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
err = 0; err = 0;
} }
out_unlock: out_unlock:
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
return err; return err;
} }
...@@ -143,11 +145,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, ...@@ -143,11 +145,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
{ {
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct bcm43xx_radioinfo *radio; struct bcm43xx_radioinfo *radio;
unsigned long flags;
int err = -ENODEV; int err = -ENODEV;
u16 channel; u16 channel;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
radio = bcm43xx_current_radio(bcm); radio = bcm43xx_current_radio(bcm);
channel = radio->channel; channel = radio->channel;
if (channel == 0xFF) { if (channel == 0xFF) {
...@@ -162,7 +163,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, ...@@ -162,7 +163,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
err = 0; err = 0;
out_unlock: out_unlock:
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
return err; return err;
} }
...@@ -180,13 +181,15 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, ...@@ -180,13 +181,15 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev,
if (mode == IW_MODE_AUTO) if (mode == IW_MODE_AUTO)
mode = BCM43xx_INITIAL_IWMODE; mode = BCM43xx_INITIAL_IWMODE;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
if (bcm->ieee->iw_mode != mode) if (bcm->ieee->iw_mode != mode)
bcm43xx_set_iwmode(bcm, mode); bcm43xx_set_iwmode(bcm, mode);
} else } else
bcm->ieee->iw_mode = mode; bcm->ieee->iw_mode = mode;
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
return 0; return 0;
} }
...@@ -197,11 +200,10 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, ...@@ -197,11 +200,10 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev,
char *extra) char *extra)
{ {
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
data->mode = bcm->ieee->iw_mode; data->mode = bcm->ieee->iw_mode;
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
return 0; return 0;
} }
...@@ -214,7 +216,6 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, ...@@ -214,7 +216,6 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct iw_range *range = (struct iw_range *)extra; struct iw_range *range = (struct iw_range *)extra;
const struct ieee80211_geo *geo; const struct ieee80211_geo *geo;
unsigned long flags;
int i, j; int i, j;
struct bcm43xx_phyinfo *phy; struct bcm43xx_phyinfo *phy;
...@@ -254,7 +255,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, ...@@ -254,7 +255,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_TKIP |
IW_ENC_CAPA_CIPHER_CCMP; IW_ENC_CAPA_CIPHER_CCMP;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
phy = bcm43xx_current_phy(bcm); phy = bcm43xx_current_phy(bcm);
range->num_bitrates = 0; range->num_bitrates = 0;
...@@ -301,7 +302,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, ...@@ -301,7 +302,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
} }
range->num_frequency = j; range->num_frequency = j;
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
return 0; return 0;
} }
...@@ -314,11 +315,11 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev, ...@@ -314,11 +315,11 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
size_t len; size_t len;
bcm43xx_lock_noirq(bcm); mutex_lock(&bcm->mutex);
len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
memcpy(bcm->nick, extra, len); memcpy(bcm->nick, extra, len);
bcm->nick[len] = '\0'; bcm->nick[len] = '\0';
bcm43xx_unlock_noirq(bcm); mutex_unlock(&bcm->mutex);
return 0; return 0;
} }
...@@ -331,12 +332,12 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev, ...@@ -331,12 +332,12 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
size_t len; size_t len;
bcm43xx_lock_noirq(bcm); mutex_lock(&bcm->mutex);
len = strlen(bcm->nick) + 1; len = strlen(bcm->nick) + 1;
memcpy(extra, bcm->nick, len); memcpy(extra, bcm->nick, len);
data->data.length = (__u16)len; data->data.length = (__u16)len;
data->data.flags = 1; data->data.flags = 1;
bcm43xx_unlock_noirq(bcm); mutex_unlock(&bcm->mutex);
return 0; return 0;
} }
...@@ -350,7 +351,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, ...@@ -350,7 +351,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
unsigned long flags; unsigned long flags;
int err = -EINVAL; int err = -EINVAL;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (data->rts.disabled) { if (data->rts.disabled) {
bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
err = 0; err = 0;
...@@ -361,7 +363,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, ...@@ -361,7 +363,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
err = 0; err = 0;
} }
} }
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
return err; return err;
} }
...@@ -372,13 +375,12 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev, ...@@ -372,13 +375,12 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev,
char *extra) char *extra)
{ {
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
data->rts.value = bcm->rts_threshold; data->rts.value = bcm->rts_threshold;
data->rts.fixed = 0; data->rts.fixed = 0;
data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
return 0; return 0;
} }
...@@ -392,7 +394,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, ...@@ -392,7 +394,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
unsigned long flags; unsigned long flags;
int err = -EINVAL; int err = -EINVAL;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (data->frag.disabled) { if (data->frag.disabled) {
bcm->ieee->fts = MAX_FRAG_THRESHOLD; bcm->ieee->fts = MAX_FRAG_THRESHOLD;
err = 0; err = 0;
...@@ -403,7 +406,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, ...@@ -403,7 +406,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
err = 0; err = 0;
} }
} }
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
return err; return err;
} }
...@@ -414,13 +418,12 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev, ...@@ -414,13 +418,12 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev,
char *extra) char *extra)
{ {
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
data->frag.value = bcm->ieee->fts; data->frag.value = bcm->ieee->fts;
data->frag.fixed = 0; data->frag.fixed = 0;
data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
return 0; return 0;
} }
...@@ -442,7 +445,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, ...@@ -442,7 +445,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock; goto out_unlock;
radio = bcm43xx_current_radio(bcm); radio = bcm43xx_current_radio(bcm);
...@@ -466,7 +470,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, ...@@ -466,7 +470,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
err = 0; err = 0;
out_unlock: out_unlock:
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
return err; return err;
} }
...@@ -478,10 +483,9 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, ...@@ -478,10 +483,9 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
{ {
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct bcm43xx_radioinfo *radio; struct bcm43xx_radioinfo *radio;
unsigned long flags;
int err = -ENODEV; int err = -ENODEV;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock; goto out_unlock;
radio = bcm43xx_current_radio(bcm); radio = bcm43xx_current_radio(bcm);
...@@ -493,7 +497,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, ...@@ -493,7 +497,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
err = 0; err = 0;
out_unlock: out_unlock:
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
return err; return err;
} }
...@@ -580,7 +584,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, ...@@ -580,7 +584,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
return -EINVAL; return -EINVAL;
} }
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
err = bcm43xx_radio_set_interference_mitigation(bcm, mode); err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) { if (err) {
...@@ -595,7 +600,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, ...@@ -595,7 +600,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
} else } else
bcm43xx_current_radio(bcm)->interfmode = mode; bcm43xx_current_radio(bcm)->interfmode = mode;
} }
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
return err; return err;
} }
...@@ -606,12 +612,11 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, ...@@ -606,12 +612,11 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
char *extra) char *extra)
{ {
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
int mode; int mode;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
mode = bcm43xx_current_radio(bcm)->interfmode; mode = bcm43xx_current_radio(bcm)->interfmode;
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
switch (mode) { switch (mode) {
case BCM43xx_RADIO_INTERFMODE_NONE: case BCM43xx_RADIO_INTERFMODE_NONE:
...@@ -641,9 +646,11 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, ...@@ -641,9 +646,11 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
int on; int on;
on = *((int *)extra); on = *((int *)extra);
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
bcm->short_preamble = !!on; bcm->short_preamble = !!on;
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
return 0; return 0;
} }
...@@ -654,12 +661,11 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, ...@@ -654,12 +661,11 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
char *extra) char *extra)
{ {
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
int on; int on;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
on = bcm->short_preamble; on = bcm->short_preamble;
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
if (on) if (on)
strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
...@@ -681,11 +687,13 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, ...@@ -681,11 +687,13 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
on = *((int *)extra); on = *((int *)extra);
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
bcm->ieee->host_encrypt = !!on; bcm->ieee->host_encrypt = !!on;
bcm->ieee->host_decrypt = !!on; bcm->ieee->host_decrypt = !!on;
bcm->ieee->host_build_iv = !on; bcm->ieee->host_build_iv = !on;
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
return 0; return 0;
} }
...@@ -696,12 +704,11 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, ...@@ -696,12 +704,11 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
char *extra) char *extra)
{ {
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
int on; int on;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
on = bcm->ieee->host_encrypt; on = bcm->ieee->host_encrypt;
bcm43xx_unlock_irqsafe(bcm, flags); mutex_unlock(&bcm->mutex);
if (on) if (on)
strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
...@@ -764,11 +771,13 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, ...@@ -764,11 +771,13 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
if (!sprom) if (!sprom)
goto out; goto out;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
err = -ENODEV; err = -ENODEV;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_read(bcm, sprom); err = bcm43xx_sprom_read(bcm, sprom);
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
if (!err) if (!err)
data->data.length = sprom2hex(sprom, extra); data->data.length = sprom2hex(sprom, extra);
kfree(sprom); kfree(sprom);
...@@ -809,11 +818,15 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, ...@@ -809,11 +818,15 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
if (err) if (err)
goto out_kfree; goto out_kfree;
bcm43xx_lock_irqsafe(bcm, flags); mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
spin_lock(&bcm->leds_lock);
err = -ENODEV; err = -ENODEV;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_write(bcm, sprom); err = bcm43xx_sprom_write(bcm, sprom);
bcm43xx_unlock_irqsafe(bcm, flags); spin_unlock(&bcm->leds_lock);
spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
out_kfree: out_kfree:
kfree(sprom); kfree(sprom);
out: out:
......
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