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.h7
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c78
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h3
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c74
4 files changed, 125 insertions, 37 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 62fd7e23778..6d4ea36bc56 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -306,6 +306,13 @@
#define BCM43xx_SBF_TIME_UPDATE 0x10000000
#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?)*/
#define BCM43xx_UCODEFLAGS_OFFSET 0x005E
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 966815be695..cb9a3ae8463 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -519,6 +519,7 @@ static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
return -EBUSY;
}
bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); /* flush */
spin_unlock_irqrestore(&bcm->irq_lock, flags);
bcm43xx_synchronize_irq(bcm);
@@ -1545,17 +1546,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm)
else
average -= 48;
-/* FIXME: This is wrong, but people want fancy stats. well... */
-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);
+ bcm->stats.noise = average;
drop_calculation:
bcm->noisecalc.calculation_running = 0;
return;
@@ -2393,6 +2384,33 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
}
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;
+ }
+
err = bcm43xx_gpio_init(bcm);
if (err)
goto err_release_fw;
@@ -3150,6 +3168,7 @@ static void bcm43xx_periodic_work_handler(void *d)
/* Periodic work will take a long time, so we want it to
* be preemtible.
*/
+ mutex_lock(&bcm->mutex);
netif_stop_queue(bcm->net_dev);
synchronize_net();
spin_lock_irqsave(&bcm->irq_lock, flags);
@@ -3158,7 +3177,6 @@ static void bcm43xx_periodic_work_handler(void *d)
bcm43xx_pio_freeze_txqueues(bcm);
savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
spin_unlock_irqrestore(&bcm->irq_lock, flags);
- mutex_lock(&bcm->mutex);
bcm43xx_synchronize_irq(bcm);
} else {
/* Periodic work should take short time, so we want low
@@ -3172,13 +3190,11 @@ static void bcm43xx_periodic_work_handler(void *d)
if (badness > BADNESS_LIMIT) {
spin_lock_irqsave(&bcm->irq_lock, flags);
- if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
- tasklet_enable(&bcm->isr_tasklet);
- bcm43xx_interrupt_enable(bcm, savedirqs);
- if (bcm43xx_using_pio(bcm))
- bcm43xx_pio_thaw_txqueues(bcm);
- bcm43xx_mac_enable(bcm);
- }
+ tasklet_enable(&bcm->isr_tasklet);
+ bcm43xx_interrupt_enable(bcm, savedirqs);
+ if (bcm43xx_using_pio(bcm))
+ bcm43xx_pio_thaw_txqueues(bcm);
+ bcm43xx_mac_enable(bcm);
netif_wake_queue(bcm->net_dev);
}
mmiowb();
@@ -3186,12 +3202,12 @@ static void bcm43xx_periodic_work_handler(void *d)
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);
}
-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);
@@ -3539,14 +3555,13 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)
err = bcm43xx_select_wireless_core(bcm, -1);
if (err)
goto err_crystal_off;
-
- bcm43xx_periodic_tasks_setup(bcm);
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);
/*FIXME: This should be handled by softmac instead. */
schedule_work(&bcm->softmac->associnfo.work);
@@ -3969,6 +3984,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
err = bcm43xx_disable_interrupts_sync(bcm);
assert(!err);
bcm43xx_free_board(bcm);
+ flush_scheduled_work();
return 0;
}
@@ -4119,11 +4135,16 @@ static void bcm43xx_chip_reset(void *_bcm)
{
struct bcm43xx_private *bcm = _bcm;
struct bcm43xx_phyinfo *phy;
- int err;
+ int err = -ENODEV;
mutex_lock(&(bcm)->mutex);
- phy = bcm43xx_current_phy(bcm);
- err = bcm43xx_select_wireless_core(bcm, phy->type);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+ bcm43xx_periodic_tasks_delete(bcm);
+ phy = bcm43xx_current_phy(bcm);
+ err = bcm43xx_select_wireless_core(bcm, phy->type);
+ if (!err)
+ bcm43xx_periodic_tasks_setup(bcm);
+ }
mutex_unlock(&(bcm)->mutex);
printk(KERN_ERR PFX "Controller restart%s\n",
@@ -4132,11 +4153,12 @@ static void bcm43xx_chip_reset(void *_bcm)
/* Hard-reset the chip.
* This can be called from interrupt or process context.
+ * bcm->irq_lock must be locked.
*/
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
{
- assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
- bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
+ return;
printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
schedule_work(&bcm->restart_work);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 505c86e2007..f76357178e4 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -141,6 +141,9 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
void bcm43xx_mac_suspend(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);
int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index ece335178f6..c71b998a369 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -176,7 +176,6 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
char *buf)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
- int err;
ssize_t count = 0;
if (!capable(CAP_NET_ADMIN))
@@ -197,11 +196,10 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
default:
assert(0);
}
- err = 0;
mutex_unlock(&bcm->mutex);
- return err ? err : count;
+ return count;
}
@@ -259,7 +257,6 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
char *buf)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
- int err;
ssize_t count;
if (!capable(CAP_NET_ADMIN))
@@ -272,10 +269,9 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
else
count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
- err = 0;
mutex_unlock(&bcm->mutex);
- return err ? err : count;
+ return count;
}
static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
@@ -284,7 +280,6 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
unsigned long flags;
- int err;
int value;
if (!capable(CAP_NET_ADMIN))
@@ -298,11 +293,10 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
bcm->short_preamble = !!value;
- err = 0;
spin_unlock_irqrestore(&bcm->irq_lock, flags);
mutex_unlock(&bcm->mutex);
- return err ? err : count;
+ return count;
}
static DEVICE_ATTR(shortpreamble, 0644,
@@ -333,8 +327,11 @@ static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
goto out;
}
+ bcm43xx_periodic_tasks_delete(bcm);
mutex_lock(&(bcm)->mutex);
err = bcm43xx_select_wireless_core(bcm, phytype);
+ if (!err)
+ bcm43xx_periodic_tasks_setup(bcm);
mutex_unlock(&(bcm)->mutex);
if (err == -ESRCH)
err = -ENODEV;
@@ -373,6 +370,59 @@ static DEVICE_ATTR(phymode, 0644,
bcm43xx_attr_phymode_show,
bcm43xx_attr_phymode_store);
+static ssize_t bcm43xx_attr_microcode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ struct bcm43xx_private *bcm = dev_to_bcm(dev);
+ ssize_t count = 0;
+ u16 status;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&(bcm)->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+ status = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_STATUS);
+
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&(bcm)->mutex);
+ switch (status) {
+ case 0x0000:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (invalid)\n",
+ status);
+ break;
+ case 0x0001:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (init)\n",
+ status);
+ break;
+ case 0x0002:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (active)\n",
+ status);
+ break;
+ case 0x0003:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (suspended)\n",
+ status);
+ break;
+ case 0x0004:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (asleep)\n",
+ status);
+ break;
+ default:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (unknown)\n",
+ status);
+ break;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(microcodestatus, 0444,
+ bcm43xx_attr_microcode_show,
+ NULL);
+
int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
{
struct device *dev = &bcm->pci_dev->dev;
@@ -392,9 +442,14 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
err = device_create_file(dev, &dev_attr_phymode);
if (err)
goto err_remove_shortpreamble;
+ err = device_create_file(dev, &dev_attr_microcodestatus);
+ if (err)
+ goto err_remove_phymode;
out:
return err;
+err_remove_phymode:
+ device_remove_file(dev, &dev_attr_phymode);
err_remove_shortpreamble:
device_remove_file(dev, &dev_attr_shortpreamble);
err_remove_interfmode:
@@ -408,6 +463,7 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
{
struct device *dev = &bcm->pci_dev->dev;
+ device_remove_file(dev, &dev_attr_microcodestatus);
device_remove_file(dev, &dev_attr_phymode);
device_remove_file(dev, &dev_attr_shortpreamble);
device_remove_file(dev, &dev_attr_interference);