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); |
