diff options
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx.h | 50 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 44 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.c | 634 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 70 |
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 | */ |
831 | static inline | 832 | static inline |
833 | struct bcm43xx_coreinfo_80211 * | ||
834 | bcm43xx_current_80211_priv(struct bcm43xx_private *bcm) | ||
835 | { | ||
836 | assert(bcm->current_core->id == BCM43xx_COREID_80211); | ||
837 | return bcm->current_core->priv; | ||
838 | } | ||
839 | static inline | ||
832 | struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) | 840 | struct 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 | } |
839 | static inline | 845 | static inline |
840 | struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) | 846 | struct 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 | } |
847 | static inline | 851 | static inline |
848 | struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) | 852 | struct 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 | } |
854 | static inline | 856 | static inline |
855 | struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) | 857 | struct 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 | ||
319 | static 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 | |||
346 | out_unlock: | ||
347 | bcm43xx_unlock_irqsafe(bcm, flags); | ||
348 | out_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 | ||
386 | static struct file_operations restart_fops = { | ||
387 | .write = restart_write_file, | ||
388 | .open = open_file_generic, | ||
389 | }; | ||
390 | |||
352 | 391 | ||
353 | void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) | 392 | void 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 | ||
405 | void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) | 448 | void 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. */ |
512 | static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) | 512 | static 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 | ||
599 | err_unsupported_radio: | 585 | err_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 | |||
1257 | out: | 1239 | out: |
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. | 1409 | static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm) |
1428 | */ | ||
1429 | static 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 | |||
1461 | out: | ||
1462 | return err; | ||
1463 | } | 1425 | } |
1464 | 1426 | ||
1465 | static void handle_irq_transmit_status(struct bcm43xx_private *bcm) | 1427 | static 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 | ||
1931 | static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) | 1887 | static 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 | ||
1945 | static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | 1903 | static 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 | ||
2071 | static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) | 2029 | static 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 | ||
2132 | static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) | 2091 | static 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 | ||
2157 | static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) | 2117 | static 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); |
2519 | err_gpio_cleanup: | 2469 | err_gpio_cleanup: |
2520 | bcm43xx_gpio_cleanup(bcm); | 2470 | bcm43xx_gpio_cleanup(bcm); |
2521 | err_free_irq: | ||
2522 | free_irq(bcm->irq, bcm); | ||
2523 | err_release_fw: | 2471 | err_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 | ||
2584 | static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | 2527 | static 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 */ |
2869 | static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) | 2812 | static 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; |
2965 | out: | 2916 | out: |
2966 | return err; | 2917 | return err; |
@@ -3075,11 +3026,6 @@ out: | |||
3075 | return err; | 3026 | return err; |
3076 | } | 3027 | } |
3077 | 3028 | ||
3078 | static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) | ||
3079 | { | ||
3080 | ieee80211softmac_start(bcm->net_dev); | ||
3081 | } | ||
3082 | |||
3083 | static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) | 3029 | static 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() */ | 3230 | static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm) |
3285 | static 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() */ | ||
3262 | static 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); | 3273 | static 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 | |||
3290 | static 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 | |||
3317 | static 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 | ||
3313 | static int bcm43xx_init_board(struct bcm43xx_private *bcm) | 3359 | static 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); | ||
3373 | out: | ||
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 | */ | ||
3381 | int 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 | |
3504 | error: | ||
3505 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | ||
3506 | bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); | ||
3507 | return err; | ||
3508 | } | ||
3509 | |||
3510 | static 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); | ||
3403 | out: | 3535 | out: |
3404 | mutex_unlock(&bcm->mutex); | 3536 | bcm43xx_unlock_noirq(bcm); |
3405 | 3537 | ||
3406 | return err; | 3538 | return err; |
3407 | 3539 | ||
3408 | err_80211_unwind: | 3540 | err_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 | } | ||
3417 | err_crystal_off: | 3542 | err_crystal_off: |
3418 | bcm43xx_pctl_set_crystal(bcm, 0); | 3543 | bcm43xx_pctl_set_crystal(bcm, 0); |
3544 | err_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) | |||
3967 | static void bcm43xx_chip_reset(void *_bcm) | 4094 | static 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; | ||
3998 | failure: | ||
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 | */ | ||
4006 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) | 4112 | void 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 | ||
134 | int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); | 134 | int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); |
135 | 135 | ||
136 | int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, | ||
137 | int phytype); | ||
138 | |||
136 | void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); | 139 | void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); |
137 | 140 | ||
138 | void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); | 141 | void 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 | ||
312 | static 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 | |||
342 | out: | ||
343 | return err ? err : count; | ||
344 | } | ||
345 | |||
346 | static 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 | |||
372 | static DEVICE_ATTR(phymode, 0644, | ||
373 | bcm43xx_attr_phymode_show, | ||
374 | bcm43xx_attr_phymode_store); | ||
375 | |||
312 | int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) | 376 | int 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 | ||
329 | out: | 396 | out: |
330 | return err; | 397 | return err; |
398 | err_remove_shortpreamble: | ||
399 | device_remove_file(dev, &dev_attr_shortpreamble); | ||
331 | err_remove_interfmode: | 400 | err_remove_interfmode: |
332 | device_remove_file(dev, &dev_attr_interference); | 401 | device_remove_file(dev, &dev_attr_interference); |
333 | err_remove_sprom: | 402 | err_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); |