int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum wl1271_cmd_ps_mode mode) { int ret; u16 timeout = wl->conf.conn.dynamic_ps_timeout; switch (mode) { case STATION_AUTO_PS_MODE: case STATION_POWER_SAVE_MODE: wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)", mode, timeout); ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.wake_up_event, wl->conf.conn.listen_interval); if (ret < 0) { wl1271_error("couldn't set wake up conditions"); return ret; } ret = wl1271_cmd_ps_mode(wl, wlvif, mode, timeout); if (ret < 0) return ret; set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); if (wlvif->band == IEEE80211_BAND_2GHZ) { ret = wl1271_acx_bet_enable(wl, wlvif, true); if (ret < 0) return ret; } break; case STATION_ACTIVE_MODE: wl1271_debug(DEBUG_PSM, "leaving psm"); if (wlvif->band == IEEE80211_BAND_2GHZ) { ret = wl1271_acx_bet_enable(wl, wlvif, false); if (ret < 0) return ret; } ret = wl1271_cmd_ps_mode(wl, wlvif, mode, 0); if (ret < 0) return ret; clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); break; default: wl1271_warning("trying to set ps to unsupported mode %d", mode); ret = -EINVAL; } return ret; }
static int wl1271_event_ps_report(struct wl1271 *wl, struct event_mailbox *mbox, bool *beacon_loss) { int ret = 0; u32 total_retries = wl->conf.conn.psm_entry_retries; wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); switch (mbox->ps_status) { case EVENT_ENTER_POWER_SAVE_FAIL: wl1271_debug(DEBUG_PSM, "PSM entry failed"); if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { /* remain in active mode */ wl->psm_entry_retry = 0; break; } if (wl->psm_entry_retry < total_retries) { wl->psm_entry_retry++; ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); } else { wl1271_info("No ack to nullfunc from AP."); wl->psm_entry_retry = 0; *beacon_loss = true; } break; case EVENT_ENTER_POWER_SAVE_SUCCESS: wl->psm_entry_retry = 0; /* enable beacon filtering */ ret = wl1271_acx_beacon_filter_opt(wl, true); if (ret < 0) break; /* * BET has only a minor effect in 5GHz and masks * channel switch IEs, so we only enable BET on 2.4GHz */ if (wl->band == IEEE80211_BAND_2GHZ) /* enable beacon early termination */ ret = wl1271_acx_bet_enable(wl, true); if (wl->ps_compl) { complete(wl->ps_compl); wl->ps_compl = NULL; } break; default: break; } return ret; }
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, u32 rates, bool send) { int ret; switch (mode) { case STATION_POWER_SAVE_MODE: wl1271_debug(DEBUG_PSM, "entering psm"); ret = wl1271_acx_wake_up_conditions(wl, wl->conf.conn.wake_up_event, wl->conf.conn.listen_interval); if (ret < 0) { wl1271_error("couldn't set wake up conditions"); return ret; } ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; set_bit(WL1271_FLAG_PSM, &wl->flags); break; case STATION_ACTIVE_MODE: default: wl1271_debug(DEBUG_PSM, "leaving psm"); wl->psm_entry_retry = 0; cancel_delayed_work(&wl->ps_retry_work); /* disable beacon early termination */ if (wl->band == IEEE80211_BAND_2GHZ) { ret = wl1271_acx_bet_enable(wl, false); if (ret < 0) return ret; } /* disable beacon filtering */ ret = wl1271_acx_beacon_filter_opt(wl, false); if (ret < 0) return ret; ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; clear_bit(WL1271_FLAG_PSM, &wl->flags); break; } return ret; }
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, u32 rates, bool send) { int ret; switch (mode) { case STATION_POWER_SAVE_MODE: wl1271_debug(DEBUG_PSM, "entering psm"); ret = wl1271_acx_wake_up_conditions(wl); if (ret < 0) { wl1271_error("couldn't set wake up conditions"); return ret; } ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; set_bit(WL1271_FLAG_PSM, &wl->flags); break; case STATION_ACTIVE_MODE: default: wl1271_debug(DEBUG_PSM, "leaving psm"); ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) return ret; /* disable beacon early termination */ ret = wl1271_acx_bet_enable(wl, false); if (ret < 0) return ret; /* disable beacon filtering */ ret = wl1271_acx_beacon_filter_opt(wl, false); if (ret < 0) return ret; ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; clear_bit(WL1271_FLAG_PSM, &wl->flags); break; } return ret; }
static int wl1271_event_ps_report(struct wl1271 *wl, struct event_mailbox *mbox, bool *beacon_loss) { int ret = 0; u32 total_retries = wl->conf.conn.psm_entry_retries; wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); switch (mbox->ps_status) { case EVENT_ENTER_POWER_SAVE_FAIL: wl1271_debug(DEBUG_PSM, "PSM entry failed"); if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { /* remain in active mode */ wl->psm_entry_retry = 0; break; } if (wl->psm_entry_retry < total_retries) { wl->psm_entry_retry++; ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); } else { wl1271_info("No ack to nullfunc from AP."); wl->psm_entry_retry = 0; *beacon_loss = true; } break; case EVENT_ENTER_POWER_SAVE_SUCCESS: wl->psm_entry_retry = 0; /* enable beacon filtering */ ret = wl1271_acx_beacon_filter_opt(wl, true); if (ret < 0) break; /* enable beacon early termination */ ret = wl1271_acx_bet_enable(wl, true); if (ret < 0) break; /* go to extremely low power mode */ wl1271_ps_elp_sleep(wl); break; case EVENT_EXIT_POWER_SAVE_FAIL: wl1271_debug(DEBUG_PSM, "PSM exit failed"); if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { wl->psm_entry_retry = 0; break; } /* make sure the firmware goes to active mode - the frame to be sent next will indicate to the AP, that we are active. */ ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, wl->basic_rate, false); break; case EVENT_EXIT_POWER_SAVE_SUCCESS: default: break; } return ret; }