blob: fd54008db815101d09c4c5091b6a1eac3081c09a [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"
45#include "ol_txrx_ctrl_api.h"
46#include "wlan_tgt_def_config.h"
47
Nirav Shahcbc6d722016-03-01 16:24:53 +053048#include "qdf_nbuf.h"
Anurag Chouhan6d760662016-02-20 16:05:43 +053049#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080050#include "ol_txrx_api.h"
Anurag Chouhan600c3a02016-03-01 10:33:54 +053051#include "qdf_mem.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080052#include "ol_txrx_types.h"
53#include "ol_txrx_peer_find.h"
54
55#include "wma_types.h"
56#include "lim_api.h"
57#include "lim_session_utils.h"
58
59#include "cds_utils.h"
60
61#if !defined(REMOVE_PKT_LOG)
62#include "pktlog_ac.h"
63#endif /* REMOVE_PKT_LOG */
64
65#include "dbglog_host.h"
66#include "csr_api.h"
67#include "ol_fw.h"
68
69#include "dfs.h"
70#include "wma_internal.h"
Chandrasekaran, Manishekar0d814c72015-11-05 10:42:48 +053071#include "cds_concurrency.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080072
Naveen Rawatc0c91cd2015-11-05 14:27:37 -080073#include "linux/ieee80211.h"
74
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080075/* MCS Based rate table */
76/* HT MCS parameters with Nss = 1 */
Ryan Hsu6139d2d2015-11-04 17:29:00 -080077static struct index_data_rate_type mcs_nss1[] = {
78 /* MCS L20 S20 L40 S40 */
79 {0, {65, 72}, {135, 150 } },
80 {1, {130, 144}, {270, 300 } },
81 {2, {195, 217}, {405, 450 } },
82 {3, {260, 289}, {540, 600 } },
83 {4, {390, 433}, {815, 900 } },
84 {5, {520, 578}, {1080, 1200} },
85 {6, {585, 650}, {1215, 1350} },
86 {7, {650, 722}, {1350, 1500} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080087};
88
89/* HT MCS parameters with Nss = 2 */
Ryan Hsu6139d2d2015-11-04 17:29:00 -080090static struct index_data_rate_type mcs_nss2[] = {
91 /* MCS L20 S20 L40 S40 */
92 {0, {130, 144}, {270, 300 } },
93 {1, {260, 289}, {540, 600 } },
94 {2, {390, 433}, {810, 900 } },
95 {3, {520, 578}, {1080, 1200} },
96 {4, {780, 867}, {1620, 1800} },
97 {5, {1040, 1156}, {2160, 2400} },
98 {6, {1170, 1300}, {2430, 2700} },
99 {7, {1300, 1440}, {2700, 3000} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800100};
101
102#ifdef WLAN_FEATURE_11AC
103/* MCS Based VHT rate table */
104/* MCS parameters with Nss = 1*/
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800105static struct index_vht_data_rate_type vht_mcs_nss1[] = {
106 /* MCS L20 S20 L40 S40 L80 S80 */
107 {0, {65, 72 }, {135, 150}, {293, 325} },
108 {1, {130, 144}, {270, 300}, {585, 650} },
109 {2, {195, 217}, {405, 450}, {878, 975} },
110 {3, {260, 289}, {540, 600}, {1170, 1300} },
111 {4, {390, 433}, {810, 900}, {1755, 1950} },
112 {5, {520, 578}, {1080, 1200}, {2340, 2600} },
113 {6, {585, 650}, {1215, 1350}, {2633, 2925} },
114 {7, {650, 722}, {1350, 1500}, {2925, 3250} },
115 {8, {780, 867}, {1620, 1800}, {3510, 3900} },
116 {9, {865, 960}, {1800, 2000}, {3900, 4333} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800117};
118
119/*MCS parameters with Nss = 2*/
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800120static struct index_vht_data_rate_type vht_mcs_nss2[] = {
121 /* MCS L20 S20 L40 S40 L80 S80 */
122 {0, {130, 144}, {270, 300}, { 585, 650} },
123 {1, {260, 289}, {540, 600}, {1170, 1300} },
124 {2, {390, 433}, {810, 900}, {1755, 1950} },
125 {3, {520, 578}, {1080, 1200}, {2340, 2600} },
126 {4, {780, 867}, {1620, 1800}, {3510, 3900} },
127 {5, {1040, 1156}, {2160, 2400}, {4680, 5200} },
128 {6, {1170, 1300}, {2430, 2700}, {5265, 5850} },
129 {7, {1300, 1444}, {2700, 3000}, {5850, 6500} },
130 {8, {1560, 1733}, {3240, 3600}, {7020, 7800} },
131 {9, {1730, 1920}, {3600, 4000}, {7800, 8667} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800132};
133#endif /* WLAN_FEATURE_11AC */
134
135#ifdef BIG_ENDIAN_HOST
136
137/* ############# function definitions ############ */
138
139/**
140 * wma_swap_bytes() - swap bytes
141 * @pv: buffer
142 * @n: swap bytes
143 *
144 * Return: none
145 */
146void wma_swap_bytes(void *pv, uint32_t n)
147{
148 int32_t no_words;
149 int32_t i;
150 uint32_t *word_ptr;
151
152 no_words = n / sizeof(uint32_t);
153 word_ptr = (uint32_t *) pv;
154 for (i = 0; i < no_words; i++) {
155 *(word_ptr + i) = __cpu_to_le32(*(word_ptr + i));
156 }
157}
158
159#define SWAPME(x, len) wma_swap_bytes(&x, len);
160#endif /* BIG_ENDIAN_HOST */
161
162/**
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800163 * wma_mcs_rate_match() - find the match mcs rate
164 * @match_rate: the rate to look up
165 * @is_sgi: return if the SGI rate is found
166 * @nss: the nss in use
167 * @nss1_rate: the nss1 rate
168 * @nss1_srate: the nss1 SGI rate
169 * @nss2_rate: the nss2 rate
170 * @nss2_srate: the nss2 SGI rate
171 *
172 * This is a helper function to find the match of the tx_rate
173 * in terms of the nss1/nss2 rate with non-SGI/SGI.
174 *
175 * Return: the found rate or 0 otherwise
176 */
177static inline uint16_t wma_mcs_rate_match(uint16_t match_rate, bool *is_sgi,
178 uint8_t nss, uint16_t nss1_rate,
179 uint16_t nss1_srate,
180 uint16_t nss2_rate,
181 uint16_t nss2_srate)
182{
183 WMA_LOGD("%s match_rate: %d, %d %d %d %d",
184 __func__, match_rate, nss1_rate, nss1_srate, nss2_rate,
185 nss2_srate);
186
187 if (match_rate == nss1_rate) {
188 return nss1_rate;
189 } else if (match_rate == nss1_srate) {
190 *is_sgi = true;
191 return nss1_srate;
192 } else if (nss == 2 && match_rate == nss2_rate)
193 return nss2_rate;
194 else if (nss == 2 && match_rate == nss2_srate) {
195 *is_sgi = true;
196 return nss2_srate;
197 } else
198 return 0;
199}
200
201/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202 * wma_get_mcs_idx() - get mcs index
203 * @maxRate: max rate
204 * @rate_flags: rate flags
205 * @nss: number of nss
206 * @mcsRateFlag: mcs rate flag
207 *
208 * Return: return mcs index
209 */
210static uint8_t wma_get_mcs_idx(uint16_t maxRate, uint8_t rate_flags,
211 uint8_t nss, uint8_t *mcsRateFlag)
212{
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800213 uint8_t index = 0;
214 uint16_t match_rate;
215 bool is_sgi = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800217 WMA_LOGD("%s rate:%d rate_flgs: 0x%x, nss: %d",
218 __func__, maxRate, rate_flags, nss);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800219
220 *mcsRateFlag = rate_flags;
221 *mcsRateFlag &= ~eHAL_TX_RATE_SGI;
222#ifdef WLAN_FEATURE_11AC
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800223 for (index = 0; index < MAX_VHT_MCS_IDX; index++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800224 if (rate_flags & eHAL_TX_RATE_VHT80) {
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800225 /* check for vht80 nss1/2 rate set */
226 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
227 vht_mcs_nss1[index].ht80_rate[0],
228 vht_mcs_nss1[index].ht80_rate[1],
229 vht_mcs_nss2[index].ht80_rate[0],
230 vht_mcs_nss2[index].ht80_rate[1]);
231 if (match_rate)
232 goto rate_found;
233 }
234 if ((rate_flags & eHAL_TX_RATE_VHT40) |
235 (rate_flags & eHAL_TX_RATE_VHT80)) {
236 /* check for vht40 nss1/2 rate set */
237 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
238 vht_mcs_nss1[index].ht40_rate[0],
239 vht_mcs_nss1[index].ht40_rate[1],
240 vht_mcs_nss2[index].ht40_rate[0],
241 vht_mcs_nss2[index].ht40_rate[1]);
242 if (match_rate) {
243 *mcsRateFlag &= ~eHAL_TX_RATE_VHT80;
244 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800245 }
246 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800247 if ((rate_flags & eHAL_TX_RATE_VHT20) |
248 (rate_flags & eHAL_TX_RATE_VHT40) |
249 (rate_flags & eHAL_TX_RATE_VHT80)) {
250 /* check for vht20 nss1/2 rate set */
251 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
252 vht_mcs_nss1[index].ht20_rate[0],
253 vht_mcs_nss1[index].ht20_rate[1],
254 vht_mcs_nss2[index].ht20_rate[0],
255 vht_mcs_nss2[index].ht20_rate[1]);
256 if (match_rate) {
257 *mcsRateFlag &= ~(eHAL_TX_RATE_VHT80 |
258 eHAL_TX_RATE_VHT40);
259 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800260 }
261 }
262 }
263#endif /* WLAN_FEATURE_11AC */
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800264 for (index = 0; index < MAX_HT_MCS_IDX; index++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800265 if (rate_flags & eHAL_TX_RATE_HT40) {
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800266 /* check for ht40 nss1/2 rate set */
267 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
268 mcs_nss1[index].ht40_rate[0],
269 mcs_nss1[index].ht40_rate[1],
270 mcs_nss2[index].ht40_rate[0],
271 mcs_nss2[index].ht40_rate[1]);
272 if (match_rate) {
273 *mcsRateFlag = eHAL_TX_RATE_HT40;
274 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800275 }
276 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800277 if (rate_flags & eHAL_TX_RATE_HT20) {
278 /* check for ht20 nss1/2 rate set */
279 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
280 mcs_nss1[index].ht20_rate[0],
281 mcs_nss1[index].ht20_rate[1],
282 mcs_nss2[index].ht20_rate[0],
283 mcs_nss2[index].ht20_rate[1]);
284 if (match_rate) {
285 *mcsRateFlag = eHAL_TX_RATE_HT20;
286 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800287 }
288 }
289 }
290
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800291rate_found:
292 /* set SGI flag only if this is SGI rate */
293 if (match_rate && is_sgi == true)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800294 *mcsRateFlag |= eHAL_TX_RATE_SGI;
295
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800296 WMA_LOGD("%s - match_rate: %d index: %d rate_flag: 0x%x is_sgi: %d",
297 __func__, match_rate, index, *mcsRateFlag, is_sgi);
298
299 return match_rate ? index : INVALID_MCS_IDX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800300}
301
302/**
303 * host_map_smps_mode() - map fw smps mode to tSmpsModeValue
304 * @fw_smps_mode: fw smps mode
305 *
306 * Return: return tSmpsModeValue
307 */
308tSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode)
309{
310 tSmpsModeValue smps_mode = SMPS_MODE_DISABLED;
311 switch (fw_smps_mode) {
312 case WMI_SMPS_FORCED_MODE_STATIC:
313 smps_mode = STATIC_SMPS_MODE;
314 break;
315 case WMI_SMPS_FORCED_MODE_DYNAMIC:
316 smps_mode = DYNAMIC_SMPS_MODE;
317 break;
318 default:
319 smps_mode = SMPS_MODE_DISABLED;
320 }
321
322 return smps_mode;
323}
324
325#ifdef WLAN_FEATURE_STATS_EXT
326/**
327 * wma_stats_ext_event_handler() - extended stats event handler
328 * @handle: wma handle
329 * @event_buf: event buffer received from fw
330 * @len: length of data
331 *
332 * Return: 0 for success or error code
333 */
334int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf,
335 uint32_t len)
336{
337 WMI_STATS_EXT_EVENTID_param_tlvs *param_buf;
338 tSirStatsExtEvent *stats_ext_event;
339 wmi_stats_ext_event_fixed_param *stats_ext_info;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530340 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800341 cds_msg_t cds_msg;
342 uint8_t *buf_ptr;
343 uint32_t alloc_len;
344
345 WMA_LOGD("%s: Posting stats ext event to SME", __func__);
346
347 param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *) event_buf;
348 if (!param_buf) {
349 WMA_LOGE("%s: Invalid stats ext event buf", __func__);
350 return -EINVAL;
351 }
352
353 stats_ext_info = param_buf->fixed_param;
354 buf_ptr = (uint8_t *) stats_ext_info;
355
356 alloc_len = sizeof(tSirStatsExtEvent);
357 alloc_len += stats_ext_info->data_len;
358
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530359 stats_ext_event = (tSirStatsExtEvent *) qdf_mem_malloc(alloc_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800360 if (NULL == stats_ext_event) {
361 WMA_LOGE("%s: Memory allocation failure", __func__);
362 return -ENOMEM;
363 }
364
365 buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE;
366
367 stats_ext_event->vdev_id = stats_ext_info->vdev_id;
368 stats_ext_event->event_data_len = stats_ext_info->data_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530369 qdf_mem_copy(stats_ext_event->event_data,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370 buf_ptr, stats_ext_event->event_data_len);
371
372 cds_msg.type = eWNI_SME_STATS_EXT_EVENT;
373 cds_msg.bodyptr = (void *)stats_ext_event;
374 cds_msg.bodyval = 0;
375
376 status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530377 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800378 WMA_LOGE("%s: Failed to post stats ext event to SME", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530379 qdf_mem_free(stats_ext_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800380 return -EFAULT;
381 }
382
383 WMA_LOGD("%s: stats ext event Posted to SME", __func__);
384 return 0;
385}
386#endif /* WLAN_FEATURE_STATS_EXT */
387
Govind Singha471e5e2015-10-12 17:11:14 +0530388/**
389 * wma_profile_data_report_event_handler() - fw profiling handler
390 * @handle: wma handle
391 * @event_buf: event buffer received from fw
392 * @len: length of data
393 *
394 * Return: 0 for success or error code
395 */
396int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf,
397 uint32_t len)
398{
399 WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *param_buf;
400 wmi_wlan_profile_ctx_t *profile_ctx;
401 wmi_wlan_profile_t *profile_data;
402 uint32_t i = 0;
403 uint32_t entries;
404 uint8_t *buf_ptr;
405 param_buf = (WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *) event_buf;
406
407 if (!param_buf) {
408 WMA_LOGE("%s: Invalid profile data event buf", __func__);
409 return -EINVAL;
410 }
411 profile_ctx = param_buf->profile_ctx;
412 buf_ptr = (uint8_t *)profile_ctx;
413 buf_ptr = buf_ptr + sizeof(wmi_wlan_profile_ctx_t) + WMI_TLV_HDR_SIZE;
414 profile_data = (wmi_wlan_profile_t *) buf_ptr;
415 entries = profile_ctx->bin_count;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530416 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Govind Singha471e5e2015-10-12 17:11:14 +0530417 "Profile data stats\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530418 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Govind Singha471e5e2015-10-12 17:11:14 +0530419 "TOT: %d\n"
420 "tx_msdu_cnt: %d\n"
421 "tx_mpdu_cnt: %d\n"
422 "tx_ppdu_cnt: %d\n"
423 "rx_msdu_cnt: %d\n"
424 "rx_mpdu_cnt: %d\n"
425 "bin_count: %d\n",
426 profile_ctx->tot,
427 profile_ctx->tx_msdu_cnt,
428 profile_ctx->tx_mpdu_cnt,
429 profile_ctx->tx_ppdu_cnt,
430 profile_ctx->rx_msdu_cnt,
431 profile_ctx->rx_mpdu_cnt,
432 profile_ctx->bin_count);
433
434 for (i = 0; i < entries; i++) {
435 if (i == WMI_WLAN_PROFILE_MAX_BIN_CNT)
436 break;
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 ID: %d\n"
439 "Profile Count: %d\n"
440 "Profile TOT: %d\n"
441 "Profile Min: %d\n"
442 "Profile Max: %d\n"
443 "Profile hist_intvl: %d\n"
444 "Profile hist[0]: %d\n"
445 "Profile hist[1]: %d\n"
446 "Profile hist[2]: %d\n",
447 profile_data[i].id,
448 profile_data[i].cnt,
449 profile_data[i].tot,
450 profile_data[i].min,
451 profile_data[i].max,
452 profile_data[i].hist_intvl,
453 profile_data[i].hist[0],
454 profile_data[i].hist[1],
455 profile_data[i].hist[2]);
456 }
457
458 return 0;
459}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800460
461#ifdef WLAN_FEATURE_LINK_LAYER_STATS
462
463/**
464 * wma_unified_link_peer_stats_event_handler() - peer stats event handler
465 * @handle: wma handle
466 * @cmd_param_info: data received with event from fw
467 * @len: length of data
468 *
469 * Return: 0 for success or error code
470 */
471static int wma_unified_link_peer_stats_event_handler(void *handle,
472 uint8_t *cmd_param_info,
473 uint32_t len)
474{
475 WMI_PEER_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
476 wmi_peer_stats_event_fixed_param *fixed_param;
477 wmi_peer_link_stats *peer_stats, *temp_peer_stats;
478 wmi_rate_stats *rate_stats;
479 tSirLLStatsResults *link_stats_results;
480 uint8_t *results, *t_peer_stats, *t_rate_stats;
481 uint32_t count, num_rates = 0;
482 uint32_t next_res_offset, next_peer_offset, next_rate_offset;
483 size_t peer_info_size, peer_stats_size, rate_stats_size;
484 size_t link_stats_results_size;
485
Anurag Chouhan6d760662016-02-20 16:05:43 +0530486 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800487
488 if (!pMac) {
489 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
490 return -EINVAL;
491 }
492
493 if (!pMac->sme.pLinkLayerStatsIndCallback) {
494 WMA_LOGD("%s: HDD callback is null", __func__);
495 return -EINVAL;
496 }
497
498 WMA_LOGD("%s: Posting Peer Stats event to HDD", __func__);
499 param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
500 if (!param_tlvs) {
501 WMA_LOGA("%s: Invalid stats event", __func__);
502 return -EINVAL;
503 }
504 /*
505 * cmd_param_info contains
506 * wmi_peer_stats_event_fixed_param fixed_param;
507 * num_peers * size of(struct wmi_peer_link_stats)
508 * num_rates * size of(struct wmi_rate_stats)
509 * num_rates is the sum of the rates of all the peers.
510 */
511 fixed_param = param_tlvs->fixed_param;
512 peer_stats = param_tlvs->peer_stats;
513 rate_stats = param_tlvs->peer_rate_stats;
514
515 if (!fixed_param || !peer_stats ||
516 (peer_stats->num_rates && !rate_stats)) {
517 WMA_LOGA("%s: Invalid param_tlvs for Peer Stats", __func__);
518 return -EINVAL;
519 }
520
521 /*
522 * num_rates - sum of the rates of all the peers
523 */
524 temp_peer_stats = (wmi_peer_link_stats *) peer_stats;
525 for (count = 0; count < fixed_param->num_peers; count++) {
526 num_rates += temp_peer_stats->num_rates;
527 temp_peer_stats++;
528 }
529
530 peer_stats_size = sizeof(tSirWifiPeerStat);
531 peer_info_size = sizeof(tSirWifiPeerInfo);
532 rate_stats_size = sizeof(tSirWifiRateStat);
533 link_stats_results_size =
534 sizeof(*link_stats_results) + peer_stats_size +
535 (fixed_param->num_peers * peer_info_size) +
536 (num_rates * rate_stats_size);
537
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530538 link_stats_results = qdf_mem_malloc(link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800539 if (NULL == link_stats_results) {
540 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
541 __func__, link_stats_results_size);
542 return -ENOMEM;
543 }
544
545 WMA_LOGD("Peer stats from FW event buf");
546 WMA_LOGD("Fixed Param:");
547 WMA_LOGD("request_id %u num_peers %u peer_event_number %u more_data %u",
548 fixed_param->request_id, fixed_param->num_peers,
549 fixed_param->peer_event_number, fixed_param->more_data);
550
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530551 qdf_mem_zero(link_stats_results, link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800552
553 link_stats_results->paramId = WMI_LINK_STATS_ALL_PEER;
554 link_stats_results->rspId = fixed_param->request_id;
555 link_stats_results->ifaceId = 0;
556 link_stats_results->num_peers = fixed_param->num_peers;
557 link_stats_results->peer_event_number = fixed_param->peer_event_number;
558 link_stats_results->moreResultToFollow = fixed_param->more_data;
559
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530560 qdf_mem_copy(link_stats_results->results,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800561 &fixed_param->num_peers, peer_stats_size);
562
563 results = (uint8_t *) link_stats_results->results;
564 t_peer_stats = (uint8_t *) peer_stats;
565 t_rate_stats = (uint8_t *) rate_stats;
566 next_res_offset = peer_stats_size;
567 next_peer_offset = WMI_TLV_HDR_SIZE;
568 next_rate_offset = WMI_TLV_HDR_SIZE;
569 for (count = 0; count < fixed_param->num_peers; count++) {
570 WMA_LOGD("Peer Info:");
571 WMA_LOGD("peer_type %u capabilities %u num_rates %u",
572 peer_stats->peer_type, peer_stats->capabilities,
573 peer_stats->num_rates);
574
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530575 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800576 t_peer_stats + next_peer_offset, peer_info_size);
577 next_res_offset += peer_info_size;
578
579 /* Copy rate stats associated with this peer */
580 for (count = 0; count < peer_stats->num_rates; count++) {
581 WMA_LOGD("Rate Stats Info:");
582 WMA_LOGD("rate %u bitrate %u tx_mpdu %u rx_mpdu %u "
583 "mpdu_lost %u retries %u retries_short %u "
584 "retries_long %u", rate_stats->rate,
585 rate_stats->bitrate, rate_stats->tx_mpdu,
586 rate_stats->rx_mpdu, rate_stats->mpdu_lost,
587 rate_stats->retries, rate_stats->retries_short,
588 rate_stats->retries_long);
589 rate_stats++;
590
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530591 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800592 t_rate_stats + next_rate_offset,
593 rate_stats_size);
594 next_res_offset += rate_stats_size;
595 next_rate_offset += sizeof(*rate_stats);
596 }
597 next_peer_offset += sizeof(*peer_stats);
598 peer_stats++;
599 }
600
601 /* call hdd callback with Link Layer Statistics
602 * vdev_id/ifacId in link_stats_results will be
603 * used to retrieve the correct HDD context
604 */
605 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
606 WMA_LINK_LAYER_STATS_RESULTS_RSP,
607 link_stats_results);
608 WMA_LOGD("%s: Peer Stats event posted to HDD", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530609 qdf_mem_free(link_stats_results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800610
611 return 0;
612}
613
614
615/**
616 * wma_unified_link_radio_stats_event_handler() - radio link stats event handler
617 * @handle: wma handle
618 * @cmd_param_info: data received with event from fw
619 * @len: length of data
620 *
621 * Return: 0 for success or error code
622 */
623static int wma_unified_link_radio_stats_event_handler(void *handle,
624 uint8_t *cmd_param_info,
625 uint32_t len)
626{
627 WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
628 wmi_radio_link_stats_event_fixed_param *fixed_param;
629 wmi_radio_link_stats *radio_stats;
630 wmi_channel_stats *channel_stats;
631 tSirLLStatsResults *link_stats_results;
632 uint8_t *results, *t_radio_stats, *t_channel_stats;
633 uint32_t next_res_offset, next_chan_offset, count;
634 size_t radio_stats_size, chan_stats_size;
635 size_t link_stats_results_size;
636
Anurag Chouhan6d760662016-02-20 16:05:43 +0530637 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800638
639 if (!pMac) {
640 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
641 return -EINVAL;
642 }
643
644 if (!pMac->sme.pLinkLayerStatsIndCallback) {
645 WMA_LOGD("%s: HDD callback is null", __func__);
646 return -EINVAL;
647 }
648
649 WMA_LOGD("%s: Posting Radio Stats event to HDD", __func__);
650 param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
651 if (!param_tlvs) {
652 WMA_LOGA("%s: Invalid stats event", __func__);
653 return -EINVAL;
654 }
655
656 /*
657 * cmd_param_info contains
658 * wmi_radio_link_stats_event_fixed_param fixed_param;
659 * size of(struct wmi_radio_link_stats);
660 * num_channels * size of(struct wmi_channel_stats)
661 */
662 fixed_param = param_tlvs->fixed_param;
663 radio_stats = param_tlvs->radio_stats;
664 channel_stats = param_tlvs->channel_stats;
665
666 if (!fixed_param || !radio_stats ||
667 (radio_stats->num_channels && !channel_stats)) {
668 WMA_LOGA("%s: Invalid param_tlvs for Radio Stats", __func__);
669 return -EINVAL;
670 }
671
672 radio_stats_size = sizeof(tSirWifiRadioStat);
673 chan_stats_size = sizeof(tSirWifiChannelStats);
674 link_stats_results_size = sizeof(*link_stats_results) +
675 radio_stats_size + (radio_stats->num_channels * chan_stats_size);
676
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530677 link_stats_results = qdf_mem_malloc(link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800678 if (NULL == link_stats_results) {
679 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
680 __func__, link_stats_results_size);
681 return -ENOMEM;
682 }
683
684 WMA_LOGD("Radio stats from FW event buf");
685 WMA_LOGD("Fixed Param:");
686 WMA_LOGD("request_id %u num_radio %u more_radio_events %u",
687 fixed_param->request_id, fixed_param->num_radio,
688 fixed_param->more_radio_events);
689
690 WMA_LOGD("Radio Info");
691 WMA_LOGD("radio_id %u on_time %u tx_time %u rx_time %u on_time_scan %u "
692 "on_time_nbd %u on_time_gscan %u on_time_roam_scan %u "
693 "on_time_pno_scan %u on_time_hs20 %u num_channels %u",
694 radio_stats->radio_id, radio_stats->on_time,
695 radio_stats->tx_time, radio_stats->rx_time,
696 radio_stats->on_time_scan, radio_stats->on_time_nbd,
697 radio_stats->on_time_gscan,
698 radio_stats->on_time_roam_scan,
699 radio_stats->on_time_pno_scan,
700 radio_stats->on_time_hs20, radio_stats->num_channels);
701
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530702 qdf_mem_zero(link_stats_results, link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800703
704 link_stats_results->paramId = WMI_LINK_STATS_RADIO;
705 link_stats_results->rspId = fixed_param->request_id;
706 link_stats_results->ifaceId = 0;
707 link_stats_results->num_radio = fixed_param->num_radio;
708 link_stats_results->peer_event_number = 0;
709 link_stats_results->moreResultToFollow = fixed_param->more_radio_events;
710
711 results = (uint8_t *) link_stats_results->results;
712 t_radio_stats = (uint8_t *) radio_stats;
713 t_channel_stats = (uint8_t *) channel_stats;
714
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530715 qdf_mem_copy(results, t_radio_stats + WMI_TLV_HDR_SIZE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800716 radio_stats_size);
717
718 next_res_offset = radio_stats_size;
719 next_chan_offset = WMI_TLV_HDR_SIZE;
720 WMA_LOGD("Channel Stats Info");
721 for (count = 0; count < radio_stats->num_channels; count++) {
722 WMA_LOGD("channel_width %u center_freq %u center_freq0 %u "
723 "center_freq1 %u radio_awake_time %u cca_busy_time %u",
724 channel_stats->channel_width,
725 channel_stats->center_freq,
726 channel_stats->center_freq0,
727 channel_stats->center_freq1,
728 channel_stats->radio_awake_time,
729 channel_stats->cca_busy_time);
730 channel_stats++;
731
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530732 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800733 t_channel_stats + next_chan_offset,
734 chan_stats_size);
735 next_res_offset += chan_stats_size;
736 next_chan_offset += sizeof(*channel_stats);
737 }
738
739 /* call hdd callback with Link Layer Statistics
740 * vdev_id/ifacId in link_stats_results will be
741 * used to retrieve the correct HDD context
742 */
743 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
744 WMA_LINK_LAYER_STATS_RESULTS_RSP,
745 link_stats_results);
746 WMA_LOGD("%s: Radio Stats event posted to HDD", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530747 qdf_mem_free(link_stats_results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800748
749 return 0;
750}
751
752/**
753 * wma_register_ll_stats_event_handler() - register link layer stats related
754 * event handler
755 * @wma_handle: wma handle
756 *
757 * Return: none
758 */
759void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle)
760{
761 if (NULL == wma_handle) {
762 WMA_LOGE("%s: wma_handle is NULL", __func__);
763 return;
764 }
765
766 wmi_unified_register_event_handler(wma_handle->wmi_handle,
767 WMI_IFACE_LINK_STATS_EVENTID,
768 wma_unified_link_iface_stats_event_handler);
769 wmi_unified_register_event_handler(wma_handle->wmi_handle,
770 WMI_PEER_LINK_STATS_EVENTID,
771 wma_unified_link_peer_stats_event_handler);
772 wmi_unified_register_event_handler(wma_handle->wmi_handle,
773 WMI_RADIO_LINK_STATS_EVENTID,
774 wma_unified_link_radio_stats_event_handler);
775
776 return;
777}
778
779
780/**
781 * wma_process_ll_stats_clear_req() - clear link layer stats
782 * @wma: wma handle
783 * @clearReq: ll stats clear request command params
784 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530785 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800786 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530787QDF_STATUS wma_process_ll_stats_clear_req
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800788 (tp_wma_handle wma, const tpSirLLStatsClearReq clearReq)
789{
790 wmi_clear_link_stats_cmd_fixed_param *cmd;
791 int32_t len;
792 wmi_buf_t buf;
793 uint8_t *buf_ptr;
794 int ret;
795
796 if (!clearReq || !wma) {
797 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530798 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800799 }
800
801 len = sizeof(*cmd);
802 buf = wmi_buf_alloc(wma->wmi_handle, len);
803
804 if (!buf) {
805 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530806 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800807 }
808
809 buf_ptr = (uint8_t *) wmi_buf_data(buf);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530810 qdf_mem_zero(buf_ptr, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800811 cmd = (wmi_clear_link_stats_cmd_fixed_param *) buf_ptr;
812
813 WMITLV_SET_HDR(&cmd->tlv_header,
814 WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param,
815 WMITLV_GET_STRUCT_TLVLEN
816 (wmi_clear_link_stats_cmd_fixed_param));
817
818 cmd->stop_stats_collection_req = clearReq->stopReq;
819 cmd->vdev_id = clearReq->staId;
820 cmd->stats_clear_req_mask = clearReq->statsClearReqMask;
821
822 WMI_CHAR_ARRAY_TO_MAC_ADDR(wma->interfaces[clearReq->staId].addr,
823 &cmd->peer_macaddr);
824
825 WMA_LOGD("LINK_LAYER_STATS - Clear Request Params");
826 WMA_LOGD("StopReq : %d", cmd->stop_stats_collection_req);
827 WMA_LOGD("Vdev Id : %d", cmd->vdev_id);
828 WMA_LOGD("Clear Stat Mask : %d", cmd->stats_clear_req_mask);
829 WMA_LOGD("Peer MAC Addr : %pM",
830 wma->interfaces[clearReq->staId].addr);
831
832 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
833 WMI_CLEAR_LINK_STATS_CMDID);
834 if (ret) {
835 WMA_LOGE("%s: Failed to send clear link stats req", __func__);
836 wmi_buf_free(buf);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530837 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800838 }
839
840 WMA_LOGD("Clear Link Layer Stats request sent successfully");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530841 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800842}
843
844/**
845 * wma_process_ll_stats_set_req() - link layer stats set request
846 * @wma: wma handle
847 * @setReq: ll stats set request command params
848 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530849 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800850 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530851QDF_STATUS wma_process_ll_stats_set_req
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800852 (tp_wma_handle wma, const tpSirLLStatsSetReq setReq)
853{
854 wmi_start_link_stats_cmd_fixed_param *cmd;
855 int32_t len;
856 wmi_buf_t buf;
857 uint8_t *buf_ptr;
858 int ret;
859
860 if (!setReq || !wma) {
861 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530862 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800863 }
864
865 len = sizeof(*cmd);
866 buf = wmi_buf_alloc(wma->wmi_handle, len);
867
868 if (!buf) {
869 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530870 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800871 }
872
873 buf_ptr = (uint8_t *) wmi_buf_data(buf);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530874 qdf_mem_zero(buf_ptr, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875 cmd = (wmi_start_link_stats_cmd_fixed_param *) buf_ptr;
876
877 WMITLV_SET_HDR(&cmd->tlv_header,
878 WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param,
879 WMITLV_GET_STRUCT_TLVLEN
880 (wmi_start_link_stats_cmd_fixed_param));
881
882 cmd->mpdu_size_threshold = setReq->mpduSizeThreshold;
883 cmd->aggressive_statistics_gathering =
884 setReq->aggressiveStatisticsGathering;
885
886 WMA_LOGD("LINK_LAYER_STATS - Start/Set Request Params");
887 WMA_LOGD("MPDU Size Thresh : %d", cmd->mpdu_size_threshold);
888 WMA_LOGD("Aggressive Gather: %d", cmd->aggressive_statistics_gathering);
889
890 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
891 WMI_START_LINK_STATS_CMDID);
892 if (ret) {
893 WMA_LOGE("%s: Failed to send set link stats request", __func__);
894 wmi_buf_free(buf);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530895 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896 }
897
898 WMA_LOGD("Set Link Layer Stats request sent successfully");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530899 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800900}
901
902/**
903 * wma_process_ll_stats_get_req() - link layer stats get request
904 * @wma:wma handle
905 * @getReq:ll stats get request command params
906 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530907 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800908 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530909QDF_STATUS wma_process_ll_stats_get_req
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800910 (tp_wma_handle wma, const tpSirLLStatsGetReq getReq)
911{
912 wmi_request_link_stats_cmd_fixed_param *cmd;
913 int32_t len;
914 wmi_buf_t buf;
915 uint8_t *buf_ptr;
916 int ret;
917
918 if (!getReq || !wma) {
919 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530920 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800921 }
922
923 len = sizeof(*cmd);
924 buf = wmi_buf_alloc(wma->wmi_handle, len);
925
926 if (!buf) {
927 WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530928 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 }
930
931 buf_ptr = (uint8_t *) wmi_buf_data(buf);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530932 qdf_mem_zero(buf_ptr, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933 cmd = (wmi_request_link_stats_cmd_fixed_param *) buf_ptr;
934
935 WMITLV_SET_HDR(&cmd->tlv_header,
936 WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param,
937 WMITLV_GET_STRUCT_TLVLEN
938 (wmi_request_link_stats_cmd_fixed_param));
939
940 cmd->request_id = getReq->reqId;
941 cmd->stats_type = getReq->paramIdMask;
942 cmd->vdev_id = getReq->staId;
943
944 WMI_CHAR_ARRAY_TO_MAC_ADDR(wma->interfaces[getReq->staId].addr,
945 &cmd->peer_macaddr);
946
947 WMA_LOGD("LINK_LAYER_STATS - Get Request Params");
948 WMA_LOGD("Request ID : %d", cmd->request_id);
949 WMA_LOGD("Stats Type : %d", cmd->stats_type);
950 WMA_LOGD("Vdev ID : %d", cmd->vdev_id);
951 WMA_LOGD("Peer MAC Addr : %pM", wma->interfaces[getReq->staId].addr);
952
953 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
954 WMI_REQUEST_LINK_STATS_CMDID);
955 if (ret) {
956 WMA_LOGE("%s: Failed to send get link stats request", __func__);
957 wmi_buf_free(buf);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530958 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800959 }
960
961 WMA_LOGD("Get Link Layer Stats request sent successfully");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530962 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800963}
964
965/**
966 * wma_unified_link_iface_stats_event_handler() - link iface stats event handler
967 * @wma:wma handle
968 * @cmd_param_info: data from event
969 * @len: length
970 *
971 * Return: 0 for success or error code
972 */
973int wma_unified_link_iface_stats_event_handler(void *handle,
974 uint8_t *cmd_param_info,
975 uint32_t len)
976{
977 WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
978 wmi_iface_link_stats_event_fixed_param *fixed_param;
979 wmi_iface_link_stats *link_stats;
980 wmi_wmm_ac_stats *ac_stats;
981 tSirLLStatsResults *link_stats_results;
982 uint8_t *results, *t_link_stats, *t_ac_stats;
983 uint32_t next_res_offset, next_ac_offset, count;
984 uint32_t roaming_offset, roaming_size;
985 size_t link_stats_size, ac_stats_size, iface_info_size;
986 size_t link_stats_results_size;
987
Anurag Chouhan6d760662016-02-20 16:05:43 +0530988 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800989
990 if (!pMac) {
991 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
992 return -EINVAL;
993 }
994
995 if (!pMac->sme.pLinkLayerStatsIndCallback) {
996 WMA_LOGD("%s: HDD callback is null", __func__);
997 return -EINVAL;
998 }
999
1000 WMA_LOGD("%s: Posting Iface Stats event to HDD", __func__);
1001 param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
1002 if (!param_tlvs) {
1003 WMA_LOGA("%s: Invalid stats event", __func__);
1004 return -EINVAL;
1005 }
1006
1007 /*
1008 * cmd_param_info contains
1009 * wmi_iface_link_stats_event_fixed_param fixed_param;
1010 * wmi_iface_link_stats iface_link_stats;
1011 * iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats)
1012 */
1013 fixed_param = param_tlvs->fixed_param;
1014 link_stats = param_tlvs->iface_link_stats;
1015 ac_stats = param_tlvs->ac;
1016
1017 if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats)) {
1018 WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__);
1019 return -EINVAL;
1020 }
1021
1022 link_stats_size = sizeof(tSirWifiIfaceStat);
1023 iface_info_size = sizeof(tSirWifiInterfaceInfo);
1024 ac_stats_size = sizeof(tSirWifiWmmAcStat);
1025 link_stats_results_size = sizeof(*link_stats_results) + link_stats_size;
1026
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301027 link_stats_results = qdf_mem_malloc(link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 if (!link_stats_results) {
1029 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
1030 __func__, link_stats_results_size);
1031 return -ENOMEM;
1032 }
1033
1034 WMA_LOGD("Interface stats from FW event buf");
1035 WMA_LOGD("Fixed Param:");
1036 WMA_LOGD("request_id %u vdev_id %u",
1037 fixed_param->request_id, fixed_param->vdev_id);
1038
1039 WMA_LOGD("Iface Stats:");
1040 WMA_LOGD("beacon_rx %u mgmt_rx %u mgmt_action_rx %u mgmt_action_tx %u "
1041 "rssi_mgmt %u rssi_data %u rssi_ack %u num_peers %u "
1042 "num_peer_events %u num_ac %u roam_state %u"
1043 " avg_bcn_spread_offset_high %u"
1044 " avg_bcn_spread_offset_low %u"
1045 " is leaky_ap %u"
1046 " avg_rx_frames_leaked %u"
1047 " rx_leak_window %u",
1048 link_stats->beacon_rx, link_stats->mgmt_rx,
1049 link_stats->mgmt_action_rx, link_stats->mgmt_action_tx,
1050 link_stats->rssi_mgmt, link_stats->rssi_data,
1051 link_stats->rssi_ack, link_stats->num_peers,
1052 link_stats->num_peer_events, link_stats->num_ac,
1053 link_stats->roam_state,
1054 link_stats->avg_bcn_spread_offset_high,
1055 link_stats->avg_bcn_spread_offset_low,
1056 link_stats->is_leaky_ap,
1057 link_stats->avg_rx_frms_leaked,
1058 link_stats->rx_leak_window);
1059
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301060 qdf_mem_zero(link_stats_results, link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001061
1062 link_stats_results->paramId = WMI_LINK_STATS_IFACE;
1063 link_stats_results->rspId = fixed_param->request_id;
1064 link_stats_results->ifaceId = fixed_param->vdev_id;
1065 link_stats_results->num_peers = link_stats->num_peers;
1066 link_stats_results->peer_event_number = 0;
1067 link_stats_results->moreResultToFollow = 0;
1068
1069 results = (uint8_t *) link_stats_results->results;
1070 t_link_stats = (uint8_t *) link_stats;
1071 t_ac_stats = (uint8_t *) ac_stats;
1072
1073 /* Copy roaming state */
1074 roaming_offset = offsetof(tSirWifiInterfaceInfo, roaming);
1075 roaming_size = member_size(tSirWifiInterfaceInfo, roaming);
1076
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301077 qdf_mem_copy(results + roaming_offset, &link_stats->roam_state,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001078 roaming_size);
1079
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301080 qdf_mem_copy(results + iface_info_size,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001081 t_link_stats + WMI_TLV_HDR_SIZE,
1082 link_stats_size - iface_info_size -
1083 WIFI_AC_MAX * ac_stats_size);
1084
1085 next_res_offset = link_stats_size - WIFI_AC_MAX * ac_stats_size;
1086 next_ac_offset = WMI_TLV_HDR_SIZE;
1087
1088 WMA_LOGD("AC Stats:");
1089 for (count = 0; count < link_stats->num_ac; count++) {
1090 WMA_LOGD("ac_type %u tx_mpdu %u rx_mpdu %u tx_mcast %u "
1091 "rx_mcast %u rx_ampdu %u tx_ampdu %u mpdu_lost %u "
1092 "retries %u retries_short %u retries_long %u "
1093 "contention_time_min %u contention_time_max %u "
1094 "contention_time_avg %u contention_num_samples %u",
1095 ac_stats->ac_type, ac_stats->tx_mpdu,
1096 ac_stats->rx_mpdu, ac_stats->tx_mcast,
1097 ac_stats->rx_mcast, ac_stats->rx_ampdu,
1098 ac_stats->tx_ampdu, ac_stats->mpdu_lost,
1099 ac_stats->retries, ac_stats->retries_short,
1100 ac_stats->retries_long, ac_stats->contention_time_min,
1101 ac_stats->contention_time_max,
1102 ac_stats->contention_time_avg,
1103 ac_stats->contention_num_samples);
1104 ac_stats++;
1105
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301106 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107 t_ac_stats + next_ac_offset, ac_stats_size);
1108 next_res_offset += ac_stats_size;
1109 next_ac_offset += sizeof(*ac_stats);
1110 }
1111
1112 /* call hdd callback with Link Layer Statistics
1113 * vdev_id/ifacId in link_stats_results will be
1114 * used to retrieve the correct HDD context
1115 */
1116 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
1117 WMA_LINK_LAYER_STATS_RESULTS_RSP,
1118 link_stats_results);
1119 WMA_LOGD("%s: Iface Stats event posted to HDD", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301120 qdf_mem_free(link_stats_results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001121
1122 return 0;
1123}
1124
1125#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
1126
1127/**
1128 * wma_update_pdev_stats() - update pdev stats
1129 * @wma: wma handle
1130 * @pdev_stats: pdev stats
1131 *
1132 * Return: none
1133 */
1134static void wma_update_pdev_stats(tp_wma_handle wma,
1135 wmi_pdev_stats *pdev_stats)
1136{
1137 tAniGetPEStatsRsp *stats_rsp_params;
1138 uint32_t temp_mask;
1139 uint8_t *stats_buf;
1140 tCsrGlobalClassAStatsInfo *classa_stats = NULL;
1141 struct wma_txrx_node *node;
1142 uint8_t i;
1143
1144 for (i = 0; i < wma->max_bssid; i++) {
1145 node = &wma->interfaces[i];
1146 stats_rsp_params = node->stats_rsp;
1147 if (stats_rsp_params) {
1148 node->fw_stats_set |= FW_PDEV_STATS_SET;
1149 WMA_LOGD("<---FW PDEV STATS received for vdevId:%d", i);
1150 stats_buf = (uint8_t *) (stats_rsp_params + 1);
1151 temp_mask = stats_rsp_params->statsMask;
1152 if (temp_mask & (1 << eCsrSummaryStats))
1153 stats_buf += sizeof(tCsrSummaryStatsInfo);
1154
1155 if (temp_mask & (1 << eCsrGlobalClassAStats)) {
1156 classa_stats =
1157 (tCsrGlobalClassAStatsInfo *) stats_buf;
1158 classa_stats->max_pwr = pdev_stats->chan_tx_pwr;
1159 }
1160 }
1161 }
1162}
1163
1164/**
1165 * wma_update_vdev_stats() - update vdev stats
1166 * @wma: wma handle
1167 * @vdev_stats: vdev stats
1168 *
1169 * Return: none
1170 */
1171static void wma_update_vdev_stats(tp_wma_handle wma,
1172 wmi_vdev_stats *vdev_stats)
1173{
1174 tAniGetPEStatsRsp *stats_rsp_params;
1175 tCsrSummaryStatsInfo *summary_stats = NULL;
1176 uint8_t *stats_buf;
1177 struct wma_txrx_node *node;
1178 uint8_t i;
1179 int8_t rssi = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301180 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001181 tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) wma->pGetRssiReq;
1182 cds_msg_t sme_msg = { 0 };
1183
1184 node = &wma->interfaces[vdev_stats->vdev_id];
1185 stats_rsp_params = node->stats_rsp;
1186 if (stats_rsp_params) {
1187 stats_buf = (uint8_t *) (stats_rsp_params + 1);
1188 node->fw_stats_set |= FW_VDEV_STATS_SET;
1189 WMA_LOGD("<---FW VDEV STATS received for vdevId:%d",
1190 vdev_stats->vdev_id);
1191 if (stats_rsp_params->statsMask & (1 << eCsrSummaryStats)) {
1192 summary_stats = (tCsrSummaryStatsInfo *) stats_buf;
1193 for (i = 0; i < 4; i++) {
1194 summary_stats->tx_frm_cnt[i] =
1195 vdev_stats->tx_frm_cnt[i];
1196 summary_stats->fail_cnt[i] =
1197 vdev_stats->fail_cnt[i];
1198 summary_stats->multiple_retry_cnt[i] =
1199 vdev_stats->multiple_retry_cnt[i];
1200 }
1201
1202 summary_stats->rx_frm_cnt = vdev_stats->rx_frm_cnt;
1203 summary_stats->rx_error_cnt = vdev_stats->rx_err_cnt;
1204 summary_stats->rx_discard_cnt =
1205 vdev_stats->rx_discard_cnt;
1206 summary_stats->ack_fail_cnt = vdev_stats->ack_fail_cnt;
1207 summary_stats->rts_succ_cnt = vdev_stats->rts_succ_cnt;
1208 summary_stats->rts_fail_cnt = vdev_stats->rts_fail_cnt;
1209 }
1210 }
1211
1212 WMA_LOGD("vdev id %d beancon snr %d data snr %d",
1213 vdev_stats->vdev_id,
1214 vdev_stats->vdev_snr.bcn_snr, vdev_stats->vdev_snr.dat_snr);
1215
1216 if (pGetRssiReq && pGetRssiReq->sessionId == vdev_stats->vdev_id) {
1217 if ((vdev_stats->vdev_snr.bcn_snr == WMA_TGT_INVALID_SNR) &&
1218 (vdev_stats->vdev_snr.dat_snr == WMA_TGT_INVALID_SNR)) {
1219 /*
1220 * Firmware sends invalid snr till it sees
1221 * Beacon/Data after connection since after
1222 * vdev up fw resets the snr to invalid.
1223 * In this duartion Host will return the last know
1224 * rssi during connection.
1225 */
1226 WMA_LOGE("Invalid SNR from firmware");
1227
1228 } else {
1229 if (vdev_stats->vdev_snr.bcn_snr != WMA_TGT_INVALID_SNR) {
1230 rssi = vdev_stats->vdev_snr.bcn_snr;
1231 } else if (vdev_stats->vdev_snr.dat_snr !=
1232 WMA_TGT_INVALID_SNR) {
1233 rssi = vdev_stats->vdev_snr.dat_snr;
1234 }
1235
1236 /*
1237 * Get the absolute rssi value from the current rssi value
1238 * the sinr value is hardcoded into 0 in the core stack
1239 */
1240 rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
1241 }
1242
1243 WMA_LOGD("Average Rssi = %d, vdev id= %d", rssi,
1244 pGetRssiReq->sessionId);
1245
1246 /* update the average rssi value to UMAC layer */
1247 if (NULL != pGetRssiReq->rssiCallback) {
1248 ((tCsrRssiCallback) (pGetRssiReq->rssiCallback))(rssi,
1249 pGetRssiReq->staId,
1250 pGetRssiReq->pDevContext);
1251 }
1252
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301253 qdf_mem_free(pGetRssiReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254 wma->pGetRssiReq = NULL;
1255 }
1256
1257 if (node->psnr_req) {
1258 tAniGetSnrReq *p_snr_req = node->psnr_req;
1259
1260 if (vdev_stats->vdev_snr.bcn_snr != WMA_TGT_INVALID_SNR)
1261 p_snr_req->snr = vdev_stats->vdev_snr.bcn_snr;
1262 else if (vdev_stats->vdev_snr.dat_snr != WMA_TGT_INVALID_SNR)
1263 p_snr_req->snr = vdev_stats->vdev_snr.dat_snr;
1264 else
1265 p_snr_req->snr = WMA_TGT_INVALID_SNR;
1266
1267 sme_msg.type = eWNI_SME_SNR_IND;
1268 sme_msg.bodyptr = p_snr_req;
1269 sme_msg.bodyval = 0;
1270
Anurag Chouhan6d760662016-02-20 16:05:43 +05301271 qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301272 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001273 WMA_LOGE("%s: Fail to post snr ind msg", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301274 qdf_mem_free(p_snr_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001275 }
1276
1277 node->psnr_req = NULL;
1278 }
1279}
1280
1281/**
1282 * wma_post_stats() - update stats to PE
1283 * @wma: wma handle
1284 * @node: txrx node
1285 *
1286 * Return: none
1287 */
1288static void wma_post_stats(tp_wma_handle wma, struct wma_txrx_node *node)
1289{
1290 tAniGetPEStatsRsp *stats_rsp_params;
1291
1292 stats_rsp_params = node->stats_rsp;
1293 /* send response to UMAC */
1294 wma_send_msg(wma, WMA_GET_STATISTICS_RSP, (void *)stats_rsp_params, 0);
1295 node->stats_rsp = NULL;
1296 node->fw_stats_set = 0;
1297}
1298
1299/**
1300 * wma_update_peer_stats() - update peer stats
1301 * @wma: wma handle
1302 * @peer_stats: peer stats
1303 *
1304 * Return: none
1305 */
1306static void wma_update_peer_stats(tp_wma_handle wma,
1307 wmi_peer_stats *peer_stats)
1308{
1309 tAniGetPEStatsRsp *stats_rsp_params;
1310 tCsrGlobalClassAStatsInfo *classa_stats = NULL;
1311 struct wma_txrx_node *node;
1312 uint8_t *stats_buf, vdev_id, macaddr[IEEE80211_ADDR_LEN], mcsRateFlags;
1313 uint32_t temp_mask;
1314
1315 WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, &macaddr[0]);
1316 if (!wma_find_vdev_by_bssid(wma, macaddr, &vdev_id))
1317 return;
1318
1319 node = &wma->interfaces[vdev_id];
1320 if (node->stats_rsp) {
1321 node->fw_stats_set |= FW_PEER_STATS_SET;
1322 WMA_LOGD("<-- FW PEER STATS received for vdevId:%d", vdev_id);
1323 stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp;
1324 stats_buf = (uint8_t *) (stats_rsp_params + 1);
1325 temp_mask = stats_rsp_params->statsMask;
1326 if (temp_mask & (1 << eCsrSummaryStats))
1327 stats_buf += sizeof(tCsrSummaryStatsInfo);
1328
1329 if (temp_mask & (1 << eCsrGlobalClassAStats)) {
1330 classa_stats = (tCsrGlobalClassAStatsInfo *) stats_buf;
1331 WMA_LOGD("peer tx rate:%d", peer_stats->peer_tx_rate);
1332 /*The linkspeed returned by fw is in kbps so convert
1333 *it in to units of 500kbps which is expected by UMAC*/
1334 if (peer_stats->peer_tx_rate) {
1335 classa_stats->tx_rate =
1336 peer_stats->peer_tx_rate / 500;
1337 }
1338
1339 classa_stats->tx_rate_flags = node->rate_flags;
1340 if (!(node->rate_flags & eHAL_TX_RATE_LEGACY)) {
1341 classa_stats->mcs_index =
1342 wma_get_mcs_idx((peer_stats->peer_tx_rate /
1343 100), node->rate_flags,
1344 node->nss, &mcsRateFlags);
1345 /* rx_frag_cnt and promiscuous_rx_frag_cnt
1346 * parameter is currently not used. lets use the
1347 * same parameter to hold the nss value and mcs
1348 * rate flags */
1349 classa_stats->rx_frag_cnt = node->nss;
1350 classa_stats->promiscuous_rx_frag_cnt =
1351 mcsRateFlags;
1352 WMA_LOGD("Computed mcs_idx:%d mcs_rate_flags:%d",
1353 classa_stats->mcs_index, mcsRateFlags);
1354 }
1355 /* FW returns tx power in intervals of 0.5 dBm
1356 Convert it back to intervals of 1 dBm */
1357 classa_stats->max_pwr =
1358 roundup(classa_stats->max_pwr, 2) >> 1;
1359 WMA_LOGD("peer tx rate flags:%d nss:%d max_txpwr:%d",
1360 node->rate_flags, node->nss,
1361 classa_stats->max_pwr);
1362 }
1363
1364 if (node->fw_stats_set & FW_STATS_SET) {
1365 WMA_LOGD("<--STATS RSP VDEV_ID:%d", vdev_id);
1366 wma_post_stats(wma, node);
1367 }
1368 }
1369}
1370
1371/**
1372 * wma_post_link_status() - post link status to SME
1373 * @pGetLinkStatus: SME Link status
1374 * @link_status: Link status
1375 *
1376 * Return: none
1377 */
1378void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus,
1379 uint8_t link_status)
1380{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301381 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001382 cds_msg_t sme_msg = { 0 };
1383
1384 pGetLinkStatus->linkStatus = link_status;
1385 sme_msg.type = eWNI_SME_LINK_STATUS_IND;
1386 sme_msg.bodyptr = pGetLinkStatus;
1387 sme_msg.bodyval = 0;
1388
Anurag Chouhan6d760662016-02-20 16:05:43 +05301389 qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301390 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001391 WMA_LOGE("%s: Fail to post link status ind msg", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301392 qdf_mem_free(pGetLinkStatus);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001393 }
1394}
1395
1396/**
1397 * wma_link_status_event_handler() - link status event handler
1398 * @handle: wma handle
1399 * @cmd_param_info: data from event
1400 * @len: length
1401 *
1402 * Return: 0 for success or error code
1403 */
1404int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info,
1405 uint32_t len)
1406{
1407 tp_wma_handle wma = (tp_wma_handle) handle;
1408 WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf;
1409 wmi_vdev_rate_stats_event_fixed_param *event;
1410 wmi_vdev_rate_ht_info *ht_info;
1411 struct wma_txrx_node *intr = wma->interfaces;
1412 uint8_t link_status = LINK_STATUS_LEGACY;
1413 int i;
1414
1415 param_buf =
1416 (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *) cmd_param_info;
1417 if (!param_buf) {
1418 WMA_LOGA("%s: Invalid stats event", __func__);
1419 return -EINVAL;
1420 }
1421
1422 event = (wmi_vdev_rate_stats_event_fixed_param *) param_buf->fixed_param;
1423 ht_info = (wmi_vdev_rate_ht_info *) param_buf->ht_info;
1424
1425 WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats);
1426 for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) {
1427 WMA_LOGD("%s vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d",
1428 __func__, ht_info->vdevid, ht_info->tx_nss,
1429 ht_info->rx_nss, ht_info->tx_preamble,
1430 ht_info->rx_preamble);
1431 if (ht_info->vdevid < wma->max_bssid
1432 && intr[ht_info->vdevid].plink_status_req) {
1433 if (ht_info->tx_nss || ht_info->rx_nss)
1434 link_status = LINK_STATUS_MIMO;
1435
1436 if ((ht_info->tx_preamble == LINK_RATE_VHT) ||
1437 (ht_info->rx_preamble == LINK_RATE_VHT))
1438 link_status |= LINK_STATUS_VHT;
1439
1440 if (intr[ht_info->vdevid].nss == 2)
1441 link_status |= LINK_SUPPORT_MIMO;
1442
1443 if (intr[ht_info->vdevid].rate_flags &
1444 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
1445 eHAL_TX_RATE_VHT80))
1446 link_status |= LINK_SUPPORT_VHT;
1447
1448 wma_post_link_status(intr[ht_info->vdevid].plink_status_req,
1449 link_status);
1450 intr[ht_info->vdevid].plink_status_req = NULL;
1451 link_status = LINK_STATUS_LEGACY;
1452 }
1453
1454 ht_info++;
1455 }
1456
1457 return 0;
1458}
1459
1460/**
1461 * wma_stats_event_handler() - stats event handler
1462 * @handle: wma handle
1463 * @cmd_param_info: data from event
1464 * @len: length
1465 *
1466 * Return: 0 for success or error code
1467 */
1468int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info,
1469 uint32_t len)
1470{
1471 tp_wma_handle wma = (tp_wma_handle) handle;
1472 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
1473 wmi_stats_event_fixed_param *event;
1474 wmi_pdev_stats *pdev_stats;
1475 wmi_vdev_stats *vdev_stats;
1476 wmi_peer_stats *peer_stats;
1477 uint8_t i, *temp;
1478
1479
1480 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) cmd_param_info;
1481 if (!param_buf) {
1482 WMA_LOGA("%s: Invalid stats event", __func__);
1483 return -EINVAL;
1484 }
1485 event = param_buf->fixed_param;
1486 temp = (uint8_t *) param_buf->data;
1487
1488 WMA_LOGD("%s: num_stats: pdev: %u vdev: %u peer %u",
1489 __func__, event->num_pdev_stats, event->num_vdev_stats,
1490 event->num_peer_stats);
1491 if (event->num_pdev_stats > 0) {
1492 for (i = 0; i < event->num_pdev_stats; i++) {
1493 pdev_stats = (wmi_pdev_stats *) temp;
1494 wma_update_pdev_stats(wma, pdev_stats);
1495 temp += sizeof(wmi_pdev_stats);
1496 }
1497 }
1498
1499 if (event->num_vdev_stats > 0) {
1500 for (i = 0; i < event->num_vdev_stats; i++) {
1501 vdev_stats = (wmi_vdev_stats *) temp;
1502 wma_update_vdev_stats(wma, vdev_stats);
1503 temp += sizeof(wmi_vdev_stats);
1504 }
1505 }
1506
1507 if (event->num_peer_stats > 0) {
1508 for (i = 0; i < event->num_peer_stats; i++) {
1509 peer_stats = (wmi_peer_stats *) temp;
1510 wma_update_peer_stats(wma, peer_stats);
1511 temp += sizeof(wmi_peer_stats);
1512 }
1513 }
1514
1515 WMA_LOGI("%s: Exit", __func__);
1516 return 0;
1517}
1518
1519/**
1520 * wma_send_link_speed() - send link speed to SME
1521 * @link_speed: link speed
1522 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301523 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001524 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301525QDF_STATUS wma_send_link_speed(uint32_t link_speed)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001526{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301527 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001528 cds_msg_t sme_msg = { 0 };
1529 tSirLinkSpeedInfo *ls_ind =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301530 (tSirLinkSpeedInfo *) qdf_mem_malloc(sizeof(tSirLinkSpeedInfo));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001531 if (!ls_ind) {
1532 WMA_LOGE("%s: Memory allocation failed.", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301533 qdf_status = QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001534 } else {
1535 ls_ind->estLinkSpeed = link_speed;
1536 sme_msg.type = eWNI_SME_LINK_SPEED_IND;
1537 sme_msg.bodyptr = ls_ind;
1538 sme_msg.bodyval = 0;
1539
Anurag Chouhan6d760662016-02-20 16:05:43 +05301540 qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301541 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001542 WMA_LOGE("%s: Fail to post linkspeed ind msg",
1543 __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301544 qdf_mem_free(ls_ind);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001545 }
1546 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301547 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001548}
1549
1550/**
1551 * wma_link_speed_event_handler() - link speed event handler
1552 * @handle: wma handle
1553 * @cmd_param_info: event data
1554 * @len: length
1555 *
1556 * Return: 0 for success or error code
1557 */
1558int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info,
1559 uint32_t len)
1560{
1561 WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *param_buf;
1562 wmi_peer_estimated_linkspeed_event_fixed_param *event;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301563 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001564
1565 param_buf =
1566 (WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *) cmd_param_info;
1567 if (!param_buf) {
1568 WMA_LOGE("%s: Invalid linkspeed event", __func__);
1569 return -EINVAL;
1570 }
1571 event = param_buf->fixed_param;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301572 qdf_status = wma_send_link_speed(event->est_linkspeed_kbps);
1573 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574 return -EINVAL;
1575 }
1576 return 0;
1577}
1578
1579/**
1580 * wma_wni_cfg_dnld() - cfg download request
1581 * @handle: wma handle
1582 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301583 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001584 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301585QDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301587 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Anurag Chouhan6d760662016-02-20 16:05:43 +05301588 void *mac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001589
1590 WMA_LOGD("%s: Enter", __func__);
1591
1592 if (NULL == mac) {
1593 WMA_LOGP("%s: Invalid context", __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301594 QDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301595 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001596 }
1597
1598 process_cfg_download_req(mac);
1599
1600 WMA_LOGD("%s: Exit", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301601 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001602}
1603
1604/**
1605 * wma_unified_debug_print_event_handler() - debug print event handler
1606 * @handle: wma handle
1607 * @datap: data pointer
1608 * @len: length
1609 *
1610 * Return: 0 for success or error code
1611 */
1612int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap,
1613 uint32_t len)
1614{
1615 WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf;
1616 uint8_t *data;
1617 uint32_t datalen;
1618
1619 param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap;
1620 if (!param_buf) {
1621 WMA_LOGE("Get NULL point message from FW");
1622 return -ENOMEM;
1623 }
1624 data = param_buf->data;
1625 datalen = param_buf->num_data;
1626
1627#ifdef BIG_ENDIAN_HOST
1628 {
1629 char dbgbuf[500] = { 0 };
1630 memcpy(dbgbuf, data, datalen);
1631 SWAPME(dbgbuf, datalen);
1632 WMA_LOGD("FIRMWARE:%s", dbgbuf);
1633 return 0;
1634 }
1635#else
1636 WMA_LOGD("FIRMWARE:%s", data);
1637 return 0;
1638#endif /* BIG_ENDIAN_HOST */
1639}
1640
1641/**
1642 * wma_check_scan_in_progress() - check scan is progress or not
1643 * @handle: wma handle
1644 *
1645 * Return: true/false
1646 */
1647bool wma_check_scan_in_progress(WMA_HANDLE handle)
1648{
1649 tp_wma_handle wma_handle = handle;
1650 int i;
1651
1652 for (i = 0; i < wma_handle->max_bssid; i++) {
1653 if (wma_handle->interfaces[i].scan_info.scan_id) {
1654
1655 WMA_LOGE("%s: scan in progress on interface[%d],scanid = %d",
1656 __func__, i,
1657 wma_handle->interfaces[i].scan_info.scan_id);
1658 return true;
1659 }
1660 }
1661 return false;
1662}
1663
1664/**
1665 * wma_is_sap_active() - check sap is active or not
1666 * @handle: wma handle
1667 *
1668 * Return: true/false
1669 */
1670bool wma_is_sap_active(tp_wma_handle wma_handle)
1671{
1672 int i;
1673
1674 for (i = 0; i < wma_handle->max_bssid; i++) {
1675 if (!wma_handle->interfaces[i].vdev_up)
1676 continue;
1677 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
1678 wma_handle->interfaces[i].sub_type == 0)
1679 return true;
1680 }
1681 return false;
1682}
1683
1684/**
1685 * wma_is_p2p_go_active() - check p2p go is active or not
1686 * @handle: wma handle
1687 *
1688 * Return: true/false
1689 */
1690bool wma_is_p2p_go_active(tp_wma_handle wma_handle)
1691{
1692 int i;
1693
1694 for (i = 0; i < wma_handle->max_bssid; i++) {
1695 if (!wma_handle->interfaces[i].vdev_up)
1696 continue;
1697 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
1698 wma_handle->interfaces[i].sub_type ==
1699 WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO)
1700 return true;
1701 }
1702 return false;
1703}
1704
1705/**
1706 * wma_is_p2p_cli_active() - check p2p cli is active or not
1707 * @handle: wma handle
1708 *
1709 * Return: true/false
1710 */
1711bool wma_is_p2p_cli_active(tp_wma_handle wma_handle)
1712{
1713 int i;
1714
1715 for (i = 0; i < wma_handle->max_bssid; i++) {
1716 if (!wma_handle->interfaces[i].vdev_up)
1717 continue;
1718 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
1719 wma_handle->interfaces[i].sub_type ==
1720 WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT)
1721 return true;
1722 }
1723 return false;
1724}
1725
1726/**
1727 * wma_is_sta_active() - check sta is active or not
1728 * @handle: wma handle
1729 *
1730 * Return: true/false
1731 */
1732bool wma_is_sta_active(tp_wma_handle wma_handle)
1733{
1734 int i;
1735
1736 for (i = 0; i < wma_handle->max_bssid; i++) {
1737 if (!wma_handle->interfaces[i].vdev_up)
1738 continue;
1739 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
1740 wma_handle->interfaces[i].sub_type == 0)
1741 return true;
1742 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_IBSS)
1743 return true;
1744 }
1745 return false;
1746}
1747
1748/**
1749 * wma_peer_phymode() - get phymode
1750 * @nw_type: nw type
1751 * @sta_type: sta type
1752 * @is_ht: is ht supported
1753 * @is_cw40: is channel width 40 supported
1754 * @is_vht: is vht supported
1755 * @is_cw_vht: is channel width 80 supported
1756 *
1757 * Return: WLAN_PHY_MODE
1758 */
1759WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type,
1760 uint8_t is_ht, uint8_t ch_width,
1761 uint8_t is_vht)
1762{
1763 WLAN_PHY_MODE phymode = MODE_UNKNOWN;
1764
1765 switch (nw_type) {
1766 case eSIR_11B_NW_TYPE:
1767 phymode = MODE_11B;
1768 if (is_ht || is_vht)
1769 WMA_LOGE("HT/VHT is enabled with 11B NW type");
1770 break;
1771 case eSIR_11G_NW_TYPE:
1772 if (!(is_ht || is_vht)) {
1773 phymode = MODE_11G;
1774 break;
1775 }
1776 if (CH_WIDTH_40MHZ < ch_width)
1777 WMA_LOGE("80/160 MHz BW sent in 11G, configured 40MHz");
1778 if (ch_width)
1779 phymode = (is_vht) ?
1780 MODE_11AC_VHT40 : MODE_11NG_HT40;
1781 else
1782 phymode = (is_vht) ?
1783 MODE_11AC_VHT20 : MODE_11NG_HT20;
1784 break;
1785 case eSIR_11A_NW_TYPE:
1786 if (!(is_ht || is_vht)) {
1787 phymode = MODE_11A;
1788 break;
1789 }
1790 if (is_vht) {
1791#if CONFIG_160MHZ_SUPPORT != 0
1792 if (ch_width == CH_WIDTH_160MHZ)
1793 phymode = MODE_11AC_VHT160;
1794 else if (ch_width == CH_WIDTH_80P80MHZ)
1795 phymode = MODE_11AC_VHT80_80;
1796 else
1797#endif
1798 if (ch_width == CH_WIDTH_80MHZ)
1799 phymode = MODE_11AC_VHT80;
1800 else
1801 phymode = (ch_width) ?
1802 MODE_11AC_VHT40 : MODE_11AC_VHT20;
1803 } else
1804 phymode = (ch_width) ? MODE_11NA_HT40 : MODE_11NA_HT20;
1805 break;
1806 default:
1807 WMA_LOGP("%s: Invalid nw type %d", __func__, nw_type);
1808 break;
1809 }
1810 WMA_LOGD("%s: nw_type %d is_ht %d ch_width %d is_vht %d phymode %d",
1811 __func__, nw_type, is_ht, ch_width, is_vht, phymode);
1812
1813 return phymode;
1814}
1815
1816/**
1817 * wma_txrx_fw_stats_reset() - reset txrx fw statistics
1818 * @wma_handle: wma handle
1819 * @vdev_id: vdev id
1820 * @value: value
1821 *
1822 * Return: 0 for success or return error
1823 */
1824int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle,
1825 uint8_t vdev_id, uint32_t value)
1826{
1827 struct ol_txrx_stats_req req;
1828 ol_txrx_vdev_handle vdev;
1829
1830 vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
1831 if (!vdev) {
1832 WMA_LOGE("%s:Invalid vdev handle", __func__);
1833 return -EINVAL;
1834 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301835 qdf_mem_zero(&req, sizeof(req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001836 req.stats_type_reset_mask = value;
Nirav Shahd2310422016-01-21 18:58:06 +05301837 ol_txrx_fw_stats_get(vdev, &req, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001838
1839 return 0;
1840}
1841
1842#ifdef HELIUMPLUS
1843#define SET_UPLOAD_MASK(_mask, _rate_info) \
1844 ((_mask) = 1 << (_rate_info ## _V2))
1845#else /* !HELIUMPLUS */
1846#define SET_UPLOAD_MASK(_mask, _rate_info) \
1847 ((_mask) = 1 << (_rate_info))
1848#endif
1849
1850/**
1851 * wma_set_txrx_fw_stats_level() - set txrx fw stats level
1852 * @wma_handle: wma handle
1853 * @vdev_id: vdev id
1854 * @value: value
1855 *
1856 * Return: 0 for success or return error
1857 */
1858int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle,
1859 uint8_t vdev_id, uint32_t value)
1860{
1861 struct ol_txrx_stats_req req;
1862 ol_txrx_vdev_handle vdev;
1863 uint32_t l_up_mask;
1864
1865 vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
1866 if (!vdev) {
1867 WMA_LOGE("%s:Invalid vdev handle", __func__);
1868 return -EINVAL;
1869 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301870 qdf_mem_zero(&req, sizeof(req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001871 req.print.verbose = 1;
1872
1873 switch (value) {
1874 /* txrx_fw_stats 1 */
1875 case WMA_FW_PHY_STATS:
1876 l_up_mask = 1 << HTT_DBG_STATS_WAL_PDEV_TXRX;
1877 break;
1878
1879 /* txrx_fw_stats 2 */
1880 case WMA_FW_RX_REORDER_STATS:
1881 l_up_mask = 1 << HTT_DBG_STATS_RX_REORDER;
1882 break;
1883
1884 /* txrx_fw_stats 3 */
1885 case WMA_FW_RX_RC_STATS:
1886 SET_UPLOAD_MASK(l_up_mask, HTT_DBG_STATS_RX_RATE_INFO);
1887 break;
1888
1889 /* txrx_fw_stats 5 */
1890 case WMA_FW_TX_CONCISE_STATS:
1891 req.print.concise = 1;
1892 /* No break here, since l_up_mask is same for
1893 * both WMA_FW_TX_CONCISE_STATS & WMA_FW_TX_PPDU_STATS */
1894
1895 /* txrx_fw_stats 4 */
1896 case WMA_FW_TX_PPDU_STATS:
1897 l_up_mask = 1 << HTT_DBG_STATS_TX_PPDU_LOG;
1898 break;
1899
1900 /* txrx_fw_stats 6 */
1901 case WMA_FW_TX_RC_STATS:
1902 SET_UPLOAD_MASK(l_up_mask, HTT_DBG_STATS_TX_RATE_INFO);
1903 break;
1904
1905 /* txrx_fw_stats 12 */
1906 /*
1907 * This is 1:1 correspondence with WMA defined value
1908 * and the f/w bitmask.
1909 */
1910 case WMA_FW_RX_REM_RING_BUF:
1911 l_up_mask = 1 << HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO;
1912 break;
1913
1914 /* txrx_fw_stats 7 */
1915 case WMA_FW_TXBF_INFO_STATS:
1916 l_up_mask = 1 << HTT_DBG_STATS_TXBF_INFO;
1917 break;
1918
1919 /* txrx_fw_stats 8 */
1920 case WMA_FW_SND_INFO_STATS:
1921 l_up_mask = 1 << HTT_DBG_STATS_SND_INFO;
1922 break;
1923
1924 /* txrx_fw_stats 9 */
1925 case WMA_FW_ERROR_INFO_STATS:
1926 l_up_mask = 1 << HTT_DBG_STATS_ERROR_INFO;
1927 break;
1928
1929 /* txrx_fw_stats 10 */
1930 case WMA_FW_TX_SELFGEN_INFO_STATS:
1931 l_up_mask = 1 << HTT_DBG_STATS_TX_SELFGEN_INFO;
1932 break;
1933
1934 /* txrx_fw_stats 15 */
1935 /*
1936 * This is 1:1 correspondence with WMA defined value
1937 * and the f/w bitmask.
1938 */
1939 case WMA_FW_RX_TXBF_MUSU_NDPA:
1940 l_up_mask = 1 << HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT;
1941 break;
1942
1943 default:
Anurag Chouhan6d760662016-02-20 16:05:43 +05301944 qdf_print("%s %d Invalid value %d\n",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945 __func__, __LINE__, value);
1946 return 0;
1947 }
1948 req.stats_type_upload_mask = l_up_mask;
1949
Nirav Shahd2310422016-01-21 18:58:06 +05301950 ol_txrx_fw_stats_get(vdev, &req, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001951
1952 return 0;
1953}
1954
1955/**
1956 * wmi_crash_inject() - inject fw crash
1957 * @wma_handle: wma handle
1958 * @type: type
1959 * @delay_time_ms: delay time in ms
1960 *
1961 * Return: 0 for success or return error
1962 */
1963int wmi_crash_inject(wmi_unified_t wmi_handle, uint32_t type,
1964 uint32_t delay_time_ms)
1965{
1966 int ret = 0;
1967 WMI_FORCE_FW_HANG_CMD_fixed_param *cmd;
1968 uint16_t len = sizeof(*cmd);
1969 wmi_buf_t buf;
1970
1971 buf = wmi_buf_alloc(wmi_handle, len);
1972 if (!buf) {
1973 WMA_LOGE("%s: wmi_buf_alloc failed!", __func__);
1974 return -ENOMEM;
1975 }
1976
1977 cmd = (WMI_FORCE_FW_HANG_CMD_fixed_param *) wmi_buf_data(buf);
1978 WMITLV_SET_HDR(&cmd->tlv_header,
1979 WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param,
1980 WMITLV_GET_STRUCT_TLVLEN
1981 (WMI_FORCE_FW_HANG_CMD_fixed_param));
1982 cmd->type = type;
1983 cmd->delay_time_ms = delay_time_ms;
1984
1985 ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_FORCE_FW_HANG_CMDID);
1986 if (ret < 0) {
1987 WMA_LOGE("%s: Failed to send set param command, ret = %d",
1988 __func__, ret);
1989 wmi_buf_free(buf);
1990 }
1991
1992 return ret;
1993}
1994
1995/**
1996 * wma_get_stats_rsp_buf() - fill get stats response buffer
1997 * @get_stats_param: get stats parameters
1998 *
1999 * Return: stats response buffer
2000 */
2001static tAniGetPEStatsRsp *wma_get_stats_rsp_buf
2002 (tAniGetPEStatsReq *get_stats_param)
2003{
2004 tAniGetPEStatsRsp *stats_rsp_params;
2005 uint32_t len, temp_mask, counter = 0;
2006
2007 len = sizeof(tAniGetPEStatsRsp);
2008 temp_mask = get_stats_param->statsMask;
2009
2010 while (temp_mask) {
2011 if (temp_mask & 1) {
2012 switch (counter) {
2013 case eCsrSummaryStats:
2014 len += sizeof(tCsrSummaryStatsInfo);
2015 break;
2016 case eCsrGlobalClassAStats:
2017 len += sizeof(tCsrGlobalClassAStatsInfo);
2018 break;
2019 case eCsrGlobalClassBStats:
2020 len += sizeof(tCsrGlobalClassBStatsInfo);
2021 break;
2022 case eCsrGlobalClassCStats:
2023 len += sizeof(tCsrGlobalClassCStatsInfo);
2024 break;
2025 case eCsrGlobalClassDStats:
2026 len += sizeof(tCsrGlobalClassDStatsInfo);
2027 break;
2028 case eCsrPerStaStats:
2029 len += sizeof(tCsrPerStaStatsInfo);
2030 break;
2031 }
2032 }
2033
2034 counter++;
2035 temp_mask >>= 1;
2036 }
2037
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302038 stats_rsp_params = (tAniGetPEStatsRsp *) qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002039 if (!stats_rsp_params) {
2040 WMA_LOGE("memory allocation failed for tAniGetPEStatsRsp");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302041 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042 return NULL;
2043 }
2044
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302045 qdf_mem_zero(stats_rsp_params, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046 stats_rsp_params->staId = get_stats_param->staId;
2047 stats_rsp_params->statsMask = get_stats_param->statsMask;
2048 stats_rsp_params->msgType = WMA_GET_STATISTICS_RSP;
2049 stats_rsp_params->msgLen = len - sizeof(tAniGetPEStatsRsp);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302050 stats_rsp_params->rc = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051 return stats_rsp_params;
2052}
2053
2054/**
2055 * wma_get_stats_req() - get stats request
2056 * @handle: wma handle
2057 * @get_stats_param: stats params
2058 *
2059 * Return: none
2060 */
2061void wma_get_stats_req(WMA_HANDLE handle,
2062 tAniGetPEStatsReq *get_stats_param)
2063{
2064 tp_wma_handle wma_handle = (tp_wma_handle) handle;
2065 struct wma_txrx_node *node;
2066 wmi_buf_t buf;
2067 wmi_request_stats_cmd_fixed_param *cmd;
2068 tAniGetPEStatsRsp *pGetPEStatsRspParams;
2069 uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param);
2070
2071 WMA_LOGD("%s: Enter", __func__);
2072 node = &wma_handle->interfaces[get_stats_param->sessionId];
2073 if (node->stats_rsp) {
2074 pGetPEStatsRspParams = node->stats_rsp;
2075 if (pGetPEStatsRspParams->staId == get_stats_param->staId &&
2076 pGetPEStatsRspParams->statsMask ==
2077 get_stats_param->statsMask) {
2078 WMA_LOGI("Stats for staId %d with stats mask %d "
2079 "is pending.... ignore new request",
2080 get_stats_param->staId,
2081 get_stats_param->statsMask);
2082 goto end;
2083 } else {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302084 qdf_mem_free(node->stats_rsp);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085 node->stats_rsp = NULL;
2086 node->fw_stats_set = 0;
2087 }
2088 }
2089
2090 pGetPEStatsRspParams = wma_get_stats_rsp_buf(get_stats_param);
2091 if (!pGetPEStatsRspParams)
2092 goto end;
2093
2094 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
2095 if (!buf) {
2096 WMA_LOGE("%s: Failed to allocate wmi buffer", __func__);
2097 goto failed;
2098 }
2099
2100 node->fw_stats_set = 0;
2101 node->stats_rsp = pGetPEStatsRspParams;
2102 cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf);
2103 WMITLV_SET_HDR(&cmd->tlv_header,
2104 WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
2105 WMITLV_GET_STRUCT_TLVLEN
2106 (wmi_request_stats_cmd_fixed_param));
2107 cmd->stats_id =
2108 WMI_REQUEST_PEER_STAT | WMI_REQUEST_PDEV_STAT |
2109 WMI_REQUEST_VDEV_STAT;
2110 cmd->vdev_id = get_stats_param->sessionId;
2111 WMI_CHAR_ARRAY_TO_MAC_ADDR(node->bssid, &cmd->peer_macaddr);
2112 WMA_LOGD("STATS REQ VDEV_ID:%d-->", cmd->vdev_id);
2113 if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
2114 WMI_REQUEST_STATS_CMDID)) {
2115
2116 WMA_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID",
2117 __func__);
2118 wmi_buf_free(buf);
2119 goto failed;
2120 }
2121
2122 goto end;
2123failed:
2124
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302125 pGetPEStatsRspParams->rc = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002126 node->stats_rsp = NULL;
2127 /* send response to UMAC */
2128 wma_send_msg(wma_handle, WMA_GET_STATISTICS_RSP, pGetPEStatsRspParams,
2129 0);
2130end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302131 qdf_mem_free(get_stats_param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002132 WMA_LOGD("%s: Exit", __func__);
2133 return;
2134}
2135
2136/**
2137 * wma_get_beacon_buffer_by_vdev_id() - get the beacon buffer from vdev ID
2138 * @vdev_id: vdev id
2139 * @buffer_size: size of buffer
2140 *
2141 * Return: none
2142 */
2143void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size)
2144{
2145 tp_wma_handle wma;
2146 struct beacon_info *beacon;
2147 uint8_t *buf;
2148 uint32_t buf_size;
2149
Anurag Chouhan6d760662016-02-20 16:05:43 +05302150 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002151 if (!wma) {
2152 WMA_LOGE("%s: Invalid WMA handle", __func__);
2153 return NULL;
2154 }
2155
2156 if (vdev_id >= wma->max_bssid) {
2157 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
2158 return NULL;
2159 }
2160
2161 if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) {
2162 WMA_LOGE("%s: vdevid %d is not in AP mode", __func__, vdev_id);
2163 return NULL;
2164 }
2165
2166 beacon = wma->interfaces[vdev_id].beacon;
2167
2168 if (!beacon) {
2169 WMA_LOGE("%s: beacon invalid", __func__);
2170 return NULL;
2171 }
2172
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302173 qdf_spin_lock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002174
Nirav Shahcbc6d722016-03-01 16:24:53 +05302175 buf_size = qdf_nbuf_len(beacon->buf);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302176 buf = qdf_mem_malloc(buf_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002177
2178 if (!buf) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302179 qdf_spin_unlock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002180 WMA_LOGE("%s: alloc failed for beacon buf", __func__);
2181 return NULL;
2182 }
2183
Nirav Shahcbc6d722016-03-01 16:24:53 +05302184 qdf_mem_copy(buf, qdf_nbuf_data(beacon->buf), buf_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002185
Anurag Chouhana37b5b72016-02-21 14:53:42 +05302186 qdf_spin_unlock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002187
2188 if (buffer_size)
2189 *buffer_size = buf_size;
2190
2191 return buf;
2192}
2193
2194/**
2195 * wma_get_vdev_address_by_vdev_id() - lookup MAC address from vdev ID
2196 * @vdev_id: vdev id
2197 *
2198 * Return: mac address
2199 */
2200uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id)
2201{
2202 tp_wma_handle wma;
2203
Anurag Chouhan6d760662016-02-20 16:05:43 +05302204 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002205 if (!wma) {
2206 WMA_LOGE("%s: Invalid WMA handle", __func__);
2207 return NULL;
2208 }
2209
2210 if (vdev_id >= wma->max_bssid) {
2211 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
2212 return NULL;
2213 }
2214
2215 return wma->interfaces[vdev_id].addr;
2216}
2217
2218/**
2219 * wma_get_interface_by_vdev_id() - lookup interface entry using vdev ID
2220 * @vdev_id: vdev id
2221 *
2222 * Return: entry from vdev table
2223 */
2224struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id)
2225{
2226 tp_wma_handle wma;
2227
Anurag Chouhan6d760662016-02-20 16:05:43 +05302228 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002229 if (!wma) {
2230 WMA_LOGE("%s: Invalid WMA handle", __func__);
2231 return NULL;
2232 }
2233
2234 if (vdev_id >= wma->max_bssid) {
2235 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
2236 return NULL;
2237 }
2238
2239 return &wma->interfaces[vdev_id];
2240}
2241
2242/**
2243 * wma_is_vdev_up() - return whether a vdev is up
2244 * @vdev_id: vdev id
2245 *
2246 * Return: true if the vdev is up, false otherwise
2247 */
2248bool wma_is_vdev_up(uint8_t vdev_id)
2249{
2250 struct wma_txrx_node *vdev = wma_get_interface_by_vdev_id(vdev_id);
2251 if (vdev)
2252 return vdev->vdev_up;
2253 else
2254 return false;
2255}
2256
2257#if defined(QCA_WIFI_FTM)
2258/**
2259 * wma_utf_rsp() - utf response
2260 * @wma_handle: wma handle
2261 * @payload: payload
2262 * @len: length of payload
2263 *
2264 * Return: 0 for success or error code
2265 */
2266int wma_utf_rsp(tp_wma_handle wma_handle, uint8_t **payload, uint32_t *len)
2267{
2268 int ret = -1;
2269 uint32_t payload_len;
2270
2271 payload_len = wma_handle->utf_event_info.length;
2272 if (payload_len) {
2273 ret = 0;
2274
2275 /*
2276 * The first 4 bytes holds the payload size
2277 * and the actual payload sits next to it
2278 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302279 *payload = (uint8_t *) qdf_mem_malloc((uint32_t) payload_len
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002280 + sizeof(A_UINT32));
2281 *(A_UINT32 *) &(*payload[0]) =
2282 wma_handle->utf_event_info.length;
2283 memcpy(*payload + sizeof(A_UINT32),
2284 wma_handle->utf_event_info.data, payload_len);
2285 wma_handle->utf_event_info.length = 0;
2286 *len = payload_len;
2287 }
2288
2289 return ret;
2290}
2291
2292/**
2293 * wma_post_ftm_response() - post ftm response to upper layer
2294 * @wma_handle: wma handle
2295 *
2296 * Return: none
2297 */
2298static void wma_post_ftm_response(tp_wma_handle wma_handle)
2299{
2300 int ret;
2301 uint8_t *payload;
2302 uint32_t data_len;
2303 cds_msg_t msg = { 0 };
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302304 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002305
2306 ret = wma_utf_rsp(wma_handle, &payload, &data_len);
2307
2308 if (ret) {
2309 return;
2310 }
2311
2312 sys_build_message_header(SYS_MSG_ID_FTM_RSP, &msg);
2313 msg.bodyptr = payload;
2314 msg.bodyval = 0;
2315
2316 status = cds_mq_post_message(CDS_MQ_ID_SYS, &msg);
2317
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302318 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002319 WMA_LOGE("failed to post ftm response to SYS");
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302320 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002321 }
2322}
2323
2324/**
2325 * wma_process_utf_event() - process utf event
2326 * @handle: wma handle
2327 * @datap: data buffer
2328 * @dataplen: data length
2329 *
2330 * Return: 0 for success or error code
2331 */
2332static int
2333wma_process_utf_event(WMA_HANDLE handle, uint8_t *datap, uint32_t dataplen)
2334{
2335 tp_wma_handle wma_handle = (tp_wma_handle) handle;
2336 SEG_HDR_INFO_STRUCT segHdrInfo;
2337 uint8_t totalNumOfSegments, currentSeq;
2338 WMI_PDEV_UTF_EVENTID_param_tlvs *param_buf;
2339 uint8_t *data;
2340 uint32_t datalen;
2341
2342 param_buf = (WMI_PDEV_UTF_EVENTID_param_tlvs *) datap;
2343 if (!param_buf) {
2344 WMA_LOGE("Get NULL point message from FW");
2345 return -EINVAL;
2346 }
2347 data = param_buf->data;
2348 datalen = param_buf->num_data;
2349
2350 segHdrInfo = *(SEG_HDR_INFO_STRUCT *) &(data[0]);
2351
2352 wma_handle->utf_event_info.currentSeq = (segHdrInfo.segmentInfo & 0xF);
2353
2354 currentSeq = (segHdrInfo.segmentInfo & 0xF);
2355 totalNumOfSegments = (segHdrInfo.segmentInfo >> 4) & 0xF;
2356
2357 datalen = datalen - sizeof(segHdrInfo);
2358
2359 if (currentSeq == 0) {
2360 wma_handle->utf_event_info.expectedSeq = 0;
2361 wma_handle->utf_event_info.offset = 0;
2362 } else {
2363 if (wma_handle->utf_event_info.expectedSeq != currentSeq)
2364 WMA_LOGE("Mismatch in expecting seq expected"
2365 " Seq %d got seq %d",
2366 wma_handle->utf_event_info.expectedSeq,
2367 currentSeq);
2368 }
2369
2370 memcpy(&wma_handle->utf_event_info.
2371 data[wma_handle->utf_event_info.offset],
2372 &data[sizeof(segHdrInfo)], datalen);
2373 wma_handle->utf_event_info.offset =
2374 wma_handle->utf_event_info.offset + datalen;
2375 wma_handle->utf_event_info.expectedSeq++;
2376
2377 if (wma_handle->utf_event_info.expectedSeq == totalNumOfSegments) {
2378 if (wma_handle->utf_event_info.offset != segHdrInfo.len)
2379 WMA_LOGE("All segs received total len mismatch.."
2380 " len %zu total len %d",
2381 wma_handle->utf_event_info.offset,
2382 segHdrInfo.len);
2383
2384 wma_handle->utf_event_info.length =
2385 wma_handle->utf_event_info.offset;
2386 }
2387
2388 wma_post_ftm_response(wma_handle);
2389
2390 return 0;
2391}
2392
2393/**
2394 * wma_utf_detach() - utf detach
2395 * @wma_handle: wma handle
2396 *
2397 * Return: none
2398 */
2399void wma_utf_detach(tp_wma_handle wma_handle)
2400{
2401 if (wma_handle->utf_event_info.data) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302402 qdf_mem_free(wma_handle->utf_event_info.data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002403 wma_handle->utf_event_info.data = NULL;
2404 wma_handle->utf_event_info.length = 0;
2405 wmi_unified_unregister_event_handler(wma_handle->wmi_handle,
2406 WMI_PDEV_UTF_EVENTID);
2407 }
2408}
2409
2410/**
2411 * wma_utf_attach() - utf attach
2412 * @wma_handle: wma handle
2413 *
2414 * Return: none
2415 */
2416void wma_utf_attach(tp_wma_handle wma_handle)
2417{
2418 int ret;
2419
2420 wma_handle->utf_event_info.data = (unsigned char *)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302421 qdf_mem_malloc(MAX_UTF_EVENT_LENGTH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002422 wma_handle->utf_event_info.length = 0;
2423
2424 ret = wmi_unified_register_event_handler(wma_handle->wmi_handle,
2425 WMI_PDEV_UTF_EVENTID,
2426 wma_process_utf_event);
2427
2428 if (ret)
2429 WMA_LOGP("%s: Failed to register UTF event callback", __func__);
2430}
2431
2432/**
2433 * wmi_unified_pdev_utf_cmd() - send utf command to fw
2434 * @wmi_handle: wmi handle
2435 * @utf_payload: utf payload
2436 * @len: length
2437 *
2438 * Return: 0 for success or error code
2439 */
2440static int
2441wmi_unified_pdev_utf_cmd(wmi_unified_t wmi_handle, uint8_t *utf_payload,
2442 uint16_t len)
2443{
2444 wmi_buf_t buf;
2445 uint8_t *cmd;
2446 int ret = 0;
2447 static uint8_t msgref = 1;
2448 uint8_t segNumber = 0, segInfo, numSegments;
2449 uint16_t chunk_len, total_bytes;
2450 uint8_t *bufpos;
2451 SEG_HDR_INFO_STRUCT segHdrInfo;
2452
2453 bufpos = utf_payload;
2454 total_bytes = len;
2455 ASSERT(total_bytes / MAX_WMI_UTF_LEN ==
2456 (uint8_t) (total_bytes / MAX_WMI_UTF_LEN));
2457 numSegments = (uint8_t) (total_bytes / MAX_WMI_UTF_LEN);
2458
2459 if (len - (numSegments * MAX_WMI_UTF_LEN))
2460 numSegments++;
2461
2462 while (len) {
2463 if (len > MAX_WMI_UTF_LEN)
2464 chunk_len = MAX_WMI_UTF_LEN; /* MAX messsage */
2465 else
2466 chunk_len = len;
2467
2468 buf = wmi_buf_alloc(wmi_handle,
2469 (chunk_len + sizeof(segHdrInfo) +
2470 WMI_TLV_HDR_SIZE));
2471 if (!buf) {
2472 WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
2473 return -ENOMEM;
2474 }
2475
2476 cmd = (uint8_t *) wmi_buf_data(buf);
2477
2478 segHdrInfo.len = total_bytes;
2479 segHdrInfo.msgref = msgref;
2480 segInfo = ((numSegments << 4) & 0xF0) | (segNumber & 0xF);
2481 segHdrInfo.segmentInfo = segInfo;
2482 segHdrInfo.pad = 0;
2483
2484 WMA_LOGD("%s:segHdrInfo.len = %d, segHdrInfo.msgref = %d,"
2485 " segHdrInfo.segmentInfo = %d",
2486 __func__, segHdrInfo.len, segHdrInfo.msgref,
2487 segHdrInfo.segmentInfo);
2488
2489 WMA_LOGD("%s:total_bytes %d segNumber %d totalSegments %d"
2490 "chunk len %d", __func__, total_bytes, segNumber,
2491 numSegments, chunk_len);
2492
2493 segNumber++;
2494
2495 WMITLV_SET_HDR(cmd, WMITLV_TAG_ARRAY_BYTE,
2496 (chunk_len + sizeof(segHdrInfo)));
2497 cmd += WMI_TLV_HDR_SIZE;
2498 memcpy(cmd, &segHdrInfo, sizeof(segHdrInfo)); /* 4 bytes */
2499 memcpy(&cmd[sizeof(segHdrInfo)], bufpos, chunk_len);
2500
2501 ret = wmi_unified_cmd_send(wmi_handle, buf,
2502 (chunk_len + sizeof(segHdrInfo) +
2503 WMI_TLV_HDR_SIZE),
2504 WMI_PDEV_UTF_CMDID);
2505
2506 if (ret != EOK) {
2507 WMA_LOGE("Failed to send WMI_PDEV_UTF_CMDID command");
2508 wmi_buf_free(buf);
2509 break;
2510 }
2511
2512 len -= chunk_len;
2513 bufpos += chunk_len;
2514 }
2515
2516 msgref++;
2517
2518 return ret;
2519}
2520
2521/**
2522 * wma_utf_cmd() - utf command
2523 * @wma_handle: wma handle
2524 * @data: data
2525 * @len: length
2526 *
2527 * Return: 0 for success or error code
2528 */
2529int wma_utf_cmd(tp_wma_handle wma_handle, uint8_t *data, uint16_t len)
2530{
2531 wma_handle->utf_event_info.length = 0;
2532 return wmi_unified_pdev_utf_cmd(wma_handle->wmi_handle, data, len);
2533}
2534
2535/**
2536 * wma_process_ftm_command() - process ftm command
2537 * @wma_handle: wma handle
2538 * @msg_buffer: message buffer
2539 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302540 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002541 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302542QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002543wma_process_ftm_command(tp_wma_handle wma_handle,
2544 struct ar6k_testmode_cmd_data *msg_buffer)
2545{
2546 uint8_t *data = NULL;
2547 uint16_t len = 0;
2548 int ret;
2549
2550 if (!msg_buffer)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302551 return QDF_STATUS_E_INVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002552
Anurag Chouhan6d760662016-02-20 16:05:43 +05302553 if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002554 WMA_LOGE("FTM command issued in non-FTM mode");
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302555 qdf_mem_free(msg_buffer->data);
2556 qdf_mem_free(msg_buffer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302557 return QDF_STATUS_E_NOSUPPORT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002558 }
2559
2560 data = msg_buffer->data;
2561 len = msg_buffer->len;
2562
2563 ret = wma_utf_cmd(wma_handle, data, len);
2564
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302565 qdf_mem_free(msg_buffer->data);
2566 qdf_mem_free(msg_buffer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002567
2568 if (ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302569 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002570
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302571 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002572}
2573#endif /* QCA_WIFI_FTM */
2574
2575/**
2576 * wma_get_wcnss_software_version() - get wcnss software version
2577 * @p_cds_gctx: cds context
2578 * @pVersion: version pointer
2579 * @versionBufferSize: buffer size
2580 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302581 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002582 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302583QDF_STATUS wma_get_wcnss_software_version(void *p_cds_gctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002584 uint8_t *pVersion,
2585 uint32_t versionBufferSize)
2586{
2587 tp_wma_handle wma_handle;
Anurag Chouhan6d760662016-02-20 16:05:43 +05302588 wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002589
2590 if (NULL == wma_handle) {
2591 WMA_LOGE("%s: Failed to get wma", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302592 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002593 }
2594
2595 snprintf(pVersion, versionBufferSize, "%x",
2596 (unsigned int)wma_handle->target_fw_version);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302597 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002598}
2599
2600/**
2601 * wma_get_tx_rx_ss_from_config() - Get Tx/Rx spatial stream from HW mode config
2602 * @mac_ss: Config which indicates the HW mode as per 'hw_mode_ss_config'
2603 * @tx_ss: Contains the Tx spatial stream
2604 * @rx_ss: Contains the Rx spatial stream
2605 *
2606 * Returns the number of spatial streams of Tx and Rx
2607 *
2608 * Return: None
2609 */
2610void wma_get_tx_rx_ss_from_config(enum hw_mode_ss_config mac_ss,
2611 uint32_t *tx_ss,
2612 uint32_t *rx_ss)
2613{
2614 switch (mac_ss) {
2615 case HW_MODE_SS_0x0:
2616 *tx_ss = 0;
2617 *rx_ss = 0;
2618 break;
2619 case HW_MODE_SS_1x1:
2620 *tx_ss = 1;
2621 *rx_ss = 1;
2622 break;
2623 case HW_MODE_SS_2x2:
2624 *tx_ss = 2;
2625 *rx_ss = 2;
2626 break;
2627 case HW_MODE_SS_3x3:
2628 *tx_ss = 3;
2629 *rx_ss = 3;
2630 break;
2631 case HW_MODE_SS_4x4:
2632 *tx_ss = 4;
2633 *rx_ss = 4;
2634 break;
2635 default:
2636 *tx_ss = 0;
2637 *rx_ss = 0;
2638 }
2639}
2640
2641/**
2642 * wma_get_matching_hw_mode_index() - Get matching HW mode index
2643 * @wma: WMA handle
2644 * @mac0_tx_ss: Number of tx spatial streams of MAC0
2645 * @mac0_rx_ss: Number of rx spatial streams of MAC0
2646 * @mac0_bw: Bandwidth of MAC0 of type 'hw_mode_bandwidth'
2647 * @mac1_tx_ss: Number of tx spatial streams of MAC1
2648 * @mac1_rx_ss: Number of rx spatial streams of MAC1
2649 * @mac1_bw: Bandwidth of MAC1 of type 'hw_mode_bandwidth'
2650 * @dbs: DBS capability of type 'hw_mode_dbs_capab'
2651 * @dfs: Agile DFS capability of type 'hw_mode_agile_dfs_capab'
2652 *
2653 * Fetches the HW mode index corresponding to the HW mode provided
2654 *
2655 * Return: Positive hw mode index in case a match is found or a negative
2656 * value, otherwise
2657 */
2658static int8_t wma_get_matching_hw_mode_index(tp_wma_handle wma,
2659 uint32_t mac0_tx_ss, uint32_t mac0_rx_ss,
2660 enum hw_mode_bandwidth mac0_bw,
2661 uint32_t mac1_tx_ss, uint32_t mac1_rx_ss,
2662 enum hw_mode_bandwidth mac1_bw,
2663 enum hw_mode_dbs_capab dbs,
2664 enum hw_mode_agile_dfs_capab dfs)
2665{
2666 uint32_t i;
2667 uint32_t t_mac0_tx_ss, t_mac0_rx_ss, t_mac0_bw;
2668 uint32_t t_mac1_tx_ss, t_mac1_rx_ss, t_mac1_bw;
2669 uint32_t dbs_mode, agile_dfs_mode;
2670 int8_t found = -EINVAL;
2671
2672 if (!wma) {
2673 WMA_LOGE("%s: Invalid WMA handle", __func__);
2674 return found;
2675 }
2676
2677 for (i = 0; i < wma->num_dbs_hw_modes; i++) {
2678 t_mac0_tx_ss = WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET(
2679 wma->hw_mode.hw_mode_list[i]);
2680 if (t_mac0_tx_ss != mac0_tx_ss)
2681 continue;
2682
2683 t_mac0_rx_ss = WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET(
2684 wma->hw_mode.hw_mode_list[i]);
2685 if (t_mac0_rx_ss != mac0_rx_ss)
2686 continue;
2687
2688 t_mac0_bw = WMI_DBS_HW_MODE_MAC0_BANDWIDTH_GET(
2689 wma->hw_mode.hw_mode_list[i]);
2690 if (t_mac0_bw != mac0_bw)
2691 continue;
2692
2693 t_mac1_tx_ss = WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET(
2694 wma->hw_mode.hw_mode_list[i]);
2695 if (t_mac1_tx_ss != mac1_tx_ss)
2696 continue;
2697
2698 t_mac1_rx_ss = WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET(
2699 wma->hw_mode.hw_mode_list[i]);
2700 if (t_mac1_rx_ss != mac1_rx_ss)
2701 continue;
2702
2703 t_mac1_bw = WMI_DBS_HW_MODE_MAC1_BANDWIDTH_GET(
2704 wma->hw_mode.hw_mode_list[i]);
2705 if (t_mac1_bw != mac1_bw)
2706 continue;
2707
2708 dbs_mode = WMI_DBS_HW_MODE_DBS_MODE_GET(
2709 wma->hw_mode.hw_mode_list[i]);
2710 if (dbs_mode != dbs)
2711 continue;
2712
2713 agile_dfs_mode = WMI_DBS_HW_MODE_AGILE_DFS_GET(
2714 wma->hw_mode.hw_mode_list[i]);
2715 if (agile_dfs_mode != dfs)
2716 continue;
2717
2718 found = i;
2719 WMA_LOGI("%s: hw_mode index %d found",
2720 __func__, i);
2721 break;
2722 }
2723 return found;
2724}
2725
2726/**
2727 * wma_get_hw_mode_from_dbs_hw_list() - Get hw_mode index
2728 * @mac0_ss: MAC0 spatial stream configuration
2729 * @mac0_bw: MAC0 bandwidth configuration
2730 * @mac1_ss: MAC1 spatial stream configuration
2731 * @mac1_bw: MAC1 bandwidth configuration
2732 * @dbs: HW DBS capability
2733 * @dfs: HW Agile DFS capability
2734 *
2735 * Get the HW mode index corresponding to the HW modes spatial stream,
2736 * bandwidth, DBS and Agile DFS capability
2737 *
2738 * Return: Index number if a match is found or -negative value if not found
2739 */
2740int8_t wma_get_hw_mode_idx_from_dbs_hw_list(enum hw_mode_ss_config mac0_ss,
2741 enum hw_mode_bandwidth mac0_bw,
2742 enum hw_mode_ss_config mac1_ss,
2743 enum hw_mode_bandwidth mac1_bw,
2744 enum hw_mode_dbs_capab dbs,
2745 enum hw_mode_agile_dfs_capab dfs)
2746{
2747 tp_wma_handle wma;
2748 uint32_t mac0_tx_ss, mac0_rx_ss;
2749 uint32_t mac1_tx_ss, mac1_rx_ss;
2750
Anurag Chouhan6d760662016-02-20 16:05:43 +05302751 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002752 if (!wma) {
2753 WMA_LOGE("%s: Invalid WMA handle", __func__);
2754 return -EINVAL;
2755 }
2756
2757 wma_get_tx_rx_ss_from_config(mac0_ss, &mac0_tx_ss, &mac0_rx_ss);
2758 wma_get_tx_rx_ss_from_config(mac1_ss, &mac1_tx_ss, &mac1_rx_ss);
2759
2760 WMA_LOGI("%s: MAC0: TxSS=%d, RxSS=%d, BW=%d",
2761 __func__, mac0_tx_ss, mac0_rx_ss, mac0_bw);
2762 WMA_LOGI("%s: MAC1: TxSS=%d, RxSS=%d, BW=%d",
2763 __func__, mac1_tx_ss, mac1_rx_ss, mac1_bw);
2764 WMA_LOGI("%s: DBS capab=%d, Agile DFS capab=%d",
2765 __func__, dbs, dfs);
2766
2767 return wma_get_matching_hw_mode_index(wma, mac0_tx_ss, mac0_rx_ss,
2768 mac0_bw,
2769 mac1_tx_ss, mac1_rx_ss,
2770 mac1_bw,
2771 dbs, dfs);
2772}
2773
2774/**
2775 * wma_get_hw_mode_from_idx() - Get HW mode based on index
2776 * @idx: HW mode index
2777 * @hw_mode: HW mode params
2778 *
2779 * Fetches the HW mode parameters
2780 *
2781 * Return: Success if hw mode is obtained and the hw mode params
2782 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302783QDF_STATUS wma_get_hw_mode_from_idx(uint32_t idx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002784 struct sir_hw_mode_params *hw_mode)
2785{
2786 tp_wma_handle wma;
2787 uint32_t param;
2788
Anurag Chouhan6d760662016-02-20 16:05:43 +05302789 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002790 if (!wma) {
2791 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302792 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002793 }
2794
2795 if (idx > wma->num_dbs_hw_modes) {
2796 WMA_LOGE("%s: Invalid index", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302797 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002798 }
2799
Mahesh Kumar Kalikot Veetild43e1652015-11-02 15:35:10 -08002800 if (!wma->num_dbs_hw_modes) {
2801 WMA_LOGE("%s: No dbs hw modes available", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302802 return QDF_STATUS_E_FAILURE;
Mahesh Kumar Kalikot Veetild43e1652015-11-02 15:35:10 -08002803 }
2804
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002805 param = wma->hw_mode.hw_mode_list[idx];
2806
2807 hw_mode->mac0_tx_ss = WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET(param);
2808 hw_mode->mac0_rx_ss = WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET(param);
2809 hw_mode->mac0_bw = WMI_DBS_HW_MODE_MAC0_BANDWIDTH_GET(param);
2810 hw_mode->mac1_tx_ss = WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET(param);
2811 hw_mode->mac1_rx_ss = WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET(param);
2812 hw_mode->mac1_bw = WMI_DBS_HW_MODE_MAC1_BANDWIDTH_GET(param);
2813 hw_mode->dbs_cap = WMI_DBS_HW_MODE_DBS_MODE_GET(param);
2814 hw_mode->agile_dfs_cap = WMI_DBS_HW_MODE_AGILE_DFS_GET(param);
2815
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302816 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002817}
2818
2819/**
2820 * wma_get_num_dbs_hw_modes() - Get number of HW mode
2821 *
2822 * Fetches the number of DBS HW modes returned by the FW
2823 *
2824 * Return: Negative value on error or returns the number of DBS HW modes
2825 */
2826int8_t wma_get_num_dbs_hw_modes(void)
2827{
2828 tp_wma_handle wma;
2829
Anurag Chouhan6d760662016-02-20 16:05:43 +05302830 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002831 if (!wma) {
2832 WMA_LOGE("%s: Invalid WMA handle", __func__);
2833 return -EINVAL;
2834 }
2835 return wma->num_dbs_hw_modes;
2836}
2837
2838/**
2839 * wma_is_hw_dbs_capable() - Check if HW is DBS capable
2840 *
2841 * Checks if the HW is DBS capable
2842 *
2843 * Return: true if the HW is DBS capable
2844 */
2845bool wma_is_hw_dbs_capable(void)
2846{
2847 tp_wma_handle wma;
2848 uint32_t param, i, found = 0;
2849
Anurag Chouhan6d760662016-02-20 16:05:43 +05302850 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002851 if (!wma) {
2852 WMA_LOGE("%s: Invalid WMA handle", __func__);
2853 return false;
2854 }
2855
2856 if (!wma_is_dbs_enable()) {
2857 WMA_LOGI("%s: DBS is disabled", __func__);
2858 return false;
2859 }
2860
2861 WMA_LOGI("%s: DBS service bit map: %d", __func__,
2862 WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2863 WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT));
2864
2865 /* The agreement with FW is that: To know if the target is DBS
2866 * capable, DBS needs to be supported both in the HW mode list
2867 * and in the service ready event
2868 */
2869 if (!(WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2870 WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT)))
2871 return false;
2872
2873 for (i = 0; i < wma->num_dbs_hw_modes; i++) {
2874 param = wma->hw_mode.hw_mode_list[i];
2875 WMA_LOGI("%s: HW param: %x", __func__, param);
2876 if (WMI_DBS_HW_MODE_DBS_MODE_GET(param)) {
2877 WMA_LOGI("%s: HW (%d) is DBS capable", __func__, i);
2878 found = 1;
2879 break;
2880 }
2881 }
2882
2883 if (found)
2884 return true;
2885
2886 return false;
2887}
2888
2889/**
2890 * wma_is_hw_agile_dfs_capable() - Check if HW is agile DFS capable
2891 *
2892 * Checks if the HW is agile DFS capable
2893 *
2894 * Return: true if the HW is agile DFS capable
2895 */
2896bool wma_is_hw_agile_dfs_capable(void)
2897{
2898 tp_wma_handle wma;
2899 uint32_t param, i, found = 0;
2900
Anurag Chouhan6d760662016-02-20 16:05:43 +05302901 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002902 if (!wma) {
2903 WMA_LOGE("%s: Invalid WMA handle", __func__);
2904 return false;
2905 }
2906
2907 if (!wma_is_agile_dfs_enable()) {
2908 WMA_LOGI("%s: Agile DFS is disabled", __func__);
2909 return false;
2910 }
2911
2912 WMA_LOGI("%s: DBS service bit map: %d", __func__,
2913 WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2914 WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT));
2915
2916 /* The agreement with FW is that to know if the target is Agile DFS
2917 * capable, DBS needs to be supported in the service bit map and
2918 * Agile DFS needs to be supported in the HW mode list
2919 */
2920 if (!(WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2921 WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT)))
2922 return false;
2923
2924 for (i = 0; i < wma->num_dbs_hw_modes; i++) {
2925 param = wma->hw_mode.hw_mode_list[i];
2926 WMA_LOGI("%s: HW param: %x", __func__, param);
2927 if (WMI_DBS_HW_MODE_AGILE_DFS_GET(param)) {
2928 WMA_LOGI("%s: HW %d is agile DFS capable",
2929 __func__, i);
2930 found = 1;
2931 break;
2932 }
2933 }
2934
2935 if (found)
2936 return true;
2937
2938 return false;
2939}
2940
2941/**
2942 * wma_get_mac_id_of_vdev() - Get MAC id corresponding to a vdev
2943 * @vdev_id: VDEV whose MAC ID is required
2944 *
2945 * Get MAC id corresponding to a vdev id from the WMA structure
2946 *
2947 * Return: Negative value on failure and MAC id on success
2948 */
2949int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id)
2950{
2951 tp_wma_handle wma;
2952
Anurag Chouhan6d760662016-02-20 16:05:43 +05302953 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002954 if (!wma) {
2955 WMA_LOGE("%s: Invalid WMA handle", __func__);
2956 return -EINVAL;
2957 }
2958
2959 if (wma->interfaces)
2960 return wma->interfaces[vdev_id].mac_id;
2961
2962 return -EINVAL;
2963}
2964
2965/**
2966 * wma_get_old_and_new_hw_index() - Get the old and new HW index
2967 * @old_hw_mode_index: Value at this pointer contains the old HW mode index
2968 * Default value when not configured is WMA_DEFAULT_HW_MODE_INDEX
2969 * @new_hw_mode_index: Value at this pointer contains the new HW mode index
2970 * Default value when not configured is WMA_DEFAULT_HW_MODE_INDEX
2971 *
2972 * Get the old and new HW index configured in the driver
2973 *
2974 * Return: Failure in case the HW mode indices cannot be fetched and Success
2975 * otherwise. When no HW mode transition has happened the values of
2976 * old_hw_mode_index and new_hw_mode_index will be the same.
2977 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302978QDF_STATUS wma_get_old_and_new_hw_index(uint32_t *old_hw_mode_index,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002979 uint32_t *new_hw_mode_index)
2980{
2981 tp_wma_handle wma;
2982
Anurag Chouhan6d760662016-02-20 16:05:43 +05302983 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002984 if (!wma) {
2985 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302986 return QDF_STATUS_E_INVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002987 }
2988
2989 *old_hw_mode_index = wma->old_hw_mode_index;
2990 *new_hw_mode_index = wma->new_hw_mode_index;
2991
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302992 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002993}
2994
2995/**
2996 * wma_update_intf_hw_mode_params() - Update WMA params
2997 * @vdev_id: VDEV id whose params needs to be updated
2998 * @mac_id: MAC id to be updated
2999 * @cfgd_hw_mode_index: HW mode index from which Tx and Rx SS will be updated
3000 *
3001 * Updates the MAC id, tx spatial stream, rx spatial stream in WMA
3002 *
3003 * Return: None
3004 */
3005void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id,
3006 uint32_t cfgd_hw_mode_index)
3007{
3008 tp_wma_handle wma;
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08003009 uint32_t param;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003010
Anurag Chouhan6d760662016-02-20 16:05:43 +05303011 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003012 if (!wma) {
3013 WMA_LOGE("%s: Invalid WMA handle", __func__);
3014 return;
3015 }
3016
3017 if (!wma->interfaces) {
3018 WMA_LOGE("%s: Interface is NULL", __func__);
3019 return;
3020 }
3021
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08003022 if (cfgd_hw_mode_index > wma->num_dbs_hw_modes) {
3023 WMA_LOGE("%s: Invalid index", __func__);
3024 return;
3025 }
3026
3027 param = wma->hw_mode.hw_mode_list[cfgd_hw_mode_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003028 wma->interfaces[vdev_id].mac_id = mac_id;
3029 if (mac_id == 0) {
3030 wma->interfaces[vdev_id].tx_streams =
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08003031 WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003032 wma->interfaces[vdev_id].rx_streams =
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08003033 WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003034 } else {
3035 wma->interfaces[vdev_id].tx_streams =
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08003036 WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003037 wma->interfaces[vdev_id].rx_streams =
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08003038 WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003039 }
3040}
3041
3042/**
3043 * wma_get_dbs_hw_modes() - Get the DBS HW modes for userspace
3044 * @one_by_one_dbs: 1x1 DBS capability of HW
3045 * @two_by_two_dbs: 2x2 DBS capability of HW
3046 *
3047 * Provides the DBS HW mode capability such as whether
3048 * 1x1 DBS, 2x2 DBS is supported by the HW or not.
3049 *
3050 * Return: Failure in case of error and 0 on success
3051 * one_by_one_dbs/two_by_two_dbs will be false,
3052 * if they are not supported.
3053 * one_by_one_dbs/two_by_two_dbs will be true,
3054 * if they are supported.
3055 * false values of one_by_one_dbs/two_by_two_dbs,
3056 * indicate DBS is disabled
3057 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303058QDF_STATUS wma_get_dbs_hw_modes(bool *one_by_one_dbs, bool *two_by_two_dbs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003059{
3060 tp_wma_handle wma;
3061 uint32_t i;
3062 int8_t found_one_by_one = -EINVAL, found_two_by_two = -EINVAL;
3063 uint32_t conf1_tx_ss, conf1_rx_ss;
3064 uint32_t conf2_tx_ss, conf2_rx_ss;
3065
3066 *one_by_one_dbs = false;
3067 *two_by_two_dbs = false;
3068
3069 if (wma_is_hw_dbs_capable() == false) {
3070 WMA_LOGE("%s: HW is not DBS capable", __func__);
3071 /* Caller will understand that DBS is disabled */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303072 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003073
3074 }
3075
Anurag Chouhan6d760662016-02-20 16:05:43 +05303076 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003077 if (!wma) {
3078 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303079 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003080 }
3081
3082 /* To check 1x1 capability */
3083 wma_get_tx_rx_ss_from_config(HW_MODE_SS_1x1,
3084 &conf1_tx_ss, &conf1_rx_ss);
3085 /* To check 2x2 capability */
3086 wma_get_tx_rx_ss_from_config(HW_MODE_SS_2x2,
3087 &conf2_tx_ss, &conf2_rx_ss);
3088
3089 for (i = 0; i < wma->num_dbs_hw_modes; i++) {
3090 uint32_t t_conf0_tx_ss, t_conf0_rx_ss;
3091 uint32_t t_conf1_tx_ss, t_conf1_rx_ss;
3092 uint32_t dbs_mode;
3093
3094 t_conf0_tx_ss = WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET(
3095 wma->hw_mode.hw_mode_list[i]);
3096 t_conf0_rx_ss = WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET(
3097 wma->hw_mode.hw_mode_list[i]);
3098 t_conf1_tx_ss = WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET(
3099 wma->hw_mode.hw_mode_list[i]);
3100 t_conf1_rx_ss = WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET(
3101 wma->hw_mode.hw_mode_list[i]);
3102 dbs_mode = WMI_DBS_HW_MODE_DBS_MODE_GET(
3103 wma->hw_mode.hw_mode_list[i]);
3104
3105 if (((((t_conf0_tx_ss == conf1_tx_ss) &&
3106 (t_conf0_rx_ss == conf1_rx_ss)) ||
3107 ((t_conf1_tx_ss == conf1_tx_ss) &&
3108 (t_conf1_rx_ss == conf1_rx_ss))) &&
3109 (dbs_mode == HW_MODE_DBS)) &&
3110 (found_one_by_one < 0)) {
3111 found_one_by_one = i;
3112 WMA_LOGI("%s: 1x1 hw_mode index %d found",
3113 __func__, i);
3114 /* Once an entry is found, need not check for 1x1
3115 * again
3116 */
3117 continue;
3118 }
3119
3120 if (((((t_conf0_tx_ss == conf2_tx_ss) &&
3121 (t_conf0_rx_ss == conf2_rx_ss)) ||
3122 ((t_conf1_tx_ss == conf2_tx_ss) &&
3123 (t_conf1_rx_ss == conf2_rx_ss))) &&
3124 (dbs_mode == HW_MODE_DBS)) &&
3125 (found_two_by_two < 0)) {
3126 found_two_by_two = i;
3127 WMA_LOGI("%s: 2x2 hw_mode index %d found",
3128 __func__, i);
3129 /* Once an entry is found, need not check for 2x2
3130 * again
3131 */
3132 continue;
3133 }
3134 }
3135
3136 if (found_one_by_one >= 0)
3137 *one_by_one_dbs = true;
3138 if (found_two_by_two >= 0)
3139 *two_by_two_dbs = true;
3140
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303141 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003142}
3143
3144/**
3145 * wma_get_current_hw_mode() - Get current HW mode params
3146 * @hw_mode: HW mode parameters
3147 *
3148 * Provides the current HW mode parameters if the HW mode is initialized
3149 * in the driver
3150 *
3151 * Return: Success if the current HW mode params are successfully populated
3152 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303153QDF_STATUS wma_get_current_hw_mode(struct sir_hw_mode_params *hw_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003154{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303155 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003156 uint32_t old_hw_index = 0, new_hw_index = 0;
3157
3158 WMA_LOGI("%s: Get the current hw mode", __func__);
3159
3160 status = wma_get_old_and_new_hw_index(&old_hw_index,
3161 &new_hw_index);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303162 if (QDF_STATUS_SUCCESS != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003163 WMA_LOGE("%s: Failed to get HW mode index", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303164 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003165 }
3166
3167 if (new_hw_index == WMA_DEFAULT_HW_MODE_INDEX) {
3168 WMA_LOGE("%s: HW mode is not yet initialized", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303169 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003170 }
3171
3172 status = wma_get_hw_mode_from_idx(new_hw_index, hw_mode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303173 if (QDF_STATUS_SUCCESS != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003174 WMA_LOGE("%s: Failed to get HW mode index", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303175 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003176 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303177 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003178}
3179
3180/**
3181 * wma_is_dbs_enable() - Check if master DBS control is enabled
3182 *
3183 * Checks if the master DBS control is enabled. This will be used
3184 * to override any other DBS capability
3185 *
3186 * Return: True if master DBS control is enabled
3187 */
3188bool wma_is_dbs_enable(void)
3189{
3190 tp_wma_handle wma;
3191
3192 if (wma_is_dual_mac_disabled_in_ini())
3193 return false;
3194
Anurag Chouhan6d760662016-02-20 16:05:43 +05303195 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003196 if (!wma) {
3197 WMA_LOGE("%s: Invalid WMA handle", __func__);
3198 return false;
3199 }
3200
3201 WMA_LOGD("%s: DBS=%d", __func__,
3202 WMI_DBS_FW_MODE_CFG_DBS_GET(wma->dual_mac_cfg.cur_fw_mode_config));
3203
3204 if (WMI_DBS_FW_MODE_CFG_DBS_GET(wma->dual_mac_cfg.cur_fw_mode_config))
3205 return true;
3206
3207 return false;
3208}
3209
3210/**
3211 * wma_is_agile_dfs_enable() - Check if master Agile DFS control is enabled
3212 *
3213 * Checks if the master Agile DFS control is enabled. This will be used
3214 * to override any other Agile DFS capability
3215 *
3216 * Return: True if master Agile DFS control is enabled
3217 */
3218bool wma_is_agile_dfs_enable(void)
3219{
3220 tp_wma_handle wma;
3221
3222 if (wma_is_dual_mac_disabled_in_ini())
3223 return false;
3224
Anurag Chouhan6d760662016-02-20 16:05:43 +05303225 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003226 if (!wma) {
3227 WMA_LOGE("%s: Invalid WMA handle", __func__);
3228 return false;
3229 }
3230
3231 WMA_LOGD("%s: DFS=%d Single mac with DFS=%d", __func__,
3232 WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(
3233 wma->dual_mac_cfg.cur_fw_mode_config),
3234 WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(
3235 wma->dual_mac_cfg.cur_scan_config));
3236
3237 if ((WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(
3238 wma->dual_mac_cfg.cur_fw_mode_config)) &&
3239 (WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(
3240 wma->dual_mac_cfg.cur_scan_config)))
3241 return true;
3242
3243 return false;
3244}
3245
3246/**
3247 * wma_get_updated_scan_config() - Get the updated scan configuration
3248 * @scan_config: Pointer containing the updated scan config
3249 * @dbs_scan: 0 or 1 indicating if DBS scan needs to be enabled/disabled
3250 * @dbs_plus_agile_scan: 0 or 1 indicating if DBS plus agile scan needs to be
3251 * enabled/disabled
3252 * @single_mac_scan_with_dfs: 0 or 1 indicating if single MAC scan with DFS
3253 * needs to be enabled/disabled
3254 *
3255 * Takes the current scan configuration and set the necessary scan config
3256 * bits to either 0/1 and provides the updated value to the caller who
3257 * can use this to pass it on to the FW
3258 *
3259 * Return: 0 on success
3260 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303261QDF_STATUS wma_get_updated_scan_config(uint32_t *scan_config,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003262 bool dbs_scan,
3263 bool dbs_plus_agile_scan,
3264 bool single_mac_scan_with_dfs)
3265{
3266 tp_wma_handle wma;
3267
Anurag Chouhan6d760662016-02-20 16:05:43 +05303268 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003269 if (!wma) {
3270 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303271 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003272 }
3273 *scan_config = wma->dual_mac_cfg.cur_scan_config;
3274
3275 WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(*scan_config, dbs_scan);
3276 WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(*scan_config,
3277 dbs_plus_agile_scan);
3278 WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(*scan_config,
3279 single_mac_scan_with_dfs);
3280
3281 WMA_LOGD("%s: *scan_config:%x ", __func__, *scan_config);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303282 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003283}
3284
3285/**
3286 * wma_get_updated_fw_mode_config() - Get the updated fw mode configuration
3287 * @fw_mode_config: Pointer containing the updated fw mode config
3288 * @dbs: 0 or 1 indicating if DBS needs to be enabled/disabled
3289 * @agile_dfs: 0 or 1 indicating if agile DFS needs to be enabled/disabled
3290 *
3291 * Takes the current fw mode configuration and set the necessary fw mode config
3292 * bits to either 0/1 and provides the updated value to the caller who
3293 * can use this to pass it on to the FW
3294 *
3295 * Return: 0 on success
3296 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303297QDF_STATUS wma_get_updated_fw_mode_config(uint32_t *fw_mode_config,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003298 bool dbs,
3299 bool agile_dfs)
3300{
3301 tp_wma_handle wma;
3302
Anurag Chouhan6d760662016-02-20 16:05:43 +05303303 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003304 if (!wma) {
3305 WMA_LOGE("%s: Invalid WMA handle", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303306 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003307 }
3308 *fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config;
3309
3310 WMI_DBS_FW_MODE_CFG_DBS_SET(*fw_mode_config, dbs);
3311 WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(*fw_mode_config, agile_dfs);
3312
3313 WMA_LOGD("%s: *fw_mode_config:%x ", __func__, *fw_mode_config);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303314 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003315}
3316
3317/**
3318 * wma_get_dbs_config() - Get DBS bit
3319 *
3320 * Gets the DBS bit of fw_mode_config_bits
3321 *
3322 * Return: 0 or 1 to indicate the DBS bit
3323 */
3324bool wma_get_dbs_config(void)
3325{
3326 tp_wma_handle wma;
3327 uint32_t fw_mode_config;
3328
3329 if (wma_is_dual_mac_disabled_in_ini())
3330 return false;
3331
Anurag Chouhan6d760662016-02-20 16:05:43 +05303332 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003333 if (!wma) {
3334 WMA_LOGE("%s: Invalid WMA handle", __func__);
3335 /* We take that it is disabled and proceed */
3336 return false;
3337 }
3338 fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config;
3339
3340 return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config);
3341}
3342
3343/**
3344 * wma_get_agile_dfs_config() - Get Agile DFS bit
3345 *
3346 * Gets the Agile DFS bit of fw_mode_config_bits
3347 *
3348 * Return: 0 or 1 to indicate the Agile DFS bit
3349 */
3350bool wma_get_agile_dfs_config(void)
3351{
3352 tp_wma_handle wma;
3353 uint32_t fw_mode_config;
3354
3355 if (wma_is_dual_mac_disabled_in_ini())
3356 return false;
3357
Anurag Chouhan6d760662016-02-20 16:05:43 +05303358 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003359 if (!wma) {
3360 WMA_LOGE("%s: Invalid WMA handle", __func__);
3361 /* We take that it is disabled and proceed */
3362 return false;
3363 }
3364 fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config;
3365
3366 return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config);
3367}
3368
3369/**
3370 * wma_get_dbs_scan_config() - Get DBS scan bit
3371 *
3372 * Gets the DBS scan bit of concurrent_scan_config_bits
3373 *
3374 * Return: 0 or 1 to indicate the DBS scan bit
3375 */
3376bool wma_get_dbs_scan_config(void)
3377{
3378 tp_wma_handle wma;
3379 uint32_t scan_config;
3380
3381 if (wma_is_dual_mac_disabled_in_ini())
3382 return false;
3383
Anurag Chouhan6d760662016-02-20 16:05:43 +05303384 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003385 if (!wma) {
3386 WMA_LOGE("%s: Invalid WMA handle", __func__);
3387 /* We take that it is disabled and proceed */
3388 return false;
3389 }
3390 scan_config = wma->dual_mac_cfg.cur_scan_config;
3391
3392 return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config);
3393}
3394
3395/**
3396 * wma_get_dbs_plus_agile_scan_config() - Get DBS plus agile scan bit
3397 *
3398 * Gets the DBS plus agile scan bit of concurrent_scan_config_bits
3399 *
3400 * Return: 0 or 1 to indicate the DBS plus agile scan bit
3401 */
3402bool wma_get_dbs_plus_agile_scan_config(void)
3403{
3404 tp_wma_handle wma;
3405 uint32_t scan_config;
3406
3407 if (wma_is_dual_mac_disabled_in_ini())
3408 return false;
3409
Anurag Chouhan6d760662016-02-20 16:05:43 +05303410 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003411 if (!wma) {
3412 WMA_LOGE("%s: Invalid WMA handle", __func__);
3413 /* We take that it is disabled and proceed */
3414 return false;
3415 }
3416 scan_config = wma->dual_mac_cfg.cur_scan_config;
3417
3418 return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config);
3419}
3420
3421/**
3422 * wma_get_single_mac_scan_with_dfs_config() - Get Single MAC scan with DFS bit
3423 *
3424 * Gets the Single MAC scan with DFS bit of concurrent_scan_config_bits
3425 *
3426 * Return: 0 or 1 to indicate the Single MAC scan with DFS bit
3427 */
3428bool wma_get_single_mac_scan_with_dfs_config(void)
3429{
3430 tp_wma_handle wma;
3431 uint32_t scan_config;
3432
3433 if (wma_is_dual_mac_disabled_in_ini())
3434 return false;
3435
Anurag Chouhan6d760662016-02-20 16:05:43 +05303436 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003437 if (!wma) {
3438 WMA_LOGE("%s: Invalid WMA handle", __func__);
3439 /* We take that it is disabled and proceed */
3440 return false;
3441 }
3442 scan_config = wma->dual_mac_cfg.cur_scan_config;
3443
3444 return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config);
3445}
3446
3447/**
3448 * wma_is_dual_mac_disabled_in_ini() - Check if dual mac is disabled in INI
3449 *
3450 * Checks if the dual mac feature is disabled in INI
3451 *
3452 * Return: true if the dual mac feature is disabled from INI
3453 */
3454bool wma_is_dual_mac_disabled_in_ini(void)
3455{
Anurag Chouhan6d760662016-02-20 16:05:43 +05303456 tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003457
3458 if (!mac) {
3459 WMA_LOGE("%s: Invalid mac pointer", __func__);
3460 return true;
3461 }
3462
3463 if (mac->dual_mac_feature_disable)
3464 return true;
3465
3466 return false;
3467}
3468
3469/**
3470 * wma_get_prev_dbs_config() - Get prev DBS bit
3471 *
3472 * Gets the previous DBS bit of fw_mode_config_bits
3473 *
3474 * Return: 0 or 1 to indicate the DBS bit
3475 */
3476bool wma_get_prev_dbs_config(void)
3477{
3478 tp_wma_handle wma;
3479 uint32_t fw_mode_config;
3480
3481 if (wma_is_dual_mac_disabled_in_ini())
3482 return false;
3483
Anurag Chouhan6d760662016-02-20 16:05:43 +05303484 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003485 if (!wma) {
3486 WMA_LOGE("%s: Invalid WMA handle", __func__);
3487 /* We take that it is disabled and proceed */
3488 return false;
3489 }
3490 fw_mode_config = wma->dual_mac_cfg.prev_fw_mode_config;
3491
3492 return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config);
3493}
3494
3495/**
3496 * wma_get_prev_agile_dfs_config() - Get prev Agile DFS bit
3497 *
3498 * Gets the previous Agile DFS bit of fw_mode_config_bits
3499 *
3500 * Return: 0 or 1 to indicate the Agile DFS bit
3501 */
3502bool wma_get_prev_agile_dfs_config(void)
3503{
3504 tp_wma_handle wma;
3505 uint32_t fw_mode_config;
3506
3507 if (wma_is_dual_mac_disabled_in_ini())
3508 return false;
3509
Anurag Chouhan6d760662016-02-20 16:05:43 +05303510 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003511 if (!wma) {
3512 WMA_LOGE("%s: Invalid WMA handle", __func__);
3513 /* We take that it is disabled and proceed */
3514 return false;
3515 }
3516 fw_mode_config = wma->dual_mac_cfg.prev_fw_mode_config;
3517
3518 return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config);
3519}
3520
3521/**
3522 * wma_get_prev_dbs_scan_config() - Get prev DBS scan bit
3523 *
3524 * Gets the previous DBS scan bit of concurrent_scan_config_bits
3525 *
3526 * Return: 0 or 1 to indicate the DBS scan bit
3527 */
3528bool wma_get_prev_dbs_scan_config(void)
3529{
3530 tp_wma_handle wma;
3531 uint32_t scan_config;
3532
3533 if (wma_is_dual_mac_disabled_in_ini())
3534 return false;
3535
Anurag Chouhan6d760662016-02-20 16:05:43 +05303536 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003537 if (!wma) {
3538 WMA_LOGE("%s: Invalid WMA handle", __func__);
3539 /* We take that it is disabled and proceed */
3540 return false;
3541 }
3542 scan_config = wma->dual_mac_cfg.prev_scan_config;
3543
3544 return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config);
3545}
3546
3547/**
3548 * wma_get_prev_dbs_plus_agile_scan_config() - Get prev DBS plus agile scan bit
3549 *
3550 * Gets the previous DBS plus agile scan bit of concurrent_scan_config_bits
3551 *
3552 * Return: 0 or 1 to indicate the DBS plus agile scan bit
3553 */
3554bool wma_get_prev_dbs_plus_agile_scan_config(void)
3555{
3556 tp_wma_handle wma;
3557 uint32_t scan_config;
3558
3559 if (wma_is_dual_mac_disabled_in_ini())
3560 return false;
3561
Anurag Chouhan6d760662016-02-20 16:05:43 +05303562 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003563 if (!wma) {
3564 WMA_LOGE("%s: Invalid WMA handle", __func__);
3565 /* We take that it is disabled and proceed */
3566 return false;
3567 }
3568 scan_config = wma->dual_mac_cfg.prev_scan_config;
3569
3570 return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config);
3571}
3572
3573/**
3574 * wma_get_prev_single_mac_scan_with_dfs_config() - Get prev Single MAC scan
3575 * with DFS bit
3576 *
3577 * Gets the previous Single MAC scan with DFS bit of concurrent_scan_config_bits
3578 *
3579 * Return: 0 or 1 to indicate the Single MAC scan with DFS bit
3580 */
3581bool wma_get_prev_single_mac_scan_with_dfs_config(void)
3582{
3583 tp_wma_handle wma;
3584 uint32_t scan_config;
3585
3586 if (wma_is_dual_mac_disabled_in_ini())
3587 return false;
3588
Anurag Chouhan6d760662016-02-20 16:05:43 +05303589 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590 if (!wma) {
3591 WMA_LOGE("%s: Invalid WMA handle", __func__);
3592 /* We take that it is disabled and proceed */
3593 return false;
3594 }
3595 scan_config = wma->dual_mac_cfg.prev_scan_config;
3596
3597 return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config);
3598}
3599
3600/**
3601 * wma_is_scan_simultaneous_capable() - Check if scan parallelization is
3602 * supported or not
3603 *
3604 * currently scan parallelization feature support is dependent on DBS but
3605 * it can be independent in future.
3606 *
3607 * Return: True if master DBS control is enabled
3608 */
3609bool wma_is_scan_simultaneous_capable(void)
3610{
3611 if (wma_is_hw_dbs_capable())
3612 return true;
3613
3614 return false;
3615}
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08003616
3617/**
3618 * wma_get_vht_ch_width - return vht channel width
3619 *
3620 * Return: return vht channel width
3621 */
3622uint32_t wma_get_vht_ch_width(void)
3623{
3624 uint32_t fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ;
Anurag Chouhan6d760662016-02-20 16:05:43 +05303625 tp_wma_handle wm_hdl = cds_get_context(QDF_MODULE_ID_WMA);
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08003626
3627 if (NULL == wm_hdl)
3628 return fw_ch_wd;
3629
3630 if (wm_hdl->vht_cap_info &
3631 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)
3632 fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ;
3633 else if (wm_hdl->vht_cap_info &
3634 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
3635 fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ;
3636
3637 return fw_ch_wd;
3638}