162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2014 Redpine Signals Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/etherdevice.h> 1862306a36Sopenharmony_ci#include <linux/if.h> 1962306a36Sopenharmony_ci#include "rsi_debugfs.h" 2062306a36Sopenharmony_ci#include "rsi_mgmt.h" 2162306a36Sopenharmony_ci#include "rsi_common.h" 2262306a36Sopenharmony_ci#include "rsi_ps.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cichar *str_psstate(enum ps_state state) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci switch (state) { 2762306a36Sopenharmony_ci case PS_NONE: 2862306a36Sopenharmony_ci return "PS_NONE"; 2962306a36Sopenharmony_ci case PS_DISABLE_REQ_SENT: 3062306a36Sopenharmony_ci return "PS_DISABLE_REQ_SENT"; 3162306a36Sopenharmony_ci case PS_ENABLE_REQ_SENT: 3262306a36Sopenharmony_ci return "PS_ENABLE_REQ_SENT"; 3362306a36Sopenharmony_ci case PS_ENABLED: 3462306a36Sopenharmony_ci return "PS_ENABLED"; 3562306a36Sopenharmony_ci default: 3662306a36Sopenharmony_ci return "INVALID_STATE"; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic inline void rsi_modify_ps_state(struct rsi_hw *adapter, 4162306a36Sopenharmony_ci enum ps_state nstate) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "PS state changed %s => %s\n", 4462306a36Sopenharmony_ci str_psstate(adapter->ps_state), 4562306a36Sopenharmony_ci str_psstate(nstate)); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci adapter->ps_state = nstate; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_civoid rsi_default_ps_params(struct rsi_hw *adapter) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct rsi_ps_info *ps_info = &adapter->ps_info; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci ps_info->enabled = true; 5562306a36Sopenharmony_ci ps_info->sleep_type = RSI_SLEEP_TYPE_LP; 5662306a36Sopenharmony_ci ps_info->tx_threshold = 0; 5762306a36Sopenharmony_ci ps_info->rx_threshold = 0; 5862306a36Sopenharmony_ci ps_info->tx_hysterisis = 0; 5962306a36Sopenharmony_ci ps_info->rx_hysterisis = 0; 6062306a36Sopenharmony_ci ps_info->monitor_interval = 0; 6162306a36Sopenharmony_ci ps_info->listen_interval = RSI_DEF_LISTEN_INTERVAL; 6262306a36Sopenharmony_ci ps_info->num_bcns_per_lis_int = 0; 6362306a36Sopenharmony_ci ps_info->dtim_interval_duration = 0; 6462306a36Sopenharmony_ci ps_info->num_dtims_per_sleep = 0; 6562306a36Sopenharmony_ci ps_info->deep_sleep_wakeup_period = RSI_DEF_DS_WAKEUP_PERIOD; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_civoid rsi_enable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci if (adapter->ps_state != PS_NONE) { 7162306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 7262306a36Sopenharmony_ci "%s: Cannot accept enable PS in %s state\n", 7362306a36Sopenharmony_ci __func__, str_psstate(adapter->ps_state)); 7462306a36Sopenharmony_ci return; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (rsi_send_ps_request(adapter, true, vif)) { 7862306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 7962306a36Sopenharmony_ci "%s: Failed to send PS request to device\n", 8062306a36Sopenharmony_ci __func__); 8162306a36Sopenharmony_ci return; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci rsi_modify_ps_state(adapter, PS_ENABLE_REQ_SENT); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* This function is used to disable power save */ 8862306a36Sopenharmony_civoid rsi_disable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci if (adapter->ps_state != PS_ENABLED) { 9162306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 9262306a36Sopenharmony_ci "%s: Cannot accept disable PS in %s state\n", 9362306a36Sopenharmony_ci __func__, str_psstate(adapter->ps_state)); 9462306a36Sopenharmony_ci return; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (rsi_send_ps_request(adapter, false, vif)) { 9862306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 9962306a36Sopenharmony_ci "%s: Failed to send PS request to device\n", 10062306a36Sopenharmony_ci __func__); 10162306a36Sopenharmony_ci return; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci rsi_modify_ps_state(adapter, PS_DISABLE_REQ_SENT); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_civoid rsi_conf_uapsd(struct rsi_hw *adapter, struct ieee80211_vif *vif) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci int ret; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (adapter->ps_state != PS_ENABLED) 11262306a36Sopenharmony_ci return; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ret = rsi_send_ps_request(adapter, false, vif); 11562306a36Sopenharmony_ci if (!ret) 11662306a36Sopenharmony_ci ret = rsi_send_ps_request(adapter, true, vif); 11762306a36Sopenharmony_ci if (ret) 11862306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 11962306a36Sopenharmony_ci "%s: Failed to send PS request to device\n", 12062306a36Sopenharmony_ci __func__); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ciint rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci u16 cfm_type = get_unaligned_le16(msg + PS_CONFIRM_INDEX); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci switch (cfm_type) { 12862306a36Sopenharmony_ci case RSI_SLEEP_REQUEST: 12962306a36Sopenharmony_ci if (adapter->ps_state == PS_ENABLE_REQ_SENT) 13062306a36Sopenharmony_ci rsi_modify_ps_state(adapter, PS_ENABLED); 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci case RSI_WAKEUP_REQUEST: 13362306a36Sopenharmony_ci if (adapter->ps_state == PS_DISABLE_REQ_SENT) 13462306a36Sopenharmony_ci rsi_modify_ps_state(adapter, PS_NONE); 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci default: 13762306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 13862306a36Sopenharmony_ci "Invalid PS confirm type %x in state %s\n", 13962306a36Sopenharmony_ci cfm_type, str_psstate(adapter->ps_state)); 14062306a36Sopenharmony_ci return -1; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return 0; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 146