blob: 4330b4dede17c593af47e0b17ffea90c094cab31 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Amar Singhala297bfa2015-10-15 15:07:29 -07002 * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wma_power.c
30 * This file contains powersave related functions.
31 */
32
33/* Header files */
34
35#include "wma.h"
36#include "wma_api.h"
37#include "cds_api.h"
38#include "wmi_unified_api.h"
39#include "wlan_qct_sys.h"
40#include "wni_api.h"
41#include "ani_global.h"
42#include "wmi_unified.h"
43#include "wni_cfg.h"
44#include "cfg_api.h"
45#include "ol_txrx_ctrl_api.h"
46#include "wlan_tgt_def_config.h"
47
Nirav Shahcbc6d722016-03-01 16:24:53 +053048#include "qdf_nbuf.h"
Anurag Chouhan6d760662016-02-20 16:05:43 +053049#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080050#include "ol_txrx_api.h"
Anurag Chouhan600c3a02016-03-01 10:33:54 +053051#include "qdf_mem.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080052#include "ol_txrx_types.h"
53#include "ol_txrx_peer_find.h"
54
55#include "wma_types.h"
56#include "lim_api.h"
57#include "lim_session_utils.h"
58
59#include "cds_utils.h"
60
61#if !defined(REMOVE_PKT_LOG)
62#include "pktlog_ac.h"
63#endif /* REMOVE_PKT_LOG */
64
65#include "dbglog_host.h"
66#include "csr_api.h"
67#include "ol_fw.h"
68
69#include "dfs.h"
70#include "wma_internal.h"
71
72/**
73 * wmi_unified_modem_power_state() - set modem power state to fw
74 * @wmi_handle: wmi handle
75 * @param_value: parameter value
76 *
77 * Return: 0 for success or error code
78 */
79static int
80wmi_unified_modem_power_state(wmi_unified_t wmi_handle, uint32_t param_value)
81{
82 int ret;
83 wmi_modem_power_state_cmd_param *cmd;
84 wmi_buf_t buf;
85 uint16_t len = sizeof(*cmd);
86
87 buf = wmi_buf_alloc(wmi_handle, len);
88 if (!buf) {
89 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
90 return -ENOMEM;
91 }
92 cmd = (wmi_modem_power_state_cmd_param *) wmi_buf_data(buf);
93 WMITLV_SET_HDR(&cmd->tlv_header,
94 WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param,
95 WMITLV_GET_STRUCT_TLVLEN
96 (wmi_modem_power_state_cmd_param));
97 cmd->modem_power_state = param_value;
98 WMA_LOGD("%s: Setting cmd->modem_power_state = %u", __func__,
99 param_value);
100 ret = wmi_unified_cmd_send(wmi_handle, buf, len,
101 WMI_MODEM_POWER_STATE_CMDID);
102 if (ret != EOK) {
103 WMA_LOGE("Failed to send notify cmd ret = %d", ret);
104 wmi_buf_free(buf);
105 }
106 return ret;
107}
108
109/**
110 * wmi_unified_set_sta_ps_param() - set sta power save parameter to fw
111 * @wmi_handle: wmi handle
112 * @vdev_id: vdev id
113 * @param: param
114 * @value: parameter value
115 *
116 * Return: 0 for success or error code.
117 */
118int32_t wmi_unified_set_sta_ps_param(wmi_unified_t wmi_handle,
119 uint32_t vdev_id, uint32_t param,
120 uint32_t value)
121{
122 wmi_sta_powersave_param_cmd_fixed_param *cmd;
123 wmi_buf_t buf;
124 int32_t len = sizeof(*cmd);
125 tp_wma_handle wma;
126 struct wma_txrx_node *iface;
127
Anurag Chouhan6d760662016-02-20 16:05:43 +0530128 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800129 if (NULL == wma) {
130 WMA_LOGE("%s: wma is NULL", __func__);
131 return -EIO;
132 }
133 iface = &wma->interfaces[vdev_id];
134
135 WMA_LOGD("Set Sta Ps param vdevId %d Param %d val %d",
136 vdev_id, param, value);
137
138 buf = wmi_buf_alloc(wmi_handle, len);
139 if (!buf) {
140 WMA_LOGP("%s: Set Sta Ps param Mem Alloc Failed", __func__);
141 return -ENOMEM;
142 }
143
144 cmd = (wmi_sta_powersave_param_cmd_fixed_param *) wmi_buf_data(buf);
145 WMITLV_SET_HDR(&cmd->tlv_header,
146 WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param,
147 WMITLV_GET_STRUCT_TLVLEN
148 (wmi_sta_powersave_param_cmd_fixed_param));
149 cmd->vdev_id = vdev_id;
150 cmd->param = param;
151 cmd->value = value;
152
153 if (wmi_unified_cmd_send(wmi_handle, buf, len,
154 WMI_STA_POWERSAVE_PARAM_CMDID)) {
155 WMA_LOGE("Set Sta Ps param Failed vdevId %d Param %d val %d",
156 vdev_id, param, value);
Nirav Shahcbc6d722016-03-01 16:24:53 +0530157 qdf_nbuf_free(buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800158 return -EIO;
159 }
160 /* Store the PS Status */
161 iface->ps_enabled = value ? true : false;
162 return 0;
163}
164
165#ifdef QCA_IBSS_SUPPORT
166/**
167 * wma_set_ibss_pwrsave_params() - set ibss power save parameter to fw
168 * @wma: wma handle
169 * @vdev_id: vdev id
170 *
171 * Return: 0 for success or error code.
172 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530173QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174wma_set_ibss_pwrsave_params(tp_wma_handle wma, uint8_t vdev_id)
175{
176 int ret;
177
178 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
179 WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH,
180 wma->wma_ibss_power_save_params.atimWindowLength);
181 if (ret < 0) {
182 WMA_LOGE("Failed to set WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH ret = %d",
183 ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530184 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185 }
186
187 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
188 WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED,
189 wma->wma_ibss_power_save_params.isPowerSaveAllowed);
190 if (ret < 0) {
191 WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED ret=%d",
192 ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530193 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194 }
195
196 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
197 WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED,
198 wma->wma_ibss_power_save_params.isPowerCollapseAllowed);
199 if (ret < 0) {
200 WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED ret=%d",
201 ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530202 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800203 }
204
205 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
206 WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED,
207 wma->wma_ibss_power_save_params.isAwakeonTxRxEnabled);
208 if (ret < 0) {
209 WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED ret=%d",
210 ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530211 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800212 }
213
214 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
215 WMI_VDEV_PARAM_INACTIVITY_CNT,
216 wma->wma_ibss_power_save_params.inactivityCount);
217 if (ret < 0) {
218 WMA_LOGE("Failed, set WMI_VDEV_PARAM_INACTIVITY_CNT ret=%d",
219 ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530220 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800221 }
222
223 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
224 WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS,
225 wma->wma_ibss_power_save_params.txSPEndInactivityTime);
226 if (ret < 0) {
227 WMA_LOGE("Failed, set WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS ret=%d",
228 ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530229 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800230 }
231
232 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
233 WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS,
234 wma->wma_ibss_power_save_params.ibssPsWarmupTime);
235 if (ret < 0) {
236 WMA_LOGE("Failed, set WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS ret=%d",
237 ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530238 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800239 }
240
241 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
242 WMI_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE,
243 wma->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable);
244 if (ret < 0) {
245 WMA_LOGE("Failed to set IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE ret=%d",
246 ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530247 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800248 }
249
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530250 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800251}
252#endif /* QCA_IBSS_SUPPORT */
253
254/**
255 * wmi_unified_set_ap_ps_param() - set ap powersave parameters
256 * @wma_ctx: wma context
257 * @vdev_id: vdev id
258 * @peer_addr: peer mac address
259 * @param: parameter
260 * @value: prameter value
261 *
262 * Return: 0 for success or error code
263 */
264static int32_t wmi_unified_set_ap_ps_param(void *wma_ctx, uint32_t vdev_id,
265 uint8_t *peer_addr, uint32_t param,
266 uint32_t value)
267{
268 tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx;
269 wmi_ap_ps_peer_cmd_fixed_param *cmd;
270 wmi_buf_t buf;
271 int32_t err;
272
273 buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
274 if (!buf) {
275 WMA_LOGE("Failed to allocate buffer to send set_ap_ps_param cmd");
276 return -ENOMEM;
277 }
278 cmd = (wmi_ap_ps_peer_cmd_fixed_param *) wmi_buf_data(buf);
279 WMITLV_SET_HDR(&cmd->tlv_header,
280 WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param,
281 WMITLV_GET_STRUCT_TLVLEN
282 (wmi_ap_ps_peer_cmd_fixed_param));
283 cmd->vdev_id = vdev_id;
284 WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr);
285 cmd->param = param;
286 cmd->value = value;
287 err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
288 sizeof(*cmd), WMI_AP_PS_PEER_PARAM_CMDID);
289 if (err) {
290 WMA_LOGE("Failed to send set_ap_ps_param cmd");
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530291 qdf_mem_free(buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800292 return -EIO;
293 }
294 return 0;
295}
296
297/**
298 * wma_set_ap_peer_uapsd() - set powersave parameters in ap mode to fw
299 * @wma: wma handle
300 * @vdev_id: vdev id
301 * @peer_addr: peer mac address
302 * @uapsd_value: uapsd value
303 * @max_sp: maximum service period
304 *
305 * Return: 0 for success or error code.
306 */
307int32_t wma_set_ap_peer_uapsd(tp_wma_handle wma, uint32_t vdev_id,
308 uint8_t *peer_addr, uint8_t uapsd_value,
309 uint8_t max_sp)
310{
311 uint32_t uapsd = 0;
312 uint32_t max_sp_len = 0;
313 int32_t ret = 0;
314
315 if (uapsd_value & UAPSD_VO_ENABLED) {
316 uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
317 WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
318 }
319
320 if (uapsd_value & UAPSD_VI_ENABLED) {
321 uapsd |= WMI_AP_PS_UAPSD_AC2_DELIVERY_EN |
322 WMI_AP_PS_UAPSD_AC2_TRIGGER_EN;
323 }
324
325 if (uapsd_value & UAPSD_BK_ENABLED) {
326 uapsd |= WMI_AP_PS_UAPSD_AC1_DELIVERY_EN |
327 WMI_AP_PS_UAPSD_AC1_TRIGGER_EN;
328 }
329
330 if (uapsd_value & UAPSD_BE_ENABLED) {
331 uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN |
332 WMI_AP_PS_UAPSD_AC0_TRIGGER_EN;
333 }
334
335 switch (max_sp) {
336 case UAPSD_MAX_SP_LEN_2:
337 max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_2;
338 break;
339 case UAPSD_MAX_SP_LEN_4:
340 max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_4;
341 break;
342 case UAPSD_MAX_SP_LEN_6:
343 max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_6;
344 break;
345 default:
346 max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_UNLIMITED;
347 break;
348 }
349
350 WMA_LOGD("Set WMI_AP_PS_PEER_PARAM_UAPSD 0x%x for %pM",
351 uapsd, peer_addr);
352
353 ret = wmi_unified_set_ap_ps_param(wma, vdev_id,
354 peer_addr,
355 WMI_AP_PS_PEER_PARAM_UAPSD, uapsd);
356 if (ret) {
357 WMA_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_UAPSD for %pM",
358 peer_addr);
359 return ret;
360 }
361
362 WMA_LOGD("Set WMI_AP_PS_PEER_PARAM_MAX_SP 0x%x for %pM",
363 max_sp_len, peer_addr);
364
365 ret = wmi_unified_set_ap_ps_param(wma, vdev_id,
366 peer_addr,
367 WMI_AP_PS_PEER_PARAM_MAX_SP,
368 max_sp_len);
369 if (ret) {
370 WMA_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_MAX_SP for %pM",
371 peer_addr);
372 return ret;
373 }
374 return 0;
375}
376
377/**
378 * wma_update_edca_params_for_ac() - to update per ac EDCA parameters
379 * @edca_param: EDCA parameters
380 * @wmm_param: wmm parameters
381 * @ac: access category
382 *
383 * Return: none
384 */
385void wma_update_edca_params_for_ac(tSirMacEdcaParamRecord *edca_param,
386 wmi_wmm_vparams *wmm_param, int ac)
387{
388#define WMA_WMM_EXPO_TO_VAL(val) ((1 << (val)) - 1)
389 wmm_param->cwmin = WMA_WMM_EXPO_TO_VAL(edca_param->cw.min);
390 wmm_param->cwmax = WMA_WMM_EXPO_TO_VAL(edca_param->cw.max);
391 wmm_param->aifs = edca_param->aci.aifsn;
392 wmm_param->txoplimit = edca_param->txoplimit;
393 wmm_param->acm = edca_param->aci.acm;
394
395 /* TODO: No ack is not present in EdcaParamRecord */
396 wmm_param->no_ack = 0;
397
398 WMA_LOGI("WMM PARAMS AC[%d]: AIFS %d Min %d Max %d TXOP %d ACM %d NOACK %d",
399 ac, wmm_param->aifs, wmm_param->cwmin, wmm_param->cwmax,
400 wmm_param->txoplimit, wmm_param->acm, wmm_param->no_ack);
401}
402
403/**
404 * wma_set_tx_power() - set tx power limit in fw
405 * @handle: wma handle
406 * @tx_pwr_params: tx power parameters
407 *
408 * Return: none
409 */
410void wma_set_tx_power(WMA_HANDLE handle,
411 tMaxTxPowerParams *tx_pwr_params)
412{
413 tp_wma_handle wma_handle = (tp_wma_handle) handle;
414 uint8_t vdev_id;
415 int ret = -1;
416 void *pdev;
417
Anurag Chouhan6d760662016-02-20 16:05:43 +0530418 if (tx_pwr_params->dev_mode == QDF_SAP_MODE ||
419 tx_pwr_params->dev_mode == QDF_P2P_GO_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800420 pdev = wma_find_vdev_by_addr(wma_handle,
Srinivas Girigowda97215232015-09-24 12:26:28 -0700421 tx_pwr_params->bssId.bytes,
422 &vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423 } else {
424 pdev = wma_find_vdev_by_bssid(wma_handle,
Srinivas Girigowda97215232015-09-24 12:26:28 -0700425 tx_pwr_params->bssId.bytes,
426 &vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800427 }
428 if (!pdev) {
429 WMA_LOGE("vdev handle is invalid for %pM",
Srinivas Girigowda97215232015-09-24 12:26:28 -0700430 tx_pwr_params->bssId.bytes);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530431 qdf_mem_free(tx_pwr_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800432 return;
433 }
434
435 if (!(wma_handle->interfaces[vdev_id].vdev_up)) {
436 WMA_LOGE("%s: vdev id %d is not up for %pM", __func__, vdev_id,
Srinivas Girigowda97215232015-09-24 12:26:28 -0700437 tx_pwr_params->bssId.bytes);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530438 qdf_mem_free(tx_pwr_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800439 return;
440 }
441
442 if (tx_pwr_params->power == 0) {
443 /* set to default. Since the app does not care the tx power
444 * we keep the previous setting */
445 wma_handle->interfaces[vdev_id].tx_power = 0;
446 ret = 0;
447 goto end;
448 }
449 if (wma_handle->interfaces[vdev_id].max_tx_power != 0) {
450 /* make sure tx_power less than max_tx_power */
451 if (tx_pwr_params->power >
452 wma_handle->interfaces[vdev_id].max_tx_power) {
453 tx_pwr_params->power =
454 wma_handle->interfaces[vdev_id].max_tx_power;
455 }
456 }
457 if (wma_handle->interfaces[vdev_id].tx_power != tx_pwr_params->power) {
458
459 /* tx_power changed, Push the tx_power to FW */
460 WMA_LOGW("%s: Set TX power limit [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d",
461 __func__, tx_pwr_params->power);
462 ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
463 vdev_id,
464 WMI_VDEV_PARAM_TX_PWRLIMIT,
465 tx_pwr_params->power);
466 if (ret == 0)
467 wma_handle->interfaces[vdev_id].tx_power =
468 tx_pwr_params->power;
469 } else {
470 /* no tx_power change */
471 ret = 0;
472 }
473end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530474 qdf_mem_free(tx_pwr_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800475 if (ret)
476 WMA_LOGE("Failed to set vdev param WMI_VDEV_PARAM_TX_PWRLIMIT");
477}
478
479/**
480 * wma_set_max_tx_power() - set max tx power limit in fw
481 * @handle: wma handle
482 * @tx_pwr_params: tx power parameters
483 *
484 * Return: none
485 */
486void wma_set_max_tx_power(WMA_HANDLE handle,
487 tMaxTxPowerParams *tx_pwr_params)
488{
489 tp_wma_handle wma_handle = (tp_wma_handle) handle;
490 uint8_t vdev_id;
491 int ret = -1;
492 void *pdev;
Amar Singhala297bfa2015-10-15 15:07:29 -0700493 int8_t prev_max_power;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800494
Srinivas Girigowda97215232015-09-24 12:26:28 -0700495 pdev = wma_find_vdev_by_addr(wma_handle, tx_pwr_params->bssId.bytes,
496 &vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800497 if (pdev == NULL) {
498 /* not in SAP array. Try the station/p2p array */
499 pdev = wma_find_vdev_by_bssid(wma_handle,
Srinivas Girigowda97215232015-09-24 12:26:28 -0700500 tx_pwr_params->bssId.bytes,
501 &vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800502 }
503 if (!pdev) {
504 WMA_LOGE("vdev handle is invalid for %pM",
Srinivas Girigowda97215232015-09-24 12:26:28 -0700505 tx_pwr_params->bssId.bytes);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530506 qdf_mem_free(tx_pwr_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507 return;
508 }
509
510 if (!(wma_handle->interfaces[vdev_id].vdev_up)) {
511 WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530512 qdf_mem_free(tx_pwr_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800513 return;
514 }
515
516 if (wma_handle->interfaces[vdev_id].max_tx_power ==
517 tx_pwr_params->power) {
518 ret = 0;
519 goto end;
520 }
521 prev_max_power = wma_handle->interfaces[vdev_id].max_tx_power;
522 wma_handle->interfaces[vdev_id].max_tx_power = tx_pwr_params->power;
523 if (wma_handle->interfaces[vdev_id].max_tx_power == 0) {
524 ret = 0;
525 goto end;
526 }
527 WMA_LOGW("Set MAX TX power limit [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d",
528 wma_handle->interfaces[vdev_id].max_tx_power);
529 ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id,
530 WMI_VDEV_PARAM_TX_PWRLIMIT,
531 wma_handle->interfaces[vdev_id].max_tx_power);
532 if (ret == 0)
533 wma_handle->interfaces[vdev_id].tx_power =
534 wma_handle->interfaces[vdev_id].max_tx_power;
535 else
536 wma_handle->interfaces[vdev_id].max_tx_power = prev_max_power;
537end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530538 qdf_mem_free(tx_pwr_params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800539 if (ret)
540 WMA_LOGE("%s: Failed to set vdev param WMI_VDEV_PARAM_TX_PWRLIMIT",
541 __func__);
542}
543
544/**
545 * wmi_unified_set_sta_ps() - set sta powersave params in fw
546 * @handle: wma handle
547 * @vdev_id: vdev id
548 * @val: value
549 *
550 * Return: 0 for success or error code.
551 */
552int32_t wmi_unified_set_sta_ps(wmi_unified_t wmi_handle,
553 uint32_t vdev_id, uint8_t val)
554{
555 wmi_sta_powersave_mode_cmd_fixed_param *cmd;
556 wmi_buf_t buf;
557 int32_t len = sizeof(*cmd);
558
559 WMA_LOGD("Set Sta Mode Ps vdevId %d val %d", vdev_id, val);
560
561 buf = wmi_buf_alloc(wmi_handle, len);
562 if (!buf) {
563 WMA_LOGP("%s: Set Sta Mode Ps Mem Alloc Failed", __func__);
564 return -ENOMEM;
565 }
566 cmd = (wmi_sta_powersave_mode_cmd_fixed_param *) wmi_buf_data(buf);
567 WMITLV_SET_HDR(&cmd->tlv_header,
568 WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param,
569 WMITLV_GET_STRUCT_TLVLEN
570 (wmi_sta_powersave_mode_cmd_fixed_param));
571 cmd->vdev_id = vdev_id;
572 if (val)
573 cmd->sta_ps_mode = WMI_STA_PS_MODE_ENABLED;
574 else
575 cmd->sta_ps_mode = WMI_STA_PS_MODE_DISABLED;
576
577 if (wmi_unified_cmd_send(wmi_handle, buf, len,
578 WMI_STA_POWERSAVE_MODE_CMDID)) {
579 WMA_LOGE("Set Sta Mode Ps Failed vdevId %d val %d",
580 vdev_id, val);
Nirav Shahcbc6d722016-03-01 16:24:53 +0530581 qdf_nbuf_free(buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800582 return -EIO;
583 }
584 return 0;
585}
586
587/**
588 * wma_get_uapsd_mask() - get uapsd mask based on uapsd parameters
589 * @uapsd_params: uapsed parameters
590 *
591 * Return: uapsd mask
592 */
593static inline uint32_t wma_get_uapsd_mask(tpUapsd_Params uapsd_params)
594{
595 uint32_t uapsd_val = 0;
596
597 if (uapsd_params->beDeliveryEnabled)
598 uapsd_val |= WMI_STA_PS_UAPSD_AC0_DELIVERY_EN;
599
600 if (uapsd_params->beTriggerEnabled)
601 uapsd_val |= WMI_STA_PS_UAPSD_AC0_TRIGGER_EN;
602
603 if (uapsd_params->bkDeliveryEnabled)
604 uapsd_val |= WMI_STA_PS_UAPSD_AC1_DELIVERY_EN;
605
606 if (uapsd_params->bkTriggerEnabled)
607 uapsd_val |= WMI_STA_PS_UAPSD_AC1_TRIGGER_EN;
608
609 if (uapsd_params->viDeliveryEnabled)
610 uapsd_val |= WMI_STA_PS_UAPSD_AC2_DELIVERY_EN;
611
612 if (uapsd_params->viTriggerEnabled)
613 uapsd_val |= WMI_STA_PS_UAPSD_AC2_TRIGGER_EN;
614
615 if (uapsd_params->voDeliveryEnabled)
616 uapsd_val |= WMI_STA_PS_UAPSD_AC3_DELIVERY_EN;
617
618 if (uapsd_params->voTriggerEnabled)
619 uapsd_val |= WMI_STA_PS_UAPSD_AC3_TRIGGER_EN;
620
621 return uapsd_val;
622}
623
624/**
625 * wma_set_force_sleep() - set power save parameters to fw
626 * @wma: wma handle
627 * @vdev_id: vdev id
628 * @enable: enable/disable
629 * @qpower_config: qpower configuration
630 *
631 * Return: 0 for success or error code
632 */
633static int32_t wma_set_force_sleep(tp_wma_handle wma,
634 uint32_t vdev_id,
635 uint8_t enable,
636 enum powersave_qpower_mode qpower_config)
637{
638 int32_t ret;
639 uint32_t cfg_data_val = 0;
640 /* get mac to acess CFG data base */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530641 struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800642 uint32_t rx_wake_policy;
643 uint32_t tx_wake_threshold;
644 uint32_t pspoll_count;
645 uint32_t inactivity_time;
646 uint32_t psmode;
647
648 WMA_LOGD("Set Force Sleep vdevId %d val %d", vdev_id, enable);
649
650 if (NULL == mac) {
651 WMA_LOGE("%s: Unable to get PE context", __func__);
652 return -ENOMEM;
653 }
654
655 /* Set Tx/Rx Data InActivity Timeout */
656 if (wlan_cfg_get_int(mac, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT,
657 &cfg_data_val) != eSIR_SUCCESS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530658 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800659 "Failed to get WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT");
660 cfg_data_val = POWERSAVE_DEFAULT_INACTIVITY_TIME;
661 }
662 inactivity_time = (uint32_t) cfg_data_val;
663
664 if (enable) {
665 /* override normal configuration and force station asleep */
666 rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD;
667 tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER;
668
669 if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL,
670 &cfg_data_val) != eSIR_SUCCESS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530671 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800672 "Failed to get value for WNI_CFG_MAX_PS_POLL");
673 }
674 if (cfg_data_val)
675 pspoll_count = (uint32_t) cfg_data_val;
676 else
677 pspoll_count = WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE;
678
679 psmode = WMI_STA_PS_MODE_ENABLED;
680 } else {
681 /* Ps Poll Wake Policy */
682 if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL,
683 &cfg_data_val) != eSIR_SUCCESS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530684 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800685 "Failed to get value for WNI_CFG_MAX_PS_POLL");
686 }
687 if (cfg_data_val) {
688 /* Ps Poll is enabled */
689 rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD;
690 pspoll_count = (uint32_t) cfg_data_val;
691 tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER;
692 } else {
693 rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
694 pspoll_count = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
695 tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
696 }
697 psmode = WMI_STA_PS_MODE_ENABLED;
698 }
699
700 /*
701 * QPower is enabled by default in Firmware
702 * So Disable QPower explicitly
703 */
704 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
705 WMI_STA_PS_ENABLE_QPOWER,
706 qpower_config);
707 if (ret) {
708 WMA_LOGE("Disable QPower Failed vdevId %d", vdev_id);
709 return ret;
710 }
711 WMA_LOGD("QPower Disabled vdevId %d", vdev_id);
712
713 /* Set the Wake Policy to WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD */
714 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
715 WMI_STA_PS_PARAM_RX_WAKE_POLICY,
716 rx_wake_policy);
717
718 if (ret) {
719 WMA_LOGE("Setting wake policy Failed vdevId %d", vdev_id);
720 return ret;
721 }
722 WMA_LOGD("Setting wake policy to %d vdevId %d",
723 rx_wake_policy, vdev_id);
724
725 /* Set the Tx Wake Threshold */
726 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
727 WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD,
728 tx_wake_threshold);
729
730 if (ret) {
731 WMA_LOGE("Setting TxWake Threshold vdevId %d", vdev_id);
732 return ret;
733 }
734 WMA_LOGD("Setting TxWake Threshold to %d vdevId %d",
735 tx_wake_threshold, vdev_id);
736
737 /* Set the Ps Poll Count */
738 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
739 WMI_STA_PS_PARAM_PSPOLL_COUNT,
740 pspoll_count);
741
742 if (ret) {
743 WMA_LOGE("Set Ps Poll Count Failed vdevId %d ps poll cnt %d",
744 vdev_id, pspoll_count);
745 return ret;
746 }
747 WMA_LOGD("Set Ps Poll Count vdevId %d ps poll cnt %d",
748 vdev_id, pspoll_count);
749
750 /* Set the Tx/Rx InActivity */
751 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
752 WMI_STA_PS_PARAM_INACTIVITY_TIME,
753 inactivity_time);
754
755 if (ret) {
756 WMA_LOGE("Setting Tx/Rx InActivity Failed vdevId %d InAct %d",
757 vdev_id, inactivity_time);
758 return ret;
759 }
760 WMA_LOGD("Set Tx/Rx InActivity vdevId %d InAct %d",
761 vdev_id, inactivity_time);
762
763 /* Enable Sta Mode Power save */
764 ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, true);
765
766 if (ret) {
767 WMA_LOGE("Enable Sta Mode Ps Failed vdevId %d", vdev_id);
768 return ret;
769 }
770
771 /* Set Listen Interval */
772 if (wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL,
773 &cfg_data_val) != eSIR_SUCCESS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530774 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800775 "Failed to get value for WNI_CFG_LISTEN_INTERVAL");
776 cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL;
777 }
778
779 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
780 WMI_VDEV_PARAM_LISTEN_INTERVAL,
781 cfg_data_val);
782 if (ret) {
783 /* Even it fails continue Fw will take default LI */
784 WMA_LOGE("Failed to Set Listen Interval vdevId %d", vdev_id);
785 }
786 WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d",
787 vdev_id, cfg_data_val);
788 return 0;
789}
790
791/**
792 * wma_set_qpower_force_sleep() - set qpower params in fw
793 * @wma: wma handle
794 * @vdev_id: vdev id
795 * @enable: value
796 *
797 * Return: 0 for success or error code.
798 */
799int32_t wma_set_qpower_force_sleep(tp_wma_handle wma, uint32_t vdev_id,
800 uint8_t enable)
801{
802 int32_t ret;
803 uint32_t cfg_data_val = 0;
804 /* get mac to acess CFG data base */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530805 struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800806 uint32_t pspoll_count = WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE;
807
808 WMA_LOGE("Set QPower Force(1)/Normal(0) Sleep vdevId %d val %d",
809 vdev_id, enable);
810
811 if (NULL == mac) {
812 WMA_LOGE("%s: Unable to get PE context", __func__);
813 return -ENOMEM;
814 }
815
816 /* Get Configured Ps Poll Count */
817 if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL,
818 &cfg_data_val) != eSIR_SUCCESS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530819 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820 "Failed to get value for WNI_CFG_MAX_PS_POLL");
821 }
822 if (cfg_data_val) {
823 pspoll_count = (uint32_t) cfg_data_val;
824 }
825
826 /* Enable QPower */
827 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
828 WMI_STA_PS_ENABLE_QPOWER, 1);
829
830 if (ret) {
831 WMA_LOGE("Enable QPower Failed vdevId %d", vdev_id);
832 return ret;
833 }
834 WMA_LOGD("QPower Enabled vdevId %d", vdev_id);
835
836 /* Set the Wake Policy to WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD */
837 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
838 WMI_STA_PS_PARAM_RX_WAKE_POLICY,
839 WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD);
840
841 if (ret) {
842 WMA_LOGE("Setting wake policy to pspoll/uapsd Failed vdevId %d",
843 vdev_id);
844 return ret;
845 }
846 WMA_LOGD("Wake policy set to to pspoll/uapsd vdevId %d", vdev_id);
847
848 if (enable) {
849 /* Set the Tx Wake Threshold */
850 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
851 WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD,
852 WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER);
853
854 if (ret) {
855 WMA_LOGE("Setting TxWake Threshold vdevId %d", vdev_id);
856 return ret;
857 }
858 WMA_LOGD("TxWake Threshold set to TX_WAKE_THRESHOLD_NEVER %d",
859 vdev_id);
860 }
861
862 /* Set the QPower Ps Poll Count */
863 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
864 WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT,
865 pspoll_count);
866
867 if (ret) {
868 WMA_LOGE("Set QPower Ps Poll Count Failed vdevId %d ps poll cnt %d",
869 vdev_id, pspoll_count);
870 return ret;
871 }
872 WMA_LOGD("Set QPower Ps Poll Count vdevId %d ps poll cnt %d",
873 vdev_id, pspoll_count);
874
875 /* Enable Sta Mode Power save */
876 ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, true);
877
878 if (ret) {
879 WMA_LOGE("Enable Sta Mode Ps Failed vdevId %d", vdev_id);
880 return ret;
881 }
882
883 /* Set Listen Interval */
884 if (wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL,
885 &cfg_data_val) != eSIR_SUCCESS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530886 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800887 "Failed to get value for WNI_CFG_LISTEN_INTERVAL");
888 cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL;
889 }
890
891 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
892 WMI_VDEV_PARAM_LISTEN_INTERVAL,
893 cfg_data_val);
894 if (ret) {
895 /* Even it fails continue Fw will take default LI */
896 WMA_LOGE("Failed to Set Listen Interval vdevId %d", vdev_id);
897 }
898 WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d",
899 vdev_id, cfg_data_val);
900 return 0;
901}
902
903/**
904 * wma_get_qpower_config() - get qpower configuration
905 * @wma: WMA handle
906 *
907 * Power Save Offload configuration:
908 * 0 -> Power save offload is disabled
909 * 1 -> Legacy Power save enabled + Deep sleep Disabled
910 * 2 -> QPower enabled + Deep sleep Disabled
911 * 3 -> Legacy Power save enabled + Deep sleep Enabled
912 * 4 -> QPower enabled + Deep sleep Enabled
913 * 5 -> Duty cycling QPower enabled
914 *
915 * Return: enum powersave_qpower_mode with below values
916 * QPOWER_DISABLED if QPOWER is disabled
917 * QPOWER_ENABLED if QPOWER is enabled
918 * QPOWER_DUTY_CYCLING if DUTY CYCLING QPOWER is enabled
919 */
920static enum powersave_qpower_mode wma_get_qpower_config(tp_wma_handle wma)
921{
922 switch (wma->powersave_mode) {
923 case PS_QPOWER_NODEEPSLEEP:
924 case PS_QPOWER_DEEPSLEEP:
925 WMA_LOGI("QPOWER is enabled in power save mode %d",
926 wma->powersave_mode);
927 return QPOWER_ENABLED;
928 case PS_DUTY_CYCLING_QPOWER:
929 WMA_LOGI("DUTY cycling QPOWER is enabled in power save mode %d",
930 wma->powersave_mode);
931 return QPOWER_DUTY_CYCLING;
932
933 default:
934 WMA_LOGI("QPOWER is disabled in power save mode %d",
935 wma->powersave_mode);
936 return QPOWER_DISABLED;
937 }
938}
939
940/**
941 * wma_enable_sta_ps_mode() - enable sta powersave params in fw
942 * @wma: wma handle
943 * @ps_req: power save request
944 *
945 * Return: none
946 */
947void wma_enable_sta_ps_mode(tp_wma_handle wma, tpEnablePsParams ps_req)
948{
949 uint32_t vdev_id = ps_req->sessionid;
950 int32_t ret;
951 enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
952 struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
953 if (!iface->handle) {
954 WMA_LOGE("vdev id %d is not active", vdev_id);
955 return;
956 }
957 if (eSIR_ADDON_NOTHING == ps_req->psSetting) {
958 WMA_LOGD("Enable Sta Mode Ps vdevId %d", vdev_id);
959 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
960 WMI_STA_PS_PARAM_UAPSD, 0);
961 if (ret) {
962 WMA_LOGE("Set Uapsd param 0 Failed vdevId %d", vdev_id);
963 return;
964 }
965
966 ret = wma_set_force_sleep(wma, vdev_id, false,
967 qpower_config);
968 if (ret) {
969 WMA_LOGE("Enable Sta Ps Failed vdevId %d", vdev_id);
970 return;
971 }
972 } else if (eSIR_ADDON_ENABLE_UAPSD == ps_req->psSetting) {
973 uint32_t uapsd_val = 0;
974 uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams);
975
976 if (uapsd_val != iface->uapsd_cached_val) {
977 WMA_LOGD("Enable Uapsd vdevId %d Mask %d",
978 vdev_id, uapsd_val);
979 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
980 vdev_id,
981 WMI_STA_PS_PARAM_UAPSD,
982 uapsd_val);
983 if (ret) {
984 WMA_LOGE("Enable Uapsd Failed vdevId %d",
985 vdev_id);
986 return;
987 }
988 /* Cache the Uapsd Mask */
989 iface->uapsd_cached_val = uapsd_val;
990 } else {
991 WMA_LOGD("Already Uapsd Enabled vdevId %d Mask %d",
992 vdev_id, uapsd_val);
993 }
994
995 WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id);
996 ret = wma_set_force_sleep(wma, vdev_id, true,
997 qpower_config);
998
999 if (ret) {
1000 WMA_LOGE("Enable Forced Sleep Failed vdevId %d",
1001 vdev_id);
1002 return;
1003 }
1004 }
1005 iface->dtimPeriod = ps_req->bcnDtimPeriod;
1006}
1007
1008/**
1009 * wma_disable_sta_ps_mode() - disable sta powersave params in fw
1010 * @wma: wma handle
1011 * @ps_req: power save request
1012 *
1013 * Return: none
1014 */
1015void wma_disable_sta_ps_mode(tp_wma_handle wma, tpDisablePsParams ps_req)
1016{
1017 int32_t ret;
1018 uint32_t vdev_id = ps_req->sessionid;
1019
1020 WMA_LOGD("Disable Sta Mode Ps vdevId %d", vdev_id);
1021
1022 /* Disable Sta Mode Power save */
1023 ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false);
1024 if (ret) {
1025 WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id);
1026 return;
1027 }
1028
1029 /* Disable UAPSD incase if additional Req came */
1030 if (eSIR_ADDON_DISABLE_UAPSD == ps_req->psSetting) {
1031 WMA_LOGD("Disable Uapsd vdevId %d", vdev_id);
1032 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
1033 WMI_STA_PS_PARAM_UAPSD, 0);
1034 if (ret) {
1035 WMA_LOGE("Disable Uapsd Failed vdevId %d", vdev_id);
1036 /*
1037 * Even this fails we can proceed as success
1038 * since we disabled powersave
1039 */
1040 }
1041 }
1042}
1043
1044/**
1045 * wma_enable_uapsd_mode() - enable uapsd mode in fw
1046 * @wma: wma handle
1047 * @ps_req: power save request
1048 *
1049 * Return: none
1050 */
1051void wma_enable_uapsd_mode(tp_wma_handle wma, tpEnableUapsdParams ps_req)
1052{
1053 int32_t ret;
1054 uint32_t vdev_id = ps_req->sessionid;
1055 uint32_t uapsd_val = 0;
1056 enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
1057
1058 /* Disable Sta Mode Power save */
1059 ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false);
1060 if (ret) {
1061 WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id);
1062 return;
1063 }
1064
1065 uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams);
1066
1067 WMA_LOGD("Enable Uapsd vdevId %d Mask %d", vdev_id, uapsd_val);
1068 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
1069 WMI_STA_PS_PARAM_UAPSD, uapsd_val);
1070 if (ret) {
1071 WMA_LOGE("Enable Uapsd Failed vdevId %d", vdev_id);
1072 return;
1073 }
1074
1075 WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id);
1076 ret = wma_set_force_sleep(wma, vdev_id, true,
1077 qpower_config);
1078 if (ret) {
1079 WMA_LOGE("Enable Forced Sleep Failed vdevId %d", vdev_id);
1080 return;
1081 }
1082
1083}
1084
1085/**
1086 * wma_disable_uapsd_mode() - disable uapsd mode in fw
1087 * @wma: wma handle
1088 * @ps_req: power save request
1089 *
1090 * Return: none
1091 */
1092void wma_disable_uapsd_mode(tp_wma_handle wma,
1093 tpDisableUapsdParams ps_req)
1094{
1095 int32_t ret;
1096 uint32_t vdev_id = ps_req->sessionid;
1097 enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
1098
1099 WMA_LOGD("Disable Uapsd vdevId %d", vdev_id);
1100
1101 /* Disable Sta Mode Power save */
1102 ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false);
1103 if (ret) {
1104 WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id);
1105 return;
1106 }
1107
1108 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
1109 WMI_STA_PS_PARAM_UAPSD, 0);
1110 if (ret) {
1111 WMA_LOGE("Disable Uapsd Failed vdevId %d", vdev_id);
1112 return;
1113 }
1114
1115 /* Re enable Sta Mode Powersave with proper configuration */
1116 ret = wma_set_force_sleep(wma, vdev_id, false,
1117 qpower_config);
1118 if (ret) {
1119 WMA_LOGE("Disable Forced Sleep Failed vdevId %d", vdev_id);
1120 return;
1121 }
1122}
1123
1124/**
1125 * wmi_unified_set_sta_uapsd_auto_trig_cmd() - set uapsd auto trigger command
1126 * @wmi_handle: wma handle
1127 * @vdevid: vdev id
1128 * @peer_addr: peer mac address
1129 * @autoTriggerparam: auto trigger parameters
1130 * @num_ac: number of access category
1131 *
1132 * This function sets the trigger
1133 * uapsd params such as service interval, delay interval
1134 * and suspend interval which will be used by the firmware
1135 * to send trigger frames periodically when there is no
1136 * traffic on the transmit side.
1137 *
1138 * Return: 0 for success or error code.
1139 */
1140int32_t
1141wmi_unified_set_sta_uapsd_auto_trig_cmd(wmi_unified_t wmi_handle,
1142 uint32_t vdevid,
1143 uint8_t peer_addr[IEEE80211_ADDR_LEN],
1144 uint8_t *autoTriggerparam,
1145 uint32_t num_ac)
1146{
1147 wmi_sta_uapsd_auto_trig_cmd_fixed_param *cmd;
1148 int32_t ret;
1149 uint32_t param_len = num_ac * sizeof(wmi_sta_uapsd_auto_trig_param);
1150 uint32_t cmd_len = sizeof(*cmd) + param_len + WMI_TLV_HDR_SIZE;
1151 uint32_t i;
1152 wmi_buf_t buf;
1153 uint8_t *buf_ptr;
1154
1155 buf = wmi_buf_alloc(wmi_handle, cmd_len);
1156 if (!buf) {
1157 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
1158 return -ENOMEM;
1159 }
1160
1161 buf_ptr = (uint8_t *) wmi_buf_data(buf);
1162 cmd = (wmi_sta_uapsd_auto_trig_cmd_fixed_param *) buf_ptr;
1163 WMITLV_SET_HDR(&cmd->tlv_header,
1164 WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param,
1165 WMITLV_GET_STRUCT_TLVLEN
1166 (wmi_sta_uapsd_auto_trig_cmd_fixed_param));
1167 cmd->vdev_id = vdevid;
1168 cmd->num_ac = num_ac;
1169 WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr);
1170
1171 /* TLV indicating array of structures to follow */
1172 buf_ptr += sizeof(*cmd);
1173 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, param_len);
1174
1175 buf_ptr += WMI_TLV_HDR_SIZE;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301176 qdf_mem_copy(buf_ptr, autoTriggerparam, param_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001177
1178 /*
1179 * Update tag and length for uapsd auto trigger params (this will take
1180 * care of updating tag and length if it is not pre-filled by caller).
1181 */
1182 for (i = 0; i < num_ac; i++) {
1183 WMITLV_SET_HDR((buf_ptr +
1184 (i * sizeof(wmi_sta_uapsd_auto_trig_param))),
1185 WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_param,
1186 WMITLV_GET_STRUCT_TLVLEN
1187 (wmi_sta_uapsd_auto_trig_param));
1188 }
1189
1190 ret = wmi_unified_cmd_send(wmi_handle, buf, cmd_len,
1191 WMI_STA_UAPSD_AUTO_TRIG_CMDID);
1192 if (ret != EOK) {
1193 WMA_LOGE("Failed to send set uapsd param ret = %d", ret);
1194 wmi_buf_free(buf);
1195 }
1196 return ret;
1197}
1198
1199/**
1200 * wma_trigger_uapsd_params() - set trigger uapsd parameter
1201 * @wmi_handle: wma handle
1202 * @vdev_id: vdev id
1203 * @trigger_uapsd_params: trigger uapsd parameters
1204 *
1205 * This function sets the trigger uapsd
1206 * params such as service interval, delay
1207 * interval and suspend interval which
1208 * will be used by the firmware to send
1209 * trigger frames periodically when there
1210 * is no traffic on the transmit side.
1211 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301212 * Return: QDF_STATUS_SUCCESS for success or error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001213 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301214QDF_STATUS wma_trigger_uapsd_params(tp_wma_handle wma_handle, uint32_t vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001215 tp_wma_trigger_uapsd_params
1216 trigger_uapsd_params)
1217{
1218 int32_t ret;
1219 wmi_sta_uapsd_auto_trig_param uapsd_trigger_param;
1220
1221 WMA_LOGD("Trigger uapsd params vdev id %d", vdev_id);
1222
1223 WMA_LOGD("WMM AC %d User Priority %d SvcIntv %d DelIntv %d SusIntv %d",
1224 trigger_uapsd_params->wmm_ac,
1225 trigger_uapsd_params->user_priority,
1226 trigger_uapsd_params->service_interval,
1227 trigger_uapsd_params->delay_interval,
1228 trigger_uapsd_params->suspend_interval);
1229
1230 if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
1231 WMI_STA_UAPSD_BASIC_AUTO_TRIG) ||
1232 !WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
1233 WMI_STA_UAPSD_VAR_AUTO_TRIG)) {
1234 WMA_LOGD("Trigger uapsd is not supported vdev id %d", vdev_id);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301235 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 }
1237
1238 uapsd_trigger_param.wmm_ac = trigger_uapsd_params->wmm_ac;
1239 uapsd_trigger_param.user_priority = trigger_uapsd_params->user_priority;
1240 uapsd_trigger_param.service_interval =
1241 trigger_uapsd_params->service_interval;
1242 uapsd_trigger_param.suspend_interval =
1243 trigger_uapsd_params->suspend_interval;
1244 uapsd_trigger_param.delay_interval =
1245 trigger_uapsd_params->delay_interval;
1246
1247 ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle,
1248 vdev_id, wma_handle->interfaces[vdev_id].bssid,
1249 (uint8_t *) (&uapsd_trigger_param), 1);
1250 if (ret) {
1251 WMA_LOGE("Fail to send uapsd param cmd for vdevid %d ret = %d",
1252 ret, vdev_id);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301253 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301255 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001256}
1257
1258/**
1259 * wma_disable_uapsd_per_ac() - disable uapsd per ac
1260 * @wmi_handle: wma handle
1261 * @vdev_id: vdev id
1262 * @ac: access category
1263 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301264 * Return: QDF_STATUS_SUCCESS for success or error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301266QDF_STATUS wma_disable_uapsd_per_ac(tp_wma_handle wma_handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001267 uint32_t vdev_id, enum uapsd_ac ac)
1268{
1269 int32_t ret;
1270 struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id];
1271 wmi_sta_uapsd_auto_trig_param uapsd_trigger_param;
1272 enum uapsd_up user_priority;
1273
1274 WMA_LOGD("Disable Uapsd per ac vdevId %d ac %d", vdev_id, ac);
1275
1276 switch (ac) {
1277 case UAPSD_VO:
1278 iface->uapsd_cached_val &=
1279 ~(WMI_STA_PS_UAPSD_AC3_DELIVERY_EN |
1280 WMI_STA_PS_UAPSD_AC3_TRIGGER_EN);
1281 user_priority = UAPSD_UP_VO;
1282 break;
1283 case UAPSD_VI:
1284 iface->uapsd_cached_val &=
1285 ~(WMI_STA_PS_UAPSD_AC2_DELIVERY_EN |
1286 WMI_STA_PS_UAPSD_AC2_TRIGGER_EN);
1287 user_priority = UAPSD_UP_VI;
1288 break;
1289 case UAPSD_BK:
1290 iface->uapsd_cached_val &=
1291 ~(WMI_STA_PS_UAPSD_AC1_DELIVERY_EN |
1292 WMI_STA_PS_UAPSD_AC1_TRIGGER_EN);
1293 user_priority = UAPSD_UP_BK;
1294 break;
1295 case UAPSD_BE:
1296 iface->uapsd_cached_val &=
1297 ~(WMI_STA_PS_UAPSD_AC0_DELIVERY_EN |
1298 WMI_STA_PS_UAPSD_AC0_TRIGGER_EN);
1299 user_priority = UAPSD_UP_BE;
1300 break;
1301 default:
1302 WMA_LOGE("Invalid AC vdevId %d ac %d", vdev_id, ac);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301303 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001304 }
1305
1306 /*
1307 * Disable Auto Trigger Functionality before
1308 * disabling uapsd for a particular AC
1309 */
1310 uapsd_trigger_param.wmm_ac = ac;
1311 uapsd_trigger_param.user_priority = user_priority;
1312 uapsd_trigger_param.service_interval = 0;
1313 uapsd_trigger_param.suspend_interval = 0;
1314 uapsd_trigger_param.delay_interval = 0;
1315
1316 ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle,
1317 vdev_id, wma_handle->interfaces[vdev_id].bssid,
1318 (uint8_t *)(&uapsd_trigger_param), 1);
1319 if (ret) {
1320 WMA_LOGE("Fail to send auto trig cmd for vdevid %d ret = %d",
1321 ret, vdev_id);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301322 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001323 }
1324
1325 ret = wmi_unified_set_sta_ps_param(wma_handle->wmi_handle, vdev_id,
1326 WMI_STA_PS_PARAM_UAPSD,
1327 iface->uapsd_cached_val);
1328 if (ret) {
1329 WMA_LOGE("Disable Uapsd per ac Failed vdevId %d ac %d", vdev_id,
1330 ac);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301331 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001332 }
1333 WMA_LOGD("Disable Uapsd per ac vdevId %d val %d", vdev_id,
1334 iface->uapsd_cached_val);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301335 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001336}
1337
1338/**
1339 * wma_get_temperature() - get pdev temperature req
1340 * @wmi_handle: wma handle
1341 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301342 * Return: QDF_STATUS_SUCCESS for success or error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001343 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301344QDF_STATUS wma_get_temperature(tp_wma_handle wma_handle)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001345{
1346 wmi_pdev_get_temperature_cmd_fixed_param *cmd;
1347 wmi_buf_t wmi_buf;
1348 uint32_t len = sizeof(wmi_pdev_get_temperature_cmd_fixed_param);
1349 uint8_t *buf_ptr;
1350
1351 if (!wma_handle) {
1352 WMA_LOGE(FL("WMA is closed, can not issue cmd"));
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301353 return QDF_STATUS_E_INVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354 }
1355
1356 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
1357 if (!wmi_buf) {
1358 WMA_LOGE(FL("wmi_buf_alloc failed"));
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301359 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001360 }
1361
1362 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
1363
1364 cmd = (wmi_pdev_get_temperature_cmd_fixed_param *) buf_ptr;
1365 WMITLV_SET_HDR(&cmd->tlv_header,
1366 WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param,
1367 WMITLV_GET_STRUCT_TLVLEN
1368 (wmi_pdev_get_temperature_cmd_fixed_param));
1369
1370 if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
1371 WMI_PDEV_GET_TEMPERATURE_CMDID)) {
1372 WMA_LOGE(FL("failed to send get temperature command"));
1373 wmi_buf_free(wmi_buf);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301374 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001375 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301376 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377}
1378
1379/**
1380 * wma_pdev_temperature_evt_handler() - pdev temperature event handler
1381 * @handle: wma handle
1382 * @event: event buffer
1383 * @len : length
1384 *
1385 * Return: 0 for success or error code.
1386 */
1387int wma_pdev_temperature_evt_handler(void *handle, uint8_t *event,
1388 uint32_t len)
1389{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301390 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001391 cds_msg_t sme_msg = { 0 };
1392 WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *param_buf;
1393 wmi_pdev_temperature_event_fixed_param *wmi_event;
1394
1395 param_buf = (WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *) event;
1396 if (!param_buf) {
1397 WMA_LOGE("Invalid pdev_temperature event buffer");
1398 return -EINVAL;
1399 }
1400
1401 wmi_event = param_buf->fixed_param;
1402 WMA_LOGI(FL("temperature: %d"), wmi_event->value);
1403
1404 sme_msg.type = eWNI_SME_MSG_GET_TEMPERATURE_IND;
1405 sme_msg.bodyptr = NULL;
1406 sme_msg.bodyval = wmi_event->value;
1407
Anurag Chouhan6d760662016-02-20 16:05:43 +05301408 qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301409 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001410 WMA_LOGE(FL("Fail to post get temperature ind msg"));
1411 }
1412
1413 return 0;
1414}
1415
1416/**
1417 * wma_process_tx_power_limits() - sends the power limits for 2g/5g to firmware
1418 * @handle: wma handle
1419 * @ptxlim: power limit value
1420 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301421 * Return: QDF_STATUS_SUCCESS for success or error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001422 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301423QDF_STATUS wma_process_tx_power_limits(WMA_HANDLE handle,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001424 tSirTxPowerLimit *ptxlim)
1425{
1426 tp_wma_handle wma = (tp_wma_handle) handle;
1427 int32_t ret = 0;
1428 uint32_t txpower_params2g = 0;
1429 uint32_t txpower_params5g = 0;
1430
1431 if (!wma || !wma->wmi_handle) {
1432 WMA_LOGE("%s: WMA is closed, can not issue tx power limit",
1433 __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301434 return QDF_STATUS_E_INVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001435 }
1436 /* Set value and reason code for 2g and 5g power limit */
1437
1438 SET_PDEV_PARAM_TXPOWER_REASON(txpower_params2g,
1439 WMI_PDEV_PARAM_TXPOWER_REASON_SAR);
1440 SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params2g, ptxlim->txPower2g);
1441
1442 SET_PDEV_PARAM_TXPOWER_REASON(txpower_params5g,
1443 WMI_PDEV_PARAM_TXPOWER_REASON_SAR);
1444 SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params5g, ptxlim->txPower5g);
1445
1446 WMA_LOGD("%s: txpower2g: %x txpower5g: %x",
1447 __func__, txpower_params2g, txpower_params5g);
1448
1449 ret = wmi_unified_pdev_set_param(wma->wmi_handle,
1450 WMI_PDEV_PARAM_TXPOWER_LIMIT2G,
1451 txpower_params2g);
1452 if (ret) {
1453 WMA_LOGE("%s: Failed to set txpower 2g (%d)", __func__, ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301454 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001455 }
1456 ret = wmi_unified_pdev_set_param(wma->wmi_handle,
1457 WMI_PDEV_PARAM_TXPOWER_LIMIT5G,
1458 txpower_params5g);
1459 if (ret) {
1460 WMA_LOGE("%s: Failed to set txpower 5g (%d)", __func__, ret);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301461 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001462 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301463 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464}
1465
1466/**
1467 * wma_add_p2p_ie() - add p2p IE
1468 * @frm: ptr where p2p ie needs to add
1469 *
1470 * Return: ptr after p2p ie
1471 */
1472uint8_t *wma_add_p2p_ie(uint8_t *frm)
1473{
1474 uint8_t wfa_oui[3] = WMA_P2P_WFA_OUI;
1475 struct p2p_ie *p2p_ie = (struct p2p_ie *)frm;
1476
1477 p2p_ie->p2p_id = WMA_P2P_IE_ID;
1478 p2p_ie->p2p_oui[0] = wfa_oui[0];
1479 p2p_ie->p2p_oui[1] = wfa_oui[1];
1480 p2p_ie->p2p_oui[2] = wfa_oui[2];
1481 p2p_ie->p2p_oui_type = WMA_P2P_WFA_VER;
1482 p2p_ie->p2p_len = 4;
1483 return frm + sizeof(struct p2p_ie);
1484}
1485
1486/**
1487 * wma_update_beacon_noa_ie() - update beacon ie
1488 * @bcn: beacon info
1489 * @new_noa_sub_ie_len: ie length
1490 *
1491 * Return: none
1492 */
1493static void wma_update_beacon_noa_ie(struct beacon_info *bcn,
1494 uint16_t new_noa_sub_ie_len)
1495{
1496 struct p2p_ie *p2p_ie;
1497 uint8_t *buf;
1498
1499 /* if there is nothing to add, just return */
1500 if (new_noa_sub_ie_len == 0) {
1501 if (bcn->noa_sub_ie_len && bcn->noa_ie) {
1502 WMA_LOGD("%s: NoA is present in previous beacon, "
1503 "but not present in swba event, "
1504 "So Reset the NoA", __func__);
1505 /* TODO: Assuming p2p noa ie is last ie in the beacon */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301506 qdf_mem_zero(bcn->noa_ie, (bcn->noa_sub_ie_len +
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001507 sizeof(struct p2p_ie)));
1508 bcn->len -= (bcn->noa_sub_ie_len +
1509 sizeof(struct p2p_ie));
1510 bcn->noa_ie = NULL;
1511 bcn->noa_sub_ie_len = 0;
1512 }
1513 WMA_LOGD("%s: No need to update NoA", __func__);
1514 return;
1515 }
1516
1517 if (bcn->noa_sub_ie_len && bcn->noa_ie) {
1518 /* NoA present in previous beacon, update it */
1519 WMA_LOGD("%s: NoA present in previous beacon, "
1520 "update the NoA IE, bcn->len %u"
1521 "bcn->noa_sub_ie_len %u",
1522 __func__, bcn->len, bcn->noa_sub_ie_len);
1523 bcn->len -= (bcn->noa_sub_ie_len + sizeof(struct p2p_ie));
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301524 qdf_mem_zero(bcn->noa_ie,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001525 (bcn->noa_sub_ie_len + sizeof(struct p2p_ie)));
1526 } else { /* NoA is not present in previous beacon */
1527 WMA_LOGD("%s: NoA not present in previous beacon, add it"
1528 "bcn->len %u", __func__, bcn->len);
Nirav Shahcbc6d722016-03-01 16:24:53 +05301529 buf = qdf_nbuf_data(bcn->buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001530 bcn->noa_ie = buf + bcn->len;
1531 }
1532
1533 bcn->noa_sub_ie_len = new_noa_sub_ie_len;
1534 wma_add_p2p_ie(bcn->noa_ie);
1535 p2p_ie = (struct p2p_ie *)bcn->noa_ie;
1536 p2p_ie->p2p_len += new_noa_sub_ie_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301537 qdf_mem_copy((bcn->noa_ie + sizeof(struct p2p_ie)), bcn->noa_sub_ie,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001538 new_noa_sub_ie_len);
1539
1540 bcn->len += (new_noa_sub_ie_len + sizeof(struct p2p_ie));
1541 WMA_LOGI("%s: Updated beacon length with NoA Ie is %u",
1542 __func__, bcn->len);
1543}
1544
1545/**
1546 * wma_p2p_create_sub_ie_noa() - put p2p noa ie
1547 * @buf: buffer
1548 * @noa: noa element ie
1549 * @new_noa_sub_ie_len: ie length
1550 *
1551 * Return: none
1552 */
1553static void wma_p2p_create_sub_ie_noa(uint8_t *buf,
1554 struct p2p_sub_element_noa *noa,
1555 uint16_t *new_noa_sub_ie_len)
1556{
1557 uint8_t tmp_octet = 0;
1558 int i;
1559 uint8_t *buf_start = buf;
1560
1561 *buf++ = WMA_P2P_SUB_ELEMENT_NOA; /* sub-element id */
1562 ASSERT(noa->num_descriptors <= WMA_MAX_NOA_DESCRIPTORS);
1563
1564 /*
1565 * Length = (2 octets for Index and CTWin/Opp PS) and
1566 * (13 octets for each NOA Descriptors)
1567 */
1568 P2PIE_PUT_LE16(buf, WMA_NOA_IE_SIZE(noa->num_descriptors));
1569 buf += 2;
1570
1571 *buf++ = noa->index; /* Instance Index */
1572
1573 tmp_octet = noa->ctwindow & WMA_P2P_NOA_IE_CTWIN_MASK;
1574 if (noa->oppPS) {
1575 tmp_octet |= WMA_P2P_NOA_IE_OPP_PS_SET;
1576 }
1577 *buf++ = tmp_octet; /* Opp Ps and CTWin capabilities */
1578
1579 for (i = 0; i < noa->num_descriptors; i++) {
1580 ASSERT(noa->noa_descriptors[i].type_count != 0);
1581
1582 *buf++ = noa->noa_descriptors[i].type_count;
1583
1584 P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].duration);
1585 buf += 4;
1586 P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].interval);
1587 buf += 4;
1588 P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].start_time);
1589 buf += 4;
1590 }
1591 *new_noa_sub_ie_len = (buf - buf_start);
1592}
1593
1594/**
1595 * wma_update_noa() - update noa params
1596 * @beacon: beacon info
1597 * @noa_ie: noa ie
1598 *
1599 * Return: none
1600 */
1601void wma_update_noa(struct beacon_info *beacon,
1602 struct p2p_sub_element_noa *noa_ie)
1603{
1604 uint16_t new_noa_sub_ie_len;
1605
1606 /* Call this function by holding the spinlock on beacon->lock */
1607
1608 if (noa_ie) {
1609 if ((noa_ie->ctwindow == 0) && (noa_ie->oppPS == 0) &&
1610 (noa_ie->num_descriptors == 0)) {
1611 /* NoA is not present */
1612 WMA_LOGD("%s: NoA is not present", __func__);
1613 new_noa_sub_ie_len = 0;
1614 } else {
1615 /* Create the binary blob containing NOA sub-IE */
1616 WMA_LOGD("%s: Create NOA sub ie", __func__);
1617 wma_p2p_create_sub_ie_noa(&beacon->noa_sub_ie[0],
1618 noa_ie, &new_noa_sub_ie_len);
1619 }
1620 } else {
1621 WMA_LOGD("%s: No need to add NOA", __func__);
1622 new_noa_sub_ie_len = 0; /* no NOA IE sub-attributes */
1623 }
1624
1625 wma_update_beacon_noa_ie(beacon, new_noa_sub_ie_len);
1626}
1627
1628/**
1629 * wma_update_probe_resp_noa() - update noa IE in probe response
1630 * @wma_handle: wma handle
1631 * @noa_ie: noa ie
1632 *
1633 * Return: none
1634 */
1635void wma_update_probe_resp_noa(tp_wma_handle wma_handle,
1636 struct p2p_sub_element_noa *noa_ie)
1637{
1638 tSirP2PNoaAttr *noa_attr =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301639 (tSirP2PNoaAttr *) qdf_mem_malloc(sizeof(tSirP2PNoaAttr));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001640 WMA_LOGD("Received update NoA event");
1641 if (!noa_attr) {
1642 WMA_LOGE("Failed to allocate memory for tSirP2PNoaAttr");
1643 return;
1644 }
1645
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301646 qdf_mem_zero(noa_attr, sizeof(tSirP2PNoaAttr));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647
1648 noa_attr->index = noa_ie->index;
1649 noa_attr->oppPsFlag = noa_ie->oppPS;
1650 noa_attr->ctWin = noa_ie->ctwindow;
1651 if (!noa_ie->num_descriptors) {
1652 WMA_LOGD("Zero NoA descriptors");
1653 } else {
1654 WMA_LOGD("%d NoA descriptors", noa_ie->num_descriptors);
1655 noa_attr->uNoa1IntervalCnt =
1656 noa_ie->noa_descriptors[0].type_count;
1657 noa_attr->uNoa1Duration = noa_ie->noa_descriptors[0].duration;
1658 noa_attr->uNoa1Interval = noa_ie->noa_descriptors[0].interval;
1659 noa_attr->uNoa1StartTime =
1660 noa_ie->noa_descriptors[0].start_time;
1661 if (noa_ie->num_descriptors > 1) {
1662 noa_attr->uNoa2IntervalCnt =
1663 noa_ie->noa_descriptors[1].type_count;
1664 noa_attr->uNoa2Duration =
1665 noa_ie->noa_descriptors[1].duration;
1666 noa_attr->uNoa2Interval =
1667 noa_ie->noa_descriptors[1].interval;
1668 noa_attr->uNoa2StartTime =
1669 noa_ie->noa_descriptors[1].start_time;
1670 }
1671 }
1672 WMA_LOGI("Sending SIR_HAL_P2P_NOA_ATTR_IND to LIM");
1673 wma_send_msg(wma_handle, SIR_HAL_P2P_NOA_ATTR_IND, (void *)noa_attr, 0);
1674}
1675
1676/**
1677 * wma_p2p_noa_event_handler() - p2p noa event handler
1678 * @handle: wma handle
1679 * @event: event data
1680 * @len: length
1681 *
1682 * Return: 0 for success or error code.
1683 */
1684int wma_p2p_noa_event_handler(void *handle, uint8_t *event,
1685 uint32_t len)
1686{
1687 tp_wma_handle wma = (tp_wma_handle) handle;
1688 WMI_P2P_NOA_EVENTID_param_tlvs *param_buf;
1689 wmi_p2p_noa_event_fixed_param *p2p_noa_event;
1690 uint8_t vdev_id, i;
1691 wmi_p2p_noa_info *p2p_noa_info;
1692 struct p2p_sub_element_noa noa_ie;
1693 uint8_t *buf_ptr;
1694 uint32_t descriptors;
1695
1696 param_buf = (WMI_P2P_NOA_EVENTID_param_tlvs *) event;
1697 if (!param_buf) {
1698 WMA_LOGE("Invalid P2P NoA event buffer");
1699 return -EINVAL;
1700 }
1701
1702 p2p_noa_event = param_buf->fixed_param;
1703 buf_ptr = (uint8_t *) p2p_noa_event;
1704 buf_ptr += sizeof(wmi_p2p_noa_event_fixed_param);
1705 p2p_noa_info = (wmi_p2p_noa_info *) (buf_ptr);
1706 vdev_id = p2p_noa_event->vdev_id;
1707
1708 if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) {
1709
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301710 qdf_mem_zero(&noa_ie, sizeof(noa_ie));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711 noa_ie.index =
1712 (uint8_t) WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info);
1713 noa_ie.oppPS =
1714 (uint8_t) WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info);
1715 noa_ie.ctwindow =
1716 (uint8_t) WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info);
1717 descriptors = WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info);
1718 noa_ie.num_descriptors = (uint8_t) descriptors;
1719
1720 WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, "
1721 "num_descriptors = %u", __func__, noa_ie.index,
1722 noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors);
1723 for (i = 0; i < noa_ie.num_descriptors; i++) {
1724 noa_ie.noa_descriptors[i].type_count =
1725 (uint8_t) p2p_noa_info->noa_descriptors[i].
1726 type_count;
1727 noa_ie.noa_descriptors[i].duration =
1728 p2p_noa_info->noa_descriptors[i].duration;
1729 noa_ie.noa_descriptors[i].interval =
1730 p2p_noa_info->noa_descriptors[i].interval;
1731 noa_ie.noa_descriptors[i].start_time =
1732 p2p_noa_info->noa_descriptors[i].start_time;
1733 WMA_LOGI("%s: NoA descriptor[%d] type_count %u, "
1734 "duration %u, interval %u, start_time = %u",
1735 __func__, i,
1736 noa_ie.noa_descriptors[i].type_count,
1737 noa_ie.noa_descriptors[i].duration,
1738 noa_ie.noa_descriptors[i].interval,
1739 noa_ie.noa_descriptors[i].start_time);
1740 }
1741
1742 /* Send a msg to LIM to update the NoA IE in probe response
1743 * frames transmitted by the host */
1744 wma_update_probe_resp_noa(wma, &noa_ie);
1745 }
1746
1747 return 0;
1748}
1749
1750/**
1751 * wma_set_p2pgo_noa_req() - send p2p go noa request to fw
1752 * @wma: wma handle
1753 * @noa: p2p power save parameters
1754 *
1755 * Return: none
1756 */
1757static void wma_set_p2pgo_noa_req(tp_wma_handle wma, tP2pPsParams *noa)
1758{
1759 wmi_p2p_set_noa_cmd_fixed_param *cmd;
1760 wmi_p2p_noa_descriptor *noa_discriptor;
1761 wmi_buf_t buf;
1762 uint8_t *buf_ptr;
1763 uint16_t len;
1764 int32_t status;
1765 uint32_t duration;
1766
1767 WMA_LOGD("%s: Enter", __func__);
1768 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + sizeof(*noa_discriptor);
1769 buf = wmi_buf_alloc(wma->wmi_handle, len);
1770 if (!buf) {
1771 WMA_LOGE("Failed to allocate memory");
1772 goto end;
1773 }
1774
1775 buf_ptr = (uint8_t *) wmi_buf_data(buf);
1776 cmd = (wmi_p2p_set_noa_cmd_fixed_param *) buf_ptr;
1777 WMITLV_SET_HDR(&cmd->tlv_header,
1778 WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param,
1779 WMITLV_GET_STRUCT_TLVLEN
1780 (wmi_p2p_set_noa_cmd_fixed_param));
1781 duration = (noa->count == 1) ? noa->single_noa_duration : noa->duration;
1782 cmd->vdev_id = noa->sessionId;
1783 cmd->enable = (duration) ? true : false;
1784 cmd->num_noa = 1;
1785
1786 WMITLV_SET_HDR((buf_ptr + sizeof(wmi_p2p_set_noa_cmd_fixed_param)),
1787 WMITLV_TAG_ARRAY_STRUC, sizeof(wmi_p2p_noa_descriptor));
1788 noa_discriptor = (wmi_p2p_noa_descriptor *) (buf_ptr +
1789 sizeof
1790 (wmi_p2p_set_noa_cmd_fixed_param)
1791 + WMI_TLV_HDR_SIZE);
1792 WMITLV_SET_HDR(&noa_discriptor->tlv_header,
1793 WMITLV_TAG_STRUC_wmi_p2p_noa_descriptor,
1794 WMITLV_GET_STRUCT_TLVLEN(wmi_p2p_noa_descriptor));
1795 noa_discriptor->type_count = noa->count;
1796 noa_discriptor->duration = duration;
1797 noa_discriptor->interval = noa->interval;
1798 noa_discriptor->start_time = 0;
1799
1800 WMA_LOGI("SET P2P GO NOA:vdev_id:%d count:%d duration:%d interval:%d",
1801 cmd->vdev_id, noa->count, noa_discriptor->duration,
1802 noa->interval);
1803 status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
1804 WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID);
1805 if (status != EOK) {
1806 WMA_LOGE("Failed to send WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID");
1807 wmi_buf_free(buf);
1808 }
1809
1810end:
1811 WMA_LOGD("%s: Exit", __func__);
1812}
1813
1814/**
1815 * wma_set_p2pgo_oppps_req() - send p2p go opp power save request to fw
1816 * @wma: wma handle
1817 * @noa: p2p opp power save parameters
1818 *
1819 * Return: none
1820 */
1821static void wma_set_p2pgo_oppps_req(tp_wma_handle wma, tP2pPsParams *oppps)
1822{
1823 wmi_p2p_set_oppps_cmd_fixed_param *cmd;
1824 wmi_buf_t buf;
1825 int32_t status;
1826
1827 WMA_LOGD("%s: Enter", __func__);
1828 buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd));
1829 if (!buf) {
1830 WMA_LOGE("Failed to allocate memory");
1831 goto end;
1832 }
1833
1834 cmd = (wmi_p2p_set_oppps_cmd_fixed_param *) wmi_buf_data(buf);
1835 WMITLV_SET_HDR(&cmd->tlv_header,
1836 WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param,
1837 WMITLV_GET_STRUCT_TLVLEN
1838 (wmi_p2p_set_oppps_cmd_fixed_param));
1839 cmd->vdev_id = oppps->sessionId;
1840 if (oppps->ctWindow)
1841 WMI_UNIFIED_OPPPS_ATTR_ENABLED_SET(cmd);
1842
1843 WMI_UNIFIED_OPPPS_ATTR_CTWIN_SET(cmd, oppps->ctWindow);
1844 WMA_LOGI("SET P2P GO OPPPS:vdev_id:%d ctwindow:%d",
1845 cmd->vdev_id, oppps->ctWindow);
1846 status = wmi_unified_cmd_send(wma->wmi_handle, buf, sizeof(*cmd),
1847 WMI_P2P_SET_OPPPS_PARAM_CMDID);
1848 if (status != EOK) {
1849 WMA_LOGE("Failed to send WMI_P2P_SET_OPPPS_PARAM_CMDID");
1850 wmi_buf_free(buf);
1851 }
1852
1853end:
1854 WMA_LOGD("%s: Exit", __func__);
1855}
1856
1857/**
1858 * wma_process_set_p2pgo_noa_req() - process p2pgo noa request
1859 * @handle: wma handle
1860 * @ps_params: powersave params
1861 *
1862 * Return: none
1863 */
1864void wma_process_set_p2pgo_noa_req(tp_wma_handle wma,
1865 tP2pPsParams *ps_params)
1866{
1867 WMA_LOGD("%s: Enter", __func__);
1868 if (ps_params->opp_ps) {
1869 wma_set_p2pgo_oppps_req(wma, ps_params);
1870 } else {
1871 wma_set_p2pgo_noa_req(wma, ps_params);
1872 }
1873
1874 WMA_LOGD("%s: Exit", __func__);
1875}
1876
1877/**
1878 * wma_process_set_mimops_req() - Set the received MiMo PS state to firmware
1879 * @handle: wma handle
1880 * @mimops: MIMO powersave params
1881 *
1882 * Return: none
1883 */
1884void wma_process_set_mimops_req(tp_wma_handle wma_handle,
1885 tSetMIMOPS *mimops)
1886{
1887 /* Translate to what firmware understands */
1888 if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_DYNAMIC)
1889 mimops->htMIMOPSState = WMI_PEER_MIMO_PS_DYNAMIC;
1890 else if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_STATIC)
1891 mimops->htMIMOPSState = WMI_PEER_MIMO_PS_STATIC;
1892 else if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_NO_LIMIT)
1893 mimops->htMIMOPSState = WMI_PEER_MIMO_PS_NONE;
1894
1895 WMA_LOGD("%s: htMIMOPSState = %d, sessionId = %d \
1896 peerMac <%02x:%02x:%02x:%02x:%02x:%02x>", __func__,
1897 mimops->htMIMOPSState, mimops->sessionId, mimops->peerMac[0],
1898 mimops->peerMac[1], mimops->peerMac[2], mimops->peerMac[3],
1899 mimops->peerMac[4], mimops->peerMac[5]);
1900
1901 wma_set_peer_param(wma_handle, mimops->peerMac,
1902 WMI_PEER_MIMO_PS_STATE, mimops->htMIMOPSState,
1903 mimops->sessionId);
1904}
1905
1906/**
1907 * wma_set_mimops() - set MIMO powersave
1908 * @handle: wma handle
1909 * @vdev_id: vdev id
1910 * @value: value
1911 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301912 * Return: QDF_STATUS_SUCCESS for success or error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001913 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301914QDF_STATUS wma_set_mimops(tp_wma_handle wma, uint8_t vdev_id, int value)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001915{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301916 int ret = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001917 wmi_sta_smps_force_mode_cmd_fixed_param *cmd;
1918 wmi_buf_t buf;
1919 uint16_t len = sizeof(*cmd);
1920
1921 buf = wmi_buf_alloc(wma->wmi_handle, len);
1922 if (!buf) {
1923 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
1924 return -ENOMEM;
1925 }
1926 cmd = (wmi_sta_smps_force_mode_cmd_fixed_param *) wmi_buf_data(buf);
1927 WMITLV_SET_HDR(&cmd->tlv_header,
1928 WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param,
1929 WMITLV_GET_STRUCT_TLVLEN
1930 (wmi_sta_smps_force_mode_cmd_fixed_param));
1931
1932 cmd->vdev_id = vdev_id;
1933
1934 switch (value) {
1935 case 0:
1936 cmd->forced_mode = WMI_SMPS_FORCED_MODE_NONE;
1937 break;
1938 case 1:
1939 cmd->forced_mode = WMI_SMPS_FORCED_MODE_DISABLED;
1940 break;
1941 case 2:
1942 cmd->forced_mode = WMI_SMPS_FORCED_MODE_STATIC;
1943 break;
1944 case 3:
1945 cmd->forced_mode = WMI_SMPS_FORCED_MODE_DYNAMIC;
1946 break;
1947 default:
1948 WMA_LOGE("%s:INVALID Mimo PS CONFIG", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301949 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950 }
1951
1952 WMA_LOGD("Setting vdev %d value = %u", vdev_id, value);
1953
1954 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
1955 WMI_STA_SMPS_FORCE_MODE_CMDID);
1956 if (ret < 0) {
1957 WMA_LOGE("Failed to send set Mimo PS ret = %d", ret);
1958 wmi_buf_free(buf);
1959 }
1960
1961 return ret;
1962}
1963
1964/**
1965 * wma_notify_modem_power_state() - notify modem power state
1966 * @wma_ptr: wma handle
1967 * @pReq: modem power state
1968 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301969 * Return: QDF_STATUS_SUCCESS for success or error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301971QDF_STATUS wma_notify_modem_power_state(void *wma_ptr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972 tSirModemPowerStateInd *pReq)
1973{
1974 int32_t ret;
1975 tp_wma_handle wma = (tp_wma_handle) wma_ptr;
1976
1977 WMA_LOGD("%s: WMA notify Modem Power State %d", __func__, pReq->param);
1978
1979 ret = wmi_unified_modem_power_state(wma->wmi_handle, pReq->param);
1980 if (ret) {
1981 WMA_LOGE("%s: Fail to notify Modem Power State %d",
1982 __func__, pReq->param);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301983 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001984 }
1985
1986 WMA_LOGD("Successfully notify Modem Power State %d", pReq->param);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301987 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001988}
1989
1990/**
1991 * wma_set_idle_ps_config() - enable/disble Low Power Support(Pdev Specific)
1992 * @wma_ptr: wma handle
1993 * @idle_ps: idle powersave
1994 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301995 * Return: QDF_STATUS_SUCCESS for success or error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001996 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301997QDF_STATUS wma_set_idle_ps_config(void *wma_ptr, uint32_t idle_ps)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001998{
1999 int32_t ret;
2000 tp_wma_handle wma = (tp_wma_handle) wma_ptr;
2001
2002 WMA_LOGD("WMA Set Idle Ps Config [1:set 0:clear] val %d", idle_ps);
2003
2004 /* Set Idle Mode Power Save Config */
2005 ret = wmi_unified_pdev_set_param(wma->wmi_handle,
2006 WMI_PDEV_PARAM_IDLE_PS_CONFIG,
2007 idle_ps);
2008 if (ret) {
2009 WMA_LOGE("Fail to Set Idle Ps Config %d", idle_ps);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302010 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 }
2012
2013 WMA_LOGD("Successfully Set Idle Ps Config %d", idle_ps);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302014 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015}
2016
2017/**
2018 * wma_set_smps_params() - set smps params
2019 * @wma: wma handle
2020 * @vdev_id: vdev id
2021 * @value: value
2022 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302023 * Return: QDF_STATUS_SUCCESS for success or error code.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302025QDF_STATUS wma_set_smps_params(tp_wma_handle wma, uint8_t vdev_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002026 int value)
2027{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302028 int ret = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029 wmi_sta_smps_param_cmd_fixed_param *cmd;
2030 wmi_buf_t buf;
2031 uint16_t len = sizeof(*cmd);
2032
2033 buf = wmi_buf_alloc(wma->wmi_handle, len);
2034 if (!buf) {
2035 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
2036 return -ENOMEM;
2037 }
2038 cmd = (wmi_sta_smps_param_cmd_fixed_param *) wmi_buf_data(buf);
2039 WMITLV_SET_HDR(&cmd->tlv_header,
2040 WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param,
2041 WMITLV_GET_STRUCT_TLVLEN
2042 (wmi_sta_smps_param_cmd_fixed_param));
2043
2044 cmd->vdev_id = vdev_id;
2045 cmd->value = value & WMA_SMPS_MASK_LOWER_16BITS;
2046 cmd->param =
2047 (value >> WMA_SMPS_PARAM_VALUE_S) & WMA_SMPS_MASK_UPPER_3BITS;
2048
2049 WMA_LOGD("Setting vdev %d value = %x param %x", vdev_id, cmd->value,
2050 cmd->param);
2051
2052 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
2053 WMI_STA_SMPS_PARAM_CMDID);
2054 if (ret < 0) {
2055 WMA_LOGE("Failed to send set Mimo PS ret = %d", ret);
2056 wmi_buf_free(buf);
2057 }
2058
2059 return ret;
2060}
2061
2062/**
2063 * wma_set_vdev_suspend_dtim() - set suspend dtim parameters in fw
2064 * @wma: wma handle
2065 * @vdev_id: vdev id
2066 *
2067 * Return: none
2068 */
2069static void wma_set_vdev_suspend_dtim(tp_wma_handle wma, uint8_t vdev_id)
2070{
2071 struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
2072 enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
2073
2074 if ((iface->type == WMI_VDEV_TYPE_STA) &&
2075 (iface->ps_enabled == true) &&
2076 (iface->dtimPeriod != 0)) {
2077 int32_t ret;
2078 uint32_t listen_interval;
2079 uint32_t max_mod_dtim;
2080
2081 if (wma->staDynamicDtim) {
2082 listen_interval = wma->staDynamicDtim;
2083 } else if ((wma->staModDtim) &&
2084 (wma->staMaxLIModDtim)) {
2085 /*
2086 * When the system is in suspend
2087 * (maximum beacon will be at 1s == 10)
2088 * If maxModulatedDTIM ((MAX_LI_VAL = 10) / AP_DTIM)
2089 * equal or larger than MDTIM
2090 * (configured in WCNSS_qcom_cfg.ini)
2091 * Set LI to MDTIM * AP_DTIM
2092 * If Dtim = 2 and Mdtim = 2 then LI is 4
2093 * Else
2094 * Set LI to maxModulatedDTIM * AP_DTIM
2095 */
2096 max_mod_dtim = wma->staMaxLIModDtim / iface->dtimPeriod;
2097 if (max_mod_dtim >= wma->staModDtim) {
2098 listen_interval =
2099 (wma->staModDtim * iface->dtimPeriod);
2100 } else {
2101 listen_interval =
2102 (max_mod_dtim * iface->dtimPeriod);
2103 }
2104 } else {
2105 return;
2106 }
2107
2108 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2109 WMI_VDEV_PARAM_LISTEN_INTERVAL,
2110 listen_interval);
2111 if (ret) {
2112 /* Even it fails continue Fw will take default LI */
2113 WMA_LOGE("Failed to Set Listen Interval vdevId %d",
2114 vdev_id);
2115 }
2116
2117 WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d",
2118 vdev_id, listen_interval);
2119
2120 if (qpower_config) {
2121 WMA_LOGD("disable Qpower in suspend mode!");
2122 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
2123 vdev_id,
2124 WMI_STA_PS_ENABLE_QPOWER,
2125 0);
2126 if (ret)
2127 WMA_LOGE("Failed to disable Qpower in suspend mode!");
2128
2129 iface->ps_enabled = true;
2130 }
2131
2132 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2133 WMI_VDEV_PARAM_DTIM_POLICY,
2134 NORMAL_DTIM);
2135 if (ret)
2136 WMA_LOGE("Failed to Set to Normal DTIM vdevId %d",
2137 vdev_id);
2138
2139 /* Set it to Normal DTIM */
2140 iface->dtim_policy = NORMAL_DTIM;
2141 WMA_LOGD("Set DTIM Policy to Normal Dtim vdevId %d", vdev_id);
2142 }
2143}
2144
2145/**
2146 * wma_set_suspend_dtim() - set suspend dtim
2147 * @wma: wma handle
2148 *
2149 * Return: none
2150 */
2151void wma_set_suspend_dtim(tp_wma_handle wma)
2152{
2153 uint8_t i;
2154
2155 if (NULL == wma) {
2156 WMA_LOGE("%s: wma is NULL", __func__);
2157 return;
2158 }
2159
2160 for (i = 0; i < wma->max_bssid; i++) {
2161 if ((wma->interfaces[i].handle) &&
2162 (false == wma->interfaces[i].alt_modulated_dtim_enabled)) {
2163 wma_set_vdev_suspend_dtim(wma, i);
2164 }
2165 }
2166}
2167
2168/**
2169 * wma_set_vdev_resume_dtim() - set resume dtim parameters in fw
2170 * @wma: wma handle
2171 * @vdev_id: vdev id
2172 *
2173 * Return: none
2174 */
2175static void wma_set_vdev_resume_dtim(tp_wma_handle wma, uint8_t vdev_id)
2176{
2177 struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
2178 enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
2179
2180 if ((iface->type == WMI_VDEV_TYPE_STA) &&
2181 (iface->ps_enabled == true) &&
2182 (iface->dtim_policy == NORMAL_DTIM)) {
2183 int32_t ret;
2184 uint32_t cfg_data_val = 0;
2185 /* get mac to acess CFG data base */
Anurag Chouhan6d760662016-02-20 16:05:43 +05302186 struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002187 /* Set Listen Interval */
2188 if ((NULL == mac) || (wlan_cfg_get_int(mac,
2189 WNI_CFG_LISTEN_INTERVAL,
2190 &cfg_data_val) !=
2191 eSIR_SUCCESS)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302192 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002193 "Failed to get value for listen interval");
2194 cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL;
2195 }
2196
2197 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2198 WMI_VDEV_PARAM_LISTEN_INTERVAL,
2199 cfg_data_val);
2200 if (ret) {
2201 /* Even it fails continue Fw will take default LI */
2202 WMA_LOGE("Failed to Set Listen Interval vdevId %d",
2203 vdev_id);
2204 }
2205
2206 WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d",
2207 vdev_id, cfg_data_val);
2208
2209 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2210 WMI_VDEV_PARAM_DTIM_POLICY,
2211 STICK_DTIM);
2212 if (ret) {
2213 /* Set it back to Stick DTIM */
2214 WMA_LOGE("Failed to Set to Stick DTIM vdevId %d",
2215 vdev_id);
2216 }
2217 iface->dtim_policy = STICK_DTIM;
2218 WMA_LOGD("Set DTIM Policy to Stick Dtim vdevId %d", vdev_id);
2219
2220 if (qpower_config) {
2221 WMA_LOGD("enable Qpower in resume mode!");
2222 ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
2223 vdev_id,
2224 WMI_STA_PS_ENABLE_QPOWER,
2225 1);
2226 if (ret)
2227 WMA_LOGE("Failed to enable Qpower in resume mode!");
2228 }
2229 }
2230}
2231
2232/**
2233 * wma_set_resume_dtim() - set resume dtim
2234 * @wma: wma handle
2235 *
2236 * Return: none
2237 */
2238void wma_set_resume_dtim(tp_wma_handle wma)
2239{
2240 uint8_t i;
2241
2242 if (NULL == wma) {
2243 WMA_LOGE("%s: wma is NULL", __func__);
2244 return;
2245 }
2246
2247 for (i = 0; i < wma->max_bssid; i++) {
2248 if ((wma->interfaces[i].handle) &&
2249 (false == wma->interfaces[i].alt_modulated_dtim_enabled)) {
2250 wma_set_vdev_resume_dtim(wma, i);
2251 }
2252 }
2253}
2254
Peng Xu4d67c8f2015-10-16 16:02:26 -07002255/**
2256 * wma_set_tx_power_scale() - set tx power scale
2257 * @vdev_id: vdev id
2258 * @value: value
2259 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302260 * Return: QDF_STATUS_SUCCESS for success or error code.
Peng Xu4d67c8f2015-10-16 16:02:26 -07002261 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302262QDF_STATUS wma_set_tx_power_scale(uint8_t vdev_id, int value)
Peng Xu4d67c8f2015-10-16 16:02:26 -07002263{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302264 int ret = QDF_STATUS_SUCCESS;
Peng Xu4d67c8f2015-10-16 16:02:26 -07002265 tp_wma_handle wma_handle =
Anurag Chouhan6d760662016-02-20 16:05:43 +05302266 (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA);
Peng Xu4d67c8f2015-10-16 16:02:26 -07002267 if (NULL == wma_handle) {
2268 WMA_LOGE("%s: wma_handle is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302269 return QDF_STATUS_E_FAILURE;
Peng Xu4d67c8f2015-10-16 16:02:26 -07002270 }
2271
2272 if (!(wma_handle->interfaces[vdev_id].vdev_up)) {
2273 WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302274 return QDF_STATUS_E_FAILURE;
Peng Xu4d67c8f2015-10-16 16:02:26 -07002275 }
2276
2277 ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id,
2278 WMI_VDEV_PARAM_TXPOWER_SCALE, value);
2279 if (ret != 0)
2280 WMA_LOGE("Set tx power scale failed");
2281
2282 return ret;
2283}
2284
2285/**
2286 * wma_set_tx_power_scale_decr_db() - decrease power by DB value
2287 * @vdev_id: vdev id
2288 * @value: value
2289 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302290 * Return: QDF_STATUS_SUCCESS for success or error code.
Peng Xu4d67c8f2015-10-16 16:02:26 -07002291 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302292QDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value)
Peng Xu4d67c8f2015-10-16 16:02:26 -07002293{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302294 int ret = QDF_STATUS_SUCCESS;
Peng Xu4d67c8f2015-10-16 16:02:26 -07002295 tp_wma_handle wma_handle =
Anurag Chouhan6d760662016-02-20 16:05:43 +05302296 (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA);
Peng Xu4d67c8f2015-10-16 16:02:26 -07002297 if (NULL == wma_handle) {
2298 WMA_LOGE("%s: wma_handle is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302299 return QDF_STATUS_E_FAILURE;
Peng Xu4d67c8f2015-10-16 16:02:26 -07002300 }
2301
2302 if (!(wma_handle->interfaces[vdev_id].vdev_up)) {
2303 WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302304 return QDF_STATUS_E_FAILURE;
Peng Xu4d67c8f2015-10-16 16:02:26 -07002305 }
2306
2307 ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id,
2308 WMI_VDEV_PARAM_TXPOWER_SCALE_DECR_DB, value);
2309 if (ret != 0)
2310 WMA_LOGE("Decrease tx power value failed");
2311
2312 return ret;
2313}