From: Yuri Ershov Date: Wed, 27 Oct 2010 13:21:09 +0000 (+0400) Subject: wl1251: Handle failing PS entry X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1747910973bbd49edca2e476832d730d51fe44b4;p=pandora-wifi.git wl1251: Handle failing PS entry It is possible, that the nullfunc message used to indicate to the associated-to AP that we are going to power save fails to reach the intended recipient. In that case, the STA and AP can become out of sync, resulting in connection loss. This patch adds code to attempt to recover from such failure by resending the nullfunc. Also fixed one compiler warning. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Yuri Ershov --- diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 4a353e1..a851e7d 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -365,6 +365,8 @@ struct wl1251 { /* PSM mode requested */ bool psm_requested; + u8 ps_entry_retry; + u16 beacon_int; u8 dtim_period; diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 447fb20..f2ec416 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -301,7 +301,8 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) ROAMING_TRIGGER_LOW_RSSI_EVENT_ID | ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID | REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID | - BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID; + BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID | + PS_REPORT_EVENT_ID; ret = wl1251_event_unmask(wl); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 6743690..8fed56b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -46,6 +46,38 @@ static int wl1251_event_scan_complete(struct wl1251 *wl, return 0; } +#define WL1251_PS_ENTRY_RETRIES 3 +static int wl1251_event_ps_report(struct wl1251 *wl, + struct event_mailbox *mbox) +{ + int ret = 0; + + wl1251_debug(DEBUG_EVENT, "ps status: %x", mbox->ps_status); + + switch (mbox->ps_status) { + case ENTER_POWER_SAVE_FAIL: + if (!wl->psm) { + wl->ps_entry_retry = 0; + break; + } + + if (wl->ps_entry_retry < WL1251_PS_ENTRY_RETRIES) { + ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + wl->ps_entry_retry++; + } else { + wl1251_error("Power save entry failed, giving up"); + wl->ps_entry_retry = 0; + } + break; + case ENTER_POWER_SAVE_SUCCESS: + default: + wl->ps_entry_retry = 0; + break; + } + + return 0; +} + static void wl1251_event_mbox_dump(struct event_mailbox *mbox) { wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); @@ -79,6 +111,13 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) } } + if (vector & PS_REPORT_EVENT_ID) { + wl1251_debug(DEBUG_EVENT, "PS_REPORT_EVENT_ID"); + ret = wl1251_event_ps_report(wl, mbox); + if (ret < 0) + return ret; + } + if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) { wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); /* need to unlock mutex to avoid deadlocking with rtnl */ diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h index ec45647..e2ce0b1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.h +++ b/drivers/net/wireless/wl12xx/wl1251_event.h @@ -75,6 +75,13 @@ enum { EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, }; +enum { + ENTER_POWER_SAVE_FAIL = 0, + ENTER_POWER_SAVE_SUCCESS, + EXIT_POWER_SAVE_FAIL, + EXIT_POWER_SAVE_SUCCESS +}; + struct event_debug_report { u8 debug_event_id; u8 num_params; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 049f6c8..2f7c65c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -503,6 +503,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) wl->next_tx_complete = 0; wl->elp = false; wl->psm = 0; + wl->ps_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->channel = WL1251_DEFAULT_CHANNEL; @@ -1357,6 +1358,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->elp = false; wl->psm = 0; wl->psm_requested = false; + wl->ps_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->beacon_int = WL1251_DEFAULT_BEACON_INT;