aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm43xx
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2006-07-08 16:02:18 -0400
committerJohn W. Linville <linville@tuxdriver.com>2006-07-27 18:19:18 -0400
commit58e5528ee464d38040b9489e10033c9387a10d56 (patch)
tree58023ac8bf79757e37a4d05ce7fa63fb3f2388b9 /drivers/net/wireless/bcm43xx
parent3234faa8abe0c3d6da12cc4a38ce790134c92564 (diff)
[PATCH] bcm43xx: init routine rewrite
Rewrite of the bcm43xx initialization routines. This fixes several issues: * up-down-up-down-up... stale data issue (May fix some DHCP issues) * Fix the init vs IRQ handler race (and remove the workaround) * Fix init for cards with multiple cores (APHY) As softmac has no internal PHY handling (unlike dscape), this adds the file "phymode" to sysfs. The active PHY can be selected by writing either a, b or g to this file. Current PHY can be determined by reading from it. * Fix the controller restart code. Controller restart can now also be triggered through echo 1 > /debug/bcm43xx/ethX/restart Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/bcm43xx')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h50
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c44
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c634
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h3
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c70
6 files changed, 510 insertions, 292 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index bee84b58060c..c6ee1e974c84 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -504,6 +504,12 @@ struct bcm43xx_phyinfo {
504 * This lock is only used by bcm43xx_phy_{un}lock() 504 * This lock is only used by bcm43xx_phy_{un}lock()
505 */ 505 */
506 spinlock_t lock; 506 spinlock_t lock;
507
508 /* Firmware. */
509 const struct firmware *ucode;
510 const struct firmware *pcm;
511 const struct firmware *initvals0;
512 const struct firmware *initvals1;
507}; 513};
508 514
509 515
@@ -593,12 +599,14 @@ struct bcm43xx_coreinfo {
593 u8 available:1, 599 u8 available:1,
594 enabled:1, 600 enabled:1,
595 initialized:1; 601 initialized:1;
596 /** core_id ID number */
597 u16 id;
598 /** core_rev revision number */ 602 /** core_rev revision number */
599 u8 rev; 603 u8 rev;
600 /** Index number for _switch_core() */ 604 /** Index number for _switch_core() */
601 u8 index; 605 u8 index;
606 /** core_id ID number */
607 u16 id;
608 /** Core-specific data. */
609 void *priv;
602}; 610};
603 611
604/* Additional information for each 80211 core. */ 612/* Additional information for each 80211 core. */
@@ -647,7 +655,10 @@ enum {
647 BCM43xx_STAT_RESTARTING, /* controller_restart() called. */ 655 BCM43xx_STAT_RESTARTING, /* controller_restart() called. */
648}; 656};
649#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status) 657#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status)
650#define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat)) 658#define bcm43xx_set_status(bcm, stat) do { \
659 atomic_set(&(bcm)->init_status, (stat)); \
660 smp_wmb(); \
661 } while (0)
651 662
652/* *** THEORY OF LOCKING *** 663/* *** THEORY OF LOCKING ***
653 * 664 *
@@ -721,10 +732,6 @@ struct bcm43xx_private {
721 struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; 732 struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
722 /* Additional information, specific to the 80211 cores. */ 733 /* Additional information, specific to the 80211 cores. */
723 struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; 734 struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
724 /* Index of the current 80211 core. If current_core is not
725 * an 80211 core, this is -1.
726 */
727 int current_80211_core_idx;
728 /* Number of available 80211 cores. */ 735 /* Number of available 80211 cores. */
729 int nr_80211_available; 736 int nr_80211_available;
730 737
@@ -761,12 +768,6 @@ struct bcm43xx_private {
761 struct bcm43xx_key key[54]; 768 struct bcm43xx_key key[54];
762 u8 default_key_idx; 769 u8 default_key_idx;
763 770
764 /* Firmware. */
765 const struct firmware *ucode;
766 const struct firmware *pcm;
767 const struct firmware *initvals0;
768 const struct firmware *initvals1;
769
770 /* Random Number Generator. */ 771 /* Random Number Generator. */
771 struct hwrng rng; 772 struct hwrng rng;
772 char rng_name[20 + 1]; 773 char rng_name[20 + 1];
@@ -829,34 +830,33 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm)
829 * any of these functions. 830 * any of these functions.
830 */ 831 */
831static inline 832static inline
833struct bcm43xx_coreinfo_80211 *
834bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
835{
836 assert(bcm->current_core->id == BCM43xx_COREID_80211);
837 return bcm->current_core->priv;
838}
839static inline
832struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) 840struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
833{ 841{
834 assert(bcm43xx_using_pio(bcm)); 842 assert(bcm43xx_using_pio(bcm));
835 assert(bcm->current_80211_core_idx >= 0); 843 return &(bcm43xx_current_80211_priv(bcm)->pio);
836 assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
837 return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
838} 844}
839static inline 845static inline
840struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) 846struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
841{ 847{
842 assert(!bcm43xx_using_pio(bcm)); 848 assert(!bcm43xx_using_pio(bcm));
843 assert(bcm->current_80211_core_idx >= 0); 849 return &(bcm43xx_current_80211_priv(bcm)->dma);
844 assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
845 return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
846} 850}
847static inline 851static inline
848struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) 852struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
849{ 853{
850 assert(bcm->current_80211_core_idx >= 0); 854 return &(bcm43xx_current_80211_priv(bcm)->phy);
851 assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
852 return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
853} 855}
854static inline 856static inline
855struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) 857struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
856{ 858{
857 assert(bcm->current_80211_core_idx >= 0); 859 return &(bcm43xx_current_80211_priv(bcm)->radio);
858 assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
859 return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
860} 860}
861 861
862 862
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index 2600ee4b803a..634d3d8093cf 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -316,6 +316,40 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
316 return res; 316 return res;
317} 317}
318 318
319static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
320 size_t count, loff_t *ppos)
321{
322 struct bcm43xx_private *bcm = file->private_data;
323 char *buf = really_big_buffer;
324 ssize_t buf_size;
325 ssize_t res;
326 unsigned long flags;
327
328 buf_size = min(count, sizeof (really_big_buffer) - 1);
329 down(&big_buffer_sem);
330 if (copy_from_user(buf, user_buf, buf_size)) {
331 res = -EFAULT;
332 goto out_up;
333 }
334 bcm43xx_lock_irqsafe(bcm, flags);
335 if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
336 printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
337 res = -EFAULT;
338 goto out_unlock;
339 }
340 if (count > 0 && buf[0] == '1') {
341 bcm43xx_controller_restart(bcm, "manually restarted");
342 res = count;
343 } else
344 res = -EINVAL;
345
346out_unlock:
347 bcm43xx_unlock_irqsafe(bcm, flags);
348out_up:
349 up(&big_buffer_sem);
350 return res;
351}
352
319#undef fappend 353#undef fappend
320 354
321 355
@@ -349,6 +383,11 @@ static struct file_operations txstat_fops = {
349 .open = open_file_generic, 383 .open = open_file_generic,
350}; 384};
351 385
386static struct file_operations restart_fops = {
387 .write = restart_write_file,
388 .open = open_file_generic,
389};
390
352 391
353void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) 392void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
354{ 393{
@@ -400,6 +439,10 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
400 bcm, &txstat_fops); 439 bcm, &txstat_fops);
401 if (!e->dentry_txstat) 440 if (!e->dentry_txstat)
402 printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); 441 printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
442 e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
443 bcm, &restart_fops);
444 if (!e->dentry_restart)
445 printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
403} 446}
404 447
405void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) 448void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
@@ -415,6 +458,7 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
415 debugfs_remove(e->dentry_devinfo); 458 debugfs_remove(e->dentry_devinfo);
416 debugfs_remove(e->dentry_tsf); 459 debugfs_remove(e->dentry_tsf);
417 debugfs_remove(e->dentry_txstat); 460 debugfs_remove(e->dentry_txstat);
461 debugfs_remove(e->dentry_restart);
418 debugfs_remove(e->subdir); 462 debugfs_remove(e->subdir);
419 kfree(e->xmitstatus_buffer); 463 kfree(e->xmitstatus_buffer);
420 kfree(e->xmitstatus_print_buffer); 464 kfree(e->xmitstatus_print_buffer);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
index 50ce267f794d..a40d1af35545 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
@@ -20,6 +20,7 @@ struct bcm43xx_dfsentry {
20 struct dentry *dentry_spromdump; 20 struct dentry *dentry_spromdump;
21 struct dentry *dentry_tsf; 21 struct dentry *dentry_tsf;
22 struct dentry *dentry_txstat; 22 struct dentry *dentry_txstat;
23 struct dentry *dentry_restart;
23 24
24 struct bcm43xx_private *bcm; 25 struct bcm43xx_private *bcm;
25 26
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 1c04722edaa0..e5829056cc3f 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -509,23 +509,19 @@ static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
509} 509}
510 510
511/* Make sure we don't receive more data from the device. */ 511/* Make sure we don't receive more data from the device. */
512static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) 512static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
513{ 513{
514 unsigned long flags; 514 unsigned long flags;
515 u32 old;
516 515
517 spin_lock_irqsave(&bcm->irq_lock, flags); 516 spin_lock_irqsave(&bcm->irq_lock, flags);
518 if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { 517 if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
519 spin_unlock_irqrestore(&bcm->irq_lock, flags); 518 spin_unlock_irqrestore(&bcm->irq_lock, flags);
520 return -EBUSY; 519 return -EBUSY;
521 } 520 }
522 old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 521 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
523 spin_unlock_irqrestore(&bcm->irq_lock, flags); 522 spin_unlock_irqrestore(&bcm->irq_lock, flags);
524 bcm43xx_synchronize_irq(bcm); 523 bcm43xx_synchronize_irq(bcm);
525 524
526 if (oldstate)
527 *oldstate = old;
528
529 return 0; 525 return 0;
530} 526}
531 527
@@ -537,7 +533,6 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
537 u16 manufact; 533 u16 manufact;
538 u16 version; 534 u16 version;
539 u8 revision; 535 u8 revision;
540 s8 i;
541 536
542 if (bcm->chip_id == 0x4317) { 537 if (bcm->chip_id == 0x4317) {
543 if (bcm->chip_rev == 0x00) 538 if (bcm->chip_rev == 0x00)
@@ -580,20 +575,11 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
580 radio->version = version; 575 radio->version = version;
581 radio->revision = revision; 576 radio->revision = revision;
582 577
583 /* Set default attenuation values. */
584 radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
585 radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
586 radio->txctl1 = bcm43xx_default_txctl1(bcm);
587 radio->txctl2 = 0xFFFF;
588 if (phy->type == BCM43xx_PHYTYPE_A) 578 if (phy->type == BCM43xx_PHYTYPE_A)
589 radio->txpower_desired = bcm->sprom.maxpower_aphy; 579 radio->txpower_desired = bcm->sprom.maxpower_aphy;
590 else 580 else
591 radio->txpower_desired = bcm->sprom.maxpower_bgphy; 581 radio->txpower_desired = bcm->sprom.maxpower_bgphy;
592 582
593 /* Initialize the in-memory nrssi Lookup Table. */
594 for (i = 0; i < 64; i++)
595 radio->nrssi_lt[i] = i;
596
597 return 0; 583 return 0;
598 584
599err_unsupported_radio: 585err_unsupported_radio:
@@ -1250,10 +1236,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne
1250 goto out; 1236 goto out;
1251 1237
1252 bcm->current_core = new_core; 1238 bcm->current_core = new_core;
1253 bcm->current_80211_core_idx = -1;
1254 if (new_core->id == BCM43xx_COREID_80211)
1255 bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
1256
1257out: 1239out:
1258 return err; 1240 return err;
1259} 1241}
@@ -1423,43 +1405,23 @@ static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
1423 bcm43xx_core_disable(bcm, 0); 1405 bcm43xx_core_disable(bcm, 0);
1424} 1406}
1425 1407
1426/* Mark the current 80211 core inactive. 1408/* Mark the current 80211 core inactive. */
1427 * "active_80211_core" is the other 80211 core, which is used. 1409static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm)
1428 */
1429static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
1430 struct bcm43xx_coreinfo *active_80211_core)
1431{ 1410{
1432 u32 sbtmstatelow; 1411 u32 sbtmstatelow;
1433 struct bcm43xx_coreinfo *old_core;
1434 int err = 0;
1435 1412
1436 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 1413 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
1437 bcm43xx_radio_turn_off(bcm); 1414 bcm43xx_radio_turn_off(bcm);
1438 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 1415 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1439 sbtmstatelow &= ~0x200a0000; 1416 sbtmstatelow &= 0xDFF5FFFF;
1440 sbtmstatelow |= 0xa0000; 1417 sbtmstatelow |= 0x000A0000;
1441 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1418 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1442 udelay(1); 1419 udelay(1);
1443 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); 1420 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1444 sbtmstatelow &= ~0xa0000; 1421 sbtmstatelow &= 0xFFF5FFFF;
1445 sbtmstatelow |= 0x80000; 1422 sbtmstatelow |= 0x00080000;
1446 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); 1423 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1447 udelay(1); 1424 udelay(1);
1448
1449 if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
1450 old_core = bcm->current_core;
1451 err = bcm43xx_switch_core(bcm, active_80211_core);
1452 if (err)
1453 goto out;
1454 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
1455 sbtmstatelow &= ~0x20000000;
1456 sbtmstatelow |= 0x20000000;
1457 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
1458 err = bcm43xx_switch_core(bcm, old_core);
1459 }
1460
1461out:
1462 return err;
1463} 1425}
1464 1426
1465static void handle_irq_transmit_status(struct bcm43xx_private *bcm) 1427static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
@@ -1885,14 +1847,8 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
1885 1847
1886 spin_lock(&bcm->irq_lock); 1848 spin_lock(&bcm->irq_lock);
1887 1849
1888 /* Only accept IRQs, if we are initialized properly. 1850 assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
1889 * This avoids an RX race while initializing. 1851 assert(bcm->current_core->id == BCM43xx_COREID_80211);
1890 * We should probably not enable IRQs before we are initialized
1891 * completely, but some careful work is needed to fix this. I think it
1892 * is best to stay with this cheap workaround for now... .
1893 */
1894 if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
1895 goto out;
1896 1852
1897 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); 1853 reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
1898 if (reason == 0xffffffff) { 1854 if (reason == 0xffffffff) {
@@ -1930,16 +1886,18 @@ out:
1930 1886
1931static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) 1887static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
1932{ 1888{
1889 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
1890
1933 if (bcm->firmware_norelease && !force) 1891 if (bcm->firmware_norelease && !force)
1934 return; /* Suspending or controller reset. */ 1892 return; /* Suspending or controller reset. */
1935 release_firmware(bcm->ucode); 1893 release_firmware(phy->ucode);
1936 bcm->ucode = NULL; 1894 phy->ucode = NULL;
1937 release_firmware(bcm->pcm); 1895 release_firmware(phy->pcm);
1938 bcm->pcm = NULL; 1896 phy->pcm = NULL;
1939 release_firmware(bcm->initvals0); 1897 release_firmware(phy->initvals0);
1940 bcm->initvals0 = NULL; 1898 phy->initvals0 = NULL;
1941 release_firmware(bcm->initvals1); 1899 release_firmware(phy->initvals1);
1942 bcm->initvals1 = NULL; 1900 phy->initvals1 = NULL;
1943} 1901}
1944 1902
1945static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) 1903static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
@@ -1950,11 +1908,11 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
1950 int nr; 1908 int nr;
1951 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; 1909 char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
1952 1910
1953 if (!bcm->ucode) { 1911 if (!phy->ucode) {
1954 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", 1912 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
1955 (rev >= 5 ? 5 : rev), 1913 (rev >= 5 ? 5 : rev),
1956 modparam_fwpostfix); 1914 modparam_fwpostfix);
1957 err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); 1915 err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev);
1958 if (err) { 1916 if (err) {
1959 printk(KERN_ERR PFX 1917 printk(KERN_ERR PFX
1960 "Error: Microcode \"%s\" not available or load failed.\n", 1918 "Error: Microcode \"%s\" not available or load failed.\n",
@@ -1963,12 +1921,12 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
1963 } 1921 }
1964 } 1922 }
1965 1923
1966 if (!bcm->pcm) { 1924 if (!phy->pcm) {
1967 snprintf(buf, ARRAY_SIZE(buf), 1925 snprintf(buf, ARRAY_SIZE(buf),
1968 "bcm43xx_pcm%d%s.fw", 1926 "bcm43xx_pcm%d%s.fw",
1969 (rev < 5 ? 4 : 5), 1927 (rev < 5 ? 4 : 5),
1970 modparam_fwpostfix); 1928 modparam_fwpostfix);
1971 err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); 1929 err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev);
1972 if (err) { 1930 if (err) {
1973 printk(KERN_ERR PFX 1931 printk(KERN_ERR PFX
1974 "Error: PCM \"%s\" not available or load failed.\n", 1932 "Error: PCM \"%s\" not available or load failed.\n",
@@ -1977,7 +1935,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
1977 } 1935 }
1978 } 1936 }
1979 1937
1980 if (!bcm->initvals0) { 1938 if (!phy->initvals0) {
1981 if (rev == 2 || rev == 4) { 1939 if (rev == 2 || rev == 4) {
1982 switch (phy->type) { 1940 switch (phy->type) {
1983 case BCM43xx_PHYTYPE_A: 1941 case BCM43xx_PHYTYPE_A:
@@ -2008,20 +1966,20 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
2008 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", 1966 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2009 nr, modparam_fwpostfix); 1967 nr, modparam_fwpostfix);
2010 1968
2011 err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); 1969 err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev);
2012 if (err) { 1970 if (err) {
2013 printk(KERN_ERR PFX 1971 printk(KERN_ERR PFX
2014 "Error: InitVals \"%s\" not available or load failed.\n", 1972 "Error: InitVals \"%s\" not available or load failed.\n",
2015 buf); 1973 buf);
2016 goto error; 1974 goto error;
2017 } 1975 }
2018 if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { 1976 if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) {
2019 printk(KERN_ERR PFX "InitVals fileformat error.\n"); 1977 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2020 goto error; 1978 goto error;
2021 } 1979 }
2022 } 1980 }
2023 1981
2024 if (!bcm->initvals1) { 1982 if (!phy->initvals1) {
2025 if (rev >= 5) { 1983 if (rev >= 5) {
2026 u32 sbtmstatehigh; 1984 u32 sbtmstatehigh;
2027 1985
@@ -2043,14 +2001,14 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
2043 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", 2001 snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
2044 nr, modparam_fwpostfix); 2002 nr, modparam_fwpostfix);
2045 2003
2046 err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); 2004 err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev);
2047 if (err) { 2005 if (err) {
2048 printk(KERN_ERR PFX 2006 printk(KERN_ERR PFX
2049 "Error: InitVals \"%s\" not available or load failed.\n", 2007 "Error: InitVals \"%s\" not available or load failed.\n",
2050 buf); 2008 buf);
2051 goto error; 2009 goto error;
2052 } 2010 }
2053 if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { 2011 if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) {
2054 printk(KERN_ERR PFX "InitVals fileformat error.\n"); 2012 printk(KERN_ERR PFX "InitVals fileformat error.\n");
2055 goto error; 2013 goto error;
2056 } 2014 }
@@ -2070,12 +2028,13 @@ err_noinitval:
2070 2028
2071static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) 2029static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2072{ 2030{
2031 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2073 const u32 *data; 2032 const u32 *data;
2074 unsigned int i, len; 2033 unsigned int i, len;
2075 2034
2076 /* Upload Microcode. */ 2035 /* Upload Microcode. */
2077 data = (u32 *)(bcm->ucode->data); 2036 data = (u32 *)(phy->ucode->data);
2078 len = bcm->ucode->size / sizeof(u32); 2037 len = phy->ucode->size / sizeof(u32);
2079 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); 2038 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
2080 for (i = 0; i < len; i++) { 2039 for (i = 0; i < len; i++) {
2081 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 2040 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
@@ -2084,8 +2043,8 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
2084 } 2043 }
2085 2044
2086 /* Upload PCM data. */ 2045 /* Upload PCM data. */
2087 data = (u32 *)(bcm->pcm->data); 2046 data = (u32 *)(phy->pcm->data);
2088 len = bcm->pcm->size / sizeof(u32); 2047 len = phy->pcm->size / sizeof(u32);
2089 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); 2048 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
2090 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); 2049 bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
2091 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); 2050 bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
@@ -2131,15 +2090,16 @@ err_format:
2131 2090
2132static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) 2091static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
2133{ 2092{
2093 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2134 int err; 2094 int err;
2135 2095
2136 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, 2096 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data,
2137 bcm->initvals0->size / sizeof(struct bcm43xx_initval)); 2097 phy->initvals0->size / sizeof(struct bcm43xx_initval));
2138 if (err) 2098 if (err)
2139 goto out; 2099 goto out;
2140 if (bcm->initvals1) { 2100 if (phy->initvals1) {
2141 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, 2101 err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data,
2142 bcm->initvals1->size / sizeof(struct bcm43xx_initval)); 2102 phy->initvals1->size / sizeof(struct bcm43xx_initval));
2143 if (err) 2103 if (err)
2144 goto out; 2104 goto out;
2145 } 2105 }
@@ -2156,9 +2116,7 @@ static struct pci_device_id bcm43xx_47xx_ids[] = {
2156 2116
2157static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) 2117static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2158{ 2118{
2159 int res; 2119 int err;
2160 unsigned int i;
2161 u32 data;
2162 2120
2163 bcm->irq = bcm->pci_dev->irq; 2121 bcm->irq = bcm->pci_dev->irq;
2164#ifdef CONFIG_BCM947XX 2122#ifdef CONFIG_BCM947XX
@@ -2175,32 +2133,12 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
2175 } 2133 }
2176 } 2134 }
2177#endif 2135#endif
2178 res = request_irq(bcm->irq, bcm43xx_interrupt_handler, 2136 err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
2179 IRQF_SHARED, KBUILD_MODNAME, bcm); 2137 IRQF_SHARED, KBUILD_MODNAME, bcm);
2180 if (res) { 2138 if (err)
2181 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); 2139 printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
2182 return -ENODEV;
2183 }
2184 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
2185 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2186 i = 0;
2187 while (1) {
2188 data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2189 if (data == BCM43xx_IRQ_READY)
2190 break;
2191 i++;
2192 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2193 printk(KERN_ERR PFX "Card IRQ register not responding. "
2194 "Giving up.\n");
2195 free_irq(bcm->irq, bcm);
2196 return -ENODEV;
2197 }
2198 udelay(10);
2199 }
2200 // dummy read
2201 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2202 2140
2203 return 0; 2141 return err;
2204} 2142}
2205 2143
2206/* Switch to the core used to write the GPIO register. 2144/* Switch to the core used to write the GPIO register.
@@ -2403,7 +2341,6 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
2403 if (!modparam_noleds) 2341 if (!modparam_noleds)
2404 bcm43xx_leds_exit(bcm); 2342 bcm43xx_leds_exit(bcm);
2405 bcm43xx_gpio_cleanup(bcm); 2343 bcm43xx_gpio_cleanup(bcm);
2406 free_irq(bcm->irq, bcm);
2407 bcm43xx_release_firmware(bcm, 0); 2344 bcm43xx_release_firmware(bcm, 0);
2408} 2345}
2409 2346
@@ -2415,7 +2352,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2415 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 2352 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
2416 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 2353 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2417 int err; 2354 int err;
2418 int tmp; 2355 int i, tmp;
2419 u32 value32; 2356 u32 value32;
2420 u16 value16; 2357 u16 value16;
2421 2358
@@ -2428,13 +2365,26 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
2428 goto out; 2365 goto out;
2429 bcm43xx_upload_microcode(bcm); 2366 bcm43xx_upload_microcode(bcm);
2430 2367
2431 err = bcm43xx_initialize_irq(bcm); 2368 bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF);
2432 if (err) 2369 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
2433 goto err_release_fw; 2370 i = 0;
2371 while (1) {
2372 value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
2373 if (value32 == BCM43xx_IRQ_READY)
2374 break;
2375 i++;
2376 if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
2377 printk(KERN_ERR PFX "IRQ_READY timeout\n");
2378 err = -ENODEV;
2379 goto err_release_fw;
2380 }
2381 udelay(10);
2382 }
2383 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
2434 2384
2435 err = bcm43xx_gpio_init(bcm); 2385 err = bcm43xx_gpio_init(bcm);
2436 if (err) 2386 if (err)
2437 goto err_free_irq; 2387 goto err_release_fw;
2438 2388
2439 err = bcm43xx_upload_initvals(bcm); 2389 err = bcm43xx_upload_initvals(bcm);
2440 if (err) 2390 if (err)
@@ -2518,8 +2468,6 @@ err_radio_off:
2518 bcm43xx_radio_turn_off(bcm); 2468 bcm43xx_radio_turn_off(bcm);
2519err_gpio_cleanup: 2469err_gpio_cleanup:
2520 bcm43xx_gpio_cleanup(bcm); 2470 bcm43xx_gpio_cleanup(bcm);
2521err_free_irq:
2522 free_irq(bcm->irq, bcm);
2523err_release_fw: 2471err_release_fw:
2524 bcm43xx_release_firmware(bcm, 1); 2472 bcm43xx_release_firmware(bcm, 1);
2525 goto out; 2473 goto out;
@@ -2559,11 +2507,9 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
2559{ 2507{
2560 /* Initialize a "phyinfo" structure. The structure is already 2508 /* Initialize a "phyinfo" structure. The structure is already
2561 * zeroed out. 2509 * zeroed out.
2510 * This is called on insmod time to initialize members.
2562 */ 2511 */
2563 phy->antenna_diversity = 0xFFFF;
2564 phy->savedpctlreg = 0xFFFF; 2512 phy->savedpctlreg = 0xFFFF;
2565 phy->minlowsig[0] = 0xFFFF;
2566 phy->minlowsig[1] = 0xFFFF;
2567 spin_lock_init(&phy->lock); 2513 spin_lock_init(&phy->lock);
2568} 2514}
2569 2515
@@ -2571,14 +2517,11 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
2571{ 2517{
2572 /* Initialize a "radioinfo" structure. The structure is already 2518 /* Initialize a "radioinfo" structure. The structure is already
2573 * zeroed out. 2519 * zeroed out.
2520 * This is called on insmod time to initialize members.
2574 */ 2521 */
2575 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; 2522 radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
2576 radio->channel = 0xFF; 2523 radio->channel = 0xFF;
2577 radio->initial_channel = 0xFF; 2524 radio->initial_channel = 0xFF;
2578 radio->lofcal = 0xFFFF;
2579 radio->initval = 0xFFFF;
2580 radio->nrssi[0] = -1000;
2581 radio->nrssi[1] = -1000;
2582} 2525}
2583 2526
2584static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) 2527static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
@@ -2596,7 +2539,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2596 * BCM43xx_MAX_80211_CORES); 2539 * BCM43xx_MAX_80211_CORES);
2597 memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) 2540 memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
2598 * BCM43xx_MAX_80211_CORES); 2541 * BCM43xx_MAX_80211_CORES);
2599 bcm->current_80211_core_idx = -1;
2600 bcm->nr_80211_available = 0; 2542 bcm->nr_80211_available = 0;
2601 bcm->current_core = NULL; 2543 bcm->current_core = NULL;
2602 bcm->active_80211_core = NULL; 2544 bcm->active_80211_core = NULL;
@@ -2766,6 +2708,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
2766 goto out; 2708 goto out;
2767 } 2709 }
2768 bcm->nr_80211_available++; 2710 bcm->nr_80211_available++;
2711 core->priv = ext_80211;
2769 bcm43xx_init_struct_phyinfo(&ext_80211->phy); 2712 bcm43xx_init_struct_phyinfo(&ext_80211->phy);
2770 bcm43xx_init_struct_radioinfo(&ext_80211->radio); 2713 bcm43xx_init_struct_radioinfo(&ext_80211->radio);
2771 break; 2714 break;
@@ -2866,7 +2809,8 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
2866} 2809}
2867 2810
2868/* http://bcm-specs.sipsolutions.net/80211Init */ 2811/* http://bcm-specs.sipsolutions.net/80211Init */
2869static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) 2812static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
2813 int active_wlcore)
2870{ 2814{
2871 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 2815 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
2872 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); 2816 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
@@ -2948,19 +2892,26 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
2948 if (bcm->current_core->rev >= 5) 2892 if (bcm->current_core->rev >= 5)
2949 bcm43xx_write16(bcm, 0x043C, 0x000C); 2893 bcm43xx_write16(bcm, 0x043C, 0x000C);
2950 2894
2951 if (bcm43xx_using_pio(bcm)) 2895 if (active_wlcore) {
2952 err = bcm43xx_pio_init(bcm); 2896 if (bcm43xx_using_pio(bcm))
2953 else 2897 err = bcm43xx_pio_init(bcm);
2954 err = bcm43xx_dma_init(bcm); 2898 else
2955 if (err) 2899 err = bcm43xx_dma_init(bcm);
2956 goto err_chip_cleanup; 2900 if (err)
2901 goto err_chip_cleanup;
2902 }
2957 bcm43xx_write16(bcm, 0x0612, 0x0050); 2903 bcm43xx_write16(bcm, 0x0612, 0x0050);
2958 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); 2904 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
2959 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); 2905 bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
2960 2906
2961 bcm43xx_mac_enable(bcm); 2907 if (active_wlcore) {
2962 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); 2908 if (radio->initial_channel != 0xFF)
2909 bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0);
2910 }
2963 2911
2912 /* Don't enable MAC/IRQ here, as it will race with the IRQ handler.
2913 * We enable it later.
2914 */
2964 bcm->current_core->initialized = 1; 2915 bcm->current_core->initialized = 1;
2965out: 2916out:
2966 return err; 2917 return err;
@@ -3075,11 +3026,6 @@ out:
3075 return err; 3026 return err;
3076} 3027}
3077 3028
3078static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
3079{
3080 ieee80211softmac_start(bcm->net_dev);
3081}
3082
3083static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) 3029static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
3084{ 3030{
3085 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); 3031 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -3281,141 +3227,322 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
3281 return err; 3227 return err;
3282} 3228}
3283 3229
3284/* This is the opposite of bcm43xx_init_board() */ 3230static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
3285static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3286{ 3231{
3232 int ret = 0;
3287 int i, err; 3233 int i, err;
3234 struct bcm43xx_coreinfo *core;
3288 3235
3289 mutex_lock(&bcm->mutex); 3236 bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
3237 for (i = 0; i < bcm->nr_80211_available; i++) {
3238 core = &(bcm->core_80211[i]);
3239 assert(core->available);
3240 if (!core->initialized)
3241 continue;
3242 err = bcm43xx_switch_core(bcm, core);
3243 if (err) {
3244 dprintk(KERN_ERR PFX "shutdown_all_wireless_cores "
3245 "switch_core failed (%d)\n", err);
3246 ret = err;
3247 continue;
3248 }
3249 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3250 bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
3251 bcm43xx_wireless_core_cleanup(bcm);
3252 if (core == bcm->active_80211_core)
3253 bcm->active_80211_core = NULL;
3254 }
3255 free_irq(bcm->irq, bcm);
3256 bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
3257
3258 return ret;
3259}
3260
3261/* This is the opposite of bcm43xx_init_board() */
3262static void bcm43xx_free_board(struct bcm43xx_private *bcm)
3263{
3290 bcm43xx_sysfs_unregister(bcm); 3264 bcm43xx_sysfs_unregister(bcm);
3291 bcm43xx_periodic_tasks_delete(bcm); 3265 bcm43xx_periodic_tasks_delete(bcm);
3292 3266
3293 bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); 3267 bcm43xx_lock_noirq(bcm);
3268 bcm43xx_shutdown_all_wireless_cores(bcm);
3269 bcm43xx_pctl_set_crystal(bcm, 0);
3270 bcm43xx_unlock_noirq(bcm);
3271}
3294 3272
3295 bcm43xx_rng_exit(bcm); 3273static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy)
3274{
3275 phy->antenna_diversity = 0xFFFF;
3276 memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
3277 memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
3278
3279 /* Flags */
3280 phy->calibrated = 0;
3281 phy->is_locked = 0;
3282
3283 if (phy->_lo_pairs) {
3284 memset(phy->_lo_pairs, 0,
3285 sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT);
3286 }
3287 memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
3288}
3289
3290static void prepare_radiodata_for_init(struct bcm43xx_private *bcm,
3291 struct bcm43xx_radioinfo *radio)
3292{
3293 int i;
3294
3295 /* Set default attenuation values. */
3296 radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
3297 radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
3298 radio->txctl1 = bcm43xx_default_txctl1(bcm);
3299 radio->txctl2 = 0xFFFF;
3300 radio->txpwr_offset = 0;
3301
3302 /* NRSSI */
3303 radio->nrssislope = 0;
3304 for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++)
3305 radio->nrssi[i] = -1000;
3306 for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++)
3307 radio->nrssi_lt[i] = i;
3308
3309 radio->lofcal = 0xFFFF;
3310 radio->initval = 0xFFFF;
3311
3312 radio->aci_enable = 0;
3313 radio->aci_wlan_automatic = 0;
3314 radio->aci_hw_rssi = 0;
3315}
3316
3317static void prepare_priv_for_init(struct bcm43xx_private *bcm)
3318{
3319 int i;
3320 struct bcm43xx_coreinfo *core;
3321 struct bcm43xx_coreinfo_80211 *wlext;
3322
3323 assert(!bcm->active_80211_core);
3324
3325 bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
3326
3327 /* Flags */
3328 bcm->was_initialized = 0;
3329 bcm->reg124_set_0x4 = 0;
3330
3331 /* Stats */
3332 memset(&bcm->stats, 0, sizeof(bcm->stats));
3333
3334 /* Wireless core data */
3296 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { 3335 for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
3297 if (!bcm->core_80211[i].available) 3336 core = &(bcm->core_80211[i]);
3298 continue; 3337 wlext = core->priv;
3299 if (!bcm->core_80211[i].initialized) 3338
3339 if (!core->available)
3300 continue; 3340 continue;
3341 assert(wlext == &(bcm->core_80211_ext[i]));
3301 3342
3302 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); 3343 prepare_phydata_for_init(&wlext->phy);
3303 assert(err == 0); 3344 prepare_radiodata_for_init(bcm, &wlext->radio);
3304 bcm43xx_wireless_core_cleanup(bcm);
3305 } 3345 }
3306 3346
3307 bcm43xx_pctl_set_crystal(bcm, 0); 3347 /* IRQ related flags */
3348 bcm->irq_reason = 0;
3349 memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason));
3350 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
3308 3351
3309 bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); 3352 /* Noise calculation context */
3310 mutex_unlock(&bcm->mutex); 3353 memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc));
3354
3355 /* Periodic work context */
3356 bcm->periodic_state = 0;
3311} 3357}
3312 3358
3313static int bcm43xx_init_board(struct bcm43xx_private *bcm) 3359static int wireless_core_up(struct bcm43xx_private *bcm,
3360 int active_wlcore)
3361{
3362 int err;
3363
3364 if (!bcm43xx_core_enabled(bcm))
3365 bcm43xx_wireless_core_reset(bcm, 1);
3366 if (!active_wlcore)
3367 bcm43xx_wireless_core_mark_inactive(bcm);
3368 err = bcm43xx_wireless_core_init(bcm, active_wlcore);
3369 if (err)
3370 goto out;
3371 if (!active_wlcore)
3372 bcm43xx_radio_turn_off(bcm);
3373out:
3374 return err;
3375}
3376
3377/* Select and enable the "to be used" wireless core.
3378 * Locking: bcm->mutex must be aquired before calling this.
3379 * bcm->irq_lock must not be aquired.
3380 */
3381int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
3382 int phytype)
3314{ 3383{
3315 int i, err; 3384 int i, err;
3316 int connect_phy; 3385 struct bcm43xx_coreinfo *active_core = NULL;
3386 struct bcm43xx_coreinfo_80211 *active_wlext = NULL;
3387 struct bcm43xx_coreinfo *core;
3388 struct bcm43xx_coreinfo_80211 *wlext;
3389 int adjust_active_sbtmstatelow = 0;
3317 3390
3318 might_sleep(); 3391 might_sleep();
3319 3392
3320 mutex_lock(&bcm->mutex); 3393 if (phytype < 0) {
3321 bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); 3394 /* If no phytype is requested, select the first core. */
3395 assert(bcm->core_80211[0].available);
3396 wlext = bcm->core_80211[0].priv;
3397 phytype = wlext->phy.type;
3398 }
3399 /* Find the requested core. */
3400 for (i = 0; i < bcm->nr_80211_available; i++) {
3401 core = &(bcm->core_80211[i]);
3402 wlext = core->priv;
3403 if (wlext->phy.type == phytype) {
3404 active_core = core;
3405 active_wlext = wlext;
3406 break;
3407 }
3408 }
3409 if (!active_core)
3410 return -ESRCH; /* No such PHYTYPE on this board. */
3411
3412 if (bcm->active_80211_core) {
3413 /* We already selected a wl core in the past.
3414 * So first clean up everything.
3415 */
3416 dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n");
3417 ieee80211softmac_stop(bcm->net_dev);
3418 bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
3419 err = bcm43xx_disable_interrupts_sync(bcm);
3420 assert(!err);
3421 tasklet_enable(&bcm->isr_tasklet);
3422 err = bcm43xx_shutdown_all_wireless_cores(bcm);
3423 if (err)
3424 goto error;
3425 /* Ok, everything down, continue to re-initialize. */
3426 bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
3427 }
3322 3428
3323 bcm->mac_suspended = 1; 3429 /* Reset all data structures. */
3430 prepare_priv_for_init(bcm);
3324 3431
3325 err = bcm43xx_pctl_set_crystal(bcm, 1);
3326 if (err)
3327 goto out;
3328 err = bcm43xx_pctl_init(bcm);
3329 if (err)
3330 goto err_crystal_off;
3331 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); 3432 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
3332 if (err) 3433 if (err)
3333 goto err_crystal_off; 3434 goto error;
3334 3435
3335 tasklet_enable(&bcm->isr_tasklet); 3436 /* Mark all unused cores "inactive". */
3336 for (i = 0; i < bcm->nr_80211_available; i++) { 3437 for (i = 0; i < bcm->nr_80211_available; i++) {
3337 err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); 3438 core = &(bcm->core_80211[i]);
3338 assert(err != -ENODEV); 3439 wlext = core->priv;
3339 if (err)
3340 goto err_80211_unwind;
3341 3440
3342 /* Enable the selected wireless core. 3441 if (core == active_core)
3343 * Connect PHY only on the first core. 3442 continue;
3344 */ 3443 err = bcm43xx_switch_core(bcm, core);
3345 if (!bcm43xx_core_enabled(bcm)) { 3444 if (err) {
3346 if (bcm->nr_80211_available == 1) { 3445 dprintk(KERN_ERR PFX "Could not switch to inactive "
3347 connect_phy = bcm43xx_current_phy(bcm)->connected; 3446 "802.11 core (%d)\n", err);
3348 } else { 3447 goto error;
3349 if (i == 0)
3350 connect_phy = 1;
3351 else
3352 connect_phy = 0;
3353 }
3354 bcm43xx_wireless_core_reset(bcm, connect_phy);
3355 } 3448 }
3449 err = wireless_core_up(bcm, 0);
3450 if (err) {
3451 dprintk(KERN_ERR PFX "core_up for inactive 802.11 core "
3452 "failed (%d)\n", err);
3453 goto error;
3454 }
3455 adjust_active_sbtmstatelow = 1;
3456 }
3356 3457
3357 if (i != 0) 3458 /* Now initialize the active 802.11 core. */
3358 bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); 3459 err = bcm43xx_switch_core(bcm, active_core);
3359 3460 if (err) {
3360 err = bcm43xx_wireless_core_init(bcm); 3461 dprintk(KERN_ERR PFX "Could not switch to active "
3361 if (err) 3462 "802.11 core (%d)\n", err);
3362 goto err_80211_unwind; 3463 goto error;
3464 }
3465 if (adjust_active_sbtmstatelow &&
3466 active_wlext->phy.type == BCM43xx_PHYTYPE_G) {
3467 u32 sbtmstatelow;
3363 3468
3364 if (i != 0) { 3469 sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
3365 bcm43xx_mac_suspend(bcm); 3470 sbtmstatelow |= 0x20000000;
3366 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); 3471 bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
3367 bcm43xx_radio_turn_off(bcm);
3368 }
3369 } 3472 }
3370 bcm->active_80211_core = &bcm->core_80211[0]; 3473 err = wireless_core_up(bcm, 1);
3371 if (bcm->nr_80211_available >= 2) { 3474 if (err) {
3372 bcm43xx_switch_core(bcm, &bcm->core_80211[0]); 3475 dprintk(KERN_ERR PFX "core_up for active 802.11 core "
3373 bcm43xx_mac_enable(bcm); 3476 "failed (%d)\n", err);
3477 goto error;
3374 } 3478 }
3375 err = bcm43xx_rng_init(bcm); 3479 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
3376 if (err) 3480 if (err)
3377 goto err_80211_unwind; 3481 goto error;
3482 bcm->active_80211_core = active_core;
3483
3378 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); 3484 bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
3379 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); 3485 bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
3380 dprintk(KERN_INFO PFX "80211 cores initialized\n");
3381 bcm43xx_security_init(bcm); 3486 bcm43xx_security_init(bcm);
3382 bcm43xx_softmac_init(bcm); 3487 ieee80211softmac_start(bcm->net_dev);
3383 3488
3384 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); 3489 /* Let's go! Be careful after enabling the IRQs.
3490 * Don't switch cores, for example.
3491 */
3492 bcm43xx_mac_enable(bcm);
3493 bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
3494 err = bcm43xx_initialize_irq(bcm);
3495 if (err)
3496 goto error;
3497 bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
3385 3498
3386 if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { 3499 dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
3387 bcm43xx_mac_suspend(bcm); 3500 active_wlext->phy.type);
3388 bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
3389 bcm43xx_mac_enable(bcm);
3390 }
3391 3501
3392 /* Initialization of the board is done. Flag it as such. */ 3502 return 0;
3393 bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); 3503
3504error:
3505 bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
3506 bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
3507 return err;
3508}
3509
3510static int bcm43xx_init_board(struct bcm43xx_private *bcm)
3511{
3512 int err;
3513
3514 bcm43xx_lock_noirq(bcm);
3515
3516 tasklet_enable(&bcm->isr_tasklet);
3517 err = bcm43xx_pctl_set_crystal(bcm, 1);
3518 if (err)
3519 goto err_tasklet;
3520 err = bcm43xx_pctl_init(bcm);
3521 if (err)
3522 goto err_crystal_off;
3523 err = bcm43xx_select_wireless_core(bcm, -1);
3524 if (err)
3525 goto err_crystal_off;
3394 3526
3395 bcm43xx_periodic_tasks_setup(bcm); 3527 bcm43xx_periodic_tasks_setup(bcm);
3396 bcm43xx_sysfs_register(bcm); 3528 err = bcm43xx_sysfs_register(bcm);
3397 //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though... 3529 if (err)
3530 goto err_wlshutdown;
3398 3531
3399 /*FIXME: This should be handled by softmac instead. */ 3532 /*FIXME: This should be handled by softmac instead. */
3400 schedule_work(&bcm->softmac->associnfo.work); 3533 schedule_work(&bcm->softmac->associnfo.work);
3401 3534
3402 assert(err == 0);
3403out: 3535out:
3404 mutex_unlock(&bcm->mutex); 3536 bcm43xx_unlock_noirq(bcm);
3405 3537
3406 return err; 3538 return err;
3407 3539
3408err_80211_unwind: 3540err_wlshutdown:
3409 tasklet_disable(&bcm->isr_tasklet); 3541 bcm43xx_shutdown_all_wireless_cores(bcm);
3410 /* unwind all 80211 initialization */
3411 for (i = 0; i < bcm->nr_80211_available; i++) {
3412 if (!bcm->core_80211[i].initialized)
3413 continue;
3414 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
3415 bcm43xx_wireless_core_cleanup(bcm);
3416 }
3417err_crystal_off: 3542err_crystal_off:
3418 bcm43xx_pctl_set_crystal(bcm, 0); 3543 bcm43xx_pctl_set_crystal(bcm, 0);
3544err_tasklet:
3545 tasklet_disable(&bcm->isr_tasklet);
3419 goto out; 3546 goto out;
3420} 3547}
3421 3548
@@ -3797,7 +3924,8 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev)
3797 unsigned long flags; 3924 unsigned long flags;
3798 3925
3799 local_irq_save(flags); 3926 local_irq_save(flags);
3800 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); 3927 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
3928 bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
3801 local_irq_restore(flags); 3929 local_irq_restore(flags);
3802} 3930}
3803#endif /* CONFIG_NET_POLL_CONTROLLER */ 3931#endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -3815,7 +3943,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
3815 int err; 3943 int err;
3816 3944
3817 ieee80211softmac_stop(net_dev); 3945 ieee80211softmac_stop(net_dev);
3818 err = bcm43xx_disable_interrupts_sync(bcm, NULL); 3946 err = bcm43xx_disable_interrupts_sync(bcm);
3819 assert(!err); 3947 assert(!err);
3820 bcm43xx_free_board(bcm); 3948 bcm43xx_free_board(bcm);
3821 3949
@@ -3957,7 +4085,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
3957 bcm43xx_debugfs_remove_device(bcm); 4085 bcm43xx_debugfs_remove_device(bcm);
3958 unregister_netdev(net_dev); 4086 unregister_netdev(net_dev);
3959 bcm43xx_detach_board(bcm); 4087 bcm43xx_detach_board(bcm);
3960 assert(bcm->ucode == NULL);
3961 free_ieee80211softmac(net_dev); 4088 free_ieee80211softmac(net_dev);
3962} 4089}
3963 4090
@@ -3967,47 +4094,25 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
3967static void bcm43xx_chip_reset(void *_bcm) 4094static void bcm43xx_chip_reset(void *_bcm)
3968{ 4095{
3969 struct bcm43xx_private *bcm = _bcm; 4096 struct bcm43xx_private *bcm = _bcm;
3970 struct net_device *net_dev = bcm->net_dev; 4097 struct bcm43xx_phyinfo *phy;
3971 struct pci_dev *pci_dev = bcm->pci_dev;
3972 int err; 4098 int err;
3973 int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
3974 4099
3975 netif_stop_queue(bcm->net_dev); 4100 bcm43xx_lock_noirq(bcm);
3976 tasklet_disable(&bcm->isr_tasklet); 4101 phy = bcm43xx_current_phy(bcm);
4102 err = bcm43xx_select_wireless_core(bcm, phy->type);
4103 bcm43xx_unlock_noirq(bcm);
3977 4104
3978 bcm->firmware_norelease = 1; 4105 printk(KERN_ERR PFX "Controller restart%s\n",
3979 if (was_initialized) 4106 (err == 0) ? "ed" : " failed");
3980 bcm43xx_free_board(bcm);
3981 bcm->firmware_norelease = 0;
3982 bcm43xx_detach_board(bcm);
3983 err = bcm43xx_init_private(bcm, net_dev, pci_dev);
3984 if (err)
3985 goto failure;
3986 err = bcm43xx_attach_board(bcm);
3987 if (err)
3988 goto failure;
3989 if (was_initialized) {
3990 err = bcm43xx_init_board(bcm);
3991 if (err)
3992 goto failure;
3993 }
3994 netif_wake_queue(bcm->net_dev);
3995 printk(KERN_INFO PFX "Controller restarted\n");
3996
3997 return;
3998failure:
3999 printk(KERN_ERR PFX "Controller restart failed\n");
4000} 4107}
4001 4108
4002/* Hard-reset the chip. 4109/* Hard-reset the chip.
4003 * This can be called from interrupt or process context. 4110 * This can be called from interrupt or process context.
4004 * Make sure to _not_ re-enable device interrupts after this has been called. 4111 */
4005*/
4006void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) 4112void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
4007{ 4113{
4114 assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
4008 bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); 4115 bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
4009 bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
4010 bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
4011 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); 4116 printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
4012 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); 4117 INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
4013 schedule_work(&bcm->restart_work); 4118 schedule_work(&bcm->restart_work);
@@ -4019,18 +4124,16 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
4019{ 4124{
4020 struct net_device *net_dev = pci_get_drvdata(pdev); 4125 struct net_device *net_dev = pci_get_drvdata(pdev);
4021 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); 4126 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
4022 int try_to_shutdown = 0, err; 4127 int err;
4023 4128
4024 dprintk(KERN_INFO PFX "Suspending...\n"); 4129 dprintk(KERN_INFO PFX "Suspending...\n");
4025 4130
4026 bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
4027 if (bcm->was_initialized)
4028 try_to_shutdown = 1;
4029
4030 netif_device_detach(net_dev); 4131 netif_device_detach(net_dev);
4031 if (try_to_shutdown) { 4132 bcm->was_initialized = 0;
4133 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
4134 bcm->was_initialized = 1;
4032 ieee80211softmac_stop(net_dev); 4135 ieee80211softmac_stop(net_dev);
4033 err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); 4136 err = bcm43xx_disable_interrupts_sync(bcm);
4034 if (unlikely(err)) { 4137 if (unlikely(err)) {
4035 dprintk(KERN_ERR PFX "Suspend failed.\n"); 4138 dprintk(KERN_ERR PFX "Suspend failed.\n");
4036 return -EAGAIN; 4139 return -EAGAIN;
@@ -4063,17 +4166,14 @@ static int bcm43xx_resume(struct pci_dev *pdev)
4063 pci_restore_state(pdev); 4166 pci_restore_state(pdev);
4064 4167
4065 bcm43xx_chipset_attach(bcm); 4168 bcm43xx_chipset_attach(bcm);
4066 if (bcm->was_initialized) { 4169 if (bcm->was_initialized)
4067 bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
4068 err = bcm43xx_init_board(bcm); 4170 err = bcm43xx_init_board(bcm);
4069 }
4070 if (err) { 4171 if (err) {
4071 printk(KERN_ERR PFX "Resume failed!\n"); 4172 printk(KERN_ERR PFX "Resume failed!\n");
4072 return err; 4173 return err;
4073 } 4174 }
4074
4075 netif_device_attach(net_dev); 4175 netif_device_attach(net_dev);
4076 4176
4077 dprintk(KERN_INFO PFX "Device resumed.\n"); 4177 dprintk(KERN_INFO PFX "Device resumed.\n");
4078 4178
4079 return 0; 4179 return 0;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 116493671f88..505c86e2007a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -133,6 +133,9 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
133 133
134int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); 134int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
135 135
136int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
137 int phytype);
138
136void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); 139void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
137 140
138void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); 141void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index cc1ff3c6f140..ac394013cd98 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -309,6 +309,70 @@ static DEVICE_ATTR(shortpreamble, 0644,
309 bcm43xx_attr_preamble_show, 309 bcm43xx_attr_preamble_show,
310 bcm43xx_attr_preamble_store); 310 bcm43xx_attr_preamble_store);
311 311
312static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
313 struct device_attribute *attr,
314 const char *buf, size_t count)
315{
316 struct bcm43xx_private *bcm = dev_to_bcm(dev);
317 int phytype;
318 int err = -EINVAL;
319
320 if (count < 1)
321 goto out;
322 switch (buf[0]) {
323 case 'a': case 'A':
324 phytype = BCM43xx_PHYTYPE_A;
325 break;
326 case 'b': case 'B':
327 phytype = BCM43xx_PHYTYPE_B;
328 break;
329 case 'g': case 'G':
330 phytype = BCM43xx_PHYTYPE_G;
331 break;
332 default:
333 goto out;
334 }
335
336 bcm43xx_lock_noirq(bcm);
337 err = bcm43xx_select_wireless_core(bcm, phytype);
338 bcm43xx_unlock_noirq(bcm);
339 if (err == -ESRCH)
340 err = -ENODEV;
341
342out:
343 return err ? err : count;
344}
345
346static ssize_t bcm43xx_attr_phymode_show(struct device *dev,
347 struct device_attribute *attr,
348 char *buf)
349{
350 struct bcm43xx_private *bcm = dev_to_bcm(dev);
351 ssize_t count = 0;
352
353 bcm43xx_lock_noirq(bcm);
354 switch (bcm43xx_current_phy(bcm)->type) {
355 case BCM43xx_PHYTYPE_A:
356 snprintf(buf, PAGE_SIZE, "A");
357 break;
358 case BCM43xx_PHYTYPE_B:
359 snprintf(buf, PAGE_SIZE, "B");
360 break;
361 case BCM43xx_PHYTYPE_G:
362 snprintf(buf, PAGE_SIZE, "G");
363 break;
364 default:
365 assert(0);
366 }
367 bcm43xx_unlock_noirq(bcm);
368
369 return count;
370}
371
372static DEVICE_ATTR(phymode, 0644,
373 bcm43xx_attr_phymode_show,
374 bcm43xx_attr_phymode_store);
375
312int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) 376int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
313{ 377{
314 struct device *dev = &bcm->pci_dev->dev; 378 struct device *dev = &bcm->pci_dev->dev;
@@ -325,9 +389,14 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
325 err = device_create_file(dev, &dev_attr_shortpreamble); 389 err = device_create_file(dev, &dev_attr_shortpreamble);
326 if (err) 390 if (err)
327 goto err_remove_interfmode; 391 goto err_remove_interfmode;
392 err = device_create_file(dev, &dev_attr_phymode);
393 if (err)
394 goto err_remove_shortpreamble;
328 395
329out: 396out:
330 return err; 397 return err;
398err_remove_shortpreamble:
399 device_remove_file(dev, &dev_attr_shortpreamble);
331err_remove_interfmode: 400err_remove_interfmode:
332 device_remove_file(dev, &dev_attr_interference); 401 device_remove_file(dev, &dev_attr_interference);
333err_remove_sprom: 402err_remove_sprom:
@@ -339,6 +408,7 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
339{ 408{
340 struct device *dev = &bcm->pci_dev->dev; 409 struct device *dev = &bcm->pci_dev->dev;
341 410
411 device_remove_file(dev, &dev_attr_phymode);
342 device_remove_file(dev, &dev_attr_shortpreamble); 412 device_remove_file(dev, &dev_attr_shortpreamble);
343 device_remove_file(dev, &dev_attr_interference); 413 device_remove_file(dev, &dev_attr_interference);
344 device_remove_file(dev, &dev_attr_sprom); 414 device_remove_file(dev, &dev_attr_sprom);