diff options
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx.h | 52 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 46 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.c | 687 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 70 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 28 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 5 |
8 files changed, 565 insertions, 327 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index ee6571ed706d..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 | ||
@@ -737,6 +744,8 @@ struct bcm43xx_private { | |||
737 | u32 irq_savedstate; | 744 | u32 irq_savedstate; |
738 | /* Link Quality calculation context. */ | 745 | /* Link Quality calculation context. */ |
739 | struct bcm43xx_noise_calculation noisecalc; | 746 | struct bcm43xx_noise_calculation noisecalc; |
747 | /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ | ||
748 | int mac_suspended; | ||
740 | 749 | ||
741 | /* Threshold values. */ | 750 | /* Threshold values. */ |
742 | //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. | 751 | //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. |
@@ -759,12 +768,6 @@ struct bcm43xx_private { | |||
759 | struct bcm43xx_key key[54]; | 768 | struct bcm43xx_key key[54]; |
760 | u8 default_key_idx; | 769 | u8 default_key_idx; |
761 | 770 | ||
762 | /* Firmware. */ | ||
763 | const struct firmware *ucode; | ||
764 | const struct firmware *pcm; | ||
765 | const struct firmware *initvals0; | ||
766 | const struct firmware *initvals1; | ||
767 | |||
768 | /* Random Number Generator. */ | 771 | /* Random Number Generator. */ |
769 | struct hwrng rng; | 772 | struct hwrng rng; |
770 | char rng_name[20 + 1]; | 773 | char rng_name[20 + 1]; |
@@ -827,34 +830,33 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm) | |||
827 | * any of these functions. | 830 | * any of these functions. |
828 | */ | 831 | */ |
829 | 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 | ||
830 | struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) | 840 | struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) |
831 | { | 841 | { |
832 | assert(bcm43xx_using_pio(bcm)); | 842 | assert(bcm43xx_using_pio(bcm)); |
833 | assert(bcm->current_80211_core_idx >= 0); | 843 | return &(bcm43xx_current_80211_priv(bcm)->pio); |
834 | assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); | ||
835 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio); | ||
836 | } | 844 | } |
837 | static inline | 845 | static inline |
838 | struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) | 846 | struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) |
839 | { | 847 | { |
840 | assert(!bcm43xx_using_pio(bcm)); | 848 | assert(!bcm43xx_using_pio(bcm)); |
841 | assert(bcm->current_80211_core_idx >= 0); | 849 | return &(bcm43xx_current_80211_priv(bcm)->dma); |
842 | assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); | ||
843 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma); | ||
844 | } | 850 | } |
845 | static inline | 851 | static inline |
846 | struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) | 852 | struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) |
847 | { | 853 | { |
848 | assert(bcm->current_80211_core_idx >= 0); | 854 | return &(bcm43xx_current_80211_priv(bcm)->phy); |
849 | assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); | ||
850 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy); | ||
851 | } | 855 | } |
852 | static inline | 856 | static inline |
853 | struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) | 857 | struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) |
854 | { | 858 | { |
855 | assert(bcm->current_80211_core_idx >= 0); | 859 | return &(bcm43xx_current_80211_priv(bcm)->radio); |
856 | assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); | ||
857 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); | ||
858 | } | 860 | } |
859 | 861 | ||
860 | 862 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index 2600ee4b803a..923275ea0789 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | |||
@@ -316,6 +316,42 @@ 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 | mutex_lock(&(bcm)->mutex); | ||
335 | spin_lock_irqsave(&(bcm)->irq_lock, flags); | ||
336 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { | ||
337 | printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); | ||
338 | res = -EFAULT; | ||
339 | goto out_unlock; | ||
340 | } | ||
341 | if (count > 0 && buf[0] == '1') { | ||
342 | bcm43xx_controller_restart(bcm, "manually restarted"); | ||
343 | res = count; | ||
344 | } else | ||
345 | res = -EINVAL; | ||
346 | |||
347 | out_unlock: | ||
348 | spin_unlock_irqrestore(&(bcm)->irq_lock, flags); | ||
349 | mutex_unlock(&(bcm)->mutex); | ||
350 | out_up: | ||
351 | up(&big_buffer_sem); | ||
352 | return res; | ||
353 | } | ||
354 | |||
319 | #undef fappend | 355 | #undef fappend |
320 | 356 | ||
321 | 357 | ||
@@ -349,6 +385,11 @@ static struct file_operations txstat_fops = { | |||
349 | .open = open_file_generic, | 385 | .open = open_file_generic, |
350 | }; | 386 | }; |
351 | 387 | ||
388 | static struct file_operations restart_fops = { | ||
389 | .write = restart_write_file, | ||
390 | .open = open_file_generic, | ||
391 | }; | ||
392 | |||
352 | 393 | ||
353 | void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) | 394 | void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) |
354 | { | 395 | { |
@@ -400,6 +441,10 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) | |||
400 | bcm, &txstat_fops); | 441 | bcm, &txstat_fops); |
401 | if (!e->dentry_txstat) | 442 | if (!e->dentry_txstat) |
402 | printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); | 443 | printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); |
444 | e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir, | ||
445 | bcm, &restart_fops); | ||
446 | if (!e->dentry_restart) | ||
447 | printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir); | ||
403 | } | 448 | } |
404 | 449 | ||
405 | void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) | 450 | void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) |
@@ -415,6 +460,7 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) | |||
415 | debugfs_remove(e->dentry_devinfo); | 460 | debugfs_remove(e->dentry_devinfo); |
416 | debugfs_remove(e->dentry_tsf); | 461 | debugfs_remove(e->dentry_tsf); |
417 | debugfs_remove(e->dentry_txstat); | 462 | debugfs_remove(e->dentry_txstat); |
463 | debugfs_remove(e->dentry_restart); | ||
418 | debugfs_remove(e->subdir); | 464 | debugfs_remove(e->subdir); |
419 | kfree(e->xmitstatus_buffer); | 465 | kfree(e->xmitstatus_buffer); |
420 | kfree(e->xmitstatus_print_buffer); | 466 | 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 ab3a0ee9fac8..b095f3cc6730 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. |
@@ -2298,13 +2236,17 @@ static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm) | |||
2298 | /* http://bcm-specs.sipsolutions.net/EnableMac */ | 2236 | /* http://bcm-specs.sipsolutions.net/EnableMac */ |
2299 | void bcm43xx_mac_enable(struct bcm43xx_private *bcm) | 2237 | void bcm43xx_mac_enable(struct bcm43xx_private *bcm) |
2300 | { | 2238 | { |
2301 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, | 2239 | bcm->mac_suspended--; |
2302 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) | 2240 | assert(bcm->mac_suspended >= 0); |
2303 | | BCM43xx_SBF_MAC_ENABLED); | 2241 | if (bcm->mac_suspended == 0) { |
2304 | bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); | 2242 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, |
2305 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ | 2243 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) |
2306 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | 2244 | | BCM43xx_SBF_MAC_ENABLED); |
2307 | bcm43xx_power_saving_ctl_bits(bcm, -1, -1); | 2245 | bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); |
2246 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ | ||
2247 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | ||
2248 | bcm43xx_power_saving_ctl_bits(bcm, -1, -1); | ||
2249 | } | ||
2308 | } | 2250 | } |
2309 | 2251 | ||
2310 | /* http://bcm-specs.sipsolutions.net/SuspendMAC */ | 2252 | /* http://bcm-specs.sipsolutions.net/SuspendMAC */ |
@@ -2313,18 +2255,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) | |||
2313 | int i; | 2255 | int i; |
2314 | u32 tmp; | 2256 | u32 tmp; |
2315 | 2257 | ||
2316 | bcm43xx_power_saving_ctl_bits(bcm, -1, 1); | 2258 | assert(bcm->mac_suspended >= 0); |
2317 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, | 2259 | if (bcm->mac_suspended == 0) { |
2318 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) | 2260 | bcm43xx_power_saving_ctl_bits(bcm, -1, 1); |
2319 | & ~BCM43xx_SBF_MAC_ENABLED); | 2261 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, |
2320 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | 2262 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) |
2321 | for (i = 100000; i; i--) { | 2263 | & ~BCM43xx_SBF_MAC_ENABLED); |
2322 | tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | 2264 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ |
2323 | if (tmp & BCM43xx_IRQ_READY) | 2265 | for (i = 10000; i; i--) { |
2324 | return; | 2266 | tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); |
2325 | udelay(10); | 2267 | if (tmp & BCM43xx_IRQ_READY) |
2268 | goto out; | ||
2269 | udelay(1); | ||
2270 | } | ||
2271 | printkl(KERN_ERR PFX "MAC suspend failed\n"); | ||
2326 | } | 2272 | } |
2327 | printkl(KERN_ERR PFX "MAC suspend failed\n"); | 2273 | out: |
2274 | bcm->mac_suspended++; | ||
2328 | } | 2275 | } |
2329 | 2276 | ||
2330 | void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, | 2277 | void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, |
@@ -2394,7 +2341,6 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) | |||
2394 | if (!modparam_noleds) | 2341 | if (!modparam_noleds) |
2395 | bcm43xx_leds_exit(bcm); | 2342 | bcm43xx_leds_exit(bcm); |
2396 | bcm43xx_gpio_cleanup(bcm); | 2343 | bcm43xx_gpio_cleanup(bcm); |
2397 | free_irq(bcm->irq, bcm); | ||
2398 | bcm43xx_release_firmware(bcm, 0); | 2344 | bcm43xx_release_firmware(bcm, 0); |
2399 | } | 2345 | } |
2400 | 2346 | ||
@@ -2406,7 +2352,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) | |||
2406 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | 2352 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); |
2407 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 2353 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
2408 | int err; | 2354 | int err; |
2409 | int tmp; | 2355 | int i, tmp; |
2410 | u32 value32; | 2356 | u32 value32; |
2411 | u16 value16; | 2357 | u16 value16; |
2412 | 2358 | ||
@@ -2419,13 +2365,26 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) | |||
2419 | goto out; | 2365 | goto out; |
2420 | bcm43xx_upload_microcode(bcm); | 2366 | bcm43xx_upload_microcode(bcm); |
2421 | 2367 | ||
2422 | err = bcm43xx_initialize_irq(bcm); | 2368 | bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF); |
2423 | if (err) | 2369 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); |
2424 | 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 */ | ||
2425 | 2384 | ||
2426 | err = bcm43xx_gpio_init(bcm); | 2385 | err = bcm43xx_gpio_init(bcm); |
2427 | if (err) | 2386 | if (err) |
2428 | goto err_free_irq; | 2387 | goto err_release_fw; |
2429 | 2388 | ||
2430 | err = bcm43xx_upload_initvals(bcm); | 2389 | err = bcm43xx_upload_initvals(bcm); |
2431 | if (err) | 2390 | if (err) |
@@ -2509,8 +2468,6 @@ err_radio_off: | |||
2509 | bcm43xx_radio_turn_off(bcm); | 2468 | bcm43xx_radio_turn_off(bcm); |
2510 | err_gpio_cleanup: | 2469 | err_gpio_cleanup: |
2511 | bcm43xx_gpio_cleanup(bcm); | 2470 | bcm43xx_gpio_cleanup(bcm); |
2512 | err_free_irq: | ||
2513 | free_irq(bcm->irq, bcm); | ||
2514 | err_release_fw: | 2471 | err_release_fw: |
2515 | bcm43xx_release_firmware(bcm, 1); | 2472 | bcm43xx_release_firmware(bcm, 1); |
2516 | goto out; | 2473 | goto out; |
@@ -2550,11 +2507,9 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) | |||
2550 | { | 2507 | { |
2551 | /* Initialize a "phyinfo" structure. The structure is already | 2508 | /* Initialize a "phyinfo" structure. The structure is already |
2552 | * zeroed out. | 2509 | * zeroed out. |
2510 | * This is called on insmod time to initialize members. | ||
2553 | */ | 2511 | */ |
2554 | phy->antenna_diversity = 0xFFFF; | ||
2555 | phy->savedpctlreg = 0xFFFF; | 2512 | phy->savedpctlreg = 0xFFFF; |
2556 | phy->minlowsig[0] = 0xFFFF; | ||
2557 | phy->minlowsig[1] = 0xFFFF; | ||
2558 | spin_lock_init(&phy->lock); | 2513 | spin_lock_init(&phy->lock); |
2559 | } | 2514 | } |
2560 | 2515 | ||
@@ -2562,14 +2517,11 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) | |||
2562 | { | 2517 | { |
2563 | /* Initialize a "radioinfo" structure. The structure is already | 2518 | /* Initialize a "radioinfo" structure. The structure is already |
2564 | * zeroed out. | 2519 | * zeroed out. |
2520 | * This is called on insmod time to initialize members. | ||
2565 | */ | 2521 | */ |
2566 | radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; | 2522 | radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; |
2567 | radio->channel = 0xFF; | 2523 | radio->channel = 0xFF; |
2568 | radio->initial_channel = 0xFF; | 2524 | radio->initial_channel = 0xFF; |
2569 | radio->lofcal = 0xFFFF; | ||
2570 | radio->initval = 0xFFFF; | ||
2571 | radio->nrssi[0] = -1000; | ||
2572 | radio->nrssi[1] = -1000; | ||
2573 | } | 2525 | } |
2574 | 2526 | ||
2575 | static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | 2527 | static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) |
@@ -2587,7 +2539,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | |||
2587 | * BCM43xx_MAX_80211_CORES); | 2539 | * BCM43xx_MAX_80211_CORES); |
2588 | memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) | 2540 | memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) |
2589 | * BCM43xx_MAX_80211_CORES); | 2541 | * BCM43xx_MAX_80211_CORES); |
2590 | bcm->current_80211_core_idx = -1; | ||
2591 | bcm->nr_80211_available = 0; | 2542 | bcm->nr_80211_available = 0; |
2592 | bcm->current_core = NULL; | 2543 | bcm->current_core = NULL; |
2593 | bcm->active_80211_core = NULL; | 2544 | bcm->active_80211_core = NULL; |
@@ -2757,6 +2708,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | |||
2757 | goto out; | 2708 | goto out; |
2758 | } | 2709 | } |
2759 | bcm->nr_80211_available++; | 2710 | bcm->nr_80211_available++; |
2711 | core->priv = ext_80211; | ||
2760 | bcm43xx_init_struct_phyinfo(&ext_80211->phy); | 2712 | bcm43xx_init_struct_phyinfo(&ext_80211->phy); |
2761 | bcm43xx_init_struct_radioinfo(&ext_80211->radio); | 2713 | bcm43xx_init_struct_radioinfo(&ext_80211->radio); |
2762 | break; | 2714 | break; |
@@ -2857,7 +2809,8 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) | |||
2857 | } | 2809 | } |
2858 | 2810 | ||
2859 | /* http://bcm-specs.sipsolutions.net/80211Init */ | 2811 | /* http://bcm-specs.sipsolutions.net/80211Init */ |
2860 | 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) | ||
2861 | { | 2814 | { |
2862 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 2815 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
2863 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | 2816 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); |
@@ -2939,19 +2892,26 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) | |||
2939 | if (bcm->current_core->rev >= 5) | 2892 | if (bcm->current_core->rev >= 5) |
2940 | bcm43xx_write16(bcm, 0x043C, 0x000C); | 2893 | bcm43xx_write16(bcm, 0x043C, 0x000C); |
2941 | 2894 | ||
2942 | if (bcm43xx_using_pio(bcm)) | 2895 | if (active_wlcore) { |
2943 | err = bcm43xx_pio_init(bcm); | 2896 | if (bcm43xx_using_pio(bcm)) |
2944 | else | 2897 | err = bcm43xx_pio_init(bcm); |
2945 | err = bcm43xx_dma_init(bcm); | 2898 | else |
2946 | if (err) | 2899 | err = bcm43xx_dma_init(bcm); |
2947 | goto err_chip_cleanup; | 2900 | if (err) |
2901 | goto err_chip_cleanup; | ||
2902 | } | ||
2948 | bcm43xx_write16(bcm, 0x0612, 0x0050); | 2903 | bcm43xx_write16(bcm, 0x0612, 0x0050); |
2949 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); | 2904 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); |
2950 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); | 2905 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); |
2951 | 2906 | ||
2952 | bcm43xx_mac_enable(bcm); | 2907 | if (active_wlcore) { |
2953 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); | 2908 | if (radio->initial_channel != 0xFF) |
2909 | bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0); | ||
2910 | } | ||
2954 | 2911 | ||
2912 | /* Don't enable MAC/IRQ here, as it will race with the IRQ handler. | ||
2913 | * We enable it later. | ||
2914 | */ | ||
2955 | bcm->current_core->initialized = 1; | 2915 | bcm->current_core->initialized = 1; |
2956 | out: | 2916 | out: |
2957 | return err; | 2917 | return err; |
@@ -3066,11 +3026,6 @@ out: | |||
3066 | return err; | 3026 | return err; |
3067 | } | 3027 | } |
3068 | 3028 | ||
3069 | static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) | ||
3070 | { | ||
3071 | ieee80211softmac_start(bcm->net_dev); | ||
3072 | } | ||
3073 | |||
3074 | static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) | 3029 | static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) |
3075 | { | 3030 | { |
3076 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 3031 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
@@ -3183,7 +3138,9 @@ static void bcm43xx_periodic_work_handler(void *d) | |||
3183 | * be preemtible. | 3138 | * be preemtible. |
3184 | */ | 3139 | */ |
3185 | netif_stop_queue(bcm->net_dev); | 3140 | netif_stop_queue(bcm->net_dev); |
3141 | synchronize_net(); | ||
3186 | spin_lock_irqsave(&bcm->irq_lock, flags); | 3142 | spin_lock_irqsave(&bcm->irq_lock, flags); |
3143 | bcm43xx_mac_suspend(bcm); | ||
3187 | if (bcm43xx_using_pio(bcm)) | 3144 | if (bcm43xx_using_pio(bcm)) |
3188 | bcm43xx_pio_freeze_txqueues(bcm); | 3145 | bcm43xx_pio_freeze_txqueues(bcm); |
3189 | savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 3146 | savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
@@ -3207,6 +3164,7 @@ static void bcm43xx_periodic_work_handler(void *d) | |||
3207 | bcm43xx_interrupt_enable(bcm, savedirqs); | 3164 | bcm43xx_interrupt_enable(bcm, savedirqs); |
3208 | if (bcm43xx_using_pio(bcm)) | 3165 | if (bcm43xx_using_pio(bcm)) |
3209 | bcm43xx_pio_thaw_txqueues(bcm); | 3166 | bcm43xx_pio_thaw_txqueues(bcm); |
3167 | bcm43xx_mac_enable(bcm); | ||
3210 | } | 3168 | } |
3211 | netif_wake_queue(bcm->net_dev); | 3169 | netif_wake_queue(bcm->net_dev); |
3212 | } | 3170 | } |
@@ -3241,9 +3199,9 @@ static int bcm43xx_rng_read(struct hwrng *rng, u32 *data) | |||
3241 | struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv; | 3199 | struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv; |
3242 | unsigned long flags; | 3200 | unsigned long flags; |
3243 | 3201 | ||
3244 | bcm43xx_lock_irqonly(bcm, flags); | 3202 | spin_lock_irqsave(&(bcm)->irq_lock, flags); |
3245 | *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG); | 3203 | *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG); |
3246 | bcm43xx_unlock_irqonly(bcm, flags); | 3204 | spin_unlock_irqrestore(&(bcm)->irq_lock, flags); |
3247 | 3205 | ||
3248 | return (sizeof(u16)); | 3206 | return (sizeof(u16)); |
3249 | } | 3207 | } |
@@ -3269,139 +3227,322 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm) | |||
3269 | return err; | 3227 | return err; |
3270 | } | 3228 | } |
3271 | 3229 | ||
3272 | /* This is the opposite of bcm43xx_init_board() */ | 3230 | static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm) |
3273 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) | ||
3274 | { | 3231 | { |
3232 | int ret = 0; | ||
3275 | int i, err; | 3233 | int i, err; |
3234 | struct bcm43xx_coreinfo *core; | ||
3276 | 3235 | ||
3277 | 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 | { | ||
3278 | bcm43xx_sysfs_unregister(bcm); | 3264 | bcm43xx_sysfs_unregister(bcm); |
3279 | bcm43xx_periodic_tasks_delete(bcm); | 3265 | bcm43xx_periodic_tasks_delete(bcm); |
3280 | 3266 | ||
3281 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); | 3267 | mutex_lock(&(bcm)->mutex); |
3268 | bcm43xx_shutdown_all_wireless_cores(bcm); | ||
3269 | bcm43xx_pctl_set_crystal(bcm, 0); | ||
3270 | mutex_unlock(&(bcm)->mutex); | ||
3271 | } | ||
3272 | |||
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); | ||
3282 | 3326 | ||
3283 | bcm43xx_rng_exit(bcm); | 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 */ | ||
3284 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { | 3335 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { |
3285 | if (!bcm->core_80211[i].available) | 3336 | core = &(bcm->core_80211[i]); |
3286 | continue; | 3337 | wlext = core->priv; |
3287 | if (!bcm->core_80211[i].initialized) | 3338 | |
3339 | if (!core->available) | ||
3288 | continue; | 3340 | continue; |
3341 | assert(wlext == &(bcm->core_80211_ext[i])); | ||
3289 | 3342 | ||
3290 | err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); | 3343 | prepare_phydata_for_init(&wlext->phy); |
3291 | assert(err == 0); | 3344 | prepare_radiodata_for_init(bcm, &wlext->radio); |
3292 | bcm43xx_wireless_core_cleanup(bcm); | ||
3293 | } | 3345 | } |
3294 | 3346 | ||
3295 | 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; | ||
3296 | 3351 | ||
3297 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | 3352 | /* Noise calculation context */ |
3298 | mutex_unlock(&bcm->mutex); | 3353 | memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc)); |
3354 | |||
3355 | /* Periodic work context */ | ||
3356 | bcm->periodic_state = 0; | ||
3299 | } | 3357 | } |
3300 | 3358 | ||
3301 | 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) | ||
3302 | { | 3383 | { |
3303 | int i, err; | 3384 | int i, err; |
3304 | 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; | ||
3305 | 3390 | ||
3306 | might_sleep(); | 3391 | might_sleep(); |
3307 | 3392 | ||
3308 | mutex_lock(&bcm->mutex); | 3393 | if (phytype < 0) { |
3309 | 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 | } | ||
3428 | |||
3429 | /* Reset all data structures. */ | ||
3430 | prepare_priv_for_init(bcm); | ||
3310 | 3431 | ||
3311 | err = bcm43xx_pctl_set_crystal(bcm, 1); | ||
3312 | if (err) | ||
3313 | goto out; | ||
3314 | err = bcm43xx_pctl_init(bcm); | ||
3315 | if (err) | ||
3316 | goto err_crystal_off; | ||
3317 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); | 3432 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); |
3318 | if (err) | 3433 | if (err) |
3319 | goto err_crystal_off; | 3434 | goto error; |
3320 | 3435 | ||
3321 | tasklet_enable(&bcm->isr_tasklet); | 3436 | /* Mark all unused cores "inactive". */ |
3322 | for (i = 0; i < bcm->nr_80211_available; i++) { | 3437 | for (i = 0; i < bcm->nr_80211_available; i++) { |
3323 | err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); | 3438 | core = &(bcm->core_80211[i]); |
3324 | assert(err != -ENODEV); | 3439 | wlext = core->priv; |
3325 | if (err) | ||
3326 | goto err_80211_unwind; | ||
3327 | 3440 | ||
3328 | /* Enable the selected wireless core. | 3441 | if (core == active_core) |
3329 | * Connect PHY only on the first core. | 3442 | continue; |
3330 | */ | 3443 | err = bcm43xx_switch_core(bcm, core); |
3331 | if (!bcm43xx_core_enabled(bcm)) { | 3444 | if (err) { |
3332 | if (bcm->nr_80211_available == 1) { | 3445 | dprintk(KERN_ERR PFX "Could not switch to inactive " |
3333 | connect_phy = bcm43xx_current_phy(bcm)->connected; | 3446 | "802.11 core (%d)\n", err); |
3334 | } else { | 3447 | goto error; |
3335 | if (i == 0) | ||
3336 | connect_phy = 1; | ||
3337 | else | ||
3338 | connect_phy = 0; | ||
3339 | } | ||
3340 | bcm43xx_wireless_core_reset(bcm, connect_phy); | ||
3341 | } | 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 | } | ||
3342 | 3457 | ||
3343 | if (i != 0) | 3458 | /* Now initialize the active 802.11 core. */ |
3344 | bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); | 3459 | err = bcm43xx_switch_core(bcm, active_core); |
3345 | 3460 | if (err) { | |
3346 | err = bcm43xx_wireless_core_init(bcm); | 3461 | dprintk(KERN_ERR PFX "Could not switch to active " |
3347 | if (err) | 3462 | "802.11 core (%d)\n", err); |
3348 | goto err_80211_unwind; | 3463 | goto error; |
3464 | } | ||
3465 | if (adjust_active_sbtmstatelow && | ||
3466 | active_wlext->phy.type == BCM43xx_PHYTYPE_G) { | ||
3467 | u32 sbtmstatelow; | ||
3349 | 3468 | ||
3350 | if (i != 0) { | 3469 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
3351 | bcm43xx_mac_suspend(bcm); | 3470 | sbtmstatelow |= 0x20000000; |
3352 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 3471 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); |
3353 | bcm43xx_radio_turn_off(bcm); | ||
3354 | } | ||
3355 | } | 3472 | } |
3356 | bcm->active_80211_core = &bcm->core_80211[0]; | 3473 | err = wireless_core_up(bcm, 1); |
3357 | if (bcm->nr_80211_available >= 2) { | 3474 | if (err) { |
3358 | bcm43xx_switch_core(bcm, &bcm->core_80211[0]); | 3475 | dprintk(KERN_ERR PFX "core_up for active 802.11 core " |
3359 | bcm43xx_mac_enable(bcm); | 3476 | "failed (%d)\n", err); |
3477 | goto error; | ||
3360 | } | 3478 | } |
3361 | err = bcm43xx_rng_init(bcm); | 3479 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); |
3362 | if (err) | 3480 | if (err) |
3363 | goto err_80211_unwind; | 3481 | goto error; |
3482 | bcm->active_80211_core = active_core; | ||
3483 | |||
3364 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); | 3484 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); |
3365 | 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)); |
3366 | dprintk(KERN_INFO PFX "80211 cores initialized\n"); | ||
3367 | bcm43xx_security_init(bcm); | 3486 | bcm43xx_security_init(bcm); |
3368 | bcm43xx_softmac_init(bcm); | 3487 | ieee80211softmac_start(bcm->net_dev); |
3369 | 3488 | ||
3370 | 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); | ||
3371 | 3498 | ||
3372 | if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { | 3499 | dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n", |
3373 | bcm43xx_mac_suspend(bcm); | 3500 | active_wlext->phy.type); |
3374 | bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0); | ||
3375 | bcm43xx_mac_enable(bcm); | ||
3376 | } | ||
3377 | 3501 | ||
3378 | /* Initialization of the board is done. Flag it as such. */ | 3502 | return 0; |
3379 | 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 | mutex_lock(&(bcm)->mutex); | ||
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; | ||
3380 | 3526 | ||
3381 | bcm43xx_periodic_tasks_setup(bcm); | 3527 | bcm43xx_periodic_tasks_setup(bcm); |
3382 | bcm43xx_sysfs_register(bcm); | 3528 | err = bcm43xx_sysfs_register(bcm); |
3383 | //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though... | 3529 | if (err) |
3530 | goto err_wlshutdown; | ||
3384 | 3531 | ||
3385 | /*FIXME: This should be handled by softmac instead. */ | 3532 | /*FIXME: This should be handled by softmac instead. */ |
3386 | schedule_work(&bcm->softmac->associnfo.work); | 3533 | schedule_work(&bcm->softmac->associnfo.work); |
3387 | 3534 | ||
3388 | assert(err == 0); | ||
3389 | out: | 3535 | out: |
3390 | mutex_unlock(&bcm->mutex); | 3536 | mutex_unlock(&(bcm)->mutex); |
3391 | 3537 | ||
3392 | return err; | 3538 | return err; |
3393 | 3539 | ||
3394 | err_80211_unwind: | 3540 | err_wlshutdown: |
3395 | tasklet_disable(&bcm->isr_tasklet); | 3541 | bcm43xx_shutdown_all_wireless_cores(bcm); |
3396 | /* unwind all 80211 initialization */ | ||
3397 | for (i = 0; i < bcm->nr_80211_available; i++) { | ||
3398 | if (!bcm->core_80211[i].initialized) | ||
3399 | continue; | ||
3400 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
3401 | bcm43xx_wireless_core_cleanup(bcm); | ||
3402 | } | ||
3403 | err_crystal_off: | 3542 | err_crystal_off: |
3404 | bcm43xx_pctl_set_crystal(bcm, 0); | 3543 | bcm43xx_pctl_set_crystal(bcm, 0); |
3544 | err_tasklet: | ||
3545 | tasklet_disable(&bcm->isr_tasklet); | ||
3405 | goto out; | 3546 | goto out; |
3406 | } | 3547 | } |
3407 | 3548 | ||
@@ -3783,7 +3924,8 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev) | |||
3783 | unsigned long flags; | 3924 | unsigned long flags; |
3784 | 3925 | ||
3785 | local_irq_save(flags); | 3926 | local_irq_save(flags); |
3786 | bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); | 3927 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) |
3928 | bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); | ||
3787 | local_irq_restore(flags); | 3929 | local_irq_restore(flags); |
3788 | } | 3930 | } |
3789 | #endif /* CONFIG_NET_POLL_CONTROLLER */ | 3931 | #endif /* CONFIG_NET_POLL_CONTROLLER */ |
@@ -3801,7 +3943,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev) | |||
3801 | int err; | 3943 | int err; |
3802 | 3944 | ||
3803 | ieee80211softmac_stop(net_dev); | 3945 | ieee80211softmac_stop(net_dev); |
3804 | err = bcm43xx_disable_interrupts_sync(bcm, NULL); | 3946 | err = bcm43xx_disable_interrupts_sync(bcm); |
3805 | assert(!err); | 3947 | assert(!err); |
3806 | bcm43xx_free_board(bcm); | 3948 | bcm43xx_free_board(bcm); |
3807 | 3949 | ||
@@ -3820,6 +3962,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, | |||
3820 | bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; | 3962 | bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; |
3821 | 3963 | ||
3822 | bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; | 3964 | bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; |
3965 | bcm->mac_suspended = 1; | ||
3823 | bcm->pci_dev = pci_dev; | 3966 | bcm->pci_dev = pci_dev; |
3824 | bcm->net_dev = net_dev; | 3967 | bcm->net_dev = net_dev; |
3825 | bcm->bad_frames_preempt = modparam_bad_frames_preempt; | 3968 | bcm->bad_frames_preempt = modparam_bad_frames_preempt; |
@@ -3943,7 +4086,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) | |||
3943 | bcm43xx_debugfs_remove_device(bcm); | 4086 | bcm43xx_debugfs_remove_device(bcm); |
3944 | unregister_netdev(net_dev); | 4087 | unregister_netdev(net_dev); |
3945 | bcm43xx_detach_board(bcm); | 4088 | bcm43xx_detach_board(bcm); |
3946 | assert(bcm->ucode == NULL); | ||
3947 | free_ieee80211softmac(net_dev); | 4089 | free_ieee80211softmac(net_dev); |
3948 | } | 4090 | } |
3949 | 4091 | ||
@@ -3953,47 +4095,25 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) | |||
3953 | static void bcm43xx_chip_reset(void *_bcm) | 4095 | static void bcm43xx_chip_reset(void *_bcm) |
3954 | { | 4096 | { |
3955 | struct bcm43xx_private *bcm = _bcm; | 4097 | struct bcm43xx_private *bcm = _bcm; |
3956 | struct net_device *net_dev = bcm->net_dev; | 4098 | struct bcm43xx_phyinfo *phy; |
3957 | struct pci_dev *pci_dev = bcm->pci_dev; | ||
3958 | int err; | 4099 | int err; |
3959 | int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); | ||
3960 | 4100 | ||
3961 | netif_stop_queue(bcm->net_dev); | 4101 | mutex_lock(&(bcm)->mutex); |
3962 | tasklet_disable(&bcm->isr_tasklet); | 4102 | phy = bcm43xx_current_phy(bcm); |
4103 | err = bcm43xx_select_wireless_core(bcm, phy->type); | ||
4104 | mutex_unlock(&(bcm)->mutex); | ||
3963 | 4105 | ||
3964 | bcm->firmware_norelease = 1; | 4106 | printk(KERN_ERR PFX "Controller restart%s\n", |
3965 | if (was_initialized) | 4107 | (err == 0) ? "ed" : " failed"); |
3966 | bcm43xx_free_board(bcm); | ||
3967 | bcm->firmware_norelease = 0; | ||
3968 | bcm43xx_detach_board(bcm); | ||
3969 | err = bcm43xx_init_private(bcm, net_dev, pci_dev); | ||
3970 | if (err) | ||
3971 | goto failure; | ||
3972 | err = bcm43xx_attach_board(bcm); | ||
3973 | if (err) | ||
3974 | goto failure; | ||
3975 | if (was_initialized) { | ||
3976 | err = bcm43xx_init_board(bcm); | ||
3977 | if (err) | ||
3978 | goto failure; | ||
3979 | } | ||
3980 | netif_wake_queue(bcm->net_dev); | ||
3981 | printk(KERN_INFO PFX "Controller restarted\n"); | ||
3982 | |||
3983 | return; | ||
3984 | failure: | ||
3985 | printk(KERN_ERR PFX "Controller restart failed\n"); | ||
3986 | } | 4108 | } |
3987 | 4109 | ||
3988 | /* Hard-reset the chip. | 4110 | /* Hard-reset the chip. |
3989 | * This can be called from interrupt or process context. | 4111 | * This can be called from interrupt or process context. |
3990 | * Make sure to _not_ re-enable device interrupts after this has been called. | 4112 | */ |
3991 | */ | ||
3992 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) | 4113 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) |
3993 | { | 4114 | { |
4115 | assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); | ||
3994 | bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); | 4116 | bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); |
3995 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
3996 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ | ||
3997 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); | 4117 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); |
3998 | INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); | 4118 | INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); |
3999 | schedule_work(&bcm->restart_work); | 4119 | schedule_work(&bcm->restart_work); |
@@ -4005,18 +4125,16 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) | |||
4005 | { | 4125 | { |
4006 | struct net_device *net_dev = pci_get_drvdata(pdev); | 4126 | struct net_device *net_dev = pci_get_drvdata(pdev); |
4007 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 4127 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
4008 | int try_to_shutdown = 0, err; | 4128 | int err; |
4009 | 4129 | ||
4010 | dprintk(KERN_INFO PFX "Suspending...\n"); | 4130 | dprintk(KERN_INFO PFX "Suspending...\n"); |
4011 | 4131 | ||
4012 | bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); | ||
4013 | if (bcm->was_initialized) | ||
4014 | try_to_shutdown = 1; | ||
4015 | |||
4016 | netif_device_detach(net_dev); | 4132 | netif_device_detach(net_dev); |
4017 | if (try_to_shutdown) { | 4133 | bcm->was_initialized = 0; |
4134 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { | ||
4135 | bcm->was_initialized = 1; | ||
4018 | ieee80211softmac_stop(net_dev); | 4136 | ieee80211softmac_stop(net_dev); |
4019 | err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); | 4137 | err = bcm43xx_disable_interrupts_sync(bcm); |
4020 | if (unlikely(err)) { | 4138 | if (unlikely(err)) { |
4021 | dprintk(KERN_ERR PFX "Suspend failed.\n"); | 4139 | dprintk(KERN_ERR PFX "Suspend failed.\n"); |
4022 | return -EAGAIN; | 4140 | return -EAGAIN; |
@@ -4049,17 +4167,14 @@ static int bcm43xx_resume(struct pci_dev *pdev) | |||
4049 | pci_restore_state(pdev); | 4167 | pci_restore_state(pdev); |
4050 | 4168 | ||
4051 | bcm43xx_chipset_attach(bcm); | 4169 | bcm43xx_chipset_attach(bcm); |
4052 | if (bcm->was_initialized) { | 4170 | if (bcm->was_initialized) |
4053 | bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; | ||
4054 | err = bcm43xx_init_board(bcm); | 4171 | err = bcm43xx_init_board(bcm); |
4055 | } | ||
4056 | if (err) { | 4172 | if (err) { |
4057 | printk(KERN_ERR PFX "Resume failed!\n"); | 4173 | printk(KERN_ERR PFX "Resume failed!\n"); |
4058 | return err; | 4174 | return err; |
4059 | } | 4175 | } |
4060 | |||
4061 | netif_device_attach(net_dev); | 4176 | netif_device_attach(net_dev); |
4062 | 4177 | ||
4063 | dprintk(KERN_INFO PFX "Device resumed.\n"); | 4178 | dprintk(KERN_INFO PFX "Device resumed.\n"); |
4064 | 4179 | ||
4065 | return 0; | 4180 | 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..ece335178f6a 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 | mutex_lock(&(bcm)->mutex); | ||
337 | err = bcm43xx_select_wireless_core(bcm, phytype); | ||
338 | mutex_unlock(&(bcm)->mutex); | ||
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 | mutex_lock(&(bcm)->mutex); | ||
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 | mutex_unlock(&(bcm)->mutex); | ||
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); |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 8ffd760dc830..1d3a3aaf96ec 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c | |||
@@ -47,9 +47,8 @@ | |||
47 | #define BCM43xx_WX_VERSION 18 | 47 | #define BCM43xx_WX_VERSION 18 |
48 | 48 | ||
49 | #define MAX_WX_STRING 80 | 49 | #define MAX_WX_STRING 80 |
50 | /* FIXME: the next line is a guess as to what the maximum value of RX power | 50 | /* FIXME: the next line is a guess as to what the maximum RSSI value might be */ |
51 | (in dBm) might be */ | 51 | #define RX_RSSI_MAX 60 |
52 | #define RX_POWER_MAX -10 | ||
53 | 52 | ||
54 | 53 | ||
55 | static int bcm43xx_wx_get_name(struct net_device *net_dev, | 54 | static int bcm43xx_wx_get_name(struct net_device *net_dev, |
@@ -230,9 +229,8 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, | |||
230 | range->throughput = 27 * 1000 * 1000; | 229 | range->throughput = 27 * 1000 * 1000; |
231 | 230 | ||
232 | range->max_qual.qual = 100; | 231 | range->max_qual.qual = 100; |
233 | /* TODO: Real max RSSI */ | 232 | range->max_qual.level = 152; /* set floor at -104 dBm (152 - 256) */ |
234 | range->max_qual.level = 0; | 233 | range->max_qual.noise = 152; |
235 | range->max_qual.noise = 0; | ||
236 | range->max_qual.updated = IW_QUAL_ALL_UPDATED; | 234 | range->max_qual.updated = IW_QUAL_ALL_UPDATED; |
237 | 235 | ||
238 | range->avg_qual.qual = 50; | 236 | range->avg_qual.qual = 50; |
@@ -845,6 +843,7 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d | |||
845 | struct iw_statistics *wstats; | 843 | struct iw_statistics *wstats; |
846 | struct ieee80211_network *network = NULL; | 844 | struct ieee80211_network *network = NULL; |
847 | static int tmp_level = 0; | 845 | static int tmp_level = 0; |
846 | static int tmp_qual = 0; | ||
848 | unsigned long flags; | 847 | unsigned long flags; |
849 | 848 | ||
850 | wstats = &bcm->stats.wstats; | 849 | wstats = &bcm->stats.wstats; |
@@ -863,25 +862,28 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d | |||
863 | wstats->qual.level = 0; | 862 | wstats->qual.level = 0; |
864 | wstats->qual.noise = 0; | 863 | wstats->qual.noise = 0; |
865 | wstats->qual.updated = 7; | 864 | wstats->qual.updated = 7; |
866 | wstats->qual.updated |= IW_QUAL_ALL_UPDATED; | 865 | wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; |
867 | return wstats; | 866 | return wstats; |
868 | } | 867 | } |
869 | /* fill in the real statistics when iface associated */ | 868 | /* fill in the real statistics when iface associated */ |
870 | spin_lock_irqsave(&mac->ieee->lock, flags); | 869 | spin_lock_irqsave(&mac->ieee->lock, flags); |
871 | list_for_each_entry(network, &mac->ieee->network_list, list) { | 870 | list_for_each_entry(network, &mac->ieee->network_list, list) { |
872 | if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) { | 871 | if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) { |
873 | if (!tmp_level) /* get initial value */ | 872 | if (!tmp_level) { /* get initial values */ |
874 | tmp_level = network->stats.rssi; | 873 | tmp_level = network->stats.signal; |
875 | else /* smooth results */ | 874 | tmp_qual = network->stats.rssi; |
876 | tmp_level = (7 * tmp_level + network->stats.rssi)/8; | 875 | } else { /* smooth results */ |
876 | tmp_level = (15 * tmp_level + network->stats.signal)/16; | ||
877 | tmp_qual = (15 * tmp_qual + network->stats.rssi)/16; | ||
878 | } | ||
877 | break; | 879 | break; |
878 | } | 880 | } |
879 | } | 881 | } |
880 | spin_unlock_irqrestore(&mac->ieee->lock, flags); | 882 | spin_unlock_irqrestore(&mac->ieee->lock, flags); |
881 | wstats->qual.level = tmp_level; | 883 | wstats->qual.level = tmp_level; |
882 | wstats->qual.qual = 100 + tmp_level - RX_POWER_MAX; // TODO: get the real signal quality | 884 | wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX; |
883 | wstats->qual.noise = bcm->stats.noise; | 885 | wstats->qual.noise = bcm->stats.noise; |
884 | wstats->qual.updated = IW_QUAL_ALL_UPDATED; | 886 | wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; |
885 | wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; | 887 | wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; |
886 | wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; | 888 | wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; |
887 | wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; | 889 | wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index 6dbd855b3647..c0efbfe605a5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | |||
@@ -492,16 +492,15 @@ int bcm43xx_rx(struct bcm43xx_private *bcm, | |||
492 | 492 | ||
493 | memset(&stats, 0, sizeof(stats)); | 493 | memset(&stats, 0, sizeof(stats)); |
494 | stats.mac_time = le16_to_cpu(rxhdr->mactime); | 494 | stats.mac_time = le16_to_cpu(rxhdr->mactime); |
495 | stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, | 495 | stats.rssi = rxhdr->rssi; |
496 | stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, | ||
496 | !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), | 497 | !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), |
497 | !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); | 498 | !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); |
498 | stats.signal = rxhdr->signal_quality; //FIXME | ||
499 | //TODO stats.noise = | 499 | //TODO stats.noise = |
500 | if (is_ofdm) | 500 | if (is_ofdm) |
501 | stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); | 501 | stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); |
502 | else | 502 | else |
503 | stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); | 503 | stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); |
504 | //printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); | ||
505 | stats.received_channel = radio->channel; | 504 | stats.received_channel = radio->channel; |
506 | //TODO stats.control = | 505 | //TODO stats.control = |
507 | stats.mask = IEEE80211_STATMASK_SIGNAL | | 506 | stats.mask = IEEE80211_STATMASK_SIGNAL | |