diff options
author | Juuso Oikarinen <juuso.oikarinen@nokia.com> | 2009-12-11 08:41:01 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-12-28 16:31:34 -0500 |
commit | 9ccd921792e5b6719ff9e561438e095cba757727 (patch) | |
tree | a27d7edc9d5cbe5710ea86c0f155b7f72b271bcb /drivers | |
parent | af5e084b3200ab6e3033068a34fe16fd139be17b (diff) |
wl1271: Implement chipset boot retry
The wl1271 has a hardware bug which causes it to randomly (very infrequently)
to fail powering up properly. This patch implements retry for the chipset boot
sequence, to work around the hardware problem.
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 130 |
1 files changed, 77 insertions, 53 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d07f03565196..0795bf3c60da 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -47,6 +47,8 @@ | |||
47 | #include "wl1271_cmd.h" | 47 | #include "wl1271_cmd.h" |
48 | #include "wl1271_boot.h" | 48 | #include "wl1271_boot.h" |
49 | 49 | ||
50 | #define WL1271_BOOT_RETRIES 3 | ||
51 | |||
50 | static struct conf_drv_settings default_conf = { | 52 | static struct conf_drv_settings default_conf = { |
51 | .sg = { | 53 | .sg = { |
52 | .per_threshold = 7500, | 54 | .per_threshold = 7500, |
@@ -645,7 +647,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) | |||
645 | 647 | ||
646 | ret = wl1271_setup(wl); | 648 | ret = wl1271_setup(wl); |
647 | if (ret < 0) | 649 | if (ret < 0) |
648 | goto out_power_off; | 650 | goto out; |
649 | break; | 651 | break; |
650 | case CHIP_ID_1271_PG20: | 652 | case CHIP_ID_1271_PG20: |
651 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", | 653 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", |
@@ -653,38 +655,34 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) | |||
653 | 655 | ||
654 | ret = wl1271_setup(wl); | 656 | ret = wl1271_setup(wl); |
655 | if (ret < 0) | 657 | if (ret < 0) |
656 | goto out_power_off; | 658 | goto out; |
657 | break; | 659 | break; |
658 | default: | 660 | default: |
659 | wl1271_error("unsupported chip id: 0x%x", wl->chip.id); | 661 | wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); |
660 | ret = -ENODEV; | 662 | ret = -ENODEV; |
661 | goto out_power_off; | 663 | goto out; |
662 | } | 664 | } |
663 | 665 | ||
664 | if (wl->fw == NULL) { | 666 | if (wl->fw == NULL) { |
665 | ret = wl1271_fetch_firmware(wl); | 667 | ret = wl1271_fetch_firmware(wl); |
666 | if (ret < 0) | 668 | if (ret < 0) |
667 | goto out_power_off; | 669 | goto out; |
668 | } | 670 | } |
669 | 671 | ||
670 | /* No NVS from netlink, try to get it from the filesystem */ | 672 | /* No NVS from netlink, try to get it from the filesystem */ |
671 | if (wl->nvs == NULL) { | 673 | if (wl->nvs == NULL) { |
672 | ret = wl1271_fetch_nvs(wl); | 674 | ret = wl1271_fetch_nvs(wl); |
673 | if (ret < 0) | 675 | if (ret < 0) |
674 | goto out_power_off; | 676 | goto out; |
675 | } | 677 | } |
676 | 678 | ||
677 | goto out; | ||
678 | |||
679 | out_power_off: | ||
680 | wl1271_power_off(wl); | ||
681 | |||
682 | out: | 679 | out: |
683 | return ret; | 680 | return ret; |
684 | } | 681 | } |
685 | 682 | ||
686 | int wl1271_plt_start(struct wl1271 *wl) | 683 | int wl1271_plt_start(struct wl1271 *wl) |
687 | { | 684 | { |
685 | int retries = WL1271_BOOT_RETRIES; | ||
688 | int ret; | 686 | int ret; |
689 | 687 | ||
690 | mutex_lock(&wl->mutex); | 688 | mutex_lock(&wl->mutex); |
@@ -698,35 +696,48 @@ int wl1271_plt_start(struct wl1271 *wl) | |||
698 | goto out; | 696 | goto out; |
699 | } | 697 | } |
700 | 698 | ||
701 | wl->state = WL1271_STATE_PLT; | 699 | while (retries) { |
702 | 700 | retries--; | |
703 | ret = wl1271_chip_wakeup(wl); | 701 | ret = wl1271_chip_wakeup(wl); |
704 | if (ret < 0) | 702 | if (ret < 0) |
705 | goto out; | 703 | goto power_off; |
706 | |||
707 | ret = wl1271_boot(wl); | ||
708 | if (ret < 0) | ||
709 | goto out_power_off; | ||
710 | |||
711 | wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); | ||
712 | 704 | ||
713 | ret = wl1271_plt_init(wl); | 705 | ret = wl1271_boot(wl); |
714 | if (ret < 0) | 706 | if (ret < 0) |
715 | goto out_irq_disable; | 707 | goto power_off; |
716 | 708 | ||
717 | /* Make sure power saving is disabled */ | 709 | ret = wl1271_plt_init(wl); |
718 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | 710 | if (ret < 0) |
719 | if (ret < 0) | 711 | goto irq_disable; |
720 | goto out_irq_disable; | ||
721 | 712 | ||
722 | goto out; | 713 | /* Make sure power saving is disabled */ |
714 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||
715 | if (ret < 0) | ||
716 | goto irq_disable; | ||
723 | 717 | ||
724 | out_irq_disable: | 718 | wl->state = WL1271_STATE_PLT; |
725 | wl1271_disable_interrupts(wl); | 719 | wl1271_notice("firmware booted in PLT mode (%s)", |
720 | wl->chip.fw_ver); | ||
721 | goto out; | ||
726 | 722 | ||
727 | out_power_off: | 723 | irq_disable: |
728 | wl1271_power_off(wl); | 724 | wl1271_disable_interrupts(wl); |
725 | mutex_unlock(&wl->mutex); | ||
726 | /* Unlocking the mutex in the middle of handling is | ||
727 | inherently unsafe. In this case we deem it safe to do, | ||
728 | because we need to let any possibly pending IRQ out of | ||
729 | the system (and while we are WL1271_STATE_OFF the IRQ | ||
730 | work function will not do anything.) Also, any other | ||
731 | possible concurrent operations will fail due to the | ||
732 | current state, hence the wl1271 struct should be safe. */ | ||
733 | cancel_work_sync(&wl->irq_work); | ||
734 | mutex_lock(&wl->mutex); | ||
735 | power_off: | ||
736 | wl1271_power_off(wl); | ||
737 | } | ||
729 | 738 | ||
739 | wl1271_error("firmware boot in PLT mode failed despite %d retries", | ||
740 | WL1271_BOOT_RETRIES); | ||
730 | out: | 741 | out: |
731 | mutex_unlock(&wl->mutex); | 742 | mutex_unlock(&wl->mutex); |
732 | 743 | ||
@@ -882,6 +893,7 @@ static struct notifier_block wl1271_dev_notifier = { | |||
882 | static int wl1271_op_start(struct ieee80211_hw *hw) | 893 | static int wl1271_op_start(struct ieee80211_hw *hw) |
883 | { | 894 | { |
884 | struct wl1271 *wl = hw->priv; | 895 | struct wl1271 *wl = hw->priv; |
896 | int retries = WL1271_BOOT_RETRIES; | ||
885 | int ret = 0; | 897 | int ret = 0; |
886 | 898 | ||
887 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | 899 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); |
@@ -895,30 +907,42 @@ static int wl1271_op_start(struct ieee80211_hw *hw) | |||
895 | goto out; | 907 | goto out; |
896 | } | 908 | } |
897 | 909 | ||
898 | ret = wl1271_chip_wakeup(wl); | 910 | while (retries) { |
899 | if (ret < 0) | 911 | retries--; |
900 | goto out; | 912 | ret = wl1271_chip_wakeup(wl); |
901 | 913 | if (ret < 0) | |
902 | ret = wl1271_boot(wl); | 914 | goto power_off; |
903 | if (ret < 0) | ||
904 | goto out_power_off; | ||
905 | |||
906 | ret = wl1271_hw_init(wl); | ||
907 | if (ret < 0) | ||
908 | goto out_irq_disable; | ||
909 | |||
910 | wl->state = WL1271_STATE_ON; | ||
911 | 915 | ||
912 | wl1271_info("firmware booted (%s)", wl->chip.fw_ver); | 916 | ret = wl1271_boot(wl); |
917 | if (ret < 0) | ||
918 | goto power_off; | ||
913 | 919 | ||
914 | goto out; | 920 | ret = wl1271_hw_init(wl); |
921 | if (ret < 0) | ||
922 | goto irq_disable; | ||
915 | 923 | ||
916 | out_irq_disable: | 924 | wl->state = WL1271_STATE_ON; |
917 | wl1271_disable_interrupts(wl); | 925 | wl1271_info("firmware booted (%s)", wl->chip.fw_ver); |
926 | goto out; | ||
918 | 927 | ||
919 | out_power_off: | 928 | irq_disable: |
920 | wl1271_power_off(wl); | 929 | wl1271_disable_interrupts(wl); |
930 | mutex_unlock(&wl->mutex); | ||
931 | /* Unlocking the mutex in the middle of handling is | ||
932 | inherently unsafe. In this case we deem it safe to do, | ||
933 | because we need to let any possibly pending IRQ out of | ||
934 | the system (and while we are WL1271_STATE_OFF the IRQ | ||
935 | work function will not do anything.) Also, any other | ||
936 | possible concurrent operations will fail due to the | ||
937 | current state, hence the wl1271 struct should be safe. */ | ||
938 | cancel_work_sync(&wl->irq_work); | ||
939 | mutex_lock(&wl->mutex); | ||
940 | power_off: | ||
941 | wl1271_power_off(wl); | ||
942 | } | ||
921 | 943 | ||
944 | wl1271_error("firmware boot failed despite %d retries", | ||
945 | WL1271_BOOT_RETRIES); | ||
922 | out: | 946 | out: |
923 | mutex_unlock(&wl->mutex); | 947 | mutex_unlock(&wl->mutex); |
924 | 948 | ||