Skip to content

Commit

Permalink
wl1271: Implement chipset boot retry
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Juuso Oikarinen authored and John W. Linville committed Dec 28, 2009
1 parent af5e084 commit 9ccd921
Showing 1 changed file with 77 additions and 53 deletions.
130 changes: 77 additions & 53 deletions drivers/net/wireless/wl12xx/wl1271_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
#include "wl1271_cmd.h"
#include "wl1271_boot.h"

#define WL1271_BOOT_RETRIES 3

static struct conf_drv_settings default_conf = {
.sg = {
.per_threshold = 7500,
Expand Down Expand Up @@ -645,46 +647,42 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)

ret = wl1271_setup(wl);
if (ret < 0)
goto out_power_off;
goto out;
break;
case CHIP_ID_1271_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
wl->chip.id);

ret = wl1271_setup(wl);
if (ret < 0)
goto out_power_off;
goto out;
break;
default:
wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
goto out_power_off;
goto out;
}

if (wl->fw == NULL) {
ret = wl1271_fetch_firmware(wl);
if (ret < 0)
goto out_power_off;
goto out;
}

/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
ret = wl1271_fetch_nvs(wl);
if (ret < 0)
goto out_power_off;
goto out;
}

goto out;

out_power_off:
wl1271_power_off(wl);

out:
return ret;
}

int wl1271_plt_start(struct wl1271 *wl)
{
int retries = WL1271_BOOT_RETRIES;
int ret;

mutex_lock(&wl->mutex);
Expand All @@ -698,35 +696,48 @@ int wl1271_plt_start(struct wl1271 *wl)
goto out;
}

wl->state = WL1271_STATE_PLT;

ret = wl1271_chip_wakeup(wl);
if (ret < 0)
goto out;

ret = wl1271_boot(wl);
if (ret < 0)
goto out_power_off;

wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
while (retries) {
retries--;
ret = wl1271_chip_wakeup(wl);
if (ret < 0)
goto power_off;

ret = wl1271_plt_init(wl);
if (ret < 0)
goto out_irq_disable;
ret = wl1271_boot(wl);
if (ret < 0)
goto power_off;

/* Make sure power saving is disabled */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
if (ret < 0)
goto out_irq_disable;
ret = wl1271_plt_init(wl);
if (ret < 0)
goto irq_disable;

goto out;
/* Make sure power saving is disabled */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
if (ret < 0)
goto irq_disable;

out_irq_disable:
wl1271_disable_interrupts(wl);
wl->state = WL1271_STATE_PLT;
wl1271_notice("firmware booted in PLT mode (%s)",
wl->chip.fw_ver);
goto out;

out_power_off:
wl1271_power_off(wl);
irq_disable:
wl1271_disable_interrupts(wl);
mutex_unlock(&wl->mutex);
/* Unlocking the mutex in the middle of handling is
inherently unsafe. In this case we deem it safe to do,
because we need to let any possibly pending IRQ out of
the system (and while we are WL1271_STATE_OFF the IRQ
work function will not do anything.) Also, any other
possible concurrent operations will fail due to the
current state, hence the wl1271 struct should be safe. */
cancel_work_sync(&wl->irq_work);
mutex_lock(&wl->mutex);
power_off:
wl1271_power_off(wl);
}

wl1271_error("firmware boot in PLT mode failed despite %d retries",
WL1271_BOOT_RETRIES);
out:
mutex_unlock(&wl->mutex);

Expand Down Expand Up @@ -882,6 +893,7 @@ static struct notifier_block wl1271_dev_notifier = {
static int wl1271_op_start(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
int retries = WL1271_BOOT_RETRIES;
int ret = 0;

wl1271_debug(DEBUG_MAC80211, "mac80211 start");
Expand All @@ -895,30 +907,42 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
goto out;
}

ret = wl1271_chip_wakeup(wl);
if (ret < 0)
goto out;

ret = wl1271_boot(wl);
if (ret < 0)
goto out_power_off;

ret = wl1271_hw_init(wl);
if (ret < 0)
goto out_irq_disable;

wl->state = WL1271_STATE_ON;
while (retries) {
retries--;
ret = wl1271_chip_wakeup(wl);
if (ret < 0)
goto power_off;

wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
ret = wl1271_boot(wl);
if (ret < 0)
goto power_off;

goto out;
ret = wl1271_hw_init(wl);
if (ret < 0)
goto irq_disable;

out_irq_disable:
wl1271_disable_interrupts(wl);
wl->state = WL1271_STATE_ON;
wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
goto out;

out_power_off:
wl1271_power_off(wl);
irq_disable:
wl1271_disable_interrupts(wl);
mutex_unlock(&wl->mutex);
/* Unlocking the mutex in the middle of handling is
inherently unsafe. In this case we deem it safe to do,
because we need to let any possibly pending IRQ out of
the system (and while we are WL1271_STATE_OFF the IRQ
work function will not do anything.) Also, any other
possible concurrent operations will fail due to the
current state, hence the wl1271 struct should be safe. */
cancel_work_sync(&wl->irq_work);
mutex_lock(&wl->mutex);
power_off:
wl1271_power_off(wl);
}

wl1271_error("firmware boot failed despite %d retries",
WL1271_BOOT_RETRIES);
out:
mutex_unlock(&wl->mutex);

Expand Down

0 comments on commit 9ccd921

Please sign in to comment.