blob: ecd5508dafd19bd7fd3ec062e9c219a38dbea808 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302 * 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_utis.c
30 * This file contains utilities and stats 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"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080045
Nirav Shahcbc6d722016-03-01 16:24:53 +053046#include "qdf_nbuf.h"
Anurag Chouhan6d760662016-02-20 16:05:43 +053047#include "qdf_types.h"
Anurag Chouhan600c3a02016-03-01 10:33:54 +053048#include "qdf_mem.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080049
50#include "wma_types.h"
51#include "lim_api.h"
52#include "lim_session_utils.h"
53
54#include "cds_utils.h"
55
56#if !defined(REMOVE_PKT_LOG)
57#include "pktlog_ac.h"
58#endif /* REMOVE_PKT_LOG */
59
60#include "dbglog_host.h"
61#include "csr_api.h"
62#include "ol_fw.h"
63
64#include "dfs.h"
65#include "wma_internal.h"
Chandrasekaran, Manishekar0d814c72015-11-05 10:42:48 +053066#include "cds_concurrency.h"
Govind Singhd76a5b02016-03-08 15:12:14 +053067#include "wmi_unified_param.h"
Naveen Rawatc0c91cd2015-11-05 14:27:37 -080068#include "linux/ieee80211.h"
69
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080070/* MCS Based rate table */
71/* HT MCS parameters with Nss = 1 */
Ryan Hsu6139d2d2015-11-04 17:29:00 -080072static struct index_data_rate_type mcs_nss1[] = {
73 /* MCS L20 S20 L40 S40 */
74 {0, {65, 72}, {135, 150 } },
75 {1, {130, 144}, {270, 300 } },
76 {2, {195, 217}, {405, 450 } },
77 {3, {260, 289}, {540, 600 } },
78 {4, {390, 433}, {815, 900 } },
79 {5, {520, 578}, {1080, 1200} },
80 {6, {585, 650}, {1215, 1350} },
81 {7, {650, 722}, {1350, 1500} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080082};
83
84/* HT MCS parameters with Nss = 2 */
Ryan Hsu6139d2d2015-11-04 17:29:00 -080085static struct index_data_rate_type mcs_nss2[] = {
86 /* MCS L20 S20 L40 S40 */
87 {0, {130, 144}, {270, 300 } },
88 {1, {260, 289}, {540, 600 } },
89 {2, {390, 433}, {810, 900 } },
90 {3, {520, 578}, {1080, 1200} },
91 {4, {780, 867}, {1620, 1800} },
92 {5, {1040, 1156}, {2160, 2400} },
93 {6, {1170, 1300}, {2430, 2700} },
94 {7, {1300, 1440}, {2700, 3000} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080095};
96
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080097/* MCS Based VHT rate table */
98/* MCS parameters with Nss = 1*/
Ryan Hsu6139d2d2015-11-04 17:29:00 -080099static struct index_vht_data_rate_type vht_mcs_nss1[] = {
100 /* MCS L20 S20 L40 S40 L80 S80 */
101 {0, {65, 72 }, {135, 150}, {293, 325} },
102 {1, {130, 144}, {270, 300}, {585, 650} },
103 {2, {195, 217}, {405, 450}, {878, 975} },
104 {3, {260, 289}, {540, 600}, {1170, 1300} },
105 {4, {390, 433}, {810, 900}, {1755, 1950} },
106 {5, {520, 578}, {1080, 1200}, {2340, 2600} },
107 {6, {585, 650}, {1215, 1350}, {2633, 2925} },
108 {7, {650, 722}, {1350, 1500}, {2925, 3250} },
109 {8, {780, 867}, {1620, 1800}, {3510, 3900} },
110 {9, {865, 960}, {1800, 2000}, {3900, 4333} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800111};
112
113/*MCS parameters with Nss = 2*/
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800114static struct index_vht_data_rate_type vht_mcs_nss2[] = {
115 /* MCS L20 S20 L40 S40 L80 S80 */
116 {0, {130, 144}, {270, 300}, { 585, 650} },
117 {1, {260, 289}, {540, 600}, {1170, 1300} },
118 {2, {390, 433}, {810, 900}, {1755, 1950} },
119 {3, {520, 578}, {1080, 1200}, {2340, 2600} },
120 {4, {780, 867}, {1620, 1800}, {3510, 3900} },
121 {5, {1040, 1156}, {2160, 2400}, {4680, 5200} },
122 {6, {1170, 1300}, {2430, 2700}, {5265, 5850} },
123 {7, {1300, 1444}, {2700, 3000}, {5850, 6500} },
124 {8, {1560, 1733}, {3240, 3600}, {7020, 7800} },
125 {9, {1730, 1920}, {3600, 4000}, {7800, 8667} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800126};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800127
128#ifdef BIG_ENDIAN_HOST
129
130/* ############# function definitions ############ */
131
132/**
133 * wma_swap_bytes() - swap bytes
134 * @pv: buffer
135 * @n: swap bytes
136 *
137 * Return: none
138 */
139void wma_swap_bytes(void *pv, uint32_t n)
140{
141 int32_t no_words;
142 int32_t i;
143 uint32_t *word_ptr;
144
145 no_words = n / sizeof(uint32_t);
146 word_ptr = (uint32_t *) pv;
147 for (i = 0; i < no_words; i++) {
148 *(word_ptr + i) = __cpu_to_le32(*(word_ptr + i));
149 }
150}
151
152#define SWAPME(x, len) wma_swap_bytes(&x, len);
153#endif /* BIG_ENDIAN_HOST */
154
155/**
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800156 * wma_mcs_rate_match() - find the match mcs rate
157 * @match_rate: the rate to look up
158 * @is_sgi: return if the SGI rate is found
159 * @nss: the nss in use
160 * @nss1_rate: the nss1 rate
161 * @nss1_srate: the nss1 SGI rate
162 * @nss2_rate: the nss2 rate
163 * @nss2_srate: the nss2 SGI rate
164 *
165 * This is a helper function to find the match of the tx_rate
166 * in terms of the nss1/nss2 rate with non-SGI/SGI.
167 *
168 * Return: the found rate or 0 otherwise
169 */
170static inline uint16_t wma_mcs_rate_match(uint16_t match_rate, bool *is_sgi,
171 uint8_t nss, uint16_t nss1_rate,
172 uint16_t nss1_srate,
173 uint16_t nss2_rate,
174 uint16_t nss2_srate)
175{
176 WMA_LOGD("%s match_rate: %d, %d %d %d %d",
177 __func__, match_rate, nss1_rate, nss1_srate, nss2_rate,
178 nss2_srate);
179
180 if (match_rate == nss1_rate) {
181 return nss1_rate;
182 } else if (match_rate == nss1_srate) {
183 *is_sgi = true;
184 return nss1_srate;
185 } else if (nss == 2 && match_rate == nss2_rate)
186 return nss2_rate;
187 else if (nss == 2 && match_rate == nss2_srate) {
188 *is_sgi = true;
189 return nss2_srate;
190 } else
191 return 0;
192}
193
194/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800195 * wma_get_mcs_idx() - get mcs index
196 * @maxRate: max rate
197 * @rate_flags: rate flags
198 * @nss: number of nss
199 * @mcsRateFlag: mcs rate flag
200 *
201 * Return: return mcs index
202 */
203static uint8_t wma_get_mcs_idx(uint16_t maxRate, uint8_t rate_flags,
204 uint8_t nss, uint8_t *mcsRateFlag)
205{
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800206 uint8_t index = 0;
Arif Hussainb8fef842016-07-19 09:43:13 -0700207 uint16_t match_rate = 0;
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800208 bool is_sgi = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800209
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800210 WMA_LOGD("%s rate:%d rate_flgs: 0x%x, nss: %d",
211 __func__, maxRate, rate_flags, nss);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800212
213 *mcsRateFlag = rate_flags;
214 *mcsRateFlag &= ~eHAL_TX_RATE_SGI;
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800215 for (index = 0; index < MAX_VHT_MCS_IDX; index++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216 if (rate_flags & eHAL_TX_RATE_VHT80) {
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800217 /* check for vht80 nss1/2 rate set */
218 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
219 vht_mcs_nss1[index].ht80_rate[0],
220 vht_mcs_nss1[index].ht80_rate[1],
221 vht_mcs_nss2[index].ht80_rate[0],
222 vht_mcs_nss2[index].ht80_rate[1]);
223 if (match_rate)
224 goto rate_found;
225 }
226 if ((rate_flags & eHAL_TX_RATE_VHT40) |
227 (rate_flags & eHAL_TX_RATE_VHT80)) {
228 /* check for vht40 nss1/2 rate set */
229 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
230 vht_mcs_nss1[index].ht40_rate[0],
231 vht_mcs_nss1[index].ht40_rate[1],
232 vht_mcs_nss2[index].ht40_rate[0],
233 vht_mcs_nss2[index].ht40_rate[1]);
234 if (match_rate) {
235 *mcsRateFlag &= ~eHAL_TX_RATE_VHT80;
236 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800237 }
238 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800239 if ((rate_flags & eHAL_TX_RATE_VHT20) |
240 (rate_flags & eHAL_TX_RATE_VHT40) |
241 (rate_flags & eHAL_TX_RATE_VHT80)) {
242 /* check for vht20 nss1/2 rate set */
243 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
244 vht_mcs_nss1[index].ht20_rate[0],
245 vht_mcs_nss1[index].ht20_rate[1],
246 vht_mcs_nss2[index].ht20_rate[0],
247 vht_mcs_nss2[index].ht20_rate[1]);
248 if (match_rate) {
249 *mcsRateFlag &= ~(eHAL_TX_RATE_VHT80 |
250 eHAL_TX_RATE_VHT40);
251 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800252 }
253 }
254 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800255 for (index = 0; index < MAX_HT_MCS_IDX; index++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256 if (rate_flags & eHAL_TX_RATE_HT40) {
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800257 /* check for ht40 nss1/2 rate set */
258 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
259 mcs_nss1[index].ht40_rate[0],
260 mcs_nss1[index].ht40_rate[1],
261 mcs_nss2[index].ht40_rate[0],
262 mcs_nss2[index].ht40_rate[1]);
263 if (match_rate) {
264 *mcsRateFlag = eHAL_TX_RATE_HT40;
265 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800266 }
267 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800268 if (rate_flags & eHAL_TX_RATE_HT20) {
269 /* check for ht20 nss1/2 rate set */
270 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
271 mcs_nss1[index].ht20_rate[0],
272 mcs_nss1[index].ht20_rate[1],
273 mcs_nss2[index].ht20_rate[0],
274 mcs_nss2[index].ht20_rate[1]);
275 if (match_rate) {
276 *mcsRateFlag = eHAL_TX_RATE_HT20;
277 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800278 }
279 }
280 }
281
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800282rate_found:
283 /* set SGI flag only if this is SGI rate */
284 if (match_rate && is_sgi == true)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800285 *mcsRateFlag |= eHAL_TX_RATE_SGI;
286
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800287 WMA_LOGD("%s - match_rate: %d index: %d rate_flag: 0x%x is_sgi: %d",
288 __func__, match_rate, index, *mcsRateFlag, is_sgi);
289
290 return match_rate ? index : INVALID_MCS_IDX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800291}
292
293/**
294 * host_map_smps_mode() - map fw smps mode to tSmpsModeValue
295 * @fw_smps_mode: fw smps mode
296 *
297 * Return: return tSmpsModeValue
298 */
299tSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode)
300{
301 tSmpsModeValue smps_mode = SMPS_MODE_DISABLED;
302 switch (fw_smps_mode) {
303 case WMI_SMPS_FORCED_MODE_STATIC:
304 smps_mode = STATIC_SMPS_MODE;
305 break;
306 case WMI_SMPS_FORCED_MODE_DYNAMIC:
307 smps_mode = DYNAMIC_SMPS_MODE;
308 break;
309 default:
310 smps_mode = SMPS_MODE_DISABLED;
311 }
312
313 return smps_mode;
314}
315
Archana Ramachandran20d2e232016-02-11 16:58:40 -0800316/**
317 * wma_smps_mode_to_force_mode_param() - Map smps mode to force
318 * mode commmand param
319 * @smps_mode: SMPS mode according to the protocol
320 *
321 * Return: int > 0 for success else failure
322 */
323int wma_smps_mode_to_force_mode_param(uint8_t smps_mode)
324{
325 int param = -EINVAL;
326
327 switch (smps_mode) {
328 case STATIC_SMPS_MODE:
329 param = WMI_SMPS_FORCED_MODE_STATIC;
330 break;
331 case DYNAMIC_SMPS_MODE:
332 param = WMI_SMPS_FORCED_MODE_DYNAMIC;
333 break;
334 case SMPS_MODE_DISABLED:
335 param = WMI_SMPS_FORCED_MODE_DISABLED;
336 break;
337 default:
338 WMA_LOGE(FL("smps mode cannot be mapped :%d "),
339 smps_mode);
340 }
341 return param;
342}
343
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800344#ifdef WLAN_FEATURE_STATS_EXT
345/**
346 * wma_stats_ext_event_handler() - extended stats event handler
347 * @handle: wma handle
348 * @event_buf: event buffer received from fw
349 * @len: length of data
350 *
351 * Return: 0 for success or error code
352 */
353int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf,
354 uint32_t len)
355{
356 WMI_STATS_EXT_EVENTID_param_tlvs *param_buf;
357 tSirStatsExtEvent *stats_ext_event;
358 wmi_stats_ext_event_fixed_param *stats_ext_info;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530359 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800360 cds_msg_t cds_msg;
361 uint8_t *buf_ptr;
362 uint32_t alloc_len;
363
364 WMA_LOGD("%s: Posting stats ext event to SME", __func__);
365
366 param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *) event_buf;
367 if (!param_buf) {
368 WMA_LOGE("%s: Invalid stats ext event buf", __func__);
369 return -EINVAL;
370 }
371
372 stats_ext_info = param_buf->fixed_param;
373 buf_ptr = (uint8_t *) stats_ext_info;
374
375 alloc_len = sizeof(tSirStatsExtEvent);
376 alloc_len += stats_ext_info->data_len;
377
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530378 stats_ext_event = (tSirStatsExtEvent *) qdf_mem_malloc(alloc_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800379 if (NULL == stats_ext_event) {
380 WMA_LOGE("%s: Memory allocation failure", __func__);
381 return -ENOMEM;
382 }
383
384 buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE;
385
386 stats_ext_event->vdev_id = stats_ext_info->vdev_id;
387 stats_ext_event->event_data_len = stats_ext_info->data_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530388 qdf_mem_copy(stats_ext_event->event_data,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800389 buf_ptr, stats_ext_event->event_data_len);
390
391 cds_msg.type = eWNI_SME_STATS_EXT_EVENT;
392 cds_msg.bodyptr = (void *)stats_ext_event;
393 cds_msg.bodyval = 0;
394
395 status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530396 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800397 WMA_LOGE("%s: Failed to post stats ext event to SME", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530398 qdf_mem_free(stats_ext_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800399 return -EFAULT;
400 }
401
402 WMA_LOGD("%s: stats ext event Posted to SME", __func__);
403 return 0;
404}
405#endif /* WLAN_FEATURE_STATS_EXT */
406
Nirav Shah93e789e2016-04-14 19:47:43 +0530407
Govind Singha471e5e2015-10-12 17:11:14 +0530408/**
409 * wma_profile_data_report_event_handler() - fw profiling handler
410 * @handle: wma handle
411 * @event_buf: event buffer received from fw
412 * @len: length of data
413 *
414 * Return: 0 for success or error code
415 */
416int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf,
417 uint32_t len)
418{
419 WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *param_buf;
420 wmi_wlan_profile_ctx_t *profile_ctx;
421 wmi_wlan_profile_t *profile_data;
422 uint32_t i = 0;
423 uint32_t entries;
424 uint8_t *buf_ptr;
Nirav Shah93e789e2016-04-14 19:47:43 +0530425 char temp_str[150];
Govind Singha471e5e2015-10-12 17:11:14 +0530426 param_buf = (WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *) event_buf;
427
428 if (!param_buf) {
429 WMA_LOGE("%s: Invalid profile data event buf", __func__);
430 return -EINVAL;
431 }
432 profile_ctx = param_buf->profile_ctx;
433 buf_ptr = (uint8_t *)profile_ctx;
434 buf_ptr = buf_ptr + sizeof(wmi_wlan_profile_ctx_t) + WMI_TLV_HDR_SIZE;
435 profile_data = (wmi_wlan_profile_t *) buf_ptr;
436 entries = profile_ctx->bin_count;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530437 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Govind Singha471e5e2015-10-12 17:11:14 +0530438 "Profile data stats\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530439 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Govind Singha471e5e2015-10-12 17:11:14 +0530440 "TOT: %d\n"
441 "tx_msdu_cnt: %d\n"
442 "tx_mpdu_cnt: %d\n"
443 "tx_ppdu_cnt: %d\n"
444 "rx_msdu_cnt: %d\n"
445 "rx_mpdu_cnt: %d\n"
446 "bin_count: %d\n",
447 profile_ctx->tot,
448 profile_ctx->tx_msdu_cnt,
449 profile_ctx->tx_mpdu_cnt,
450 profile_ctx->tx_ppdu_cnt,
451 profile_ctx->rx_msdu_cnt,
452 profile_ctx->rx_mpdu_cnt,
453 profile_ctx->bin_count);
454
Nirav Shah93e789e2016-04-14 19:47:43 +0530455 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
456 "Profile ID: Count: TOT: Min: Max: hist_intvl: hist[0]: hist[1]:hist[2]");
457
Govind Singha471e5e2015-10-12 17:11:14 +0530458 for (i = 0; i < entries; i++) {
459 if (i == WMI_WLAN_PROFILE_MAX_BIN_CNT)
460 break;
Nirav Shah93e789e2016-04-14 19:47:43 +0530461 snprintf(temp_str, sizeof(temp_str),
462 " %d : %d : %d : %d : %d : %d : %d : %d : %d",
Govind Singha471e5e2015-10-12 17:11:14 +0530463 profile_data[i].id,
464 profile_data[i].cnt,
465 profile_data[i].tot,
466 profile_data[i].min,
467 profile_data[i].max,
468 profile_data[i].hist_intvl,
469 profile_data[i].hist[0],
470 profile_data[i].hist[1],
471 profile_data[i].hist[2]);
Nirav Shah93e789e2016-04-14 19:47:43 +0530472 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
473 "%s", temp_str);
Govind Singha471e5e2015-10-12 17:11:14 +0530474 }
475
476 return 0;
477}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800478
479#ifdef WLAN_FEATURE_LINK_LAYER_STATS
480
481/**
482 * wma_unified_link_peer_stats_event_handler() - peer stats event handler
483 * @handle: wma handle
484 * @cmd_param_info: data received with event from fw
485 * @len: length of data
486 *
487 * Return: 0 for success or error code
488 */
489static int wma_unified_link_peer_stats_event_handler(void *handle,
490 uint8_t *cmd_param_info,
491 uint32_t len)
492{
493 WMI_PEER_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
494 wmi_peer_stats_event_fixed_param *fixed_param;
495 wmi_peer_link_stats *peer_stats, *temp_peer_stats;
496 wmi_rate_stats *rate_stats;
497 tSirLLStatsResults *link_stats_results;
498 uint8_t *results, *t_peer_stats, *t_rate_stats;
Kondabattini, Ganesh32be0832016-08-09 15:19:50 +0530499 uint32_t count, num_rates = 0, rate_cnt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800500 uint32_t next_res_offset, next_peer_offset, next_rate_offset;
501 size_t peer_info_size, peer_stats_size, rate_stats_size;
502 size_t link_stats_results_size;
503
Anurag Chouhan6d760662016-02-20 16:05:43 +0530504 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800505
506 if (!pMac) {
507 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
508 return -EINVAL;
509 }
510
511 if (!pMac->sme.pLinkLayerStatsIndCallback) {
512 WMA_LOGD("%s: HDD callback is null", __func__);
513 return -EINVAL;
514 }
515
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800516 param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
517 if (!param_tlvs) {
518 WMA_LOGA("%s: Invalid stats event", __func__);
519 return -EINVAL;
520 }
521 /*
522 * cmd_param_info contains
523 * wmi_peer_stats_event_fixed_param fixed_param;
524 * num_peers * size of(struct wmi_peer_link_stats)
525 * num_rates * size of(struct wmi_rate_stats)
526 * num_rates is the sum of the rates of all the peers.
527 */
528 fixed_param = param_tlvs->fixed_param;
529 peer_stats = param_tlvs->peer_stats;
530 rate_stats = param_tlvs->peer_rate_stats;
531
532 if (!fixed_param || !peer_stats ||
533 (peer_stats->num_rates && !rate_stats)) {
534 WMA_LOGA("%s: Invalid param_tlvs for Peer Stats", __func__);
535 return -EINVAL;
536 }
537
538 /*
539 * num_rates - sum of the rates of all the peers
540 */
541 temp_peer_stats = (wmi_peer_link_stats *) peer_stats;
542 for (count = 0; count < fixed_param->num_peers; count++) {
543 num_rates += temp_peer_stats->num_rates;
544 temp_peer_stats++;
545 }
546
547 peer_stats_size = sizeof(tSirWifiPeerStat);
548 peer_info_size = sizeof(tSirWifiPeerInfo);
549 rate_stats_size = sizeof(tSirWifiRateStat);
550 link_stats_results_size =
551 sizeof(*link_stats_results) + peer_stats_size +
552 (fixed_param->num_peers * peer_info_size) +
553 (num_rates * rate_stats_size);
554
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530555 link_stats_results = qdf_mem_malloc(link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800556 if (NULL == link_stats_results) {
557 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
558 __func__, link_stats_results_size);
559 return -ENOMEM;
560 }
561
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530562 qdf_mem_zero(link_stats_results, link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800563
564 link_stats_results->paramId = WMI_LINK_STATS_ALL_PEER;
565 link_stats_results->rspId = fixed_param->request_id;
566 link_stats_results->ifaceId = 0;
567 link_stats_results->num_peers = fixed_param->num_peers;
568 link_stats_results->peer_event_number = fixed_param->peer_event_number;
569 link_stats_results->moreResultToFollow = fixed_param->more_data;
570
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530571 qdf_mem_copy(link_stats_results->results,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800572 &fixed_param->num_peers, peer_stats_size);
573
574 results = (uint8_t *) link_stats_results->results;
575 t_peer_stats = (uint8_t *) peer_stats;
576 t_rate_stats = (uint8_t *) rate_stats;
577 next_res_offset = peer_stats_size;
578 next_peer_offset = WMI_TLV_HDR_SIZE;
579 next_rate_offset = WMI_TLV_HDR_SIZE;
Kondabattini, Ganesh32be0832016-08-09 15:19:50 +0530580 for (rate_cnt = 0; rate_cnt < fixed_param->num_peers; rate_cnt++) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530581 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800582 t_peer_stats + next_peer_offset, peer_info_size);
583 next_res_offset += peer_info_size;
584
585 /* Copy rate stats associated with this peer */
586 for (count = 0; count < peer_stats->num_rates; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800587 rate_stats++;
588
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530589 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800590 t_rate_stats + next_rate_offset,
591 rate_stats_size);
592 next_res_offset += rate_stats_size;
593 next_rate_offset += sizeof(*rate_stats);
594 }
595 next_peer_offset += sizeof(*peer_stats);
596 peer_stats++;
597 }
598
599 /* call hdd callback with Link Layer Statistics
600 * vdev_id/ifacId in link_stats_results will be
601 * used to retrieve the correct HDD context
602 */
603 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
604 WMA_LINK_LAYER_STATS_RESULTS_RSP,
605 link_stats_results);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530606 qdf_mem_free(link_stats_results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800607
608 return 0;
609}
610
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700611/**
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700612 * wma_unified_radio_tx_mem_free() - Free radio tx power stats memory
613 * @handle: WMI handle
614 *
615 * Return: 0 on success, error number otherwise.
616 */
617static int wma_unified_radio_tx_mem_free(void *handle)
618{
619 tp_wma_handle wma_handle = (tp_wma_handle) handle;
620 tSirWifiRadioStat *rs_results;
621 uint32_t i = 0;
622
623 if (!wma_handle->link_stats_results)
624 return 0;
625
626 rs_results = (tSirWifiRadioStat *)&wma_handle->link_stats_results->results[0];
627 for (i = 0; i < wma_handle->link_stats_results->num_radio; i++) {
628 rs_results += i;
629 if (rs_results->tx_time_per_power_level) {
630 qdf_mem_free(rs_results->tx_time_per_power_level);
631 rs_results->tx_time_per_power_level = NULL;
632 }
633
634 if (rs_results->channels) {
635 qdf_mem_free(rs_results->channels);
636 rs_results->channels = NULL;
637 }
638 }
639
640 qdf_mem_free(wma_handle->link_stats_results);
641 wma_handle->link_stats_results = NULL;
642
643 return 0;
644}
645
646/**
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700647 * wma_unified_radio_tx_power_level_stats_event_handler() - tx power level stats
648 * @handle: WMI handle
649 * @cmd_param_info: command param info
650 * @len: Length of @cmd_param_info
651 *
652 * This is the WMI event handler function to receive radio stats tx
653 * power level stats.
654 *
655 * Return: 0 on success, error number otherwise.
656*/
657static int wma_unified_radio_tx_power_level_stats_event_handler(void *handle,
658 u_int8_t *cmd_param_info, u_int32_t len)
659{
660 tp_wma_handle wma_handle = (tp_wma_handle) handle;
661 WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *param_tlvs;
662 wmi_tx_power_level_stats_evt_fixed_param *fixed_param;
663 uint8_t *tx_power_level_values;
664 tSirLLStatsResults *link_stats_results;
665 tSirWifiRadioStat *rs_results;
666
667 tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE);
668
669 if (!mac) {
670 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
671 return -EINVAL;
672 }
673
674 if (!mac->sme.pLinkLayerStatsIndCallback) {
675 WMA_LOGD("%s: HDD callback is null", __func__);
676 return -EINVAL;
677 }
678
679 param_tlvs = (WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *)cmd_param_info;
680 if (!param_tlvs) {
681 WMA_LOGA("%s: Invalid tx power level stats event", __func__);
682 return -EINVAL;
683 }
684
685 fixed_param = param_tlvs->fixed_param;
686 if (!fixed_param) {
687 WMA_LOGA("%s: Invalid param_tlvs for Radio tx_power level Stats", __func__);
688 return -EINVAL;
689 }
690
691 link_stats_results = wma_handle->link_stats_results;
Srinivas Girigowda52cbce42016-10-25 14:11:58 -0700692 if (!link_stats_results) {
693 WMA_LOGA("%s: link_stats_results is NULL", __func__);
694 return -EINVAL;
695 }
696
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700697 WMA_LOGD("%s: tot_num_tx_pwr_lvls: %u num_tx_pwr_lvls: %u pwr_lvl_offset: %u radio_id: %u",
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700698 __func__, fixed_param->total_num_tx_power_levels,
699 fixed_param->num_tx_power_levels,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700700 fixed_param->power_level_offset,
701 fixed_param->radio_id);
702
703 rs_results = (tSirWifiRadioStat *) &link_stats_results->results[0] + fixed_param->radio_id;
704 tx_power_level_values = (uint8_t *) param_tlvs->tx_time_per_power_level;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700705
706 rs_results->total_num_tx_power_levels =
707 fixed_param->total_num_tx_power_levels;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700708 if (!rs_results->total_num_tx_power_levels) {
709 link_stats_results->nr_received++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700710 goto post_stats;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700711 }
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700712
713 if (!rs_results->tx_time_per_power_level) {
714 rs_results->tx_time_per_power_level = qdf_mem_malloc(
715 sizeof(uint32_t) *
716 rs_results->total_num_tx_power_levels);
717 if (!rs_results->tx_time_per_power_level) {
718 WMA_LOGA("%s: Mem alloc failed for tx power level stats", __func__);
719 /* In error case, atleast send the radio stats without
720 * tx_power_level stats */
721 rs_results->total_num_tx_power_levels = 0;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700722 link_stats_results->nr_received++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700723 goto post_stats;
724 }
725 }
726 qdf_mem_copy(&rs_results->tx_time_per_power_level[fixed_param->power_level_offset],
727 tx_power_level_values,
728 sizeof(uint32_t) * fixed_param->num_tx_power_levels);
729 if (rs_results->total_num_tx_power_levels ==
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700730 (fixed_param->num_tx_power_levels + fixed_param->power_level_offset)) {
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700731 link_stats_results->moreResultToFollow = 0;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700732 link_stats_results->nr_received++;
733 }
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700734
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700735 WMA_LOGD("%s: moreResultToFollow: %u nr: %u nr_received: %u",
736 __func__, link_stats_results->moreResultToFollow,
737 link_stats_results->num_radio,
738 link_stats_results->nr_received);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700739
740 /* If still data to receive, return from here */
741 if (link_stats_results->moreResultToFollow)
742 return 0;
743
744post_stats:
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700745 if (link_stats_results->num_radio != link_stats_results->nr_received) {
746 /* Not received all radio stats yet, don't post yet */
747 return 0;
748 }
749
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700750 /* call hdd callback with Link Layer Statistics
751 * vdev_id/ifacId in link_stats_results will be
752 * used to retrieve the correct HDD context
753 */
754 mac->sme.pLinkLayerStatsIndCallback(mac->hHdd,
755 WMA_LINK_LAYER_STATS_RESULTS_RSP,
756 link_stats_results);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700757 wma_unified_radio_tx_mem_free(handle);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700758
759 return 0;
760}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761
762/**
763 * wma_unified_link_radio_stats_event_handler() - radio link stats event handler
764 * @handle: wma handle
765 * @cmd_param_info: data received with event from fw
766 * @len: length of data
767 *
768 * Return: 0 for success or error code
769 */
770static int wma_unified_link_radio_stats_event_handler(void *handle,
771 uint8_t *cmd_param_info,
772 uint32_t len)
773{
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700774 tp_wma_handle wma_handle = (tp_wma_handle) handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800775 WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
776 wmi_radio_link_stats_event_fixed_param *fixed_param;
777 wmi_radio_link_stats *radio_stats;
778 wmi_channel_stats *channel_stats;
779 tSirLLStatsResults *link_stats_results;
780 uint8_t *results, *t_radio_stats, *t_channel_stats;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700781 uint32_t next_chan_offset, count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800782 size_t radio_stats_size, chan_stats_size;
783 size_t link_stats_results_size;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700784 tSirWifiRadioStat *rs_results;
785 tSirWifiChannelStats *chn_results;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800786
Anurag Chouhan6d760662016-02-20 16:05:43 +0530787 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800788
789 if (!pMac) {
790 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
791 return -EINVAL;
792 }
793
794 if (!pMac->sme.pLinkLayerStatsIndCallback) {
795 WMA_LOGD("%s: HDD callback is null", __func__);
796 return -EINVAL;
797 }
798
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800799 param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
800 if (!param_tlvs) {
801 WMA_LOGA("%s: Invalid stats event", __func__);
802 return -EINVAL;
803 }
804
805 /*
806 * cmd_param_info contains
807 * wmi_radio_link_stats_event_fixed_param fixed_param;
808 * size of(struct wmi_radio_link_stats);
809 * num_channels * size of(struct wmi_channel_stats)
810 */
811 fixed_param = param_tlvs->fixed_param;
812 radio_stats = param_tlvs->radio_stats;
813 channel_stats = param_tlvs->channel_stats;
814
815 if (!fixed_param || !radio_stats ||
816 (radio_stats->num_channels && !channel_stats)) {
817 WMA_LOGA("%s: Invalid param_tlvs for Radio Stats", __func__);
818 return -EINVAL;
819 }
820
821 radio_stats_size = sizeof(tSirWifiRadioStat);
822 chan_stats_size = sizeof(tSirWifiChannelStats);
823 link_stats_results_size = sizeof(*link_stats_results) +
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700824 fixed_param->num_radio * radio_stats_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800825
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700826 if (!wma_handle->link_stats_results) {
827 wma_handle->link_stats_results = qdf_mem_malloc(link_stats_results_size);
828 if (NULL == wma_handle->link_stats_results) {
829 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
830 __func__, link_stats_results_size);
831 return -ENOMEM;
832 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833 }
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700834 link_stats_results = wma_handle->link_stats_results;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800835
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700836 WMA_LOGD("Radio stats Fixed Param:");
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700837 WMA_LOGD("req_id: %u num_radio: %u more_radio_events: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800838 fixed_param->request_id, fixed_param->num_radio,
839 fixed_param->more_radio_events);
840
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700841 WMA_LOGD("Radio Info: radio_id: %u on_time: %u tx_time: %u rx_time: %u on_time_scan: %u "
842 "on_time_nbd: %u on_time_gscan: %u on_time_roam_scan: %u "
843 "on_time_pno_scan: %u on_time_hs20: %u num_channels: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800844 radio_stats->radio_id, radio_stats->on_time,
845 radio_stats->tx_time, radio_stats->rx_time,
846 radio_stats->on_time_scan, radio_stats->on_time_nbd,
847 radio_stats->on_time_gscan,
848 radio_stats->on_time_roam_scan,
849 radio_stats->on_time_pno_scan,
850 radio_stats->on_time_hs20, radio_stats->num_channels);
851
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800852 link_stats_results->paramId = WMI_LINK_STATS_RADIO;
853 link_stats_results->rspId = fixed_param->request_id;
854 link_stats_results->ifaceId = 0;
855 link_stats_results->num_radio = fixed_param->num_radio;
856 link_stats_results->peer_event_number = 0;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700857
858 /*
859 * Backward compatibility:
860 * There are firmware(s) which will send Radio stats only with
861 * more_radio_events set to 0 and firmware which sends Radio stats
862 * followed by tx_power level stats with more_radio_events set to 1.
863 * if more_radio_events is set to 1, buffer the radio stats and
864 * wait for tx_power_level stats.
865 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800866 link_stats_results->moreResultToFollow = fixed_param->more_radio_events;
867
868 results = (uint8_t *) link_stats_results->results;
869 t_radio_stats = (uint8_t *) radio_stats;
870 t_channel_stats = (uint8_t *) channel_stats;
871
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700872 rs_results = (tSirWifiRadioStat *) &results[0] + radio_stats->radio_id;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700873 rs_results->radio = radio_stats->radio_id;
874 rs_results->onTime = radio_stats->on_time;
875 rs_results->txTime = radio_stats->tx_time;
876 rs_results->rxTime = radio_stats->rx_time;
877 rs_results->onTimeScan = radio_stats->on_time_scan;
878 rs_results->onTimeNbd = radio_stats->on_time_nbd;
879 rs_results->onTimeGscan = radio_stats->on_time_gscan;
880 rs_results->onTimeRoamScan = radio_stats->on_time_roam_scan;
881 rs_results->onTimePnoScan = radio_stats->on_time_pno_scan;
882 rs_results->onTimeHs20 = radio_stats->on_time_hs20;
883 rs_results->total_num_tx_power_levels = 0;
884 rs_results->tx_time_per_power_level = NULL;
885 rs_results->numChannels = radio_stats->num_channels;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700886 rs_results->channels = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800887
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700888 if (rs_results->numChannels) {
889 rs_results->channels = (tSirWifiChannelStats *) qdf_mem_malloc(
890 radio_stats->num_channels *
891 chan_stats_size);
892 if (rs_results->channels == NULL) {
893 WMA_LOGD("%s: could not allocate mem for channel stats (size=%zu)",
894 __func__, radio_stats->num_channels * chan_stats_size);
895 wma_unified_radio_tx_mem_free(handle);
896 return -ENOMEM;
897 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700899 chn_results = (tSirWifiChannelStats *) &rs_results->channels[0];
900 next_chan_offset = WMI_TLV_HDR_SIZE;
901 WMA_LOGD("Channel Stats Info");
902 for (count = 0; count < radio_stats->num_channels; count++) {
903 WMA_LOGD("channel_width %u center_freq %u center_freq0 %u "
904 "center_freq1 %u radio_awake_time %u cca_busy_time %u",
905 channel_stats->channel_width,
906 channel_stats->center_freq,
907 channel_stats->center_freq0,
908 channel_stats->center_freq1,
909 channel_stats->radio_awake_time,
910 channel_stats->cca_busy_time);
911 channel_stats++;
912
913 qdf_mem_copy(chn_results,
914 t_channel_stats + next_chan_offset,
915 chan_stats_size);
916 chn_results++;
917 next_chan_offset += sizeof(*channel_stats);
918 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800919 }
920
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700921 if (link_stats_results->moreResultToFollow) {
922 /* More results coming, don't post yet */
923 return 0;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700924 } else {
925 link_stats_results->nr_received++;
926 }
927
928 if (link_stats_results->num_radio != link_stats_results->nr_received) {
929 /* Not received all radio stats yet, don't post yet */
930 return 0;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700931 }
932
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
934 WMA_LINK_LAYER_STATS_RESULTS_RSP,
935 link_stats_results);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700936 wma_unified_radio_tx_mem_free(handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800937
938 return 0;
939}
940
941/**
942 * wma_register_ll_stats_event_handler() - register link layer stats related
943 * event handler
944 * @wma_handle: wma handle
945 *
946 * Return: none
947 */
948void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle)
949{
950 if (NULL == wma_handle) {
951 WMA_LOGE("%s: wma_handle is NULL", __func__);
952 return;
953 }
954
955 wmi_unified_register_event_handler(wma_handle->wmi_handle,
Govind Singhd76a5b02016-03-08 15:12:14 +0530956 WMI_IFACE_LINK_STATS_EVENTID,
957 wma_unified_link_iface_stats_event_handler,
958 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800959 wmi_unified_register_event_handler(wma_handle->wmi_handle,
Govind Singhd76a5b02016-03-08 15:12:14 +0530960 WMI_PEER_LINK_STATS_EVENTID,
961 wma_unified_link_peer_stats_event_handler,
962 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800963 wmi_unified_register_event_handler(wma_handle->wmi_handle,
Govind Singhd76a5b02016-03-08 15:12:14 +0530964 WMI_RADIO_LINK_STATS_EVENTID,
965 wma_unified_link_radio_stats_event_handler,
966 WMA_RX_SERIALIZER_CTX);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700967 wmi_unified_register_event_handler(wma_handle->wmi_handle,
968 WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID,
969 wma_unified_radio_tx_power_level_stats_event_handler,
970 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800971
972 return;
973}
974
975
976/**
977 * wma_process_ll_stats_clear_req() - clear link layer stats
978 * @wma: wma handle
979 * @clearReq: ll stats clear request command params
980 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530981 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800982 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530983QDF_STATUS wma_process_ll_stats_clear_req
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800984 (tp_wma_handle wma, const tpSirLLStatsClearReq clearReq)
985{
Govind Singh4863da42016-03-08 11:45:00 +0530986 struct ll_stats_clear_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800987 int ret;
988
989 if (!clearReq || !wma) {
990 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530991 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800992 }
993
Govind Singh4863da42016-03-08 11:45:00 +0530994 cmd.stop_req = clearReq->stopReq;
995 cmd.sta_id = clearReq->staId;
996 cmd.stats_clear_mask = clearReq->statsClearReqMask;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800997
Govind Singh4863da42016-03-08 11:45:00 +0530998 ret = wmi_unified_process_ll_stats_clear_cmd(wma->wmi_handle, &cmd,
999 wma->interfaces[clearReq->staId].addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001000 if (ret) {
1001 WMA_LOGE("%s: Failed to send clear link stats req", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301002 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001003 }
1004
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301005 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006}
1007
1008/**
1009 * wma_process_ll_stats_set_req() - link layer stats set request
1010 * @wma: wma handle
1011 * @setReq: ll stats set request command params
1012 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301013 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301015QDF_STATUS wma_process_ll_stats_set_req
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001016 (tp_wma_handle wma, const tpSirLLStatsSetReq setReq)
1017{
Govind Singh4863da42016-03-08 11:45:00 +05301018 struct ll_stats_set_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001019 int ret;
1020
1021 if (!setReq || !wma) {
1022 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301023 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001024 }
1025
Govind Singh4863da42016-03-08 11:45:00 +05301026 cmd.mpdu_size_threshold = setReq->mpduSizeThreshold;
1027 cmd.aggressive_statistics_gathering =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 setReq->aggressiveStatisticsGathering;
1029
Govind Singh4863da42016-03-08 11:45:00 +05301030 ret = wmi_unified_process_ll_stats_set_cmd(wma->wmi_handle,
1031 &cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032 if (ret) {
1033 WMA_LOGE("%s: Failed to send set link stats request", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301034 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035 }
1036
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301037 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001038}
1039
1040/**
1041 * wma_process_ll_stats_get_req() - link layer stats get request
1042 * @wma:wma handle
1043 * @getReq:ll stats get request command params
1044 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301045 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301047QDF_STATUS wma_process_ll_stats_get_req
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001048 (tp_wma_handle wma, const tpSirLLStatsGetReq getReq)
1049{
Govind Singh4863da42016-03-08 11:45:00 +05301050 struct ll_stats_get_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001051 int ret;
1052
1053 if (!getReq || !wma) {
1054 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301055 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001056 }
1057
Selvaraj, Sridhar171e2252016-06-22 22:33:26 +05301058 if (!wma->interfaces[getReq->staId].vdev_active) {
1059 WMA_LOGE("%s: vdev not created yet", __func__);
1060 return QDF_STATUS_E_FAILURE;
1061 }
1062
Govind Singh4863da42016-03-08 11:45:00 +05301063 cmd.req_id = getReq->reqId;
1064 cmd.param_id_mask = getReq->paramIdMask;
1065 cmd.sta_id = getReq->staId;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001066
Govind Singh4863da42016-03-08 11:45:00 +05301067 ret = wmi_unified_process_ll_stats_get_cmd(wma->wmi_handle, &cmd,
1068 wma->interfaces[getReq->staId].addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069 if (ret) {
1070 WMA_LOGE("%s: Failed to send get link stats request", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301071 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001072 }
1073
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301074 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001075}
1076
1077/**
1078 * wma_unified_link_iface_stats_event_handler() - link iface stats event handler
1079 * @wma:wma handle
1080 * @cmd_param_info: data from event
1081 * @len: length
1082 *
1083 * Return: 0 for success or error code
1084 */
1085int wma_unified_link_iface_stats_event_handler(void *handle,
1086 uint8_t *cmd_param_info,
1087 uint32_t len)
1088{
1089 WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
1090 wmi_iface_link_stats_event_fixed_param *fixed_param;
1091 wmi_iface_link_stats *link_stats;
1092 wmi_wmm_ac_stats *ac_stats;
1093 tSirLLStatsResults *link_stats_results;
1094 uint8_t *results, *t_link_stats, *t_ac_stats;
1095 uint32_t next_res_offset, next_ac_offset, count;
1096 uint32_t roaming_offset, roaming_size;
1097 size_t link_stats_size, ac_stats_size, iface_info_size;
1098 size_t link_stats_results_size;
1099
Anurag Chouhan6d760662016-02-20 16:05:43 +05301100 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001101
1102 if (!pMac) {
1103 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
1104 return -EINVAL;
1105 }
1106
1107 if (!pMac->sme.pLinkLayerStatsIndCallback) {
1108 WMA_LOGD("%s: HDD callback is null", __func__);
1109 return -EINVAL;
1110 }
1111
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001112 param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
1113 if (!param_tlvs) {
1114 WMA_LOGA("%s: Invalid stats event", __func__);
1115 return -EINVAL;
1116 }
1117
1118 /*
1119 * cmd_param_info contains
1120 * wmi_iface_link_stats_event_fixed_param fixed_param;
1121 * wmi_iface_link_stats iface_link_stats;
1122 * iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats)
1123 */
1124 fixed_param = param_tlvs->fixed_param;
1125 link_stats = param_tlvs->iface_link_stats;
1126 ac_stats = param_tlvs->ac;
1127
1128 if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats)) {
1129 WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__);
1130 return -EINVAL;
1131 }
1132
1133 link_stats_size = sizeof(tSirWifiIfaceStat);
1134 iface_info_size = sizeof(tSirWifiInterfaceInfo);
1135 ac_stats_size = sizeof(tSirWifiWmmAcStat);
1136 link_stats_results_size = sizeof(*link_stats_results) + link_stats_size;
1137
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301138 link_stats_results = qdf_mem_malloc(link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001139 if (!link_stats_results) {
1140 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
1141 __func__, link_stats_results_size);
1142 return -ENOMEM;
1143 }
1144
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301145 qdf_mem_zero(link_stats_results, link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001146
1147 link_stats_results->paramId = WMI_LINK_STATS_IFACE;
1148 link_stats_results->rspId = fixed_param->request_id;
1149 link_stats_results->ifaceId = fixed_param->vdev_id;
1150 link_stats_results->num_peers = link_stats->num_peers;
1151 link_stats_results->peer_event_number = 0;
1152 link_stats_results->moreResultToFollow = 0;
1153
1154 results = (uint8_t *) link_stats_results->results;
1155 t_link_stats = (uint8_t *) link_stats;
1156 t_ac_stats = (uint8_t *) ac_stats;
1157
1158 /* Copy roaming state */
1159 roaming_offset = offsetof(tSirWifiInterfaceInfo, roaming);
1160 roaming_size = member_size(tSirWifiInterfaceInfo, roaming);
1161
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301162 qdf_mem_copy(results + roaming_offset, &link_stats->roam_state,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001163 roaming_size);
1164
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301165 qdf_mem_copy(results + iface_info_size,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001166 t_link_stats + WMI_TLV_HDR_SIZE,
1167 link_stats_size - iface_info_size -
1168 WIFI_AC_MAX * ac_stats_size);
1169
1170 next_res_offset = link_stats_size - WIFI_AC_MAX * ac_stats_size;
1171 next_ac_offset = WMI_TLV_HDR_SIZE;
1172
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001173 for (count = 0; count < link_stats->num_ac; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001174 ac_stats++;
1175
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301176 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001177 t_ac_stats + next_ac_offset, ac_stats_size);
1178 next_res_offset += ac_stats_size;
1179 next_ac_offset += sizeof(*ac_stats);
1180 }
1181
1182 /* call hdd callback with Link Layer Statistics
1183 * vdev_id/ifacId in link_stats_results will be
1184 * used to retrieve the correct HDD context
1185 */
1186 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
1187 WMA_LINK_LAYER_STATS_RESULTS_RSP,
1188 link_stats_results);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301189 qdf_mem_free(link_stats_results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001190
1191 return 0;
1192}
1193
1194#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
1195
1196/**
1197 * wma_update_pdev_stats() - update pdev stats
1198 * @wma: wma handle
1199 * @pdev_stats: pdev stats
1200 *
1201 * Return: none
1202 */
1203static void wma_update_pdev_stats(tp_wma_handle wma,
1204 wmi_pdev_stats *pdev_stats)
1205{
1206 tAniGetPEStatsRsp *stats_rsp_params;
1207 uint32_t temp_mask;
1208 uint8_t *stats_buf;
1209 tCsrGlobalClassAStatsInfo *classa_stats = NULL;
1210 struct wma_txrx_node *node;
1211 uint8_t i;
1212
1213 for (i = 0; i < wma->max_bssid; i++) {
1214 node = &wma->interfaces[i];
1215 stats_rsp_params = node->stats_rsp;
1216 if (stats_rsp_params) {
1217 node->fw_stats_set |= FW_PDEV_STATS_SET;
1218 WMA_LOGD("<---FW PDEV STATS received for vdevId:%d", i);
1219 stats_buf = (uint8_t *) (stats_rsp_params + 1);
1220 temp_mask = stats_rsp_params->statsMask;
1221 if (temp_mask & (1 << eCsrSummaryStats))
1222 stats_buf += sizeof(tCsrSummaryStatsInfo);
1223
1224 if (temp_mask & (1 << eCsrGlobalClassAStats)) {
1225 classa_stats =
1226 (tCsrGlobalClassAStatsInfo *) stats_buf;
1227 classa_stats->max_pwr = pdev_stats->chan_tx_pwr;
1228 }
1229 }
1230 }
1231}
1232
1233/**
1234 * wma_update_vdev_stats() - update vdev stats
1235 * @wma: wma handle
1236 * @vdev_stats: vdev stats
1237 *
1238 * Return: none
1239 */
1240static void wma_update_vdev_stats(tp_wma_handle wma,
1241 wmi_vdev_stats *vdev_stats)
1242{
1243 tAniGetPEStatsRsp *stats_rsp_params;
1244 tCsrSummaryStatsInfo *summary_stats = NULL;
1245 uint8_t *stats_buf;
1246 struct wma_txrx_node *node;
1247 uint8_t i;
1248 int8_t rssi = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301249 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001250 tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) wma->pGetRssiReq;
1251 cds_msg_t sme_msg = { 0 };
Varun Reddy Yeturu83ccb9b2016-06-29 11:55:41 -07001252 int8_t bcn_snr, dat_snr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253
Naveen Rawat2cb788d2016-10-11 17:44:44 -07001254 bcn_snr = vdev_stats->vdev_snr.bcn_snr;
1255 dat_snr = vdev_stats->vdev_snr.dat_snr;
1256 WMA_LOGD("vdev id %d beancon snr %d data snr %d",
1257 vdev_stats->vdev_id, bcn_snr, dat_snr);
1258
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001259 node = &wma->interfaces[vdev_stats->vdev_id];
1260 stats_rsp_params = node->stats_rsp;
1261 if (stats_rsp_params) {
1262 stats_buf = (uint8_t *) (stats_rsp_params + 1);
1263 node->fw_stats_set |= FW_VDEV_STATS_SET;
1264 WMA_LOGD("<---FW VDEV STATS received for vdevId:%d",
1265 vdev_stats->vdev_id);
1266 if (stats_rsp_params->statsMask & (1 << eCsrSummaryStats)) {
1267 summary_stats = (tCsrSummaryStatsInfo *) stats_buf;
1268 for (i = 0; i < 4; i++) {
1269 summary_stats->tx_frm_cnt[i] =
1270 vdev_stats->tx_frm_cnt[i];
1271 summary_stats->fail_cnt[i] =
1272 vdev_stats->fail_cnt[i];
1273 summary_stats->multiple_retry_cnt[i] =
1274 vdev_stats->multiple_retry_cnt[i];
1275 }
1276
1277 summary_stats->rx_frm_cnt = vdev_stats->rx_frm_cnt;
1278 summary_stats->rx_error_cnt = vdev_stats->rx_err_cnt;
1279 summary_stats->rx_discard_cnt =
1280 vdev_stats->rx_discard_cnt;
1281 summary_stats->ack_fail_cnt = vdev_stats->ack_fail_cnt;
1282 summary_stats->rts_succ_cnt = vdev_stats->rts_succ_cnt;
1283 summary_stats->rts_fail_cnt = vdev_stats->rts_fail_cnt;
Naveen Rawat2cb788d2016-10-11 17:44:44 -07001284 /* Update SNR and RSSI in SummaryStats */
1285 if (bcn_snr != WMA_TGT_INVALID_SNR) {
1286 summary_stats->snr = bcn_snr;
1287 summary_stats->rssi =
1288 bcn_snr + WMA_TGT_NOISE_FLOOR_DBM;
1289 } else if (dat_snr != WMA_TGT_INVALID_SNR) {
1290 summary_stats->snr = dat_snr;
1291 summary_stats->rssi =
1292 bcn_snr + WMA_TGT_NOISE_FLOOR_DBM;
1293 } else {
1294 summary_stats->snr = WMA_TGT_INVALID_SNR;
1295 summary_stats->rssi = 0;
1296 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001297 }
1298 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001299
1300 if (pGetRssiReq && pGetRssiReq->sessionId == vdev_stats->vdev_id) {
Varun Reddy Yeturu83ccb9b2016-06-29 11:55:41 -07001301 if ((bcn_snr == WMA_TGT_INVALID_SNR) &&
1302 (dat_snr == WMA_TGT_INVALID_SNR)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001303 /*
1304 * Firmware sends invalid snr till it sees
1305 * Beacon/Data after connection since after
1306 * vdev up fw resets the snr to invalid.
1307 * In this duartion Host will return the last know
1308 * rssi during connection.
1309 */
1310 WMA_LOGE("Invalid SNR from firmware");
1311
1312 } else {
Varun Reddy Yeturu83ccb9b2016-06-29 11:55:41 -07001313 if (bcn_snr != WMA_TGT_INVALID_SNR) {
1314 rssi = bcn_snr;
1315 } else if (dat_snr != WMA_TGT_INVALID_SNR) {
1316 rssi = dat_snr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001317 }
1318
1319 /*
1320 * Get the absolute rssi value from the current rssi value
1321 * the sinr value is hardcoded into 0 in the core stack
1322 */
1323 rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
1324 }
1325
1326 WMA_LOGD("Average Rssi = %d, vdev id= %d", rssi,
1327 pGetRssiReq->sessionId);
1328
1329 /* update the average rssi value to UMAC layer */
1330 if (NULL != pGetRssiReq->rssiCallback) {
1331 ((tCsrRssiCallback) (pGetRssiReq->rssiCallback))(rssi,
1332 pGetRssiReq->staId,
1333 pGetRssiReq->pDevContext);
1334 }
1335
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301336 qdf_mem_free(pGetRssiReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001337 wma->pGetRssiReq = NULL;
1338 }
1339
1340 if (node->psnr_req) {
1341 tAniGetSnrReq *p_snr_req = node->psnr_req;
1342
Varun Reddy Yeturu83ccb9b2016-06-29 11:55:41 -07001343 if (bcn_snr != WMA_TGT_INVALID_SNR)
1344 p_snr_req->snr = bcn_snr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001345 else
Naveen Rawat2cb788d2016-10-11 17:44:44 -07001346 p_snr_req->snr = dat_snr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001347
1348 sme_msg.type = eWNI_SME_SNR_IND;
1349 sme_msg.bodyptr = p_snr_req;
1350 sme_msg.bodyval = 0;
1351
Anurag Chouhan6d760662016-02-20 16:05:43 +05301352 qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301353 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354 WMA_LOGE("%s: Fail to post snr ind msg", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301355 qdf_mem_free(p_snr_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001356 }
1357
1358 node->psnr_req = NULL;
1359 }
1360}
1361
1362/**
1363 * wma_post_stats() - update stats to PE
1364 * @wma: wma handle
1365 * @node: txrx node
1366 *
1367 * Return: none
1368 */
1369static void wma_post_stats(tp_wma_handle wma, struct wma_txrx_node *node)
1370{
1371 tAniGetPEStatsRsp *stats_rsp_params;
1372
1373 stats_rsp_params = node->stats_rsp;
1374 /* send response to UMAC */
1375 wma_send_msg(wma, WMA_GET_STATISTICS_RSP, (void *)stats_rsp_params, 0);
1376 node->stats_rsp = NULL;
1377 node->fw_stats_set = 0;
1378}
1379
1380/**
1381 * wma_update_peer_stats() - update peer stats
1382 * @wma: wma handle
1383 * @peer_stats: peer stats
1384 *
1385 * Return: none
1386 */
1387static void wma_update_peer_stats(tp_wma_handle wma,
1388 wmi_peer_stats *peer_stats)
1389{
1390 tAniGetPEStatsRsp *stats_rsp_params;
1391 tCsrGlobalClassAStatsInfo *classa_stats = NULL;
1392 struct wma_txrx_node *node;
1393 uint8_t *stats_buf, vdev_id, macaddr[IEEE80211_ADDR_LEN], mcsRateFlags;
1394 uint32_t temp_mask;
1395
1396 WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, &macaddr[0]);
1397 if (!wma_find_vdev_by_bssid(wma, macaddr, &vdev_id))
1398 return;
1399
1400 node = &wma->interfaces[vdev_id];
1401 if (node->stats_rsp) {
1402 node->fw_stats_set |= FW_PEER_STATS_SET;
1403 WMA_LOGD("<-- FW PEER STATS received for vdevId:%d", vdev_id);
1404 stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp;
1405 stats_buf = (uint8_t *) (stats_rsp_params + 1);
1406 temp_mask = stats_rsp_params->statsMask;
1407 if (temp_mask & (1 << eCsrSummaryStats))
1408 stats_buf += sizeof(tCsrSummaryStatsInfo);
1409
1410 if (temp_mask & (1 << eCsrGlobalClassAStats)) {
1411 classa_stats = (tCsrGlobalClassAStatsInfo *) stats_buf;
1412 WMA_LOGD("peer tx rate:%d", peer_stats->peer_tx_rate);
1413 /*The linkspeed returned by fw is in kbps so convert
1414 *it in to units of 500kbps which is expected by UMAC*/
1415 if (peer_stats->peer_tx_rate) {
1416 classa_stats->tx_rate =
1417 peer_stats->peer_tx_rate / 500;
1418 }
1419
1420 classa_stats->tx_rate_flags = node->rate_flags;
1421 if (!(node->rate_flags & eHAL_TX_RATE_LEGACY)) {
1422 classa_stats->mcs_index =
1423 wma_get_mcs_idx((peer_stats->peer_tx_rate /
1424 100), node->rate_flags,
1425 node->nss, &mcsRateFlags);
1426 /* rx_frag_cnt and promiscuous_rx_frag_cnt
1427 * parameter is currently not used. lets use the
1428 * same parameter to hold the nss value and mcs
1429 * rate flags */
1430 classa_stats->rx_frag_cnt = node->nss;
1431 classa_stats->promiscuous_rx_frag_cnt =
1432 mcsRateFlags;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001433 }
1434 /* FW returns tx power in intervals of 0.5 dBm
1435 Convert it back to intervals of 1 dBm */
1436 classa_stats->max_pwr =
1437 roundup(classa_stats->max_pwr, 2) >> 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001439 }
1440}
1441
1442/**
1443 * wma_post_link_status() - post link status to SME
1444 * @pGetLinkStatus: SME Link status
1445 * @link_status: Link status
1446 *
1447 * Return: none
1448 */
1449void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus,
1450 uint8_t link_status)
1451{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301452 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 cds_msg_t sme_msg = { 0 };
1454
1455 pGetLinkStatus->linkStatus = link_status;
1456 sme_msg.type = eWNI_SME_LINK_STATUS_IND;
1457 sme_msg.bodyptr = pGetLinkStatus;
1458 sme_msg.bodyval = 0;
1459
Anurag Chouhan6d760662016-02-20 16:05:43 +05301460 qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301461 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001462 WMA_LOGE("%s: Fail to post link status ind msg", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301463 qdf_mem_free(pGetLinkStatus);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 }
1465}
1466
1467/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05301468 * wma_update_per_chain_rssi_stats() - to store per chain rssi stats
1469 * @wma: wma handle
1470 * @rssi_stats: rssi stats
1471 * @rssi_per_chain_stats: buffer where rssi stats to be stored
1472 *
1473 * This function stores per chain rssi stats received from fw for all vdevs for
1474 * which the stats were requested into a csr stats structure.
1475 *
1476 * Return: void
1477 */
1478static void wma_update_per_chain_rssi_stats(tp_wma_handle wma,
1479 wmi_rssi_stats *rssi_stats,
1480 struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats)
1481{
1482 int i;
1483 int8_t bcn_snr, dat_snr;
1484
1485 for (i = 0; i < NUM_CHAINS_MAX; i++) {
1486 bcn_snr = rssi_stats->rssi_avg_beacon[i];
1487 dat_snr = rssi_stats->rssi_avg_data[i];
1488 WMA_LOGD("chain %d beacon snr %d data snr %d",
1489 i, bcn_snr, dat_snr);
1490 if (dat_snr != WMA_TGT_INVALID_SNR)
1491 rssi_per_chain_stats->rssi[i] = dat_snr;
1492 else if (bcn_snr != WMA_TGT_INVALID_SNR)
1493 rssi_per_chain_stats->rssi[i] = bcn_snr;
1494 else
1495 /*
1496 * Firmware sends invalid snr till it sees
1497 * Beacon/Data after connection since after
1498 * vdev up fw resets the snr to invalid.
1499 * In this duartion Host will return an invalid rssi
1500 * value.
1501 */
1502 rssi_per_chain_stats->rssi[i] = WMA_TGT_RSSI_INVALID;
1503
1504 /*
1505 * Get the absolute rssi value from the current rssi value the
1506 * sinr value is hardcoded into 0 in the qcacld-new/CORE stack
1507 */
1508 rssi_per_chain_stats->rssi[i] += WMA_TGT_NOISE_FLOOR_DBM;
1509 WMI_MAC_ADDR_TO_CHAR_ARRAY(&(rssi_stats->peer_macaddr),
1510 rssi_per_chain_stats->peer_mac_addr);
1511 }
1512}
1513
1514/**
1515 * wma_update_rssi_stats() - to update rssi stats for all vdevs
1516 * for which the stats were requested.
1517 * @wma: wma handle
1518 * @rssi_stats: rssi stats
1519 *
1520 * This function updates the rssi stats for all vdevs for which
1521 * the stats were requested.
1522 *
1523 * Return: void
1524 */
1525static void wma_update_rssi_stats(tp_wma_handle wma,
1526 wmi_rssi_stats *rssi_stats)
1527{
1528 tAniGetPEStatsRsp *stats_rsp_params;
1529 struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats = NULL;
1530 struct wma_txrx_node *node;
1531 uint8_t *stats_buf;
1532 uint32_t temp_mask;
1533 uint8_t vdev_id;
1534
1535 vdev_id = rssi_stats->vdev_id;
1536 node = &wma->interfaces[vdev_id];
1537 if (node->stats_rsp) {
1538 node->fw_stats_set |= FW_RSSI_PER_CHAIN_STATS_SET;
1539 WMA_LOGD("<-- FW RSSI PER CHAIN STATS received for vdevId:%d",
1540 vdev_id);
1541 stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp;
1542 stats_buf = (uint8_t *) (stats_rsp_params + 1);
1543 temp_mask = stats_rsp_params->statsMask;
1544
1545 if (temp_mask & (1 << eCsrSummaryStats))
1546 stats_buf += sizeof(tCsrSummaryStatsInfo);
1547 if (temp_mask & (1 << eCsrGlobalClassAStats))
1548 stats_buf += sizeof(tCsrGlobalClassAStatsInfo);
1549 if (temp_mask & (1 << eCsrGlobalClassBStats))
1550 stats_buf += sizeof(tCsrGlobalClassBStatsInfo);
1551 if (temp_mask & (1 << eCsrGlobalClassCStats))
1552 stats_buf += sizeof(tCsrGlobalClassCStatsInfo);
1553 if (temp_mask & (1 << eCsrGlobalClassDStats))
1554 stats_buf += sizeof(tCsrGlobalClassDStatsInfo);
1555 if (temp_mask & (1 << eCsrPerStaStats))
1556 stats_buf += sizeof(tCsrPerStaStatsInfo);
1557
1558 if (temp_mask & (1 << csr_per_chain_rssi_stats)) {
1559 rssi_per_chain_stats =
1560 (struct csr_per_chain_rssi_stats_info *)stats_buf;
1561 wma_update_per_chain_rssi_stats(wma, rssi_stats,
1562 rssi_per_chain_stats);
1563 }
1564 }
1565}
1566
1567
1568/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001569 * wma_link_status_event_handler() - link status event handler
1570 * @handle: wma handle
1571 * @cmd_param_info: data from event
1572 * @len: length
1573 *
1574 * Return: 0 for success or error code
1575 */
1576int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info,
1577 uint32_t len)
1578{
1579 tp_wma_handle wma = (tp_wma_handle) handle;
1580 WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf;
1581 wmi_vdev_rate_stats_event_fixed_param *event;
1582 wmi_vdev_rate_ht_info *ht_info;
1583 struct wma_txrx_node *intr = wma->interfaces;
1584 uint8_t link_status = LINK_STATUS_LEGACY;
1585 int i;
1586
1587 param_buf =
1588 (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *) cmd_param_info;
1589 if (!param_buf) {
1590 WMA_LOGA("%s: Invalid stats event", __func__);
1591 return -EINVAL;
1592 }
1593
1594 event = (wmi_vdev_rate_stats_event_fixed_param *) param_buf->fixed_param;
1595 ht_info = (wmi_vdev_rate_ht_info *) param_buf->ht_info;
1596
1597 WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats);
1598 for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) {
1599 WMA_LOGD("%s vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d",
1600 __func__, ht_info->vdevid, ht_info->tx_nss,
1601 ht_info->rx_nss, ht_info->tx_preamble,
1602 ht_info->rx_preamble);
1603 if (ht_info->vdevid < wma->max_bssid
1604 && intr[ht_info->vdevid].plink_status_req) {
1605 if (ht_info->tx_nss || ht_info->rx_nss)
1606 link_status = LINK_STATUS_MIMO;
1607
1608 if ((ht_info->tx_preamble == LINK_RATE_VHT) ||
1609 (ht_info->rx_preamble == LINK_RATE_VHT))
1610 link_status |= LINK_STATUS_VHT;
1611
1612 if (intr[ht_info->vdevid].nss == 2)
1613 link_status |= LINK_SUPPORT_MIMO;
1614
1615 if (intr[ht_info->vdevid].rate_flags &
1616 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
1617 eHAL_TX_RATE_VHT80))
1618 link_status |= LINK_SUPPORT_VHT;
1619
1620 wma_post_link_status(intr[ht_info->vdevid].plink_status_req,
1621 link_status);
1622 intr[ht_info->vdevid].plink_status_req = NULL;
1623 link_status = LINK_STATUS_LEGACY;
1624 }
1625
1626 ht_info++;
1627 }
1628
1629 return 0;
1630}
1631
1632/**
1633 * wma_stats_event_handler() - stats event handler
1634 * @handle: wma handle
1635 * @cmd_param_info: data from event
1636 * @len: length
1637 *
1638 * Return: 0 for success or error code
1639 */
1640int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info,
1641 uint32_t len)
1642{
1643 tp_wma_handle wma = (tp_wma_handle) handle;
1644 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
1645 wmi_stats_event_fixed_param *event;
1646 wmi_pdev_stats *pdev_stats;
1647 wmi_vdev_stats *vdev_stats;
1648 wmi_peer_stats *peer_stats;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05301649 wmi_rssi_stats *rssi_stats;
1650 wmi_per_chain_rssi_stats *rssi_event;
1651 struct wma_txrx_node *node;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001652 uint8_t i, *temp;
1653
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) cmd_param_info;
1655 if (!param_buf) {
1656 WMA_LOGA("%s: Invalid stats event", __func__);
1657 return -EINVAL;
1658 }
1659 event = param_buf->fixed_param;
1660 temp = (uint8_t *) param_buf->data;
1661
1662 WMA_LOGD("%s: num_stats: pdev: %u vdev: %u peer %u",
1663 __func__, event->num_pdev_stats, event->num_vdev_stats,
1664 event->num_peer_stats);
1665 if (event->num_pdev_stats > 0) {
1666 for (i = 0; i < event->num_pdev_stats; i++) {
1667 pdev_stats = (wmi_pdev_stats *) temp;
1668 wma_update_pdev_stats(wma, pdev_stats);
1669 temp += sizeof(wmi_pdev_stats);
1670 }
1671 }
1672
1673 if (event->num_vdev_stats > 0) {
1674 for (i = 0; i < event->num_vdev_stats; i++) {
1675 vdev_stats = (wmi_vdev_stats *) temp;
1676 wma_update_vdev_stats(wma, vdev_stats);
1677 temp += sizeof(wmi_vdev_stats);
1678 }
1679 }
1680
1681 if (event->num_peer_stats > 0) {
1682 for (i = 0; i < event->num_peer_stats; i++) {
1683 peer_stats = (wmi_peer_stats *) temp;
1684 wma_update_peer_stats(wma, peer_stats);
1685 temp += sizeof(wmi_peer_stats);
1686 }
1687 }
1688
Himanshu Agarwal37e42412016-07-21 14:35:09 +05301689 rssi_event = (wmi_per_chain_rssi_stats *) param_buf->chain_stats;
1690 if (rssi_event) {
Himanshu Agarwalcd8a84a2016-07-21 14:59:50 +05301691 if (((rssi_event->tlv_header & 0xFFFF0000) >> 16 ==
1692 WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats) &&
1693 ((rssi_event->tlv_header & 0x0000FFFF) ==
1694 WMITLV_GET_STRUCT_TLVLEN(wmi_per_chain_rssi_stats))) {
Himanshu Agarwal37e42412016-07-21 14:35:09 +05301695 if (rssi_event->num_per_chain_rssi_stats > 0) {
1696 temp = (uint8_t *) rssi_event;
1697 temp += sizeof(*rssi_event);
Dustin Brownc4a5ba22016-11-10 17:21:18 -08001698
1699 /* skip past struct array tlv header */
1700 temp += WMI_TLV_HDR_SIZE;
1701
Himanshu Agarwal37e42412016-07-21 14:35:09 +05301702 for (i = 0;
1703 i < rssi_event->num_per_chain_rssi_stats;
1704 i++) {
1705 rssi_stats = (wmi_rssi_stats *)temp;
1706 wma_update_rssi_stats(wma, rssi_stats);
1707 temp += sizeof(wmi_rssi_stats);
1708 }
1709 }
1710 }
1711 }
1712
1713 for (i = 0; i < wma->max_bssid; i++) {
1714 node = &wma->interfaces[i];
1715 if (node->fw_stats_set & FW_PEER_STATS_SET) {
1716 WMA_LOGD("<--STATS RSP VDEV_ID:%d", i);
1717 wma_post_stats(wma, node);
1718 }
1719 }
1720
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721 WMA_LOGI("%s: Exit", __func__);
1722 return 0;
1723}
1724
1725/**
1726 * wma_send_link_speed() - send link speed to SME
1727 * @link_speed: link speed
1728 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301729 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301731QDF_STATUS wma_send_link_speed(uint32_t link_speed)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001732{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301733 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734 cds_msg_t sme_msg = { 0 };
1735 tSirLinkSpeedInfo *ls_ind =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301736 (tSirLinkSpeedInfo *) qdf_mem_malloc(sizeof(tSirLinkSpeedInfo));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001737 if (!ls_ind) {
1738 WMA_LOGE("%s: Memory allocation failed.", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301739 qdf_status = QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740 } else {
1741 ls_ind->estLinkSpeed = link_speed;
1742 sme_msg.type = eWNI_SME_LINK_SPEED_IND;
1743 sme_msg.bodyptr = ls_ind;
1744 sme_msg.bodyval = 0;
1745
Anurag Chouhan6d760662016-02-20 16:05:43 +05301746 qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301747 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748 WMA_LOGE("%s: Fail to post linkspeed ind msg",
1749 __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301750 qdf_mem_free(ls_ind);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001751 }
1752 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301753 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001754}
1755
1756/**
1757 * wma_link_speed_event_handler() - link speed event handler
1758 * @handle: wma handle
1759 * @cmd_param_info: event data
1760 * @len: length
1761 *
1762 * Return: 0 for success or error code
1763 */
1764int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info,
1765 uint32_t len)
1766{
1767 WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *param_buf;
1768 wmi_peer_estimated_linkspeed_event_fixed_param *event;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301769 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770
1771 param_buf =
1772 (WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *) cmd_param_info;
1773 if (!param_buf) {
1774 WMA_LOGE("%s: Invalid linkspeed event", __func__);
1775 return -EINVAL;
1776 }
1777 event = param_buf->fixed_param;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301778 qdf_status = wma_send_link_speed(event->est_linkspeed_kbps);
1779 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001780 return -EINVAL;
1781 }
1782 return 0;
1783}
1784
1785/**
1786 * wma_wni_cfg_dnld() - cfg download request
1787 * @handle: wma handle
1788 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301789 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001790 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301791QDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001792{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301793 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Anurag Chouhan6d760662016-02-20 16:05:43 +05301794 void *mac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001795
1796 WMA_LOGD("%s: Enter", __func__);
1797
1798 if (NULL == mac) {
1799 WMA_LOGP("%s: Invalid context", __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301800 QDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301801 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001802 }
1803
1804 process_cfg_download_req(mac);
1805
1806 WMA_LOGD("%s: Exit", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301807 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808}
1809
1810/**
1811 * wma_unified_debug_print_event_handler() - debug print event handler
1812 * @handle: wma handle
1813 * @datap: data pointer
1814 * @len: length
1815 *
1816 * Return: 0 for success or error code
1817 */
1818int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap,
1819 uint32_t len)
1820{
1821 WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf;
1822 uint8_t *data;
1823 uint32_t datalen;
1824
1825 param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap;
1826 if (!param_buf) {
1827 WMA_LOGE("Get NULL point message from FW");
1828 return -ENOMEM;
1829 }
1830 data = param_buf->data;
1831 datalen = param_buf->num_data;
1832
1833#ifdef BIG_ENDIAN_HOST
1834 {
1835 char dbgbuf[500] = { 0 };
1836 memcpy(dbgbuf, data, datalen);
1837 SWAPME(dbgbuf, datalen);
1838 WMA_LOGD("FIRMWARE:%s", dbgbuf);
1839 return 0;
1840 }
1841#else
1842 WMA_LOGD("FIRMWARE:%s", data);
1843 return 0;
1844#endif /* BIG_ENDIAN_HOST */
1845}
1846
1847/**
1848 * wma_check_scan_in_progress() - check scan is progress or not
1849 * @handle: wma handle
1850 *
1851 * Return: true/false
1852 */
1853bool wma_check_scan_in_progress(WMA_HANDLE handle)
1854{
Nitesh Shah0f3fce52016-10-13 22:01:41 +05301855 tp_wma_handle wma = handle;
1856 return qdf_atomic_read(&wma->num_pending_scans) > 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857}
1858
1859/**
1860 * wma_is_sap_active() - check sap is active or not
1861 * @handle: wma handle
1862 *
1863 * Return: true/false
1864 */
1865bool wma_is_sap_active(tp_wma_handle wma_handle)
1866{
1867 int i;
1868
1869 for (i = 0; i < wma_handle->max_bssid; i++) {
1870 if (!wma_handle->interfaces[i].vdev_up)
1871 continue;
1872 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
1873 wma_handle->interfaces[i].sub_type == 0)
1874 return true;
1875 }
1876 return false;
1877}
1878
1879/**
1880 * wma_is_p2p_go_active() - check p2p go is active or not
1881 * @handle: wma handle
1882 *
1883 * Return: true/false
1884 */
1885bool wma_is_p2p_go_active(tp_wma_handle wma_handle)
1886{
1887 int i;
1888
1889 for (i = 0; i < wma_handle->max_bssid; i++) {
1890 if (!wma_handle->interfaces[i].vdev_up)
1891 continue;
1892 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
1893 wma_handle->interfaces[i].sub_type ==
1894 WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO)
1895 return true;
1896 }
1897 return false;
1898}
1899
1900/**
1901 * wma_is_p2p_cli_active() - check p2p cli is active or not
1902 * @handle: wma handle
1903 *
1904 * Return: true/false
1905 */
1906bool wma_is_p2p_cli_active(tp_wma_handle wma_handle)
1907{
1908 int i;
1909
1910 for (i = 0; i < wma_handle->max_bssid; i++) {
1911 if (!wma_handle->interfaces[i].vdev_up)
1912 continue;
1913 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
1914 wma_handle->interfaces[i].sub_type ==
1915 WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT)
1916 return true;
1917 }
1918 return false;
1919}
1920
1921/**
1922 * wma_is_sta_active() - check sta is active or not
1923 * @handle: wma handle
1924 *
1925 * Return: true/false
1926 */
1927bool wma_is_sta_active(tp_wma_handle wma_handle)
1928{
1929 int i;
1930
1931 for (i = 0; i < wma_handle->max_bssid; i++) {
1932 if (!wma_handle->interfaces[i].vdev_up)
1933 continue;
1934 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
1935 wma_handle->interfaces[i].sub_type == 0)
1936 return true;
1937 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_IBSS)
1938 return true;
1939 }
1940 return false;
1941}
1942
1943/**
1944 * wma_peer_phymode() - get phymode
1945 * @nw_type: nw type
1946 * @sta_type: sta type
1947 * @is_ht: is ht supported
1948 * @is_cw40: is channel width 40 supported
1949 * @is_vht: is vht supported
1950 * @is_cw_vht: is channel width 80 supported
1951 *
1952 * Return: WLAN_PHY_MODE
1953 */
1954WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type,
1955 uint8_t is_ht, uint8_t ch_width,
1956 uint8_t is_vht)
1957{
1958 WLAN_PHY_MODE phymode = MODE_UNKNOWN;
1959
1960 switch (nw_type) {
1961 case eSIR_11B_NW_TYPE:
1962 phymode = MODE_11B;
1963 if (is_ht || is_vht)
1964 WMA_LOGE("HT/VHT is enabled with 11B NW type");
1965 break;
1966 case eSIR_11G_NW_TYPE:
1967 if (!(is_ht || is_vht)) {
1968 phymode = MODE_11G;
1969 break;
1970 }
1971 if (CH_WIDTH_40MHZ < ch_width)
1972 WMA_LOGE("80/160 MHz BW sent in 11G, configured 40MHz");
1973 if (ch_width)
1974 phymode = (is_vht) ?
Krishna Kumaar Natarajan294da812016-04-28 14:39:30 -07001975 MODE_11AC_VHT40_2G : MODE_11NG_HT40;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001976 else
1977 phymode = (is_vht) ?
Krishna Kumaar Natarajan294da812016-04-28 14:39:30 -07001978 MODE_11AC_VHT20_2G : MODE_11NG_HT20;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001979 break;
1980 case eSIR_11A_NW_TYPE:
1981 if (!(is_ht || is_vht)) {
1982 phymode = MODE_11A;
1983 break;
1984 }
1985 if (is_vht) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986 if (ch_width == CH_WIDTH_160MHZ)
1987 phymode = MODE_11AC_VHT160;
1988 else if (ch_width == CH_WIDTH_80P80MHZ)
1989 phymode = MODE_11AC_VHT80_80;
Amar Singhal046eb8a2016-05-05 12:50:15 -07001990 else if (ch_width == CH_WIDTH_80MHZ)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001991 phymode = MODE_11AC_VHT80;
1992 else
1993 phymode = (ch_width) ?
1994 MODE_11AC_VHT40 : MODE_11AC_VHT20;
1995 } else
1996 phymode = (ch_width) ? MODE_11NA_HT40 : MODE_11NA_HT20;
1997 break;
1998 default:
1999 WMA_LOGP("%s: Invalid nw type %d", __func__, nw_type);
2000 break;
2001 }
2002 WMA_LOGD("%s: nw_type %d is_ht %d ch_width %d is_vht %d phymode %d",
2003 __func__, nw_type, is_ht, ch_width, is_vht, phymode);
2004
2005 return phymode;
2006}
2007
2008/**
2009 * wma_txrx_fw_stats_reset() - reset txrx fw statistics
2010 * @wma_handle: wma handle
2011 * @vdev_id: vdev id
2012 * @value: value
2013 *
2014 * Return: 0 for success or return error
2015 */
2016int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle,
2017 uint8_t vdev_id, uint32_t value)
2018{
2019 struct ol_txrx_stats_req req;
Leo Chang96464902016-10-28 11:10:54 -07002020 void *vdev;
Nishank Aggarwala13b61d2016-12-01 12:53:58 +05302021 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2022
2023 if (!soc) {
2024 WMA_LOGE("%s:SOC context is NULL", __func__);
2025 return -EINVAL;
2026 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002027
2028 vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
2029 if (!vdev) {
2030 WMA_LOGE("%s:Invalid vdev handle", __func__);
2031 return -EINVAL;
2032 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302033 qdf_mem_zero(&req, sizeof(req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002034 req.stats_type_reset_mask = value;
Nishank Aggarwala13b61d2016-12-01 12:53:58 +05302035 cdp_fw_stats_get(soc, vdev, &req,
Leo Chang96464902016-10-28 11:10:54 -07002036 false, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037
2038 return 0;
2039}
2040
2041#ifdef HELIUMPLUS
2042#define SET_UPLOAD_MASK(_mask, _rate_info) \
2043 ((_mask) = 1 << (_rate_info ## _V2))
2044#else /* !HELIUMPLUS */
2045#define SET_UPLOAD_MASK(_mask, _rate_info) \
2046 ((_mask) = 1 << (_rate_info))
2047#endif
2048
Nirav Shah93e789e2016-04-14 19:47:43 +05302049#ifdef HELIUMPLUS
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07002050static bool wma_is_valid_fw_stats_cmd(uint32_t value)
Nirav Shah93e789e2016-04-14 19:47:43 +05302051{
2052 if (value > (HTT_DBG_NUM_STATS + 1) ||
2053 value == (HTT_DBG_STATS_RX_RATE_INFO + 1) ||
2054 value == (HTT_DBG_STATS_TX_RATE_INFO + 1) ||
2055 value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) {
2056 WMA_LOGE("%s: Not supported", __func__);
2057 return false;
2058 }
2059 return true;
2060}
2061#else
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07002062static bool wma_is_valid_fw_stats_cmd(uint32_t value)
Nirav Shah93e789e2016-04-14 19:47:43 +05302063{
2064 if (value > (HTT_DBG_NUM_STATS + 1) ||
2065 value == (HTT_DBG_STATS_RX_RATE_INFO_V2 + 1) ||
2066 value == (HTT_DBG_STATS_TX_RATE_INFO_V2 + 1) ||
2067 value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) {
2068 WMA_LOGE("%s: Not supported", __func__);
2069 return false;
2070 }
2071 return true;
2072}
2073#endif
2074
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002075/**
2076 * wma_set_txrx_fw_stats_level() - set txrx fw stats level
2077 * @wma_handle: wma handle
2078 * @vdev_id: vdev id
2079 * @value: value
2080 *
2081 * Return: 0 for success or return error
2082 */
2083int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle,
2084 uint8_t vdev_id, uint32_t value)
2085{
2086 struct ol_txrx_stats_req req;
Leo Chang96464902016-10-28 11:10:54 -07002087 void *vdev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002088 uint32_t l_up_mask;
Nishank Aggarwala13b61d2016-12-01 12:53:58 +05302089 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2090
2091 if (!soc) {
2092 WMA_LOGE("%s:SOC context is NULL", __func__);
2093 return -EINVAL;
2094 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002095
2096 vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
2097 if (!vdev) {
2098 WMA_LOGE("%s:Invalid vdev handle", __func__);
2099 return -EINVAL;
2100 }
Nirav Shah93e789e2016-04-14 19:47:43 +05302101
2102 if (wma_is_valid_fw_stats_cmd(value) == false)
2103 return -EINVAL;
2104
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302105 qdf_mem_zero(&req, sizeof(req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002106 req.print.verbose = 1;
2107
Nirav Shah93e789e2016-04-14 19:47:43 +05302108 /* TODO: Need to check how to avoid mem leak*/
2109 l_up_mask = 1 << (value - 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002110 req.stats_type_upload_mask = l_up_mask;
2111
Nishank Aggarwala13b61d2016-12-01 12:53:58 +05302112 cdp_fw_stats_get(soc, vdev, &req,
Leo Chang96464902016-10-28 11:10:54 -07002113 false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002114
2115 return 0;
2116}
2117
2118/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002119 * wma_get_stats_rsp_buf() - fill get stats response buffer
2120 * @get_stats_param: get stats parameters
2121 *
2122 * Return: stats response buffer
2123 */
2124static tAniGetPEStatsRsp *wma_get_stats_rsp_buf
2125 (tAniGetPEStatsReq *get_stats_param)
2126{
2127 tAniGetPEStatsRsp *stats_rsp_params;
2128 uint32_t len, temp_mask, counter = 0;
2129
2130 len = sizeof(tAniGetPEStatsRsp);
2131 temp_mask = get_stats_param->statsMask;
2132
2133 while (temp_mask) {
2134 if (temp_mask & 1) {
2135 switch (counter) {
2136 case eCsrSummaryStats:
2137 len += sizeof(tCsrSummaryStatsInfo);
2138 break;
2139 case eCsrGlobalClassAStats:
2140 len += sizeof(tCsrGlobalClassAStatsInfo);
2141 break;
2142 case eCsrGlobalClassBStats:
2143 len += sizeof(tCsrGlobalClassBStatsInfo);
2144 break;
2145 case eCsrGlobalClassCStats:
2146 len += sizeof(tCsrGlobalClassCStatsInfo);
2147 break;
2148 case eCsrGlobalClassDStats:
2149 len += sizeof(tCsrGlobalClassDStatsInfo);
2150 break;
2151 case eCsrPerStaStats:
2152 len += sizeof(tCsrPerStaStatsInfo);
2153 break;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302154 case csr_per_chain_rssi_stats:
2155 len +=
2156 sizeof(struct csr_per_chain_rssi_stats_info);
2157 break;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002158 }
2159 }
2160
2161 counter++;
2162 temp_mask >>= 1;
2163 }
2164
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302165 stats_rsp_params = (tAniGetPEStatsRsp *) qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002166 if (!stats_rsp_params) {
2167 WMA_LOGE("memory allocation failed for tAniGetPEStatsRsp");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302168 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002169 return NULL;
2170 }
2171
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302172 qdf_mem_zero(stats_rsp_params, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002173 stats_rsp_params->staId = get_stats_param->staId;
2174 stats_rsp_params->statsMask = get_stats_param->statsMask;
2175 stats_rsp_params->msgType = WMA_GET_STATISTICS_RSP;
2176 stats_rsp_params->msgLen = len - sizeof(tAniGetPEStatsRsp);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302177 stats_rsp_params->rc = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002178 return stats_rsp_params;
2179}
2180
2181/**
2182 * wma_get_stats_req() - get stats request
2183 * @handle: wma handle
2184 * @get_stats_param: stats params
2185 *
2186 * Return: none
2187 */
2188void wma_get_stats_req(WMA_HANDLE handle,
2189 tAniGetPEStatsReq *get_stats_param)
2190{
2191 tp_wma_handle wma_handle = (tp_wma_handle) handle;
2192 struct wma_txrx_node *node;
Govind Singh4863da42016-03-08 11:45:00 +05302193 struct pe_stats_req cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 tAniGetPEStatsRsp *pGetPEStatsRspParams;
Govind Singh4863da42016-03-08 11:45:00 +05302195
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002196
2197 WMA_LOGD("%s: Enter", __func__);
2198 node = &wma_handle->interfaces[get_stats_param->sessionId];
2199 if (node->stats_rsp) {
2200 pGetPEStatsRspParams = node->stats_rsp;
2201 if (pGetPEStatsRspParams->staId == get_stats_param->staId &&
2202 pGetPEStatsRspParams->statsMask ==
2203 get_stats_param->statsMask) {
2204 WMA_LOGI("Stats for staId %d with stats mask %d "
2205 "is pending.... ignore new request",
2206 get_stats_param->staId,
2207 get_stats_param->statsMask);
2208 goto end;
2209 } else {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302210 qdf_mem_free(node->stats_rsp);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211 node->stats_rsp = NULL;
2212 node->fw_stats_set = 0;
2213 }
2214 }
2215
2216 pGetPEStatsRspParams = wma_get_stats_rsp_buf(get_stats_param);
2217 if (!pGetPEStatsRspParams)
2218 goto end;
2219
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002220 node->fw_stats_set = 0;
2221 node->stats_rsp = pGetPEStatsRspParams;
Govind Singh4863da42016-03-08 11:45:00 +05302222
2223 cmd.session_id = get_stats_param->sessionId;
2224 if (wmi_unified_get_stats_cmd(wma_handle->wmi_handle, &cmd,
2225 node->bssid)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002226
2227 WMA_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID",
2228 __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002229 goto failed;
2230 }
2231
2232 goto end;
2233failed:
2234
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302235 pGetPEStatsRspParams->rc = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002236 node->stats_rsp = NULL;
2237 /* send response to UMAC */
2238 wma_send_msg(wma_handle, WMA_GET_STATISTICS_RSP, pGetPEStatsRspParams,
2239 0);
2240end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302241 qdf_mem_free(get_stats_param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002242 WMA_LOGD("%s: Exit", __func__);
2243 return;
2244}
2245
2246/**
2247 * wma_get_beacon_buffer_by_vdev_id() - get the beacon buffer from vdev ID
2248 * @vdev_id: vdev id
2249 * @buffer_size: size of buffer
2250 *
2251 * Return: none
2252 */
2253void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size)
2254{
2255 tp_wma_handle wma;
2256 struct beacon_info *beacon;
2257 uint8_t *buf;
2258 uint32_t buf_size;
2259
Anurag Chouhan6d760662016-02-20 16:05:43 +05302260 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002261 if (!wma) {
2262 WMA_LOGE("%s: Invalid WMA handle", __func__);
2263 return NULL;
2264 }
2265
2266 if (vdev_id >= wma->max_bssid) {
2267 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
2268 return NULL;
2269 }
2270
2271 if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) {
2272 WMA_LOGE("%s: vdevid %d is not in AP mode", __func__, vdev_id);
2273 return NULL;
2274 }
2275
2276 beacon = wma->interfaces[vdev_id].beacon;
2277
2278 if (!beacon) {
2279 WMA_LOGE("%s: beacon invalid", __func__);
2280 return NULL;
2281 }
2282
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302283 qdf_spin_lock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002284
Nirav Shahcbc6d722016-03-01 16:24:53 +05302285 buf_size = qdf_nbuf_len(beacon->buf);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302286 buf = qdf_mem_malloc(buf_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002287
2288 if (!buf) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302289 qdf_spin_unlock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002290 WMA_LOGE("%s: alloc failed for beacon buf", __func__);
2291 return NULL;
2292 }
2293
Nirav Shahcbc6d722016-03-01 16:24:53 +05302294 qdf_mem_copy(buf, qdf_nbuf_data(beacon->buf), buf_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002295
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302296 qdf_spin_unlock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002297
2298 if (buffer_size)
2299 *buffer_size = buf_size;
2300
2301 return buf;
2302}
2303
2304/**
2305 * wma_get_vdev_address_by_vdev_id() - lookup MAC address from vdev ID
2306 * @vdev_id: vdev id
2307 *
2308 * Return: mac address
2309 */
2310uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id)
2311{
2312 tp_wma_handle wma;
2313
Anurag Chouhan6d760662016-02-20 16:05:43 +05302314 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002315 if (!wma) {
2316 WMA_LOGE("%s: Invalid WMA handle", __func__);
2317 return NULL;
2318 }
2319
2320 if (vdev_id >= wma->max_bssid) {
2321 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
2322 return NULL;
2323 }
2324
2325 return wma->interfaces[vdev_id].addr;
2326}
2327
2328/**
2329 * wma_get_interface_by_vdev_id() - lookup interface entry using vdev ID
2330 * @vdev_id: vdev id
2331 *
2332 * Return: entry from vdev table
2333 */
2334struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id)
2335{
2336 tp_wma_handle wma;
2337
Anurag Chouhan6d760662016-02-20 16:05:43 +05302338 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339 if (!wma) {
2340 WMA_LOGE("%s: Invalid WMA handle", __func__);
2341 return NULL;
2342 }
2343
2344 if (vdev_id >= wma->max_bssid) {
2345 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
2346 return NULL;
2347 }
2348
2349 return &wma->interfaces[vdev_id];
2350}
2351
2352/**
2353 * wma_is_vdev_up() - return whether a vdev is up
2354 * @vdev_id: vdev id
2355 *
2356 * Return: true if the vdev is up, false otherwise
2357 */
2358bool wma_is_vdev_up(uint8_t vdev_id)
2359{
2360 struct wma_txrx_node *vdev = wma_get_interface_by_vdev_id(vdev_id);
2361 if (vdev)
2362 return vdev->vdev_up;
2363 else
2364 return false;
2365}
2366
2367#if defined(QCA_WIFI_FTM)
2368/**
2369 * wma_utf_rsp() - utf response
2370 * @wma_handle: wma handle
2371 * @payload: payload
2372 * @len: length of payload
2373 *
2374 * Return: 0 for success or error code
2375 */
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07002376static int wma_utf_rsp(tp_wma_handle wma_handle, uint8_t **payload,
2377 uint32_t *len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002378{
2379 int ret = -1;
2380 uint32_t payload_len;
2381
2382 payload_len = wma_handle->utf_event_info.length;
2383 if (payload_len) {
2384 ret = 0;
2385
2386 /*
2387 * The first 4 bytes holds the payload size
2388 * and the actual payload sits next to it
2389 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302390 *payload = (uint8_t *) qdf_mem_malloc((uint32_t) payload_len
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002391 + sizeof(A_UINT32));
2392 *(A_UINT32 *) &(*payload[0]) =
2393 wma_handle->utf_event_info.length;
2394 memcpy(*payload + sizeof(A_UINT32),
2395 wma_handle->utf_event_info.data, payload_len);
2396 wma_handle->utf_event_info.length = 0;
2397 *len = payload_len;
2398 }
2399
2400 return ret;
2401}
2402
2403/**
2404 * wma_post_ftm_response() - post ftm response to upper layer
2405 * @wma_handle: wma handle
2406 *
2407 * Return: none
2408 */
2409static void wma_post_ftm_response(tp_wma_handle wma_handle)
2410{
2411 int ret;
2412 uint8_t *payload;
2413 uint32_t data_len;
2414 cds_msg_t msg = { 0 };
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302415 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002416
2417 ret = wma_utf_rsp(wma_handle, &payload, &data_len);
2418
2419 if (ret) {
2420 return;
2421 }
2422
2423 sys_build_message_header(SYS_MSG_ID_FTM_RSP, &msg);
2424 msg.bodyptr = payload;
2425 msg.bodyval = 0;
2426
2427 status = cds_mq_post_message(CDS_MQ_ID_SYS, &msg);
2428
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302429 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002430 WMA_LOGE("failed to post ftm response to SYS");
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302431 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002432 }
2433}
2434
2435/**
2436 * wma_process_utf_event() - process utf event
2437 * @handle: wma handle
2438 * @datap: data buffer
2439 * @dataplen: data length
2440 *
2441 * Return: 0 for success or error code
2442 */
2443static int
2444wma_process_utf_event(WMA_HANDLE handle, uint8_t *datap, uint32_t dataplen)
2445{
2446 tp_wma_handle wma_handle = (tp_wma_handle) handle;
Govind Singhd76a5b02016-03-08 15:12:14 +05302447 struct seg_hdr_info segHdrInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002448 uint8_t totalNumOfSegments, currentSeq;
2449 WMI_PDEV_UTF_EVENTID_param_tlvs *param_buf;
2450 uint8_t *data;
2451 uint32_t datalen;
2452
2453 param_buf = (WMI_PDEV_UTF_EVENTID_param_tlvs *) datap;
2454 if (!param_buf) {
2455 WMA_LOGE("Get NULL point message from FW");
2456 return -EINVAL;
2457 }
2458 data = param_buf->data;
2459 datalen = param_buf->num_data;
2460
Govind Singhd76a5b02016-03-08 15:12:14 +05302461 segHdrInfo = *(struct seg_hdr_info *) &(data[0]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002462
2463 wma_handle->utf_event_info.currentSeq = (segHdrInfo.segmentInfo & 0xF);
2464
2465 currentSeq = (segHdrInfo.segmentInfo & 0xF);
2466 totalNumOfSegments = (segHdrInfo.segmentInfo >> 4) & 0xF;
2467
2468 datalen = datalen - sizeof(segHdrInfo);
2469
2470 if (currentSeq == 0) {
2471 wma_handle->utf_event_info.expectedSeq = 0;
2472 wma_handle->utf_event_info.offset = 0;
2473 } else {
2474 if (wma_handle->utf_event_info.expectedSeq != currentSeq)
2475 WMA_LOGE("Mismatch in expecting seq expected"
2476 " Seq %d got seq %d",
2477 wma_handle->utf_event_info.expectedSeq,
2478 currentSeq);
2479 }
2480
2481 memcpy(&wma_handle->utf_event_info.
2482 data[wma_handle->utf_event_info.offset],
2483 &data[sizeof(segHdrInfo)], datalen);
2484 wma_handle->utf_event_info.offset =
2485 wma_handle->utf_event_info.offset + datalen;
2486 wma_handle->utf_event_info.expectedSeq++;
2487
2488 if (wma_handle->utf_event_info.expectedSeq == totalNumOfSegments) {
2489 if (wma_handle->utf_event_info.offset != segHdrInfo.len)
2490 WMA_LOGE("All segs received total len mismatch.."
2491 " len %zu total len %d",
2492 wma_handle->utf_event_info.offset,
2493 segHdrInfo.len);
2494
2495 wma_handle->utf_event_info.length =
2496 wma_handle->utf_event_info.offset;
2497 }
2498
2499 wma_post_ftm_response(wma_handle);
2500
2501 return 0;
2502}
2503
2504/**
2505 * wma_utf_detach() - utf detach
2506 * @wma_handle: wma handle
2507 *
2508 * Return: none
2509 */
2510void wma_utf_detach(tp_wma_handle wma_handle)
2511{
2512 if (wma_handle->utf_event_info.data) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302513 qdf_mem_free(wma_handle->utf_event_info.data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002514 wma_handle->utf_event_info.data = NULL;
2515 wma_handle->utf_event_info.length = 0;
2516 wmi_unified_unregister_event_handler(wma_handle->wmi_handle,
2517 WMI_PDEV_UTF_EVENTID);
2518 }
2519}
2520
2521/**
2522 * wma_utf_attach() - utf attach
2523 * @wma_handle: wma handle
2524 *
2525 * Return: none
2526 */
2527void wma_utf_attach(tp_wma_handle wma_handle)
2528{
2529 int ret;
2530
2531 wma_handle->utf_event_info.data = (unsigned char *)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302532 qdf_mem_malloc(MAX_UTF_EVENT_LENGTH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002533 wma_handle->utf_event_info.length = 0;
2534
2535 ret = wmi_unified_register_event_handler(wma_handle->wmi_handle,
2536 WMI_PDEV_UTF_EVENTID,
Govind Singhd76a5b02016-03-08 15:12:14 +05302537 wma_process_utf_event,
2538 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002539
2540 if (ret)
2541 WMA_LOGP("%s: Failed to register UTF event callback", __func__);
2542}
2543
2544/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002545 * wma_utf_cmd() - utf command
2546 * @wma_handle: wma handle
2547 * @data: data
2548 * @len: length
2549 *
Govind Singhd76a5b02016-03-08 15:12:14 +05302550 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002551 */
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07002552static QDF_STATUS wma_utf_cmd(tp_wma_handle wma_handle, uint8_t *data,
2553 uint16_t len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002554{
Govind Singhd76a5b02016-03-08 15:12:14 +05302555 struct pdev_utf_params param = {0};
2556
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002557 wma_handle->utf_event_info.length = 0;
Govind Singhd76a5b02016-03-08 15:12:14 +05302558 param.utf_payload = data;
2559 param.len = len;
2560
2561 return wmi_unified_pdev_utf_cmd_send(wma_handle->wmi_handle, &param,
2562 WMA_WILDCARD_PDEV_ID);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002563}
2564
2565/**
2566 * wma_process_ftm_command() - process ftm command
2567 * @wma_handle: wma handle
2568 * @msg_buffer: message buffer
2569 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302570 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002571 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302572QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002573wma_process_ftm_command(tp_wma_handle wma_handle,
2574 struct ar6k_testmode_cmd_data *msg_buffer)
2575{
2576 uint8_t *data = NULL;
2577 uint16_t len = 0;
2578 int ret;
2579
2580 if (!msg_buffer)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302581 return QDF_STATUS_E_INVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002582
Anurag Chouhan6d760662016-02-20 16:05:43 +05302583 if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002584 WMA_LOGE("FTM command issued in non-FTM mode");
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302585 qdf_mem_free(msg_buffer->data);
2586 qdf_mem_free(msg_buffer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302587 return QDF_STATUS_E_NOSUPPORT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002588 }
2589
2590 data = msg_buffer->data;
2591 len = msg_buffer->len;
2592
2593 ret = wma_utf_cmd(wma_handle, data, len);
2594
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302595 qdf_mem_free(msg_buffer->data);
2596 qdf_mem_free(msg_buffer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002597
2598 if (ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302599 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002600
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302601 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002602}
2603#endif /* QCA_WIFI_FTM */
2604
2605/**
2606 * wma_get_wcnss_software_version() - get wcnss software version
2607 * @p_cds_gctx: cds context
2608 * @pVersion: version pointer
2609 * @versionBufferSize: buffer size
2610 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302611 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302613QDF_STATUS wma_get_wcnss_software_version(void *p_cds_gctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002614 uint8_t *pVersion,
2615 uint32_t versionBufferSize)
2616{
2617 tp_wma_handle wma_handle;
Anurag Chouhan6d760662016-02-20 16:05:43 +05302618 wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002619
2620 if (NULL == wma_handle) {
2621 WMA_LOGE("%s: Failed to get wma", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302622 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002623 }
2624
2625 snprintf(pVersion, versionBufferSize, "%x",
2626 (unsigned int)wma_handle->target_fw_version);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302627 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002628}
2629
2630/**
2631 * wma_get_tx_rx_ss_from_config() - Get Tx/Rx spatial stream from HW mode config
2632 * @mac_ss: Config which indicates the HW mode as per 'hw_mode_ss_config'
2633 * @tx_ss: Contains the Tx spatial stream
2634 * @rx_ss: Contains the Rx spatial stream
2635 *
2636 * Returns the number of spatial streams of Tx and Rx
2637 *
2638 * Return: None
2639 */
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07002640static void wma_get_tx_rx_ss_from_config(enum hw_mode_ss_config mac_ss,
2641 uint32_t *tx_ss, uint32_t *rx_ss)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002642{
2643 switch (mac_ss) {
2644 case HW_MODE_SS_0x0:
2645 *tx_ss = 0;
2646 *rx_ss = 0;
2647 break;
2648 case HW_MODE_SS_1x1:
2649 *tx_ss = 1;
2650 *rx_ss = 1;
2651 break;
2652 case HW_MODE_SS_2x2:
2653 *tx_ss = 2;
2654 *rx_ss = 2;
2655 break;
2656 case HW_MODE_SS_3x3:
2657 *tx_ss = 3;
2658 *rx_ss = 3;
2659 break;
2660 case HW_MODE_SS_4x4:
2661 *tx_ss = 4;
2662 *rx_ss = 4;
2663 break;
2664 default:
2665 *tx_ss = 0;
2666 *rx_ss = 0;
2667 }
2668}
2669
2670/**
2671 * wma_get_matching_hw_mode_index() - Get matching HW mode index
2672 * @wma: WMA handle
2673 * @mac0_tx_ss: Number of tx spatial streams of MAC0
2674 * @mac0_rx_ss: Number of rx spatial streams of MAC0
2675 * @mac0_bw: Bandwidth of MAC0 of type 'hw_mode_bandwidth'
2676 * @mac1_tx_ss: Number of tx spatial streams of MAC1
2677 * @mac1_rx_ss: Number of rx spatial streams of MAC1
2678 * @mac1_bw: Bandwidth of MAC1 of type 'hw_mode_bandwidth'
2679 * @dbs: DBS capability of type 'hw_mode_dbs_capab'
2680 * @dfs: Agile DFS capability of type 'hw_mode_agile_dfs_capab'
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302681 * @sbs: SBS capability of type 'hw_mode_sbs_capab'
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002682 *
2683 * Fetches the HW mode index corresponding to the HW mode provided
2684 *
2685 * Return: Positive hw mode index in case a match is found or a negative
2686 * value, otherwise
2687 */
2688static int8_t wma_get_matching_hw_mode_index(tp_wma_handle wma,
2689 uint32_t mac0_tx_ss, uint32_t mac0_rx_ss,
2690 enum hw_mode_bandwidth mac0_bw,
2691 uint32_t mac1_tx_ss, uint32_t mac1_rx_ss,
2692 enum hw_mode_bandwidth mac1_bw,
2693 enum hw_mode_dbs_capab dbs,
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302694 enum hw_mode_agile_dfs_capab dfs,
2695 enum hw_mode_sbs_capab sbs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002696{
2697 uint32_t i;
2698 uint32_t t_mac0_tx_ss, t_mac0_rx_ss, t_mac0_bw;
2699 uint32_t t_mac1_tx_ss, t_mac1_rx_ss, t_mac1_bw;
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302700 uint32_t dbs_mode, agile_dfs_mode, sbs_mode;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002701 int8_t found = -EINVAL;
2702
2703 if (!wma) {
2704 WMA_LOGE("%s: Invalid WMA handle", __func__);
2705 return found;
2706 }
2707
2708 for (i = 0; i < wma->num_dbs_hw_modes; i++) {
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302709 t_mac0_tx_ss = WMA_HW_MODE_MAC0_TX_STREAMS_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002710 wma->hw_mode.hw_mode_list[i]);
2711 if (t_mac0_tx_ss != mac0_tx_ss)
2712 continue;
2713
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302714 t_mac0_rx_ss = WMA_HW_MODE_MAC0_RX_STREAMS_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002715 wma->hw_mode.hw_mode_list[i]);
2716 if (t_mac0_rx_ss != mac0_rx_ss)
2717 continue;
2718
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302719 t_mac0_bw = WMA_HW_MODE_MAC0_BANDWIDTH_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002720 wma->hw_mode.hw_mode_list[i]);
Nitesh Shah877ad5d2016-09-22 19:27:58 +05302721 /*
2722 * Firmware advertises max bw capability as CBW 80+80
2723 * for single MAC. Thus CBW 20/40/80 should also be
2724 * supported, if CBW 80+80 is supported.
2725 */
2726 if (t_mac0_bw < mac0_bw)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002727 continue;
2728
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302729 t_mac1_tx_ss = WMA_HW_MODE_MAC1_TX_STREAMS_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002730 wma->hw_mode.hw_mode_list[i]);
2731 if (t_mac1_tx_ss != mac1_tx_ss)
2732 continue;
2733
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302734 t_mac1_rx_ss = WMA_HW_MODE_MAC1_RX_STREAMS_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002735 wma->hw_mode.hw_mode_list[i]);
2736 if (t_mac1_rx_ss != mac1_rx_ss)
2737 continue;
2738
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302739 t_mac1_bw = WMA_HW_MODE_MAC1_BANDWIDTH_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002740 wma->hw_mode.hw_mode_list[i]);
Nitesh Shah877ad5d2016-09-22 19:27:58 +05302741 if (t_mac1_bw < mac1_bw)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002742 continue;
2743
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302744 dbs_mode = WMA_HW_MODE_DBS_MODE_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002745 wma->hw_mode.hw_mode_list[i]);
2746 if (dbs_mode != dbs)
2747 continue;
2748
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302749 agile_dfs_mode = WMA_HW_MODE_AGILE_DFS_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002750 wma->hw_mode.hw_mode_list[i]);
2751 if (agile_dfs_mode != dfs)
2752 continue;
2753
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302754 sbs_mode = WMA_HW_MODE_SBS_MODE_GET(
2755 wma->hw_mode.hw_mode_list[i]);
2756 if (sbs_mode != sbs)
2757 continue;
2758
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002759 found = i;
2760 WMA_LOGI("%s: hw_mode index %d found",
2761 __func__, i);
2762 break;
2763 }
2764 return found;
2765}
2766
2767/**
2768 * wma_get_hw_mode_from_dbs_hw_list() - Get hw_mode index
2769 * @mac0_ss: MAC0 spatial stream configuration
2770 * @mac0_bw: MAC0 bandwidth configuration
2771 * @mac1_ss: MAC1 spatial stream configuration
2772 * @mac1_bw: MAC1 bandwidth configuration
2773 * @dbs: HW DBS capability
2774 * @dfs: HW Agile DFS capability
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302775 * @sbs: HW SBS capability
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002776 *
2777 * Get the HW mode index corresponding to the HW modes spatial stream,
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302778 * bandwidth, DBS, Agile DFS and SBS capability
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002779 *
2780 * Return: Index number if a match is found or -negative value if not found
2781 */
2782int8_t wma_get_hw_mode_idx_from_dbs_hw_list(enum hw_mode_ss_config mac0_ss,
2783 enum hw_mode_bandwidth mac0_bw,
2784 enum hw_mode_ss_config mac1_ss,
2785 enum hw_mode_bandwidth mac1_bw,
2786 enum hw_mode_dbs_capab dbs,
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302787 enum hw_mode_agile_dfs_capab dfs,
2788 enum hw_mode_sbs_capab sbs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002789{
2790 tp_wma_handle wma;
2791 uint32_t mac0_tx_ss, mac0_rx_ss;
2792 uint32_t mac1_tx_ss, mac1_rx_ss;
2793
Anurag Chouhan6d760662016-02-20 16:05:43 +05302794 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002795 if (!wma) {
2796 WMA_LOGE("%s: Invalid WMA handle", __func__);
2797 return -EINVAL;
2798 }
2799
2800 wma_get_tx_rx_ss_from_config(mac0_ss, &mac0_tx_ss, &mac0_rx_ss);
2801 wma_get_tx_rx_ss_from_config(mac1_ss, &mac1_tx_ss, &mac1_rx_ss);
2802
2803 WMA_LOGI("%s: MAC0: TxSS=%d, RxSS=%d, BW=%d",
2804 __func__, mac0_tx_ss, mac0_rx_ss, mac0_bw);
2805 WMA_LOGI("%s: MAC1: TxSS=%d, RxSS=%d, BW=%d",
2806 __func__, mac1_tx_ss, mac1_rx_ss, mac1_bw);
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302807 WMA_LOGI("%s: DBS=%d, Agile DFS=%d, SBS=%d",
2808 __func__, dbs, dfs, sbs);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002809
2810 return wma_get_matching_hw_mode_index(wma, mac0_tx_ss, mac0_rx_ss,
2811 mac0_bw,
2812 mac1_tx_ss, mac1_rx_ss,
2813 mac1_bw,
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302814 dbs, dfs, sbs);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002815}
2816
2817/**
2818 * wma_get_hw_mode_from_idx() - Get HW mode based on index
2819 * @idx: HW mode index
2820 * @hw_mode: HW mode params
2821 *
2822 * Fetches the HW mode parameters
2823 *
2824 * Return: Success if hw mode is obtained and the hw mode params
2825 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302826QDF_STATUS wma_get_hw_mode_from_idx(uint32_t idx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002827 struct sir_hw_mode_params *hw_mode)
2828{
2829 tp_wma_handle wma;
2830 uint32_t param;
2831
Anurag Chouhan6d760662016-02-20 16:05:43 +05302832 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002833 if (!wma) {
2834 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302835 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836 }
2837
2838 if (idx > wma->num_dbs_hw_modes) {
2839 WMA_LOGE("%s: Invalid index", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302840 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002841 }
2842
Mahesh Kumar Kalikot Veetild43e1652015-11-02 15:35:10 -08002843 if (!wma->num_dbs_hw_modes) {
2844 WMA_LOGE("%s: No dbs hw modes available", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302845 return QDF_STATUS_E_FAILURE;
Mahesh Kumar Kalikot Veetild43e1652015-11-02 15:35:10 -08002846 }
2847
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002848 param = wma->hw_mode.hw_mode_list[idx];
2849
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302850 hw_mode->mac0_tx_ss = WMA_HW_MODE_MAC0_TX_STREAMS_GET(param);
2851 hw_mode->mac0_rx_ss = WMA_HW_MODE_MAC0_RX_STREAMS_GET(param);
2852 hw_mode->mac0_bw = WMA_HW_MODE_MAC0_BANDWIDTH_GET(param);
2853 hw_mode->mac1_tx_ss = WMA_HW_MODE_MAC1_TX_STREAMS_GET(param);
2854 hw_mode->mac1_rx_ss = WMA_HW_MODE_MAC1_RX_STREAMS_GET(param);
2855 hw_mode->mac1_bw = WMA_HW_MODE_MAC1_BANDWIDTH_GET(param);
2856 hw_mode->dbs_cap = WMA_HW_MODE_DBS_MODE_GET(param);
2857 hw_mode->agile_dfs_cap = WMA_HW_MODE_AGILE_DFS_GET(param);
2858 hw_mode->sbs_cap = WMA_HW_MODE_SBS_MODE_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002859
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302860 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002861}
2862
2863/**
2864 * wma_get_num_dbs_hw_modes() - Get number of HW mode
2865 *
2866 * Fetches the number of DBS HW modes returned by the FW
2867 *
2868 * Return: Negative value on error or returns the number of DBS HW modes
2869 */
2870int8_t wma_get_num_dbs_hw_modes(void)
2871{
2872 tp_wma_handle wma;
2873
Anurag Chouhan6d760662016-02-20 16:05:43 +05302874 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002875 if (!wma) {
2876 WMA_LOGE("%s: Invalid WMA handle", __func__);
2877 return -EINVAL;
2878 }
2879 return wma->num_dbs_hw_modes;
2880}
2881
2882/**
2883 * wma_is_hw_dbs_capable() - Check if HW is DBS capable
2884 *
2885 * Checks if the HW is DBS capable
2886 *
2887 * Return: true if the HW is DBS capable
2888 */
2889bool wma_is_hw_dbs_capable(void)
2890{
2891 tp_wma_handle wma;
2892 uint32_t param, i, found = 0;
2893
Anurag Chouhan6d760662016-02-20 16:05:43 +05302894 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002895 if (!wma) {
2896 WMA_LOGE("%s: Invalid WMA handle", __func__);
2897 return false;
2898 }
2899
2900 if (!wma_is_dbs_enable()) {
2901 WMA_LOGI("%s: DBS is disabled", __func__);
2902 return false;
2903 }
2904
2905 WMA_LOGI("%s: DBS service bit map: %d", __func__,
2906 WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2907 WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT));
2908
2909 /* The agreement with FW is that: To know if the target is DBS
2910 * capable, DBS needs to be supported both in the HW mode list
2911 * and in the service ready event
2912 */
2913 if (!(WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2914 WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT)))
2915 return false;
2916
2917 for (i = 0; i < wma->num_dbs_hw_modes; i++) {
2918 param = wma->hw_mode.hw_mode_list[i];
2919 WMA_LOGI("%s: HW param: %x", __func__, param);
Nitesh Shah5b7bae02016-09-28 18:58:33 +05302920 if (WMA_HW_MODE_DBS_MODE_GET(param)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002921 WMA_LOGI("%s: HW (%d) is DBS capable", __func__, i);
2922 found = 1;
2923 break;
2924 }
2925 }
2926
2927 if (found)
2928 return true;
2929
2930 return false;
2931}
2932
2933/**
Aravind Narasimhan5b7c2cd2016-12-08 21:04:26 -08002934 * wma_is_hw_sbs_capable() - Check if HW is SBS capable
2935 *
2936 * Checks if the HW is SBS capable
2937 *
2938 * Return: true if the HW is SBS capable
2939 */
2940bool wma_is_hw_sbs_capable(void)
2941{
2942 tp_wma_handle wma;
2943 uint32_t param, i, found = 0;
2944
2945 wma = cds_get_context(QDF_MODULE_ID_WMA);
2946 if (!wma) {
2947 WMA_LOGE("%s: Invalid WMA handle", __func__);
2948 return false;
2949 }
2950
2951 WMA_LOGI("%s: SBS service bit map: %d", __func__,
2952 WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2953 WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT));
2954
2955 /* The agreement with FW is that: To know if the target is SBS
2956 * capable, SBS needs to be supported both in the HW mode list
2957 * and DBS needs to be supported in the service ready event
2958 */
2959 if (!(WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2960 WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT)))
2961 return false;
2962
2963 for (i = 0; i < wma->num_dbs_hw_modes; i++) {
2964 param = wma->hw_mode.hw_mode_list[i];
2965 WMA_LOGI("%s: HW param: %x", __func__, param);
2966 if (WMA_HW_MODE_SBS_MODE_GET(param)) {
2967 WMA_LOGI("%s: HW (%d) is SBS capable", __func__, i);
2968 found = 1;
2969 break;
2970 }
2971 }
2972
2973 if (found)
2974 return true;
2975
2976 return true;
2977}
2978
2979/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002980 * wma_get_mac_id_of_vdev() - Get MAC id corresponding to a vdev
2981 * @vdev_id: VDEV whose MAC ID is required
2982 *
2983 * Get MAC id corresponding to a vdev id from the WMA structure
2984 *
2985 * Return: Negative value on failure and MAC id on success
2986 */
2987int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id)
2988{
2989 tp_wma_handle wma;
2990
Anurag Chouhan6d760662016-02-20 16:05:43 +05302991 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002992 if (!wma) {
2993 WMA_LOGE("%s: Invalid WMA handle", __func__);
2994 return -EINVAL;
2995 }
2996
2997 if (wma->interfaces)
2998 return wma->interfaces[vdev_id].mac_id;
2999
3000 return -EINVAL;
3001}
3002
3003/**
3004 * wma_get_old_and_new_hw_index() - Get the old and new HW index
3005 * @old_hw_mode_index: Value at this pointer contains the old HW mode index
3006 * Default value when not configured is WMA_DEFAULT_HW_MODE_INDEX
3007 * @new_hw_mode_index: Value at this pointer contains the new HW mode index
3008 * Default value when not configured is WMA_DEFAULT_HW_MODE_INDEX
3009 *
3010 * Get the old and new HW index configured in the driver
3011 *
3012 * Return: Failure in case the HW mode indices cannot be fetched and Success
3013 * otherwise. When no HW mode transition has happened the values of
3014 * old_hw_mode_index and new_hw_mode_index will be the same.
3015 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303016QDF_STATUS wma_get_old_and_new_hw_index(uint32_t *old_hw_mode_index,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003017 uint32_t *new_hw_mode_index)
3018{
3019 tp_wma_handle wma;
3020
Anurag Chouhan6d760662016-02-20 16:05:43 +05303021 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003022 if (!wma) {
3023 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303024 return QDF_STATUS_E_INVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003025 }
3026
3027 *old_hw_mode_index = wma->old_hw_mode_index;
3028 *new_hw_mode_index = wma->new_hw_mode_index;
3029
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303030 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003031}
3032
3033/**
3034 * wma_update_intf_hw_mode_params() - Update WMA params
3035 * @vdev_id: VDEV id whose params needs to be updated
3036 * @mac_id: MAC id to be updated
3037 * @cfgd_hw_mode_index: HW mode index from which Tx and Rx SS will be updated
3038 *
3039 * Updates the MAC id, tx spatial stream, rx spatial stream in WMA
3040 *
3041 * Return: None
3042 */
3043void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id,
3044 uint32_t cfgd_hw_mode_index)
3045{
3046 tp_wma_handle wma;
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08003047 uint32_t param;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003048
Anurag Chouhan6d760662016-02-20 16:05:43 +05303049 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003050 if (!wma) {
3051 WMA_LOGE("%s: Invalid WMA handle", __func__);
3052 return;
3053 }
3054
3055 if (!wma->interfaces) {
3056 WMA_LOGE("%s: Interface is NULL", __func__);
3057 return;
3058 }
3059
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08003060 if (cfgd_hw_mode_index > wma->num_dbs_hw_modes) {
3061 WMA_LOGE("%s: Invalid index", __func__);
3062 return;
3063 }
3064
3065 param = wma->hw_mode.hw_mode_list[cfgd_hw_mode_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003066 wma->interfaces[vdev_id].mac_id = mac_id;
3067 if (mac_id == 0) {
3068 wma->interfaces[vdev_id].tx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05303069 WMA_HW_MODE_MAC0_TX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003070 wma->interfaces[vdev_id].rx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05303071 WMA_HW_MODE_MAC0_RX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003072 } else {
3073 wma->interfaces[vdev_id].tx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05303074 WMA_HW_MODE_MAC1_TX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003075 wma->interfaces[vdev_id].rx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05303076 WMA_HW_MODE_MAC1_RX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003077 }
3078}
3079
3080/**
3081 * wma_get_dbs_hw_modes() - Get the DBS HW modes for userspace
3082 * @one_by_one_dbs: 1x1 DBS capability of HW
3083 * @two_by_two_dbs: 2x2 DBS capability of HW
3084 *
3085 * Provides the DBS HW mode capability such as whether
3086 * 1x1 DBS, 2x2 DBS is supported by the HW or not.
3087 *
3088 * Return: Failure in case of error and 0 on success
3089 * one_by_one_dbs/two_by_two_dbs will be false,
3090 * if they are not supported.
3091 * one_by_one_dbs/two_by_two_dbs will be true,
3092 * if they are supported.
3093 * false values of one_by_one_dbs/two_by_two_dbs,
3094 * indicate DBS is disabled
3095 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303096QDF_STATUS wma_get_dbs_hw_modes(bool *one_by_one_dbs, bool *two_by_two_dbs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003097{
3098 tp_wma_handle wma;
3099 uint32_t i;
3100 int8_t found_one_by_one = -EINVAL, found_two_by_two = -EINVAL;
3101 uint32_t conf1_tx_ss, conf1_rx_ss;
3102 uint32_t conf2_tx_ss, conf2_rx_ss;
3103
3104 *one_by_one_dbs = false;
3105 *two_by_two_dbs = false;
3106
3107 if (wma_is_hw_dbs_capable() == false) {
3108 WMA_LOGE("%s: HW is not DBS capable", __func__);
3109 /* Caller will understand that DBS is disabled */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303110 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003111
3112 }
3113
Anurag Chouhan6d760662016-02-20 16:05:43 +05303114 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003115 if (!wma) {
3116 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303117 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003118 }
3119
3120 /* To check 1x1 capability */
3121 wma_get_tx_rx_ss_from_config(HW_MODE_SS_1x1,
3122 &conf1_tx_ss, &conf1_rx_ss);
3123 /* To check 2x2 capability */
3124 wma_get_tx_rx_ss_from_config(HW_MODE_SS_2x2,
3125 &conf2_tx_ss, &conf2_rx_ss);
3126
3127 for (i = 0; i < wma->num_dbs_hw_modes; i++) {
3128 uint32_t t_conf0_tx_ss, t_conf0_rx_ss;
3129 uint32_t t_conf1_tx_ss, t_conf1_rx_ss;
3130 uint32_t dbs_mode;
3131
Nitesh Shah5b7bae02016-09-28 18:58:33 +05303132 t_conf0_tx_ss = WMA_HW_MODE_MAC0_TX_STREAMS_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003133 wma->hw_mode.hw_mode_list[i]);
Nitesh Shah5b7bae02016-09-28 18:58:33 +05303134 t_conf0_rx_ss = WMA_HW_MODE_MAC0_RX_STREAMS_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003135 wma->hw_mode.hw_mode_list[i]);
Nitesh Shah5b7bae02016-09-28 18:58:33 +05303136 t_conf1_tx_ss = WMA_HW_MODE_MAC1_TX_STREAMS_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003137 wma->hw_mode.hw_mode_list[i]);
Nitesh Shah5b7bae02016-09-28 18:58:33 +05303138 t_conf1_rx_ss = WMA_HW_MODE_MAC1_RX_STREAMS_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003139 wma->hw_mode.hw_mode_list[i]);
Nitesh Shah5b7bae02016-09-28 18:58:33 +05303140 dbs_mode = WMA_HW_MODE_DBS_MODE_GET(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003141 wma->hw_mode.hw_mode_list[i]);
3142
3143 if (((((t_conf0_tx_ss == conf1_tx_ss) &&
3144 (t_conf0_rx_ss == conf1_rx_ss)) ||
3145 ((t_conf1_tx_ss == conf1_tx_ss) &&
3146 (t_conf1_rx_ss == conf1_rx_ss))) &&
3147 (dbs_mode == HW_MODE_DBS)) &&
3148 (found_one_by_one < 0)) {
3149 found_one_by_one = i;
3150 WMA_LOGI("%s: 1x1 hw_mode index %d found",
3151 __func__, i);
3152 /* Once an entry is found, need not check for 1x1
3153 * again
3154 */
3155 continue;
3156 }
3157
3158 if (((((t_conf0_tx_ss == conf2_tx_ss) &&
3159 (t_conf0_rx_ss == conf2_rx_ss)) ||
3160 ((t_conf1_tx_ss == conf2_tx_ss) &&
3161 (t_conf1_rx_ss == conf2_rx_ss))) &&
3162 (dbs_mode == HW_MODE_DBS)) &&
3163 (found_two_by_two < 0)) {
3164 found_two_by_two = i;
3165 WMA_LOGI("%s: 2x2 hw_mode index %d found",
3166 __func__, i);
3167 /* Once an entry is found, need not check for 2x2
3168 * again
3169 */
3170 continue;
3171 }
3172 }
3173
3174 if (found_one_by_one >= 0)
3175 *one_by_one_dbs = true;
3176 if (found_two_by_two >= 0)
3177 *two_by_two_dbs = true;
3178
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303179 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003180}
3181
3182/**
3183 * wma_get_current_hw_mode() - Get current HW mode params
3184 * @hw_mode: HW mode parameters
3185 *
3186 * Provides the current HW mode parameters if the HW mode is initialized
3187 * in the driver
3188 *
3189 * Return: Success if the current HW mode params are successfully populated
3190 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303191QDF_STATUS wma_get_current_hw_mode(struct sir_hw_mode_params *hw_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003192{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303193 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003194 uint32_t old_hw_index = 0, new_hw_index = 0;
3195
3196 WMA_LOGI("%s: Get the current hw mode", __func__);
3197
3198 status = wma_get_old_and_new_hw_index(&old_hw_index,
3199 &new_hw_index);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303200 if (QDF_STATUS_SUCCESS != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003201 WMA_LOGE("%s: Failed to get HW mode index", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303202 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003203 }
3204
3205 if (new_hw_index == WMA_DEFAULT_HW_MODE_INDEX) {
3206 WMA_LOGE("%s: HW mode is not yet initialized", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303207 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003208 }
3209
3210 status = wma_get_hw_mode_from_idx(new_hw_index, hw_mode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303211 if (QDF_STATUS_SUCCESS != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003212 WMA_LOGE("%s: Failed to get HW mode index", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303213 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003214 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303215 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003216}
3217
3218/**
3219 * wma_is_dbs_enable() - Check if master DBS control is enabled
3220 *
3221 * Checks if the master DBS control is enabled. This will be used
3222 * to override any other DBS capability
3223 *
3224 * Return: True if master DBS control is enabled
3225 */
3226bool wma_is_dbs_enable(void)
3227{
3228 tp_wma_handle wma;
3229
3230 if (wma_is_dual_mac_disabled_in_ini())
3231 return false;
3232
Anurag Chouhan6d760662016-02-20 16:05:43 +05303233 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003234 if (!wma) {
3235 WMA_LOGE("%s: Invalid WMA handle", __func__);
3236 return false;
3237 }
3238
3239 WMA_LOGD("%s: DBS=%d", __func__,
3240 WMI_DBS_FW_MODE_CFG_DBS_GET(wma->dual_mac_cfg.cur_fw_mode_config));
3241
3242 if (WMI_DBS_FW_MODE_CFG_DBS_GET(wma->dual_mac_cfg.cur_fw_mode_config))
3243 return true;
3244
3245 return false;
3246}
3247
3248/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003249 * wma_get_updated_scan_config() - Get the updated scan configuration
3250 * @scan_config: Pointer containing the updated scan config
3251 * @dbs_scan: 0 or 1 indicating if DBS scan needs to be enabled/disabled
3252 * @dbs_plus_agile_scan: 0 or 1 indicating if DBS plus agile scan needs to be
3253 * enabled/disabled
3254 * @single_mac_scan_with_dfs: 0 or 1 indicating if single MAC scan with DFS
3255 * needs to be enabled/disabled
3256 *
3257 * Takes the current scan configuration and set the necessary scan config
3258 * bits to either 0/1 and provides the updated value to the caller who
3259 * can use this to pass it on to the FW
3260 *
3261 * Return: 0 on success
3262 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303263QDF_STATUS wma_get_updated_scan_config(uint32_t *scan_config,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003264 bool dbs_scan,
3265 bool dbs_plus_agile_scan,
3266 bool single_mac_scan_with_dfs)
3267{
3268 tp_wma_handle wma;
3269
Anurag Chouhan6d760662016-02-20 16:05:43 +05303270 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003271 if (!wma) {
3272 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303273 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003274 }
3275 *scan_config = wma->dual_mac_cfg.cur_scan_config;
3276
3277 WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(*scan_config, dbs_scan);
3278 WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(*scan_config,
3279 dbs_plus_agile_scan);
3280 WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(*scan_config,
3281 single_mac_scan_with_dfs);
3282
3283 WMA_LOGD("%s: *scan_config:%x ", __func__, *scan_config);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303284 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003285}
3286
3287/**
3288 * wma_get_updated_fw_mode_config() - Get the updated fw mode configuration
3289 * @fw_mode_config: Pointer containing the updated fw mode config
3290 * @dbs: 0 or 1 indicating if DBS needs to be enabled/disabled
3291 * @agile_dfs: 0 or 1 indicating if agile DFS needs to be enabled/disabled
3292 *
3293 * Takes the current fw mode configuration and set the necessary fw mode config
3294 * bits to either 0/1 and provides the updated value to the caller who
3295 * can use this to pass it on to the FW
3296 *
3297 * Return: 0 on success
3298 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303299QDF_STATUS wma_get_updated_fw_mode_config(uint32_t *fw_mode_config,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003300 bool dbs,
3301 bool agile_dfs)
3302{
3303 tp_wma_handle wma;
3304
Anurag Chouhan6d760662016-02-20 16:05:43 +05303305 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003306 if (!wma) {
3307 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303308 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003309 }
3310 *fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config;
3311
3312 WMI_DBS_FW_MODE_CFG_DBS_SET(*fw_mode_config, dbs);
3313 WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(*fw_mode_config, agile_dfs);
3314
3315 WMA_LOGD("%s: *fw_mode_config:%x ", __func__, *fw_mode_config);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303316 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003317}
3318
3319/**
3320 * wma_get_dbs_config() - Get DBS bit
3321 *
3322 * Gets the DBS bit of fw_mode_config_bits
3323 *
3324 * Return: 0 or 1 to indicate the DBS bit
3325 */
3326bool wma_get_dbs_config(void)
3327{
3328 tp_wma_handle wma;
3329 uint32_t fw_mode_config;
3330
3331 if (wma_is_dual_mac_disabled_in_ini())
3332 return false;
3333
Anurag Chouhan6d760662016-02-20 16:05:43 +05303334 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003335 if (!wma) {
3336 WMA_LOGE("%s: Invalid WMA handle", __func__);
3337 /* We take that it is disabled and proceed */
3338 return false;
3339 }
3340 fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config;
3341
3342 return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config);
3343}
3344
3345/**
3346 * wma_get_agile_dfs_config() - Get Agile DFS bit
3347 *
3348 * Gets the Agile DFS bit of fw_mode_config_bits
3349 *
3350 * Return: 0 or 1 to indicate the Agile DFS bit
3351 */
3352bool wma_get_agile_dfs_config(void)
3353{
3354 tp_wma_handle wma;
3355 uint32_t fw_mode_config;
3356
3357 if (wma_is_dual_mac_disabled_in_ini())
3358 return false;
3359
Anurag Chouhan6d760662016-02-20 16:05:43 +05303360 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003361 if (!wma) {
3362 WMA_LOGE("%s: Invalid WMA handle", __func__);
3363 /* We take that it is disabled and proceed */
3364 return false;
3365 }
3366 fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config;
3367
3368 return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config);
3369}
3370
3371/**
3372 * wma_get_dbs_scan_config() - Get DBS scan bit
3373 *
3374 * Gets the DBS scan bit of concurrent_scan_config_bits
3375 *
3376 * Return: 0 or 1 to indicate the DBS scan bit
3377 */
3378bool wma_get_dbs_scan_config(void)
3379{
3380 tp_wma_handle wma;
3381 uint32_t scan_config;
3382
3383 if (wma_is_dual_mac_disabled_in_ini())
3384 return false;
3385
Anurag Chouhan6d760662016-02-20 16:05:43 +05303386 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003387 if (!wma) {
3388 WMA_LOGE("%s: Invalid WMA handle", __func__);
3389 /* We take that it is disabled and proceed */
3390 return false;
3391 }
3392 scan_config = wma->dual_mac_cfg.cur_scan_config;
3393
3394 return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config);
3395}
3396
3397/**
3398 * wma_get_dbs_plus_agile_scan_config() - Get DBS plus agile scan bit
3399 *
3400 * Gets the DBS plus agile scan bit of concurrent_scan_config_bits
3401 *
3402 * Return: 0 or 1 to indicate the DBS plus agile scan bit
3403 */
3404bool wma_get_dbs_plus_agile_scan_config(void)
3405{
3406 tp_wma_handle wma;
3407 uint32_t scan_config;
3408
3409 if (wma_is_dual_mac_disabled_in_ini())
3410 return false;
3411
Anurag Chouhan6d760662016-02-20 16:05:43 +05303412 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003413 if (!wma) {
3414 WMA_LOGE("%s: Invalid WMA handle", __func__);
3415 /* We take that it is disabled and proceed */
3416 return false;
3417 }
3418 scan_config = wma->dual_mac_cfg.cur_scan_config;
3419
3420 return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config);
3421}
3422
3423/**
3424 * wma_get_single_mac_scan_with_dfs_config() - Get Single MAC scan with DFS bit
3425 *
3426 * Gets the Single MAC scan with DFS bit of concurrent_scan_config_bits
3427 *
3428 * Return: 0 or 1 to indicate the Single MAC scan with DFS bit
3429 */
3430bool wma_get_single_mac_scan_with_dfs_config(void)
3431{
3432 tp_wma_handle wma;
3433 uint32_t scan_config;
3434
3435 if (wma_is_dual_mac_disabled_in_ini())
3436 return false;
3437
Anurag Chouhan6d760662016-02-20 16:05:43 +05303438 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003439 if (!wma) {
3440 WMA_LOGE("%s: Invalid WMA handle", __func__);
3441 /* We take that it is disabled and proceed */
3442 return false;
3443 }
3444 scan_config = wma->dual_mac_cfg.cur_scan_config;
3445
3446 return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config);
3447}
3448
3449/**
3450 * wma_is_dual_mac_disabled_in_ini() - Check if dual mac is disabled in INI
3451 *
3452 * Checks if the dual mac feature is disabled in INI
3453 *
3454 * Return: true if the dual mac feature is disabled from INI
3455 */
3456bool wma_is_dual_mac_disabled_in_ini(void)
3457{
Anurag Chouhan6d760662016-02-20 16:05:43 +05303458 tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003459
3460 if (!mac) {
3461 WMA_LOGE("%s: Invalid mac pointer", __func__);
3462 return true;
3463 }
3464
3465 if (mac->dual_mac_feature_disable)
3466 return true;
3467
3468 return false;
3469}
3470
3471/**
3472 * wma_get_prev_dbs_config() - Get prev DBS bit
3473 *
3474 * Gets the previous DBS bit of fw_mode_config_bits
3475 *
3476 * Return: 0 or 1 to indicate the DBS bit
3477 */
3478bool wma_get_prev_dbs_config(void)
3479{
3480 tp_wma_handle wma;
3481 uint32_t fw_mode_config;
3482
3483 if (wma_is_dual_mac_disabled_in_ini())
3484 return false;
3485
Anurag Chouhan6d760662016-02-20 16:05:43 +05303486 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003487 if (!wma) {
3488 WMA_LOGE("%s: Invalid WMA handle", __func__);
3489 /* We take that it is disabled and proceed */
3490 return false;
3491 }
3492 fw_mode_config = wma->dual_mac_cfg.prev_fw_mode_config;
3493
3494 return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config);
3495}
3496
3497/**
3498 * wma_get_prev_agile_dfs_config() - Get prev Agile DFS bit
3499 *
3500 * Gets the previous Agile DFS bit of fw_mode_config_bits
3501 *
3502 * Return: 0 or 1 to indicate the Agile DFS bit
3503 */
3504bool wma_get_prev_agile_dfs_config(void)
3505{
3506 tp_wma_handle wma;
3507 uint32_t fw_mode_config;
3508
3509 if (wma_is_dual_mac_disabled_in_ini())
3510 return false;
3511
Anurag Chouhan6d760662016-02-20 16:05:43 +05303512 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003513 if (!wma) {
3514 WMA_LOGE("%s: Invalid WMA handle", __func__);
3515 /* We take that it is disabled and proceed */
3516 return false;
3517 }
3518 fw_mode_config = wma->dual_mac_cfg.prev_fw_mode_config;
3519
3520 return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config);
3521}
3522
3523/**
3524 * wma_get_prev_dbs_scan_config() - Get prev DBS scan bit
3525 *
3526 * Gets the previous DBS scan bit of concurrent_scan_config_bits
3527 *
3528 * Return: 0 or 1 to indicate the DBS scan bit
3529 */
3530bool wma_get_prev_dbs_scan_config(void)
3531{
3532 tp_wma_handle wma;
3533 uint32_t scan_config;
3534
3535 if (wma_is_dual_mac_disabled_in_ini())
3536 return false;
3537
Anurag Chouhan6d760662016-02-20 16:05:43 +05303538 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003539 if (!wma) {
3540 WMA_LOGE("%s: Invalid WMA handle", __func__);
3541 /* We take that it is disabled and proceed */
3542 return false;
3543 }
3544 scan_config = wma->dual_mac_cfg.prev_scan_config;
3545
3546 return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config);
3547}
3548
3549/**
3550 * wma_get_prev_dbs_plus_agile_scan_config() - Get prev DBS plus agile scan bit
3551 *
3552 * Gets the previous DBS plus agile scan bit of concurrent_scan_config_bits
3553 *
3554 * Return: 0 or 1 to indicate the DBS plus agile scan bit
3555 */
3556bool wma_get_prev_dbs_plus_agile_scan_config(void)
3557{
3558 tp_wma_handle wma;
3559 uint32_t scan_config;
3560
3561 if (wma_is_dual_mac_disabled_in_ini())
3562 return false;
3563
Anurag Chouhan6d760662016-02-20 16:05:43 +05303564 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003565 if (!wma) {
3566 WMA_LOGE("%s: Invalid WMA handle", __func__);
3567 /* We take that it is disabled and proceed */
3568 return false;
3569 }
3570 scan_config = wma->dual_mac_cfg.prev_scan_config;
3571
3572 return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config);
3573}
3574
3575/**
3576 * wma_get_prev_single_mac_scan_with_dfs_config() - Get prev Single MAC scan
3577 * with DFS bit
3578 *
3579 * Gets the previous Single MAC scan with DFS bit of concurrent_scan_config_bits
3580 *
3581 * Return: 0 or 1 to indicate the Single MAC scan with DFS bit
3582 */
3583bool wma_get_prev_single_mac_scan_with_dfs_config(void)
3584{
3585 tp_wma_handle wma;
3586 uint32_t scan_config;
3587
3588 if (wma_is_dual_mac_disabled_in_ini())
3589 return false;
3590
Anurag Chouhan6d760662016-02-20 16:05:43 +05303591 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003592 if (!wma) {
3593 WMA_LOGE("%s: Invalid WMA handle", __func__);
3594 /* We take that it is disabled and proceed */
3595 return false;
3596 }
3597 scan_config = wma->dual_mac_cfg.prev_scan_config;
3598
3599 return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config);
3600}
3601
3602/**
3603 * wma_is_scan_simultaneous_capable() - Check if scan parallelization is
3604 * supported or not
3605 *
3606 * currently scan parallelization feature support is dependent on DBS but
3607 * it can be independent in future.
3608 *
3609 * Return: True if master DBS control is enabled
3610 */
3611bool wma_is_scan_simultaneous_capable(void)
3612{
3613 if (wma_is_hw_dbs_capable())
3614 return true;
3615
3616 return false;
3617}
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08003618
3619/**
3620 * wma_get_vht_ch_width - return vht channel width
3621 *
3622 * Return: return vht channel width
3623 */
3624uint32_t wma_get_vht_ch_width(void)
3625{
3626 uint32_t fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ;
Anurag Chouhan6d760662016-02-20 16:05:43 +05303627 tp_wma_handle wm_hdl = cds_get_context(QDF_MODULE_ID_WMA);
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08003628
3629 if (NULL == wm_hdl)
3630 return fw_ch_wd;
3631
Kiran Kumar Lokere02b9aa42016-05-26 14:54:49 -07003632 if (wm_hdl->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ)
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08003633 fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ;
Kiran Kumar Lokere02b9aa42016-05-26 14:54:49 -07003634 else if (wm_hdl->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_160MHZ)
3635 fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ;
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08003636
3637 return fw_ch_wd;
3638}
Govind Singhd76a5b02016-03-08 15:12:14 +05303639
3640/**
Krunal Soniaa664da2016-06-15 23:46:40 -07003641 * wma_get_num_of_setbits_from_bitmask() - to get num of setbits from bitmask
3642 * @mask: given bitmask
3643 *
3644 * This helper function should return number of setbits from bitmask
3645 *
3646 * Return: number of setbits from bitmask
3647 */
3648uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask)
3649{
3650 uint32_t num_of_setbits = 0;
3651
3652 while (mask) {
3653 mask &= (mask - 1);
3654 num_of_setbits++;
3655 }
3656 return num_of_setbits;
3657}
3658
3659/**
Govind Singhd76a5b02016-03-08 15:12:14 +05303660 * wma_config_debug_module_cmd - set debug log config
3661 * @wmi_handle: wmi layer handle
3662 * @param: debug log parameter
3663 * @val: debug log value
3664 * @module_id_bitmap: debug module id bitmap
3665 * @bitmap_len: debug module bitmap length
3666 *
3667 * Return: QDF_STATUS_SUCCESS for success or error code
3668 */
3669QDF_STATUS
3670wma_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param,
3671 A_UINT32 val, A_UINT32 *module_id_bitmap,
3672 A_UINT32 bitmap_len)
3673{
3674 struct dbglog_params dbg_param;
3675 dbg_param.param = param;
3676 dbg_param.val = val;
3677 dbg_param.module_id_bitmap = module_id_bitmap;
3678 dbg_param.bitmap_len = bitmap_len;
3679
3680 return wmi_unified_dbglog_cmd_send(wmi_handle, &dbg_param);
3681}
Peng Xu8fdaa492016-06-22 10:20:47 -07003682
3683/**
3684 * wma_is_p2p_lo_capable() - if driver is capable of p2p listen offload
3685 *
3686 * This function checks if driver is capable of p2p listen offload
3687 * true: capable of p2p offload
3688 * false: not capable
3689 *
3690 * Return: true - capable, false - not capable
3691 */
3692bool wma_is_p2p_lo_capable(void)
3693{
3694 tp_wma_handle wma;
3695
3696 wma = cds_get_context(QDF_MODULE_ID_WMA);
3697 if (!wma) {
3698 WMA_LOGE("%s: Invalid WMA handle", __func__);
3699 return false;
3700 }
3701
3702 if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
3703 WMI_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT))
3704 return true;
3705
3706 return false;
3707}
Aravind Narasimhan5b7c2cd2016-12-08 21:04:26 -08003708
3709/**
3710 * wma_is_hw_dbs_2x2_capable() - if hardware is capable of dbs 2x2
3711 *
3712 * This function checks if hw_modes supported are always capable of
3713 * DBS 2x2.
3714 * true: DBS 2x2 can always be supported
3715 * false: hw_modes support DBS 1x1 as well
3716 *
3717 * Return: true - DBS2x2, false - DBS1x1
3718 */
3719bool wma_is_hw_dbs_2x2_capable(void)
3720{
3721 tp_wma_handle wma;
3722 int i, j = 0, max_mac;
3723 uint32_t ht_2g, ht_5g;
3724 struct extended_caps *phy_caps;
3725 WMI_MAC_PHY_CAPABILITIES *mac_cap;
3726 uint32_t tx_chain, rx_chain, final_min_rf_chains = 0;
3727 uint32_t min_rf_chains, min_2g_rf_chains, min_5g_rf_chains;
3728
3729 wma = cds_get_context(QDF_MODULE_ID_WMA);
3730 if (!wma) {
3731 WMA_LOGE("%s: Invalid WMA handle", __func__);
3732 return false;
3733 }
3734
3735 phy_caps = &wma->phy_caps;
3736 for (i = 0; i < phy_caps->num_hw_modes.num_hw_modes; i++) {
3737 if (phy_caps->each_hw_mode_cap[i].phy_id_map == PHY1_PHY2)
3738 max_mac = j + 2;
3739 else
3740 max_mac = j + 1;
3741 for ( ; j < max_mac; j++) {
3742 mac_cap = &phy_caps->each_phy_cap_per_hwmode[j];
3743 ht_2g = mac_cap->ht_cap_info_2G;
3744 ht_5g = mac_cap->ht_cap_info_5G;
3745 if (ht_5g && ht_2g) {
3746 tx_chain = mac_cap->tx_chain_mask_2G;
3747 rx_chain = mac_cap->rx_chain_mask_2G;
3748 min_2g_rf_chains = QDF_MIN(
3749 wma_get_num_of_setbits_from_bitmask(tx_chain),
3750 wma_get_num_of_setbits_from_bitmask(rx_chain));
3751 tx_chain = mac_cap->tx_chain_mask_5G;
3752 rx_chain = mac_cap->rx_chain_mask_5G;
3753 min_5g_rf_chains = QDF_MIN(
3754 wma_get_num_of_setbits_from_bitmask(tx_chain),
3755 wma_get_num_of_setbits_from_bitmask(rx_chain));
3756 min_rf_chains = QDF_MIN(min_2g_rf_chains,
3757 min_5g_rf_chains);
3758 } else {
3759 continue;
3760 }
3761 final_min_rf_chains = QDF_MIN(final_min_rf_chains,
3762 min_rf_chains);
3763 }
3764 }
3765 return (final_min_rf_chains == 2) ? true : false;
3766}