18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2014 Redpine Signals Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 188c2ecf20Sopenharmony_ci#include <linux/if.h> 198c2ecf20Sopenharmony_ci#include <linux/version.h> 208c2ecf20Sopenharmony_ci#include "rsi_debugfs.h" 218c2ecf20Sopenharmony_ci#include "rsi_mgmt.h" 228c2ecf20Sopenharmony_ci#include "rsi_common.h" 238c2ecf20Sopenharmony_ci#include "rsi_ps.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cichar *str_psstate(enum ps_state state) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci switch (state) { 288c2ecf20Sopenharmony_ci case PS_NONE: 298c2ecf20Sopenharmony_ci return "PS_NONE"; 308c2ecf20Sopenharmony_ci case PS_DISABLE_REQ_SENT: 318c2ecf20Sopenharmony_ci return "PS_DISABLE_REQ_SENT"; 328c2ecf20Sopenharmony_ci case PS_ENABLE_REQ_SENT: 338c2ecf20Sopenharmony_ci return "PS_ENABLE_REQ_SENT"; 348c2ecf20Sopenharmony_ci case PS_ENABLED: 358c2ecf20Sopenharmony_ci return "PS_ENABLED"; 368c2ecf20Sopenharmony_ci default: 378c2ecf20Sopenharmony_ci return "INVALID_STATE"; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic inline void rsi_modify_ps_state(struct rsi_hw *adapter, 428c2ecf20Sopenharmony_ci enum ps_state nstate) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "PS state changed %s => %s\n", 458c2ecf20Sopenharmony_ci str_psstate(adapter->ps_state), 468c2ecf20Sopenharmony_ci str_psstate(nstate)); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci adapter->ps_state = nstate; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_civoid rsi_default_ps_params(struct rsi_hw *adapter) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct rsi_ps_info *ps_info = &adapter->ps_info; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci ps_info->enabled = true; 568c2ecf20Sopenharmony_ci ps_info->sleep_type = RSI_SLEEP_TYPE_LP; 578c2ecf20Sopenharmony_ci ps_info->tx_threshold = 0; 588c2ecf20Sopenharmony_ci ps_info->rx_threshold = 0; 598c2ecf20Sopenharmony_ci ps_info->tx_hysterisis = 0; 608c2ecf20Sopenharmony_ci ps_info->rx_hysterisis = 0; 618c2ecf20Sopenharmony_ci ps_info->monitor_interval = 0; 628c2ecf20Sopenharmony_ci ps_info->listen_interval = RSI_DEF_LISTEN_INTERVAL; 638c2ecf20Sopenharmony_ci ps_info->num_bcns_per_lis_int = 0; 648c2ecf20Sopenharmony_ci ps_info->dtim_interval_duration = 0; 658c2ecf20Sopenharmony_ci ps_info->num_dtims_per_sleep = 0; 668c2ecf20Sopenharmony_ci ps_info->deep_sleep_wakeup_period = RSI_DEF_DS_WAKEUP_PERIOD; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid rsi_enable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci if (adapter->ps_state != PS_NONE) { 728c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 738c2ecf20Sopenharmony_ci "%s: Cannot accept enable PS in %s state\n", 748c2ecf20Sopenharmony_ci __func__, str_psstate(adapter->ps_state)); 758c2ecf20Sopenharmony_ci return; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (rsi_send_ps_request(adapter, true, vif)) { 798c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 808c2ecf20Sopenharmony_ci "%s: Failed to send PS request to device\n", 818c2ecf20Sopenharmony_ci __func__); 828c2ecf20Sopenharmony_ci return; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci rsi_modify_ps_state(adapter, PS_ENABLE_REQ_SENT); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* This function is used to disable power save */ 898c2ecf20Sopenharmony_civoid rsi_disable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci if (adapter->ps_state != PS_ENABLED) { 928c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 938c2ecf20Sopenharmony_ci "%s: Cannot accept disable PS in %s state\n", 948c2ecf20Sopenharmony_ci __func__, str_psstate(adapter->ps_state)); 958c2ecf20Sopenharmony_ci return; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (rsi_send_ps_request(adapter, false, vif)) { 998c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 1008c2ecf20Sopenharmony_ci "%s: Failed to send PS request to device\n", 1018c2ecf20Sopenharmony_ci __func__); 1028c2ecf20Sopenharmony_ci return; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci rsi_modify_ps_state(adapter, PS_DISABLE_REQ_SENT); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_civoid rsi_conf_uapsd(struct rsi_hw *adapter, struct ieee80211_vif *vif) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int ret; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (adapter->ps_state != PS_ENABLED) 1138c2ecf20Sopenharmony_ci return; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ret = rsi_send_ps_request(adapter, false, vif); 1168c2ecf20Sopenharmony_ci if (!ret) 1178c2ecf20Sopenharmony_ci ret = rsi_send_ps_request(adapter, true, vif); 1188c2ecf20Sopenharmony_ci if (ret) 1198c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 1208c2ecf20Sopenharmony_ci "%s: Failed to send PS request to device\n", 1218c2ecf20Sopenharmony_ci __func__); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ciint rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci u16 cfm_type = get_unaligned_le16(msg + PS_CONFIRM_INDEX); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci switch (cfm_type) { 1298c2ecf20Sopenharmony_ci case RSI_SLEEP_REQUEST: 1308c2ecf20Sopenharmony_ci if (adapter->ps_state == PS_ENABLE_REQ_SENT) 1318c2ecf20Sopenharmony_ci rsi_modify_ps_state(adapter, PS_ENABLED); 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case RSI_WAKEUP_REQUEST: 1348c2ecf20Sopenharmony_ci if (adapter->ps_state == PS_DISABLE_REQ_SENT) 1358c2ecf20Sopenharmony_ci rsi_modify_ps_state(adapter, PS_NONE); 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci default: 1388c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 1398c2ecf20Sopenharmony_ci "Invalid PS confirm type %x in state %s\n", 1408c2ecf20Sopenharmony_ci cfm_type, str_psstate(adapter->ps_state)); 1418c2ecf20Sopenharmony_ci return -1; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 147