aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/bcm43xx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcm43xx')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.c28
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.h18
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c9
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.h6
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c72
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c2
6 files changed, 102 insertions, 33 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index 76e3aed4b47..978ed099e28 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -705,11 +705,30 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
struct bcm43xx_dmaring *ring;
int err = -ENOMEM;
int dma64 = 0;
- u32 sbtmstatehi;
+ u64 mask = bcm43xx_get_supported_dma_mask(bcm);
+ int nobits;
- sbtmstatehi = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
- if (sbtmstatehi & BCM43xx_SBTMSTATEHIGH_DMA64BIT)
+ if (mask == DMA_64BIT_MASK) {
dma64 = 1;
+ nobits = 64;
+ } else if (mask == DMA_32BIT_MASK)
+ nobits = 32;
+ else
+ nobits = 30;
+ err = pci_set_dma_mask(bcm->pci_dev, mask);
+ err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask);
+ if (err) {
+#ifdef CONFIG_BCM43XX_PIO
+ printk(KERN_WARNING PFX "DMA not supported on this device."
+ " Falling back to PIO.\n");
+ bcm->__using_pio = 1;
+ return -ENOSYS;
+#else
+ printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+ "Please recompile the driver with PIO support.\n");
+ return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
+ }
/* setup TX DMA channels. */
ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
@@ -755,8 +774,7 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
dma->rx_ring3 = ring;
}
- dprintk(KERN_INFO PFX "%s DMA initialized\n",
- dma64 ? "64-bit" : "32-bit");
+ dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
err = 0;
out:
return err;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
index e04bcaddd1d..d1105e569a4 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
@@ -4,6 +4,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/dma-mapping.h>
#include <linux/linkage.h>
#include <asm/atomic.h>
@@ -314,6 +315,23 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
struct ieee80211_txb *txb);
void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
+/* Helper function that returns the dma mask for this device. */
+static inline
+u64 bcm43xx_get_supported_dma_mask(struct bcm43xx_private *bcm)
+{
+ int dma64 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH) &
+ BCM43xx_SBTMSTATEHIGH_DMA64BIT;
+ u16 mmio_base = bcm43xx_dmacontroller_base(dma64, 0);
+ u32 mask = BCM43xx_DMA32_TXADDREXT_MASK;
+
+ if (dma64)
+ return DMA_64BIT_MASK;
+ bcm43xx_write32(bcm, mmio_base + BCM43xx_DMA32_TXCTL, mask);
+ if (bcm43xx_read32(bcm, mmio_base + BCM43xx_DMA32_TXCTL) & mask)
+ return DMA_32BIT_MASK;
+ return DMA_30BIT_MASK;
+}
+
#else /* CONFIG_BCM43XX_DMA */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index c3f90c8563d..7d383a27b92 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -189,20 +189,24 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
case BCM43xx_LED_INACTIVE:
continue;
case BCM43xx_LED_OFF:
+ case BCM43xx_LED_BCM4303_3:
break;
case BCM43xx_LED_ON:
turn_on = 1;
break;
case BCM43xx_LED_ACTIVITY:
+ case BCM43xx_LED_BCM4303_0:
turn_on = activity;
break;
case BCM43xx_LED_RADIO_ALL:
turn_on = radio->enabled;
break;
case BCM43xx_LED_RADIO_A:
+ case BCM43xx_LED_BCM4303_2:
turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
break;
case BCM43xx_LED_RADIO_B:
+ case BCM43xx_LED_BCM4303_1:
turn_on = (radio->enabled &&
(phy->type == BCM43xx_PHYTYPE_B ||
phy->type == BCM43xx_PHYTYPE_G));
@@ -242,7 +246,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
//TODO
break;
case BCM43xx_LED_ASSOC:
- if (bcm->softmac->associated)
+ if (bcm->softmac->associnfo.associated)
turn_on = 1;
break;
#ifdef CONFIG_BCM43XX_DEBUG
@@ -257,7 +261,8 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
continue;
#endif /* CONFIG_BCM43XX_DEBUG */
default:
- assert(0);
+ dprintkl(KERN_INFO PFX "Bad value in leds_update,"
+ " led->behaviour: 0x%x\n", led->behaviour);
};
if (led->activelow)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
index d3716cf3aeb..811e14a8119 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h
@@ -46,6 +46,12 @@ enum { /* LED behaviour values */
BCM43xx_LED_TEST_BLINKSLOW,
BCM43xx_LED_TEST_BLINKMEDIUM,
BCM43xx_LED_TEST_BLINKFAST,
+
+ /* Misc values for BCM4303 */
+ BCM43xx_LED_BCM4303_0 = 0x2B,
+ BCM43xx_LED_BCM4303_1 = 0x78,
+ BCM43xx_LED_BCM4303_2 = 0x2E,
+ BCM43xx_LED_BCM4303_3 = 0x19,
};
int bcm43xx_leds_init(struct bcm43xx_private *bcm);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index bad3452ea89..a1b783813d8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -746,7 +746,7 @@ int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
if (err)
goto err_ctlreg;
spromctl |= 0x10; /* SPROM WRITE enable. */
- bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
+ err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
if (err)
goto err_ctlreg;
/* We must burn lots of CPU cycles here, but that does not
@@ -768,7 +768,7 @@ int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
mdelay(20);
}
spromctl &= ~0x10; /* SPROM WRITE enable. */
- bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
+ err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
if (err)
goto err_ctlreg;
mdelay(500);
@@ -1463,6 +1463,23 @@ static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
}
}
+static void drain_txstatus_queue(struct bcm43xx_private *bcm)
+{
+ u32 dummy;
+
+ if (bcm->current_core->rev < 5)
+ return;
+ /* Read all entries from the microcode TXstatus FIFO
+ * and throw them away.
+ */
+ while (1) {
+ dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);
+ if (!dummy)
+ break;
+ dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);
+ }
+}
+
static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm)
{
bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);
@@ -2925,10 +2942,13 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
bcm43xx_write16(bcm, 0x043C, 0x000C);
if (active_wlcore) {
- if (bcm43xx_using_pio(bcm))
+ if (bcm43xx_using_pio(bcm)) {
err = bcm43xx_pio_init(bcm);
- else
+ } else {
err = bcm43xx_dma_init(bcm);
+ if (err == -ENOSYS)
+ err = bcm43xx_pio_init(bcm);
+ }
if (err)
goto err_chip_cleanup;
}
@@ -3160,17 +3180,30 @@ static int estimate_periodic_work_badness(unsigned int state)
static void bcm43xx_periodic_work_handler(void *d)
{
struct bcm43xx_private *bcm = d;
+ struct net_device *net_dev = bcm->net_dev;
unsigned long flags;
u32 savedirqs = 0;
int badness;
+ unsigned long orig_trans_start = 0;
+ mutex_lock(&bcm->mutex);
badness = estimate_periodic_work_badness(bcm->periodic_state);
if (badness > BADNESS_LIMIT) {
/* Periodic work will take a long time, so we want it to
* be preemtible.
*/
- mutex_lock(&bcm->mutex);
- netif_tx_disable(bcm->net_dev);
+
+ netif_tx_lock_bh(net_dev);
+ /* We must fake a started transmission here, as we are going to
+ * disable TX. If we wouldn't fake a TX, it would be possible to
+ * trigger the netdev watchdog, if the last real TX is already
+ * some time on the past (slightly less than 5secs)
+ */
+ orig_trans_start = net_dev->trans_start;
+ net_dev->trans_start = jiffies;
+ netif_stop_queue(net_dev);
+ netif_tx_unlock_bh(net_dev);
+
spin_lock_irqsave(&bcm->irq_lock, flags);
bcm43xx_mac_suspend(bcm);
if (bcm43xx_using_pio(bcm))
@@ -3182,7 +3215,6 @@ static void bcm43xx_periodic_work_handler(void *d)
/* Periodic work should take short time, so we want low
* locking overhead.
*/
- mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
}
@@ -3196,6 +3228,7 @@ static void bcm43xx_periodic_work_handler(void *d)
bcm43xx_pio_thaw_txqueues(bcm);
bcm43xx_mac_enable(bcm);
netif_wake_queue(bcm->net_dev);
+ net_dev->trans_start = orig_trans_start;
}
mmiowb();
spin_unlock_irqrestore(&bcm->irq_lock, flags);
@@ -3516,6 +3549,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
bcm43xx_security_init(bcm);
+ drain_txstatus_queue(bcm);
ieee80211softmac_start(bcm->net_dev);
/* Let's go! Be careful after enabling the IRQs.
@@ -3993,8 +4027,6 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
struct net_device *net_dev,
struct pci_dev *pci_dev)
{
- int err;
-
bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
bcm->ieee = netdev_priv(net_dev);
bcm->softmac = ieee80211_priv(net_dev);
@@ -4012,22 +4044,8 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
(void (*)(unsigned long))bcm43xx_interrupt_tasklet,
(unsigned long)bcm);
tasklet_disable_nosync(&bcm->isr_tasklet);
- if (modparam_pio) {
+ if (modparam_pio)
bcm->__using_pio = 1;
- } else {
- err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK);
- err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK);
- if (err) {
-#ifdef CONFIG_BCM43XX_PIO
- printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n");
- bcm->__using_pio = 1;
-#else
- printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
- "Recompile the driver with PIO support, please.\n");
- return -ENODEV;
-#endif /* CONFIG_BCM43XX_PIO */
- }
- }
bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD;
/* default to sw encryption for now */
@@ -4208,7 +4226,11 @@ static int bcm43xx_resume(struct pci_dev *pdev)
dprintk(KERN_INFO PFX "Resuming...\n");
pci_set_power_state(pdev, 0);
- pci_enable_device(pdev);
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR PFX "Failure with pci_enable_device!\n");
+ return err;
+ }
pci_restore_state(pdev);
bcm43xx_chipset_attach(bcm);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index 9b7b15cf656..d27016f8c73 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -847,7 +847,7 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d
unsigned long flags;
wstats = &bcm->stats.wstats;
- if (!mac->associated) {
+ if (!mac->associnfo.associated) {
wstats->miss.beacon = 0;
// bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
wstats->discard.retries = 0;