blob: 2b2319f3d24636a8fd7ac6bee0a5b5c5e69483d7 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Tushnim Bhattacharyyad07dc902017-01-11 12:49:53 -08002 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wma_utis.c
30 * This file contains utilities and stats related functions.
31 */
32
33/* Header files */
34
35#include "wma.h"
36#include "wma_api.h"
37#include "cds_api.h"
38#include "wmi_unified_api.h"
39#include "wlan_qct_sys.h"
40#include "wni_api.h"
41#include "ani_global.h"
42#include "wmi_unified.h"
43#include "wni_cfg.h"
44#include "cfg_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080045
Nirav Shahcbc6d722016-03-01 16:24:53 +053046#include "qdf_nbuf.h"
Anurag Chouhan6d760662016-02-20 16:05:43 +053047#include "qdf_types.h"
Anurag Chouhan600c3a02016-03-01 10:33:54 +053048#include "qdf_mem.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080049
50#include "wma_types.h"
51#include "lim_api.h"
52#include "lim_session_utils.h"
53
54#include "cds_utils.h"
55
56#if !defined(REMOVE_PKT_LOG)
57#include "pktlog_ac.h"
58#endif /* REMOVE_PKT_LOG */
59
60#include "dbglog_host.h"
61#include "csr_api.h"
62#include "ol_fw.h"
63
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080064#include "wma_internal.h"
Tushnim Bhattacharyya51258a72017-03-13 12:55:02 -070065#include "wlan_policy_mgr_api.h"
Govind Singhd76a5b02016-03-08 15:12:14 +053066#include "wmi_unified_param.h"
Naveen Rawatc0c91cd2015-11-05 14:27:37 -080067#include "linux/ieee80211.h"
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -080068#include <cdp_txrx_handle.h>
Varun Reddy Yeturuc3139102017-09-27 20:38:39 -070069#include "cds_reg_service.h"
70
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071/* MCS Based rate table */
72/* HT MCS parameters with Nss = 1 */
Ryan Hsu6139d2d2015-11-04 17:29:00 -080073static struct index_data_rate_type mcs_nss1[] = {
74 /* MCS L20 S20 L40 S40 */
75 {0, {65, 72}, {135, 150 } },
76 {1, {130, 144}, {270, 300 } },
77 {2, {195, 217}, {405, 450 } },
78 {3, {260, 289}, {540, 600 } },
79 {4, {390, 433}, {815, 900 } },
80 {5, {520, 578}, {1080, 1200} },
81 {6, {585, 650}, {1215, 1350} },
82 {7, {650, 722}, {1350, 1500} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080083};
84
85/* HT MCS parameters with Nss = 2 */
Ryan Hsu6139d2d2015-11-04 17:29:00 -080086static struct index_data_rate_type mcs_nss2[] = {
87 /* MCS L20 S20 L40 S40 */
88 {0, {130, 144}, {270, 300 } },
89 {1, {260, 289}, {540, 600 } },
90 {2, {390, 433}, {810, 900 } },
91 {3, {520, 578}, {1080, 1200} },
92 {4, {780, 867}, {1620, 1800} },
93 {5, {1040, 1156}, {2160, 2400} },
94 {6, {1170, 1300}, {2430, 2700} },
95 {7, {1300, 1440}, {2700, 3000} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080096};
97
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080098/* MCS Based VHT rate table */
99/* MCS parameters with Nss = 1*/
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800100static struct index_vht_data_rate_type vht_mcs_nss1[] = {
101 /* MCS L20 S20 L40 S40 L80 S80 */
102 {0, {65, 72 }, {135, 150}, {293, 325} },
103 {1, {130, 144}, {270, 300}, {585, 650} },
104 {2, {195, 217}, {405, 450}, {878, 975} },
105 {3, {260, 289}, {540, 600}, {1170, 1300} },
106 {4, {390, 433}, {810, 900}, {1755, 1950} },
107 {5, {520, 578}, {1080, 1200}, {2340, 2600} },
108 {6, {585, 650}, {1215, 1350}, {2633, 2925} },
109 {7, {650, 722}, {1350, 1500}, {2925, 3250} },
110 {8, {780, 867}, {1620, 1800}, {3510, 3900} },
111 {9, {865, 960}, {1800, 2000}, {3900, 4333} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800112};
113
114/*MCS parameters with Nss = 2*/
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800115static struct index_vht_data_rate_type vht_mcs_nss2[] = {
116 /* MCS L20 S20 L40 S40 L80 S80 */
117 {0, {130, 144}, {270, 300}, { 585, 650} },
118 {1, {260, 289}, {540, 600}, {1170, 1300} },
119 {2, {390, 433}, {810, 900}, {1755, 1950} },
120 {3, {520, 578}, {1080, 1200}, {2340, 2600} },
121 {4, {780, 867}, {1620, 1800}, {3510, 3900} },
122 {5, {1040, 1156}, {2160, 2400}, {4680, 5200} },
123 {6, {1170, 1300}, {2430, 2700}, {5265, 5850} },
124 {7, {1300, 1444}, {2700, 3000}, {5850, 6500} },
125 {8, {1560, 1733}, {3240, 3600}, {7020, 7800} },
126 {9, {1730, 1920}, {3600, 4000}, {7800, 8667} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800127};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800128
129#ifdef BIG_ENDIAN_HOST
130
131/* ############# function definitions ############ */
132
133/**
134 * wma_swap_bytes() - swap bytes
135 * @pv: buffer
136 * @n: swap bytes
137 *
138 * Return: none
139 */
140void wma_swap_bytes(void *pv, uint32_t n)
141{
142 int32_t no_words;
143 int32_t i;
144 uint32_t *word_ptr;
145
146 no_words = n / sizeof(uint32_t);
147 word_ptr = (uint32_t *) pv;
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -0700148 for (i = 0; i < no_words; i++)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800149 *(word_ptr + i) = __cpu_to_le32(*(word_ptr + i));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800150}
151
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -0700152#define SWAPME(x, len) wma_swap_bytes(&x, len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800153#endif /* BIG_ENDIAN_HOST */
154
155/**
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800156 * wma_mcs_rate_match() - find the match mcs rate
157 * @match_rate: the rate to look up
158 * @is_sgi: return if the SGI rate is found
159 * @nss: the nss in use
160 * @nss1_rate: the nss1 rate
161 * @nss1_srate: the nss1 SGI rate
162 * @nss2_rate: the nss2 rate
163 * @nss2_srate: the nss2 SGI rate
164 *
165 * This is a helper function to find the match of the tx_rate
166 * in terms of the nss1/nss2 rate with non-SGI/SGI.
167 *
168 * Return: the found rate or 0 otherwise
169 */
170static inline uint16_t wma_mcs_rate_match(uint16_t match_rate, bool *is_sgi,
171 uint8_t nss, uint16_t nss1_rate,
172 uint16_t nss1_srate,
173 uint16_t nss2_rate,
174 uint16_t nss2_srate)
175{
176 WMA_LOGD("%s match_rate: %d, %d %d %d %d",
177 __func__, match_rate, nss1_rate, nss1_srate, nss2_rate,
178 nss2_srate);
179
180 if (match_rate == nss1_rate) {
181 return nss1_rate;
182 } else if (match_rate == nss1_srate) {
183 *is_sgi = true;
184 return nss1_srate;
185 } else if (nss == 2 && match_rate == nss2_rate)
186 return nss2_rate;
187 else if (nss == 2 && match_rate == nss2_srate) {
188 *is_sgi = true;
189 return nss2_srate;
190 } else
191 return 0;
192}
193
194/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800195 * wma_get_mcs_idx() - get mcs index
196 * @maxRate: max rate
197 * @rate_flags: rate flags
198 * @nss: number of nss
199 * @mcsRateFlag: mcs rate flag
200 *
201 * Return: return mcs index
202 */
203static uint8_t wma_get_mcs_idx(uint16_t maxRate, uint8_t rate_flags,
204 uint8_t nss, uint8_t *mcsRateFlag)
205{
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800206 uint8_t index = 0;
Arif Hussainb8fef842016-07-19 09:43:13 -0700207 uint16_t match_rate = 0;
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800208 bool is_sgi = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800209
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800210 WMA_LOGD("%s rate:%d rate_flgs: 0x%x, nss: %d",
211 __func__, maxRate, rate_flags, nss);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800212
213 *mcsRateFlag = rate_flags;
214 *mcsRateFlag &= ~eHAL_TX_RATE_SGI;
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800215 for (index = 0; index < MAX_VHT_MCS_IDX; index++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216 if (rate_flags & eHAL_TX_RATE_VHT80) {
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800217 /* check for vht80 nss1/2 rate set */
218 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
219 vht_mcs_nss1[index].ht80_rate[0],
220 vht_mcs_nss1[index].ht80_rate[1],
221 vht_mcs_nss2[index].ht80_rate[0],
222 vht_mcs_nss2[index].ht80_rate[1]);
223 if (match_rate)
224 goto rate_found;
225 }
226 if ((rate_flags & eHAL_TX_RATE_VHT40) |
227 (rate_flags & eHAL_TX_RATE_VHT80)) {
228 /* check for vht40 nss1/2 rate set */
229 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
230 vht_mcs_nss1[index].ht40_rate[0],
231 vht_mcs_nss1[index].ht40_rate[1],
232 vht_mcs_nss2[index].ht40_rate[0],
233 vht_mcs_nss2[index].ht40_rate[1]);
234 if (match_rate) {
235 *mcsRateFlag &= ~eHAL_TX_RATE_VHT80;
236 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800237 }
238 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800239 if ((rate_flags & eHAL_TX_RATE_VHT20) |
240 (rate_flags & eHAL_TX_RATE_VHT40) |
241 (rate_flags & eHAL_TX_RATE_VHT80)) {
242 /* check for vht20 nss1/2 rate set */
243 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
244 vht_mcs_nss1[index].ht20_rate[0],
245 vht_mcs_nss1[index].ht20_rate[1],
246 vht_mcs_nss2[index].ht20_rate[0],
247 vht_mcs_nss2[index].ht20_rate[1]);
248 if (match_rate) {
249 *mcsRateFlag &= ~(eHAL_TX_RATE_VHT80 |
250 eHAL_TX_RATE_VHT40);
251 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800252 }
253 }
254 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800255 for (index = 0; index < MAX_HT_MCS_IDX; index++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256 if (rate_flags & eHAL_TX_RATE_HT40) {
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800257 /* check for ht40 nss1/2 rate set */
258 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
259 mcs_nss1[index].ht40_rate[0],
260 mcs_nss1[index].ht40_rate[1],
261 mcs_nss2[index].ht40_rate[0],
262 mcs_nss2[index].ht40_rate[1]);
263 if (match_rate) {
264 *mcsRateFlag = eHAL_TX_RATE_HT40;
265 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800266 }
267 }
wadesongbf665542017-02-28 14:30:51 +0800268 if ((rate_flags & eHAL_TX_RATE_HT20) ||
269 (rate_flags & eHAL_TX_RATE_HT40)) {
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800270 /* check for ht20 nss1/2 rate set */
271 match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss,
272 mcs_nss1[index].ht20_rate[0],
273 mcs_nss1[index].ht20_rate[1],
274 mcs_nss2[index].ht20_rate[0],
275 mcs_nss2[index].ht20_rate[1]);
276 if (match_rate) {
277 *mcsRateFlag = eHAL_TX_RATE_HT20;
278 goto rate_found;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800279 }
280 }
281 }
282
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800283rate_found:
284 /* set SGI flag only if this is SGI rate */
285 if (match_rate && is_sgi == true)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800286 *mcsRateFlag |= eHAL_TX_RATE_SGI;
287
Ryan Hsu6139d2d2015-11-04 17:29:00 -0800288 WMA_LOGD("%s - match_rate: %d index: %d rate_flag: 0x%x is_sgi: %d",
289 __func__, match_rate, index, *mcsRateFlag, is_sgi);
290
291 return match_rate ? index : INVALID_MCS_IDX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800292}
293
294/**
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +0530295 * wma_peek_vdev_req() - peek what request message is queued for response.
296 * the function does not delete the node after found
297 * @wma: WMA handle
298 * @vdev_id: vdev ID
299 * @type: request message type
300 *
301 * Return: the request message found
302 */
303static struct wma_target_req *wma_peek_vdev_req(tp_wma_handle wma,
304 uint8_t vdev_id, uint8_t type)
305{
306 struct wma_target_req *req_msg = NULL;
307 bool found = false;
308 qdf_list_node_t *node1 = NULL, *node2 = NULL;
309
310 qdf_spin_lock_bh(&wma->vdev_respq_lock);
311 if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->vdev_resp_queue,
312 &node2)) {
313 qdf_spin_unlock_bh(&wma->vdev_respq_lock);
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +0530314 return NULL;
315 }
316
317 do {
318 node1 = node2;
319 req_msg = qdf_container_of(node1, struct wma_target_req, node);
320 if (req_msg->vdev_id != vdev_id)
321 continue;
322 if (req_msg->type != type)
323 continue;
324
325 found = true;
326 break;
327 } while (QDF_STATUS_SUCCESS == qdf_list_peek_next(&wma->vdev_resp_queue,
328 node1, &node2));
329 qdf_spin_unlock_bh(&wma->vdev_respq_lock);
330 if (!found) {
Srinivas Girigowdad1a07a52017-03-06 22:48:16 -0800331 WMA_LOGE(FL("target request not found for vdev_id %d type %d"),
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +0530332 vdev_id, type);
333 return NULL;
334 }
335 WMA_LOGD(FL("target request found for vdev id: %d type %d msg %d"),
336 vdev_id, type, req_msg->msg_type);
337 return req_msg;
338}
339
340void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id,
341 int32_t rssi)
342{
343 struct sir_lost_link_info *lost_link_info;
344 QDF_STATUS qdf_status;
Rajeev Kumarb60abe42017-01-21 15:39:31 -0800345 struct scheduler_msg sme_msg = {0};
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +0530346
347 /* report lost link information only for STA mode */
Mukul Sharmaf9047232017-03-02 16:58:56 +0530348 if (wma_is_vdev_up(vdev_id) &&
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +0530349 (WMI_VDEV_TYPE_STA == wma->interfaces[vdev_id].type) &&
350 (0 == wma->interfaces[vdev_id].sub_type)) {
351 lost_link_info = qdf_mem_malloc(sizeof(*lost_link_info));
352 if (NULL == lost_link_info) {
353 WMA_LOGE("%s: failed to allocate memory", __func__);
354 return;
355 }
356 lost_link_info->vdev_id = vdev_id;
357 lost_link_info->rssi = rssi;
358 sme_msg.type = eWNI_SME_LOST_LINK_INFO_IND;
359 sme_msg.bodyptr = lost_link_info;
360 sme_msg.bodyval = 0;
Srinivas Girigowdad1a07a52017-03-06 22:48:16 -0800361 WMA_LOGD("%s: post msg to SME, bss_idx %d, rssi %d", __func__,
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +0530362 lost_link_info->vdev_id, lost_link_info->rssi);
363
Rajeev Kumarb60abe42017-01-21 15:39:31 -0800364 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +0530365 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
366 WMA_LOGE("%s: fail to post msg to SME", __func__);
367 qdf_mem_free(lost_link_info);
368 }
369 }
370}
371
372/**
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -0700373 * host_map_smps_mode() - map fw smps mode to enum eSmpsModeValue
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800374 * @fw_smps_mode: fw smps mode
375 *
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -0700376 * Return: return enum eSmpsModeValue
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800377 */
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -0700378enum eSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800379{
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -0700380 enum eSmpsModeValue smps_mode = SMPS_MODE_DISABLED;
381
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800382 switch (fw_smps_mode) {
383 case WMI_SMPS_FORCED_MODE_STATIC:
384 smps_mode = STATIC_SMPS_MODE;
385 break;
386 case WMI_SMPS_FORCED_MODE_DYNAMIC:
387 smps_mode = DYNAMIC_SMPS_MODE;
388 break;
389 default:
390 smps_mode = SMPS_MODE_DISABLED;
391 }
392
393 return smps_mode;
394}
395
Archana Ramachandran20d2e232016-02-11 16:58:40 -0800396/**
397 * wma_smps_mode_to_force_mode_param() - Map smps mode to force
398 * mode commmand param
399 * @smps_mode: SMPS mode according to the protocol
400 *
401 * Return: int > 0 for success else failure
402 */
403int wma_smps_mode_to_force_mode_param(uint8_t smps_mode)
404{
405 int param = -EINVAL;
406
407 switch (smps_mode) {
408 case STATIC_SMPS_MODE:
409 param = WMI_SMPS_FORCED_MODE_STATIC;
410 break;
411 case DYNAMIC_SMPS_MODE:
412 param = WMI_SMPS_FORCED_MODE_DYNAMIC;
413 break;
414 case SMPS_MODE_DISABLED:
415 param = WMI_SMPS_FORCED_MODE_DISABLED;
416 break;
417 default:
418 WMA_LOGE(FL("smps mode cannot be mapped :%d "),
419 smps_mode);
420 }
421 return param;
422}
423
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800424#ifdef WLAN_FEATURE_STATS_EXT
425/**
426 * wma_stats_ext_event_handler() - extended stats event handler
427 * @handle: wma handle
428 * @event_buf: event buffer received from fw
429 * @len: length of data
430 *
431 * Return: 0 for success or error code
432 */
433int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf,
434 uint32_t len)
435{
436 WMI_STATS_EXT_EVENTID_param_tlvs *param_buf;
437 tSirStatsExtEvent *stats_ext_event;
438 wmi_stats_ext_event_fixed_param *stats_ext_info;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530439 QDF_STATUS status;
Rajeev Kumarcf7bd802017-04-18 11:11:42 -0700440 struct scheduler_msg cds_msg = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800441 uint8_t *buf_ptr;
442 uint32_t alloc_len;
443
444 WMA_LOGD("%s: Posting stats ext event to SME", __func__);
445
446 param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *) event_buf;
447 if (!param_buf) {
448 WMA_LOGE("%s: Invalid stats ext event buf", __func__);
449 return -EINVAL;
450 }
451
452 stats_ext_info = param_buf->fixed_param;
453 buf_ptr = (uint8_t *) stats_ext_info;
454
455 alloc_len = sizeof(tSirStatsExtEvent);
456 alloc_len += stats_ext_info->data_len;
457
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -0700458 if (stats_ext_info->data_len > (WMI_SVC_MSG_MAX_SIZE -
459 sizeof(*stats_ext_info))) {
460 WMA_LOGE("Excess data_len:%d", stats_ext_info->data_len);
461 QDF_ASSERT(0);
462 return -EINVAL;
463 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530464 stats_ext_event = (tSirStatsExtEvent *) qdf_mem_malloc(alloc_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800465 if (NULL == stats_ext_event) {
466 WMA_LOGE("%s: Memory allocation failure", __func__);
467 return -ENOMEM;
468 }
469
470 buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE;
471
472 stats_ext_event->vdev_id = stats_ext_info->vdev_id;
473 stats_ext_event->event_data_len = stats_ext_info->data_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530474 qdf_mem_copy(stats_ext_event->event_data,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800475 buf_ptr, stats_ext_event->event_data_len);
476
477 cds_msg.type = eWNI_SME_STATS_EXT_EVENT;
478 cds_msg.bodyptr = (void *)stats_ext_event;
479 cds_msg.bodyval = 0;
480
Rajeev Kumarb60abe42017-01-21 15:39:31 -0800481 status = scheduler_post_msg(QDF_MODULE_ID_SME, &cds_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530482 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800483 WMA_LOGE("%s: Failed to post stats ext event to SME", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530484 qdf_mem_free(stats_ext_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800485 return -EFAULT;
486 }
487
488 WMA_LOGD("%s: stats ext event Posted to SME", __func__);
489 return 0;
490}
491#endif /* WLAN_FEATURE_STATS_EXT */
492
Nirav Shah93e789e2016-04-14 19:47:43 +0530493
Govind Singha471e5e2015-10-12 17:11:14 +0530494/**
495 * wma_profile_data_report_event_handler() - fw profiling handler
496 * @handle: wma handle
497 * @event_buf: event buffer received from fw
498 * @len: length of data
499 *
500 * Return: 0 for success or error code
501 */
502int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf,
503 uint32_t len)
504{
505 WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *param_buf;
506 wmi_wlan_profile_ctx_t *profile_ctx;
507 wmi_wlan_profile_t *profile_data;
508 uint32_t i = 0;
509 uint32_t entries;
510 uint8_t *buf_ptr;
Nirav Shah93e789e2016-04-14 19:47:43 +0530511 char temp_str[150];
Govind Singha471e5e2015-10-12 17:11:14 +0530512
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -0700513 param_buf = (WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *) event_buf;
Govind Singha471e5e2015-10-12 17:11:14 +0530514 if (!param_buf) {
515 WMA_LOGE("%s: Invalid profile data event buf", __func__);
516 return -EINVAL;
517 }
518 profile_ctx = param_buf->profile_ctx;
519 buf_ptr = (uint8_t *)profile_ctx;
520 buf_ptr = buf_ptr + sizeof(wmi_wlan_profile_ctx_t) + WMI_TLV_HDR_SIZE;
521 profile_data = (wmi_wlan_profile_t *) buf_ptr;
522 entries = profile_ctx->bin_count;
Amar Singhal4bd22232017-10-04 13:24:00 -0700523
524 if (entries > param_buf->num_profile_data) {
525 WMA_LOGE("FW bin count %d more than data %d in TLV hdr",
526 entries,
527 param_buf->num_profile_data);
528 return -EINVAL;
529 }
530
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530531 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Govind Singha471e5e2015-10-12 17:11:14 +0530532 "Profile data stats\n");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530533 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
Govind Singha471e5e2015-10-12 17:11:14 +0530534 "TOT: %d\n"
535 "tx_msdu_cnt: %d\n"
536 "tx_mpdu_cnt: %d\n"
537 "tx_ppdu_cnt: %d\n"
538 "rx_msdu_cnt: %d\n"
539 "rx_mpdu_cnt: %d\n"
540 "bin_count: %d\n",
541 profile_ctx->tot,
542 profile_ctx->tx_msdu_cnt,
543 profile_ctx->tx_mpdu_cnt,
544 profile_ctx->tx_ppdu_cnt,
545 profile_ctx->rx_msdu_cnt,
546 profile_ctx->rx_mpdu_cnt,
547 profile_ctx->bin_count);
548
Nirav Shah93e789e2016-04-14 19:47:43 +0530549 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
550 "Profile ID: Count: TOT: Min: Max: hist_intvl: hist[0]: hist[1]:hist[2]");
551
Govind Singha471e5e2015-10-12 17:11:14 +0530552 for (i = 0; i < entries; i++) {
553 if (i == WMI_WLAN_PROFILE_MAX_BIN_CNT)
554 break;
Nirav Shah93e789e2016-04-14 19:47:43 +0530555 snprintf(temp_str, sizeof(temp_str),
556 " %d : %d : %d : %d : %d : %d : %d : %d : %d",
Govind Singha471e5e2015-10-12 17:11:14 +0530557 profile_data[i].id,
558 profile_data[i].cnt,
559 profile_data[i].tot,
560 profile_data[i].min,
561 profile_data[i].max,
562 profile_data[i].hist_intvl,
563 profile_data[i].hist[0],
564 profile_data[i].hist[1],
565 profile_data[i].hist[2]);
Nirav Shah93e789e2016-04-14 19:47:43 +0530566 QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR,
567 "%s", temp_str);
Govind Singha471e5e2015-10-12 17:11:14 +0530568 }
569
570 return 0;
571}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800572
573#ifdef WLAN_FEATURE_LINK_LAYER_STATS
574
Zhang Qian73c348a2017-03-13 16:15:55 +0800575#define WMA_FILL_TX_STATS(eve, msg) do {\
576 (msg)->msdus = (eve)->tx_msdu_cnt;\
577 (msg)->mpdus = (eve)->tx_mpdu_cnt;\
578 (msg)->ppdus = (eve)->tx_ppdu_cnt;\
579 (msg)->bytes = (eve)->tx_bytes;\
580 (msg)->drops = (eve)->tx_msdu_drop_cnt;\
581 (msg)->drop_bytes = (eve)->tx_drop_bytes;\
582 (msg)->retries = (eve)->tx_mpdu_retry_cnt;\
583 (msg)->failed = (eve)->tx_mpdu_fail_cnt;\
584} while (0)
585
586#define WMA_FILL_RX_STATS(eve, msg) do {\
587 (msg)->mpdus = (eve)->mac_rx_mpdu_cnt;\
588 (msg)->bytes = (eve)->mac_rx_bytes;\
589 (msg)->ppdus = (eve)->phy_rx_ppdu_cnt;\
590 (msg)->ppdu_bytes = (eve)->phy_rx_bytes;\
591 (msg)->mpdu_retry = (eve)->rx_mpdu_retry_cnt;\
592 (msg)->mpdu_dup = (eve)->rx_mpdu_dup_cnt;\
593 (msg)->mpdu_discard = (eve)->rx_mpdu_discard_cnt;\
594} while (0)
595
596/**
597 * wma_get_ll_stats_ext_buf() - alloc result buffer for MAC counters
598 * @len: buffer length output
599 * @peer_num: peer number
600 * @fixed_param: fixed parameters in WMI event
601 *
602 * Structure of the stats message
603 * LL_EXT_STATS
604 * |
605 * |--Channel stats[1~n]
606 * |--Peer[1~n]
607 * |
608 * +---Signal
609 * +---TX
610 * | +---BE
611 * | +---BK
612 * | +---VI
613 * | +---VO
614 * |
615 * +---RX
616 * +---BE
617 * +---BK
618 * +---VI
619 * +---VO
620 * For each Access Category, the arregation and mcs
621 * stats are as this:
622 * TX
623 * +-BE/BK/VI/VO
624 * +----tx_mpdu_aggr_array
625 * +----tx_succ_mcs_array
626 * +----tx_fail_mcs_array
627 * +----tx_delay_array
628 * RX
629 * +-BE/BK/VI/VO
630 * +----rx_mpdu_aggr_array
631 * +----rx_mcs_array
632 *
633 * return: Address for result buffer.
634 */
635static tSirLLStatsResults *wma_get_ll_stats_ext_buf(uint32_t *len,
636 uint32_t peer_num,
637 wmi_report_stats_event_fixed_param *fixed_param)
638{
639 tSirLLStatsResults *buf;
640 uint32_t buf_len;
Vignesh Viswanathan9f090ad2017-09-27 20:33:55 +0530641 uint32_t total_array_len, total_peer_len;
642 bool excess_data = false;
Zhang Qian73c348a2017-03-13 16:15:55 +0800643
644 if (!len || !fixed_param) {
645 WMA_LOGE(FL("Invalid input parameters."));
646 return NULL;
647 }
648
649 /*
650 * Result buffer has a structure like this:
651 * ---------------------------------
652 * | trigger_cond_i |
653 * +-------------------------------+
654 * | cca_chgd_bitmap |
655 * +-------------------------------+
656 * | sig_chgd_bitmap |
657 * +-------------------------------+
658 * | tx_chgd_bitmap |
659 * +-------------------------------+
660 * | rx_chgd_bitmap |
661 * +-------------------------------+
662 * | peer_num |
663 * +-------------------------------+
664 * | channel_num |
665 * +-------------------------------+
666 * | tx_mpdu_aggr_array_len |
667 * +-------------------------------+
668 * | tx_succ_mcs_array_len |
669 * +-------------------------------+
670 * | tx_fail_mcs_array_len |
671 * +-------------------------------+
672 * | tx_delay_array_len |
673 * +-------------------------------+
674 * | rx_mpdu_aggr_array_len |
675 * +-------------------------------+
676 * | rx_mcs_array_len |
677 * +-------------------------------+
678 * | pointer to CCA stats |
679 * +-------------------------------+
680 * | CCA stats |
681 * +-------------------------------+
682 * | peer_stats |----+
683 * +-------------------------------+ |
684 * | TX aggr/mcs parameters array | |
685 * | Length of this buffer is | |
686 * | not fixed. |<-+ |
687 * +-------------------------------+ | |
688 * | per peer tx stats |--+ |
689 * | BE | <--+
690 * | BK | |
691 * | VI | |
692 * | VO | |
693 * +-------------------------------+ |
694 * | TX aggr/mcs parameters array | |
695 * | Length of this buffer is | |
696 * | not fixed. |<-+ |
697 * +-------------------------------+ | |
698 * | peer peer rx stats |--+ |
699 * | BE | <--+
700 * | BK |
701 * | VI |
702 * | VO |
703 * ---------------------------------
704 */
Vignesh Viswanathan9f090ad2017-09-27 20:33:55 +0530705
Zhang Qian73c348a2017-03-13 16:15:55 +0800706 buf_len = sizeof(tSirLLStatsResults) +
Vignesh Viswanathan9f090ad2017-09-27 20:33:55 +0530707 sizeof(struct sir_wifi_ll_ext_stats);
708 do {
709 if (fixed_param->num_chan_cca_stats > (WMI_SVC_MSG_MAX_SIZE /
710 sizeof(struct sir_wifi_chan_cca_stats))) {
711 excess_data = true;
712 break;
713 }
714 buf_len += (fixed_param->num_chan_cca_stats *
715 sizeof(struct sir_wifi_chan_cca_stats));
716 if (fixed_param->tx_mpdu_aggr_array_len >
717 WMI_SVC_MSG_MAX_SIZE) {
718 excess_data = true;
719 break;
720 } else {
721 total_array_len = fixed_param->tx_mpdu_aggr_array_len;
722 }
723 if (fixed_param->tx_succ_mcs_array_len >
724 (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
725 excess_data = true;
726 break;
727 } else {
728 total_array_len += fixed_param->tx_succ_mcs_array_len;
729 }
730 if (fixed_param->tx_fail_mcs_array_len >
731 (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
732 excess_data = true;
733 break;
734 } else {
735 total_array_len += fixed_param->tx_fail_mcs_array_len;
736 }
737 if (fixed_param->tx_ppdu_delay_array_len >
738 (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
739 excess_data = true;
740 break;
741 } else {
742 total_array_len += fixed_param->tx_ppdu_delay_array_len;
743 }
744 if (fixed_param->rx_mpdu_aggr_array_len >
745 (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
746 excess_data = true;
747 break;
748 } else {
749 total_array_len += fixed_param->rx_mpdu_aggr_array_len;
750 }
751 if (fixed_param->rx_mcs_array_len >
752 (WMI_SVC_MSG_MAX_SIZE - total_array_len)) {
753 excess_data = true;
754 break;
755 } else {
756 total_array_len += fixed_param->rx_mcs_array_len;
757 }
758
759 if (total_array_len > (WMI_SVC_MSG_MAX_SIZE /
760 (sizeof(uint32_t) * WLAN_MAX_AC))) {
761 excess_data = true;
762 break;
763 } else {
764 total_peer_len = (sizeof(uint32_t) * WLAN_MAX_AC *
765 total_array_len) +
766 (WLAN_MAX_AC *
767 (sizeof(struct sir_wifi_tx) +
768 sizeof(struct sir_wifi_rx)));
769 }
Vignesh Viswanathanca67e362017-10-04 23:42:00 +0530770 if (total_peer_len > WMI_SVC_MSG_MAX_SIZE) {
771 excess_data = true;
772 break;
773 }
774 if (peer_num > (WMI_SVC_MSG_MAX_SIZE - total_peer_len) /
775 sizeof(struct sir_wifi_ll_ext_peer_stats)) {
Vignesh Viswanathan9f090ad2017-09-27 20:33:55 +0530776 excess_data = true;
777 break;
778 } else {
779 buf_len += peer_num *
780 (sizeof(struct sir_wifi_ll_ext_peer_stats) +
781 total_peer_len);
782 }
783 } while (0);
784
785 if (excess_data || (buf_len > WMI_SVC_MSG_MAX_SIZE)) {
786 WMA_LOGE("%s: excess wmi buffer: peer %d cca %d tx_mpdu %d tx_succ%d tx_fail %d tx_ppdu %d rx_mpdu %d rx_mcs %d",
787 __func__, peer_num, fixed_param->num_chan_cca_stats,
788 fixed_param->tx_mpdu_aggr_array_len,
789 fixed_param->tx_succ_mcs_array_len,
790 fixed_param->tx_fail_mcs_array_len,
791 fixed_param->tx_ppdu_delay_array_len,
792 fixed_param->rx_mpdu_aggr_array_len,
793 fixed_param->rx_mcs_array_len);
Vignesh Viswanathan9f090ad2017-09-27 20:33:55 +0530794 return NULL;
795 }
Zhang Qian73c348a2017-03-13 16:15:55 +0800796
797 buf = (tSirLLStatsResults *)qdf_mem_malloc(buf_len);
798 if (buf == NULL) {
799 WMA_LOGE("%s: Cannot allocate link layer stats.", __func__);
800 buf_len = 0;
801 return NULL;
802 }
803
804 *len = buf_len;
805 return buf;
806}
807
808/**
809 * wma_fill_tx_stats() - Fix TX stats into result buffer
810 * @ll_stats: LL stats buffer
811 * @fix_param: parameters with fixed length in WMI event
812 * @param_buf: parameters without fixed length in WMI event
813 * @buf: buffer for TLV parameters
814 *
815 * Return: None
816 */
817static void wma_fill_tx_stats(struct sir_wifi_ll_ext_stats *ll_stats,
818 wmi_report_stats_event_fixed_param *fix_param,
819 WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf,
820 uint8_t **buf, uint32_t *buf_length)
821{
822 uint8_t *result;
823 uint32_t i, j, k;
824 wmi_peer_ac_tx_stats *wmi_peer_tx;
825 wmi_tx_stats *wmi_tx;
826 struct sir_wifi_tx *tx_stats;
827 struct sir_wifi_ll_ext_peer_stats *peer_stats;
828 uint32_t *tx_mpdu_aggr, *tx_succ_mcs, *tx_fail_mcs, *tx_delay;
829 uint32_t len, dst_len, tx_mpdu_aggr_array_len, tx_succ_mcs_array_len,
830 tx_fail_mcs_array_len, tx_delay_array_len;
831
832 result = *buf;
833 dst_len = *buf_length;
834 tx_mpdu_aggr_array_len = fix_param->tx_mpdu_aggr_array_len;
835 ll_stats->tx_mpdu_aggr_array_len = tx_mpdu_aggr_array_len;
836 tx_succ_mcs_array_len = fix_param->tx_succ_mcs_array_len;
837 ll_stats->tx_succ_mcs_array_len = tx_succ_mcs_array_len;
838 tx_fail_mcs_array_len = fix_param->tx_fail_mcs_array_len;
839 ll_stats->tx_fail_mcs_array_len = tx_fail_mcs_array_len;
840 tx_delay_array_len = fix_param->tx_ppdu_delay_array_len;
841 ll_stats->tx_delay_array_len = tx_delay_array_len;
842 wmi_peer_tx = param_buf->peer_ac_tx_stats;
843 wmi_tx = param_buf->tx_stats;
844
845 len = fix_param->num_peer_ac_tx_stats *
846 WLAN_MAX_AC * tx_mpdu_aggr_array_len * sizeof(uint32_t);
847 if (len <= dst_len) {
848 tx_mpdu_aggr = (uint32_t *)result;
849 qdf_mem_copy(tx_mpdu_aggr, param_buf->tx_mpdu_aggr, len);
850 result += len;
851 dst_len -= len;
852 } else {
853 WMA_LOGE(FL("TX_MPDU_AGGR buffer length is wrong."));
854 tx_mpdu_aggr = NULL;
855 }
856
857 len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC *
858 tx_succ_mcs_array_len * sizeof(uint32_t);
859 if (len <= dst_len) {
860 tx_succ_mcs = (uint32_t *)result;
861 qdf_mem_copy(tx_succ_mcs, param_buf->tx_succ_mcs, len);
862 result += len;
863 dst_len -= len;
864 } else {
865 WMA_LOGE(FL("TX_SUCC_MCS buffer length is wrong."));
866 tx_succ_mcs = NULL;
867 }
868
869 len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC *
870 tx_fail_mcs_array_len * sizeof(uint32_t);
871 if (len <= dst_len) {
872 tx_fail_mcs = (uint32_t *)result;
873 qdf_mem_copy(tx_fail_mcs, param_buf->tx_fail_mcs, len);
874 result += len;
875 dst_len -= len;
876 } else {
877 WMA_LOGE(FL("TX_FAIL_MCS buffer length is wrong."));
878 tx_fail_mcs = NULL;
879 }
880
881 len = fix_param->num_peer_ac_tx_stats *
882 WLAN_MAX_AC * tx_delay_array_len * sizeof(uint32_t);
883 if (len <= dst_len) {
884 tx_delay = (uint32_t *)result;
885 qdf_mem_copy(tx_delay, param_buf->tx_ppdu_delay, len);
886 result += len;
887 dst_len -= len;
888 } else {
889 WMA_LOGE(FL("TX_DELAY buffer length is wrong."));
890 tx_delay = NULL;
891 }
892
893 /* per peer tx stats */
894 peer_stats = ll_stats->peer_stats;
895
896 for (i = 0; i < fix_param->num_peer_ac_tx_stats; i++) {
897 uint32_t peer_id = wmi_peer_tx[i].peer_id;
898 struct sir_wifi_tx *ac;
899 wmi_tx_stats *wmi_tx_stats;
900
901 for (j = 0; j < ll_stats->peer_num; j++) {
902 peer_stats += j;
903 if (peer_stats->peer_id == WIFI_INVALID_PEER_ID ||
904 peer_stats->peer_id == peer_id)
905 break;
906 }
907
908 if (j < ll_stats->peer_num) {
909 peer_stats->peer_id = wmi_peer_tx[i].peer_id;
910 peer_stats->vdev_id = wmi_peer_tx[i].vdev_id;
911 tx_stats = (struct sir_wifi_tx *)result;
912 for (k = 0; k < WLAN_MAX_AC; k++) {
913 wmi_tx_stats = &wmi_tx[i * WLAN_MAX_AC + k];
914 ac = &tx_stats[k];
915 WMA_FILL_TX_STATS(wmi_tx_stats, ac);
916 ac->mpdu_aggr_size = tx_mpdu_aggr;
917 ac->aggr_len = tx_mpdu_aggr_array_len *
918 sizeof(uint32_t);
919 ac->success_mcs_len = tx_succ_mcs_array_len *
920 sizeof(uint32_t);
921 ac->success_mcs = tx_succ_mcs;
922 ac->fail_mcs = tx_fail_mcs;
923 ac->fail_mcs_len = tx_fail_mcs_array_len *
924 sizeof(uint32_t);
925 ac->delay = tx_delay;
926 ac->delay_len = tx_delay_array_len *
927 sizeof(uint32_t);
928 peer_stats->ac_stats[k].tx_stats = ac;
929 peer_stats->ac_stats[k].type = k;
930 tx_mpdu_aggr += tx_mpdu_aggr_array_len;
931 tx_succ_mcs += tx_succ_mcs_array_len;
932 tx_fail_mcs += tx_fail_mcs_array_len;
933 tx_delay += tx_delay_array_len;
934 }
935 result += WLAN_MAX_AC * sizeof(struct sir_wifi_tx);
936 } else {
937 /*
938 * Buffer for Peer TX counter overflow.
939 * There is peer ID mismatch between TX, RX,
940 * signal counters.
941 */
942 WMA_LOGE(FL("One peer TX info is dropped."));
943
944 tx_mpdu_aggr += tx_mpdu_aggr_array_len * WLAN_MAX_AC;
945 tx_succ_mcs += tx_succ_mcs_array_len * WLAN_MAX_AC;
946 tx_fail_mcs += tx_fail_mcs_array_len * WLAN_MAX_AC;
947 tx_delay += tx_delay_array_len * WLAN_MAX_AC;
948 }
949 }
950 *buf = result;
951 *buf_length = dst_len;
952}
953
954/**
955 * wma_fill_rx_stats() - Fix RX stats into result buffer
956 * @ll_stats: LL stats buffer
957 * @fix_param: parameters with fixed length in WMI event
958 * @param_buf: parameters without fixed length in WMI event
959 * @buf: buffer for TLV parameters
960 *
961 * Return: None
962 */
963static void wma_fill_rx_stats(struct sir_wifi_ll_ext_stats *ll_stats,
964 wmi_report_stats_event_fixed_param *fix_param,
965 WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf,
966 uint8_t **buf, uint32_t *buf_length)
967{
968 uint8_t *result;
969 uint32_t i, j, k;
970 uint32_t *rx_mpdu_aggr, *rx_mcs;
971 wmi_rx_stats *wmi_rx;
972 wmi_peer_ac_rx_stats *wmi_peer_rx;
973 struct sir_wifi_rx *rx_stats;
974 struct sir_wifi_ll_ext_peer_stats *peer_stats;
975 uint32_t len, dst_len, rx_mpdu_aggr_array_len, rx_mcs_array_len;
976
977 rx_mpdu_aggr_array_len = fix_param->rx_mpdu_aggr_array_len;
978 ll_stats->rx_mpdu_aggr_array_len = rx_mpdu_aggr_array_len;
979 rx_mcs_array_len = fix_param->rx_mcs_array_len;
980 ll_stats->rx_mcs_array_len = rx_mcs_array_len;
981 wmi_peer_rx = param_buf->peer_ac_rx_stats;
982 wmi_rx = param_buf->rx_stats;
983
984 result = *buf;
985 dst_len = *buf_length;
986 len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats *
987 WLAN_MAX_AC * rx_mpdu_aggr_array_len);
988 if (len <= dst_len) {
989 rx_mpdu_aggr = (uint32_t *)result;
990 qdf_mem_copy(rx_mpdu_aggr, param_buf->rx_mpdu_aggr, len);
991 result += len;
992 dst_len -= len;
993 } else {
994 WMA_LOGE(FL("RX_MPDU_AGGR array length is wrong."));
995 rx_mpdu_aggr = NULL;
996 }
997
998 len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats *
999 WLAN_MAX_AC * rx_mcs_array_len);
1000 if (len <= dst_len) {
1001 rx_mcs = (uint32_t *)result;
1002 qdf_mem_copy(rx_mcs, param_buf->rx_mcs, len);
1003 result += len;
1004 dst_len -= len;
1005 } else {
1006 WMA_LOGE(FL("RX_MCS array length is wrong."));
1007 rx_mcs = NULL;
1008 }
1009
1010 /* per peer rx stats */
1011 peer_stats = ll_stats->peer_stats;
1012 for (i = 0; i < fix_param->num_peer_ac_rx_stats; i++) {
1013 uint32_t peer_id = wmi_peer_rx[i].peer_id;
1014 struct sir_wifi_rx *ac;
1015 wmi_rx_stats *wmi_rx_stats;
1016
1017 for (j = 0; j < ll_stats->peer_num; j++) {
1018 peer_stats += j;
1019 if ((peer_stats->peer_id == WIFI_INVALID_PEER_ID) ||
1020 (peer_stats->peer_id == peer_id))
1021 break;
1022 }
1023
1024 if (j < ll_stats->peer_num) {
1025 peer_stats->peer_id = wmi_peer_rx[i].peer_id;
1026 peer_stats->vdev_id = wmi_peer_rx[i].vdev_id;
1027 peer_stats->sta_ps_inds = wmi_peer_rx[i].sta_ps_inds;
1028 peer_stats->sta_ps_durs = wmi_peer_rx[i].sta_ps_durs;
1029 peer_stats->rx_probe_reqs =
1030 wmi_peer_rx[i].rx_probe_reqs;
1031 peer_stats->rx_oth_mgmts = wmi_peer_rx[i].rx_oth_mgmts;
1032 rx_stats = (struct sir_wifi_rx *)result;
1033
1034 for (k = 0; k < WLAN_MAX_AC; k++) {
1035 wmi_rx_stats = &wmi_rx[i * WLAN_MAX_AC + k];
1036 ac = &rx_stats[k];
1037 WMA_FILL_RX_STATS(wmi_rx_stats, ac);
1038 ac->mpdu_aggr = rx_mpdu_aggr;
1039 ac->aggr_len = rx_mpdu_aggr_array_len *
1040 sizeof(uint32_t);
1041 ac->mcs = rx_mcs;
1042 ac->mcs_len = rx_mcs_array_len *
1043 sizeof(uint32_t);
1044 peer_stats->ac_stats[k].rx_stats = ac;
1045 peer_stats->ac_stats[k].type = k;
1046 rx_mpdu_aggr += rx_mpdu_aggr_array_len;
1047 rx_mcs += rx_mcs_array_len;
1048 }
1049 result += WLAN_MAX_AC * sizeof(struct sir_wifi_rx);
1050 } else {
1051 /*
1052 * Buffer for Peer RX counter overflow.
1053 * There is peer ID mismatch between TX, RX,
1054 * signal counters.
1055 */
1056 WMA_LOGE(FL("One peer RX info is dropped."));
1057 rx_mpdu_aggr += rx_mpdu_aggr_array_len * WLAN_MAX_AC;
1058 rx_mcs += rx_mcs_array_len * WLAN_MAX_AC;
1059 }
1060 }
1061 *buf = result;
1062 *buf_length = dst_len;
1063}
1064
1065/**
1066 * wma_ll_stats_evt_handler() - handler for MAC layer counters.
1067 * @handle - wma handle
1068 * @event - FW event
1069 * @len - length of FW event
1070 *
1071 * return: 0 success.
1072 */
1073static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
1074 u_int32_t len)
1075{
1076 WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf;
1077 wmi_report_stats_event_fixed_param *fixed_param;
1078 tSirLLStatsResults *link_stats_results;
1079 wmi_chan_cca_stats *wmi_cca_stats;
1080 wmi_peer_signal_stats *wmi_peer_signal;
1081 wmi_peer_ac_rx_stats *wmi_peer_rx;
1082 struct sir_wifi_ll_ext_stats *ll_stats;
1083 struct sir_wifi_ll_ext_peer_stats *peer_stats;
1084 struct sir_wifi_chan_cca_stats *cca_stats;
1085 struct sir_wifi_peer_signal_stats *peer_signal;
1086 uint8_t *result;
1087 uint32_t i, peer_num, result_size, dst_len;
1088 tpAniSirGlobal mac;
1089 struct scheduler_msg sme_msg = { 0 };
1090 QDF_STATUS qdf_status;
1091
1092 mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE);
1093 if (!mac) {
1094 WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1095 return -EINVAL;
1096 }
1097
1098 if (!mac->sme.link_layer_stats_ext_cb) {
1099 WMA_LOGD("%s: HDD callback is null", __func__);
1100 return -EINVAL;
1101 }
1102
1103 WMA_LOGD("%s: Posting MAC counters event to HDD", __func__);
1104
1105 param_buf = (WMI_REPORT_STATS_EVENTID_param_tlvs *)event;
1106 fixed_param = param_buf->fixed_param;
1107 wmi_cca_stats = param_buf->chan_cca_stats;
1108 wmi_peer_signal = param_buf->peer_signal_stats;
1109 wmi_peer_rx = param_buf->peer_ac_rx_stats;
1110
1111 /* Get the MAX of three peer numbers */
1112 peer_num = fixed_param->num_peer_signal_stats >
1113 fixed_param->num_peer_ac_tx_stats ?
1114 fixed_param->num_peer_signal_stats :
1115 fixed_param->num_peer_ac_tx_stats;
1116 peer_num = peer_num > fixed_param->num_peer_ac_rx_stats ?
1117 peer_num : fixed_param->num_peer_ac_rx_stats;
1118
1119 if (peer_num == 0)
1120 return -EINVAL;
1121
1122 link_stats_results = wma_get_ll_stats_ext_buf(&result_size,
1123 peer_num,
1124 fixed_param);
1125 if (!link_stats_results) {
1126 WMA_LOGE("%s: Fail to allocate stats buffer", __func__);
1127 return -EINVAL;
1128 }
1129 link_stats_results->paramId = WMI_LL_STATS_EXT_MAC_COUNTER;
1130 link_stats_results->num_peers = peer_num;
1131 link_stats_results->peer_event_number = 1;
1132 link_stats_results->moreResultToFollow = 0;
1133
1134 ll_stats = (struct sir_wifi_ll_ext_stats *)link_stats_results->results;
1135 ll_stats->trigger_cond_id = fixed_param->trigger_cond_id;
1136 ll_stats->cca_chgd_bitmap = fixed_param->cca_chgd_bitmap;
1137 ll_stats->sig_chgd_bitmap = fixed_param->sig_chgd_bitmap;
1138 ll_stats->tx_chgd_bitmap = fixed_param->tx_chgd_bitmap;
1139 ll_stats->rx_chgd_bitmap = fixed_param->rx_chgd_bitmap;
1140 ll_stats->channel_num = fixed_param->num_chan_cca_stats;
1141 ll_stats->peer_num = peer_num;
1142
1143 result = (uint8_t *)ll_stats->stats;
1144 peer_stats = (struct sir_wifi_ll_ext_peer_stats *)result;
1145 ll_stats->peer_stats = peer_stats;
1146
1147 for (i = 0; i < peer_num; i++) {
1148 peer_stats[i].peer_id = WIFI_INVALID_PEER_ID;
1149 peer_stats[i].vdev_id = WIFI_INVALID_VDEV_ID;
1150 }
1151
1152 /* Per peer signal */
1153 result_size -= sizeof(struct sir_wifi_ll_ext_stats);
1154 dst_len = sizeof(struct sir_wifi_peer_signal_stats);
1155 for (i = 0; i < fixed_param->num_peer_signal_stats; i++) {
1156 peer_stats[i].peer_id = wmi_peer_signal->peer_id;
1157 peer_stats[i].vdev_id = wmi_peer_signal->vdev_id;
1158 peer_signal = &peer_stats[i].peer_signal_stats;
1159
Zhang Qian303ebe92017-05-18 13:59:07 +08001160 WMA_LOGD("%d antennas for peer %d",
1161 wmi_peer_signal->num_chains_valid,
1162 wmi_peer_signal->peer_id);
Zhang Qian73c348a2017-03-13 16:15:55 +08001163 if (dst_len <= result_size) {
Zhang Qian303ebe92017-05-18 13:59:07 +08001164 peer_signal->vdev_id = wmi_peer_signal->vdev_id;
1165 peer_signal->peer_id = wmi_peer_signal->peer_id;
1166 peer_signal->num_chain =
1167 wmi_peer_signal->num_chains_valid;
1168 qdf_mem_copy(peer_signal->per_ant_snr,
1169 wmi_peer_signal->per_chain_snr,
1170 sizeof(peer_signal->per_ant_snr));
1171 qdf_mem_copy(peer_signal->nf,
1172 wmi_peer_signal->per_chain_nf,
1173 sizeof(peer_signal->nf));
1174 qdf_mem_copy(peer_signal->per_ant_rx_mpdus,
1175 wmi_peer_signal->per_antenna_rx_mpdus,
1176 sizeof(peer_signal->per_ant_rx_mpdus));
1177 qdf_mem_copy(peer_signal->per_ant_tx_mpdus,
1178 wmi_peer_signal->per_antenna_tx_mpdus,
1179 sizeof(peer_signal->per_ant_tx_mpdus));
Zhang Qian73c348a2017-03-13 16:15:55 +08001180 result_size -= dst_len;
1181 } else {
1182 WMA_LOGE(FL("Invalid length of PEER signal."));
1183 }
1184 wmi_peer_signal++;
1185 }
1186
1187 result += peer_num * sizeof(struct sir_wifi_ll_ext_peer_stats);
1188 cca_stats = (struct sir_wifi_chan_cca_stats *)result;
1189 ll_stats->cca = cca_stats;
1190 dst_len = sizeof(struct sir_wifi_chan_cca_stats);
1191 for (i = 0; i < ll_stats->channel_num; i++) {
1192 if (dst_len <= result_size) {
1193 qdf_mem_copy(&cca_stats[i], &wmi_cca_stats->vdev_id,
1194 dst_len);
1195 result_size -= dst_len;
1196 } else {
1197 WMA_LOGE(FL("Invalid length of CCA."));
1198 }
1199 }
1200
1201 result += i * sizeof(struct sir_wifi_chan_cca_stats);
1202 wma_fill_tx_stats(ll_stats, fixed_param, param_buf,
1203 &result, &result_size);
1204 wma_fill_rx_stats(ll_stats, fixed_param, param_buf,
1205 &result, &result_size);
1206 sme_msg.type = eWMI_SME_LL_STATS_IND;
1207 sme_msg.bodyptr = (void *)link_stats_results;
1208 sme_msg.bodyval = 0;
1209 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
1210 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1211 WMA_LOGP(FL("Failed to post peer stat change msg!"));
1212 qdf_mem_free(link_stats_results);
1213 return -EINVAL;
1214 }
1215
1216 return 0;
1217}
1218
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001219/**
1220 * wma_unified_link_peer_stats_event_handler() - peer stats event handler
1221 * @handle: wma handle
1222 * @cmd_param_info: data received with event from fw
1223 * @len: length of data
1224 *
1225 * Return: 0 for success or error code
1226 */
1227static int wma_unified_link_peer_stats_event_handler(void *handle,
1228 uint8_t *cmd_param_info,
1229 uint32_t len)
1230{
1231 WMI_PEER_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
1232 wmi_peer_stats_event_fixed_param *fixed_param;
1233 wmi_peer_link_stats *peer_stats, *temp_peer_stats;
1234 wmi_rate_stats *rate_stats;
1235 tSirLLStatsResults *link_stats_results;
1236 uint8_t *results, *t_peer_stats, *t_rate_stats;
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301237 uint32_t count, rate_cnt;
1238 uint32_t total_num_rates = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001239 uint32_t next_res_offset, next_peer_offset, next_rate_offset;
1240 size_t peer_info_size, peer_stats_size, rate_stats_size;
1241 size_t link_stats_results_size;
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001242 bool excess_data = false;
1243 uint32_t buf_len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001244
Anurag Chouhan6d760662016-02-20 16:05:43 +05301245 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001246
1247 if (!pMac) {
1248 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
1249 return -EINVAL;
1250 }
1251
1252 if (!pMac->sme.pLinkLayerStatsIndCallback) {
1253 WMA_LOGD("%s: HDD callback is null", __func__);
1254 return -EINVAL;
1255 }
1256
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257 param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
1258 if (!param_tlvs) {
1259 WMA_LOGA("%s: Invalid stats event", __func__);
1260 return -EINVAL;
1261 }
1262 /*
1263 * cmd_param_info contains
1264 * wmi_peer_stats_event_fixed_param fixed_param;
1265 * num_peers * size of(struct wmi_peer_link_stats)
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301266 * total_num_rates * size of(struct wmi_rate_stats)
1267 * total_num_rates is the sum of the rates of all the peers.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001268 */
1269 fixed_param = param_tlvs->fixed_param;
1270 peer_stats = param_tlvs->peer_stats;
1271 rate_stats = param_tlvs->peer_rate_stats;
1272
1273 if (!fixed_param || !peer_stats ||
1274 (peer_stats->num_rates && !rate_stats)) {
1275 WMA_LOGA("%s: Invalid param_tlvs for Peer Stats", __func__);
1276 return -EINVAL;
1277 }
1278
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001279 do {
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001280 if (fixed_param->num_peers >
1281 WMI_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats)) {
1282 excess_data = true;
1283 break;
1284 } else {
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301285 buf_len = fixed_param->num_peers *
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001286 sizeof(wmi_peer_link_stats);
1287 }
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301288 temp_peer_stats = (wmi_peer_link_stats *) peer_stats;
1289 for (count = 0; count < fixed_param->num_peers; count++) {
1290 if (temp_peer_stats->num_rates >
1291 WMI_SVC_MSG_MAX_SIZE / sizeof(wmi_rate_stats)) {
1292 excess_data = true;
1293 break;
1294 } else {
1295 total_num_rates += temp_peer_stats->num_rates;
1296 if (total_num_rates >
1297 WMI_SVC_MSG_MAX_SIZE /
1298 sizeof(wmi_rate_stats)) {
1299 excess_data = true;
1300 break;
1301 }
1302 buf_len += temp_peer_stats->num_rates *
1303 sizeof(wmi_rate_stats);
1304 }
1305 temp_peer_stats++;
1306 }
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001307 } while (0);
1308
1309 if (excess_data ||
1310 (sizeof(*fixed_param) > WMI_SVC_MSG_MAX_SIZE - buf_len)) {
1311 WMA_LOGE("excess wmi buffer: rates:%d, peers:%d",
1312 peer_stats->num_rates, fixed_param->num_peers);
1313 QDF_ASSERT(0);
1314 return -EINVAL;
1315 }
1316
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001317 peer_stats_size = sizeof(tSirWifiPeerStat);
1318 peer_info_size = sizeof(tSirWifiPeerInfo);
1319 rate_stats_size = sizeof(tSirWifiRateStat);
1320 link_stats_results_size =
1321 sizeof(*link_stats_results) + peer_stats_size +
1322 (fixed_param->num_peers * peer_info_size) +
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301323 (total_num_rates * rate_stats_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001324
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301325 link_stats_results = qdf_mem_malloc(link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001326 if (NULL == link_stats_results) {
1327 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
1328 __func__, link_stats_results_size);
1329 return -ENOMEM;
1330 }
1331
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301332 qdf_mem_zero(link_stats_results, link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001333
1334 link_stats_results->paramId = WMI_LINK_STATS_ALL_PEER;
1335 link_stats_results->rspId = fixed_param->request_id;
1336 link_stats_results->ifaceId = 0;
1337 link_stats_results->num_peers = fixed_param->num_peers;
1338 link_stats_results->peer_event_number = fixed_param->peer_event_number;
1339 link_stats_results->moreResultToFollow = fixed_param->more_data;
1340
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301341 qdf_mem_copy(link_stats_results->results,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001342 &fixed_param->num_peers, peer_stats_size);
1343
1344 results = (uint8_t *) link_stats_results->results;
1345 t_peer_stats = (uint8_t *) peer_stats;
1346 t_rate_stats = (uint8_t *) rate_stats;
1347 next_res_offset = peer_stats_size;
1348 next_peer_offset = WMI_TLV_HDR_SIZE;
1349 next_rate_offset = WMI_TLV_HDR_SIZE;
Kondabattini, Ganesh32be0832016-08-09 15:19:50 +05301350 for (rate_cnt = 0; rate_cnt < fixed_param->num_peers; rate_cnt++) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301351 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001352 t_peer_stats + next_peer_offset, peer_info_size);
1353 next_res_offset += peer_info_size;
1354
1355 /* Copy rate stats associated with this peer */
1356 for (count = 0; count < peer_stats->num_rates; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001357 rate_stats++;
1358
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301359 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001360 t_rate_stats + next_rate_offset,
1361 rate_stats_size);
1362 next_res_offset += rate_stats_size;
1363 next_rate_offset += sizeof(*rate_stats);
1364 }
1365 next_peer_offset += sizeof(*peer_stats);
1366 peer_stats++;
1367 }
1368
1369 /* call hdd callback with Link Layer Statistics
1370 * vdev_id/ifacId in link_stats_results will be
1371 * used to retrieve the correct HDD context
1372 */
1373 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
1374 WMA_LINK_LAYER_STATS_RESULTS_RSP,
1375 link_stats_results);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301376 qdf_mem_free(link_stats_results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377
1378 return 0;
1379}
1380
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001381/**
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001382 * wma_unified_radio_tx_mem_free() - Free radio tx power stats memory
1383 * @handle: WMI handle
1384 *
1385 * Return: 0 on success, error number otherwise.
1386 */
yeshwanth sriram guntuka584c2332017-07-29 12:50:25 +05301387int wma_unified_radio_tx_mem_free(void *handle)
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001388{
1389 tp_wma_handle wma_handle = (tp_wma_handle) handle;
1390 tSirWifiRadioStat *rs_results;
1391 uint32_t i = 0;
1392
1393 if (!wma_handle->link_stats_results)
1394 return 0;
1395
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001396 rs_results = (tSirWifiRadioStat *)
1397 &wma_handle->link_stats_results->results[0];
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001398 for (i = 0; i < wma_handle->link_stats_results->num_radio; i++) {
1399 rs_results += i;
1400 if (rs_results->tx_time_per_power_level) {
1401 qdf_mem_free(rs_results->tx_time_per_power_level);
1402 rs_results->tx_time_per_power_level = NULL;
1403 }
1404
1405 if (rs_results->channels) {
1406 qdf_mem_free(rs_results->channels);
1407 rs_results->channels = NULL;
1408 }
1409 }
1410
1411 qdf_mem_free(wma_handle->link_stats_results);
1412 wma_handle->link_stats_results = NULL;
1413
1414 return 0;
1415}
1416
1417/**
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001418 * wma_unified_radio_tx_power_level_stats_event_handler() - tx power level stats
1419 * @handle: WMI handle
1420 * @cmd_param_info: command param info
1421 * @len: Length of @cmd_param_info
1422 *
1423 * This is the WMI event handler function to receive radio stats tx
1424 * power level stats.
1425 *
1426 * Return: 0 on success, error number otherwise.
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001427 */
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001428static int wma_unified_radio_tx_power_level_stats_event_handler(void *handle,
1429 u_int8_t *cmd_param_info, u_int32_t len)
1430{
1431 tp_wma_handle wma_handle = (tp_wma_handle) handle;
1432 WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *param_tlvs;
1433 wmi_tx_power_level_stats_evt_fixed_param *fixed_param;
1434 uint8_t *tx_power_level_values;
1435 tSirLLStatsResults *link_stats_results;
1436 tSirWifiRadioStat *rs_results;
1437
1438 tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE);
1439
1440 if (!mac) {
1441 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
1442 return -EINVAL;
1443 }
1444
1445 if (!mac->sme.pLinkLayerStatsIndCallback) {
1446 WMA_LOGD("%s: HDD callback is null", __func__);
1447 return -EINVAL;
1448 }
1449
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001450 param_tlvs = (WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *)
1451 cmd_param_info;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001452 if (!param_tlvs) {
1453 WMA_LOGA("%s: Invalid tx power level stats event", __func__);
1454 return -EINVAL;
1455 }
1456
1457 fixed_param = param_tlvs->fixed_param;
1458 if (!fixed_param) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001459 WMA_LOGA("%s:Invalid param_tlvs for Radio tx_power level Stats",
1460 __func__);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001461 return -EINVAL;
1462 }
1463
1464 link_stats_results = wma_handle->link_stats_results;
Srinivas Girigowda52cbce42016-10-25 14:11:58 -07001465 if (!link_stats_results) {
1466 WMA_LOGA("%s: link_stats_results is NULL", __func__);
1467 return -EINVAL;
1468 }
1469
Wu Gao478282a2017-09-19 15:45:29 +08001470 if (fixed_param->radio_id >= link_stats_results->num_radio) {
1471 WMA_LOGE("%s, invalid radio id:%d, num radio:%d",
1472 __func__, fixed_param->radio_id,
1473 link_stats_results->num_radio);
1474 return -EINVAL;
1475 }
1476
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001477 WMA_LOGD("%s: tot_num_tx_pwr_lvls: %u num_tx_pwr_lvls: %u pwr_lvl_offset: %u radio_id: %u",
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001478 __func__, fixed_param->total_num_tx_power_levels,
1479 fixed_param->num_tx_power_levels,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001480 fixed_param->power_level_offset,
1481 fixed_param->radio_id);
1482
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001483 if (fixed_param->num_tx_power_levels > ((WMI_SVC_MSG_MAX_SIZE -
1484 sizeof(*fixed_param)) / sizeof(uint32_t))) {
1485 WMA_LOGE("%s: excess tx_power buffers:%d", __func__,
1486 fixed_param->num_tx_power_levels);
1487 QDF_ASSERT(0);
1488 return -EINVAL;
1489 }
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001490 rs_results = (tSirWifiRadioStat *) &link_stats_results->results[0] +
1491 fixed_param->radio_id;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001492 tx_power_level_values = (uint8_t *) param_tlvs->tx_time_per_power_level;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001493
1494 rs_results->total_num_tx_power_levels =
1495 fixed_param->total_num_tx_power_levels;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001496 if (!rs_results->total_num_tx_power_levels) {
1497 link_stats_results->nr_received++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001498 goto post_stats;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001499 }
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001500
1501 if (!rs_results->tx_time_per_power_level) {
1502 rs_results->tx_time_per_power_level = qdf_mem_malloc(
1503 sizeof(uint32_t) *
1504 rs_results->total_num_tx_power_levels);
1505 if (!rs_results->tx_time_per_power_level) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001506 WMA_LOGA("%s: Mem alloc fail for tx power level stats",
1507 __func__);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001508 /* In error case, atleast send the radio stats without
1509 * tx_power_level stats */
1510 rs_results->total_num_tx_power_levels = 0;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001511 link_stats_results->nr_received++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001512 goto post_stats;
1513 }
1514 }
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001515 qdf_mem_copy(&rs_results->tx_time_per_power_level[
1516 fixed_param->power_level_offset],
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001517 tx_power_level_values,
1518 sizeof(uint32_t) * fixed_param->num_tx_power_levels);
1519 if (rs_results->total_num_tx_power_levels ==
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001520 (fixed_param->num_tx_power_levels +
1521 fixed_param->power_level_offset)) {
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001522 link_stats_results->moreResultToFollow = 0;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001523 link_stats_results->nr_received++;
1524 }
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001525
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001526 WMA_LOGD("%s: moreResultToFollow: %u nr: %u nr_received: %u",
1527 __func__, link_stats_results->moreResultToFollow,
1528 link_stats_results->num_radio,
1529 link_stats_results->nr_received);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001530
1531 /* If still data to receive, return from here */
1532 if (link_stats_results->moreResultToFollow)
1533 return 0;
1534
1535post_stats:
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001536 if (link_stats_results->num_radio != link_stats_results->nr_received) {
1537 /* Not received all radio stats yet, don't post yet */
1538 return 0;
1539 }
1540
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001541 /* call hdd callback with Link Layer Statistics
1542 * vdev_id/ifacId in link_stats_results will be
1543 * used to retrieve the correct HDD context
1544 */
1545 mac->sme.pLinkLayerStatsIndCallback(mac->hHdd,
1546 WMA_LINK_LAYER_STATS_RESULTS_RSP,
1547 link_stats_results);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001548 wma_unified_radio_tx_mem_free(handle);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001549
1550 return 0;
1551}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001552
1553/**
1554 * wma_unified_link_radio_stats_event_handler() - radio link stats event handler
1555 * @handle: wma handle
1556 * @cmd_param_info: data received with event from fw
1557 * @len: length of data
1558 *
1559 * Return: 0 for success or error code
1560 */
1561static int wma_unified_link_radio_stats_event_handler(void *handle,
1562 uint8_t *cmd_param_info,
1563 uint32_t len)
1564{
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001565 tp_wma_handle wma_handle = (tp_wma_handle) handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001566 WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
1567 wmi_radio_link_stats_event_fixed_param *fixed_param;
1568 wmi_radio_link_stats *radio_stats;
1569 wmi_channel_stats *channel_stats;
1570 tSirLLStatsResults *link_stats_results;
1571 uint8_t *results, *t_radio_stats, *t_channel_stats;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001572 uint32_t next_chan_offset, count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001573 size_t radio_stats_size, chan_stats_size;
1574 size_t link_stats_results_size;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001575 tSirWifiRadioStat *rs_results;
1576 tSirWifiChannelStats *chn_results;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001577
Anurag Chouhan6d760662016-02-20 16:05:43 +05301578 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001579
1580 if (!pMac) {
1581 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
1582 return -EINVAL;
1583 }
1584
1585 if (!pMac->sme.pLinkLayerStatsIndCallback) {
1586 WMA_LOGD("%s: HDD callback is null", __func__);
1587 return -EINVAL;
1588 }
1589
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001590 param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
1591 if (!param_tlvs) {
1592 WMA_LOGA("%s: Invalid stats event", __func__);
1593 return -EINVAL;
1594 }
1595
1596 /*
1597 * cmd_param_info contains
1598 * wmi_radio_link_stats_event_fixed_param fixed_param;
1599 * size of(struct wmi_radio_link_stats);
1600 * num_channels * size of(struct wmi_channel_stats)
1601 */
1602 fixed_param = param_tlvs->fixed_param;
1603 radio_stats = param_tlvs->radio_stats;
1604 channel_stats = param_tlvs->channel_stats;
1605
1606 if (!fixed_param || !radio_stats ||
1607 (radio_stats->num_channels && !channel_stats)) {
1608 WMA_LOGA("%s: Invalid param_tlvs for Radio Stats", __func__);
1609 return -EINVAL;
1610 }
Varun Reddy Yeturuc3139102017-09-27 20:38:39 -07001611 if (radio_stats->num_channels >
1612 (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS)) {
1613 WMA_LOGE("%s: Too many channels %d",
1614 __func__, radio_stats->num_channels);
1615 return -EINVAL;
1616 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001617
1618 radio_stats_size = sizeof(tSirWifiRadioStat);
1619 chan_stats_size = sizeof(tSirWifiChannelStats);
Varun Reddy Yeturuc3139102017-09-27 20:38:39 -07001620 if (fixed_param->num_radio >
1621 (UINT_MAX - sizeof(*link_stats_results))/radio_stats_size) {
1622 WMA_LOGE("excess num_radio %d is leading to int overflow",
1623 fixed_param->num_radio);
1624 return -EINVAL;
1625 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626 link_stats_results_size = sizeof(*link_stats_results) +
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001627 fixed_param->num_radio * radio_stats_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001629 if (!wma_handle->link_stats_results) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001630 wma_handle->link_stats_results = qdf_mem_malloc(
1631 link_stats_results_size);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001632 if (NULL == wma_handle->link_stats_results) {
1633 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
1634 __func__, link_stats_results_size);
1635 return -ENOMEM;
1636 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001637 }
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001638 link_stats_results = wma_handle->link_stats_results;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001639
Paul Zhang05af1f62017-10-10 15:11:06 +08001640 if (radio_stats->radio_id >= link_stats_results->num_radio) {
1641 WMA_LOGE("%s, invalid radio id:%d, num radio:%d",
1642 __func__, radio_stats->radio_id,
1643 link_stats_results->num_radio);
1644 return -EINVAL;
1645 }
1646
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001647 WMA_LOGD("Radio stats Fixed Param:");
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001648 WMA_LOGD("req_id: %u num_radio: %u more_radio_events: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001649 fixed_param->request_id, fixed_param->num_radio,
1650 fixed_param->more_radio_events);
1651
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001652 WMA_LOGD("Radio Info: radio_id: %u on_time: %u tx_time: %u rx_time: %u on_time_scan: %u",
1653 radio_stats->radio_id, radio_stats->on_time,
1654 radio_stats->tx_time, radio_stats->rx_time,
1655 radio_stats->on_time_scan);
1656 WMA_LOGD("on_time_nbd: %u on_time_gscan: %u on_time_roam_scan: %u",
1657 radio_stats->on_time_nbd,
1658 radio_stats->on_time_gscan, radio_stats->on_time_roam_scan);
1659 WMA_LOGD("on_time_pno_scan: %u on_time_hs20: %u num_channels: %u",
1660 radio_stats->on_time_pno_scan, radio_stats->on_time_hs20,
1661 radio_stats->num_channels);
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08001662 WMA_LOGD("on_time_host_scan: %u, on_time_lpi_scan: %u",
1663 radio_stats->on_time_host_scan, radio_stats->on_time_lpi_scan);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001664
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001665 link_stats_results->paramId = WMI_LINK_STATS_RADIO;
1666 link_stats_results->rspId = fixed_param->request_id;
1667 link_stats_results->ifaceId = 0;
1668 link_stats_results->num_radio = fixed_param->num_radio;
1669 link_stats_results->peer_event_number = 0;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001670
1671 /*
1672 * Backward compatibility:
1673 * There are firmware(s) which will send Radio stats only with
1674 * more_radio_events set to 0 and firmware which sends Radio stats
1675 * followed by tx_power level stats with more_radio_events set to 1.
1676 * if more_radio_events is set to 1, buffer the radio stats and
1677 * wait for tx_power_level stats.
1678 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001679 link_stats_results->moreResultToFollow = fixed_param->more_radio_events;
1680
1681 results = (uint8_t *) link_stats_results->results;
1682 t_radio_stats = (uint8_t *) radio_stats;
1683 t_channel_stats = (uint8_t *) channel_stats;
1684
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001685 rs_results = (tSirWifiRadioStat *) &results[0] + radio_stats->radio_id;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001686 rs_results->radio = radio_stats->radio_id;
1687 rs_results->onTime = radio_stats->on_time;
1688 rs_results->txTime = radio_stats->tx_time;
1689 rs_results->rxTime = radio_stats->rx_time;
1690 rs_results->onTimeScan = radio_stats->on_time_scan;
1691 rs_results->onTimeNbd = radio_stats->on_time_nbd;
1692 rs_results->onTimeGscan = radio_stats->on_time_gscan;
1693 rs_results->onTimeRoamScan = radio_stats->on_time_roam_scan;
1694 rs_results->onTimePnoScan = radio_stats->on_time_pno_scan;
1695 rs_results->onTimeHs20 = radio_stats->on_time_hs20;
1696 rs_results->total_num_tx_power_levels = 0;
1697 rs_results->tx_time_per_power_level = NULL;
1698 rs_results->numChannels = radio_stats->num_channels;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08001699 rs_results->on_time_host_scan = radio_stats->on_time_host_scan;
1700 rs_results->on_time_lpi_scan = radio_stats->on_time_lpi_scan;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001701 rs_results->channels = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001703 if (rs_results->numChannels) {
1704 rs_results->channels = (tSirWifiChannelStats *) qdf_mem_malloc(
1705 radio_stats->num_channels *
1706 chan_stats_size);
1707 if (rs_results->channels == NULL) {
1708 WMA_LOGD("%s: could not allocate mem for channel stats (size=%zu)",
1709 __func__, radio_stats->num_channels * chan_stats_size);
1710 wma_unified_radio_tx_mem_free(handle);
1711 return -ENOMEM;
1712 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001713
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001714 chn_results = (tSirWifiChannelStats *) &rs_results->channels[0];
1715 next_chan_offset = WMI_TLV_HDR_SIZE;
1716 WMA_LOGD("Channel Stats Info");
1717 for (count = 0; count < radio_stats->num_channels; count++) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001718 WMA_LOGD("channel_width %u center_freq %u center_freq0 %u",
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001719 channel_stats->channel_width,
1720 channel_stats->center_freq,
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001721 channel_stats->center_freq0);
1722 WMA_LOGD("center_freq1 %u radio_awake_time %u cca_busy_time %u",
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001723 channel_stats->center_freq1,
1724 channel_stats->radio_awake_time,
1725 channel_stats->cca_busy_time);
1726 channel_stats++;
1727
1728 qdf_mem_copy(chn_results,
1729 t_channel_stats + next_chan_offset,
1730 chan_stats_size);
1731 chn_results++;
1732 next_chan_offset += sizeof(*channel_stats);
1733 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734 }
1735
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001736 if (link_stats_results->moreResultToFollow) {
1737 /* More results coming, don't post yet */
1738 return 0;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001739 }
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001740 link_stats_results->nr_received++;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001741
1742 if (link_stats_results->num_radio != link_stats_results->nr_received) {
1743 /* Not received all radio stats yet, don't post yet */
1744 return 0;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001745 }
1746
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001747 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
1748 WMA_LINK_LAYER_STATS_RESULTS_RSP,
1749 link_stats_results);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001750 wma_unified_radio_tx_mem_free(handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001751
1752 return 0;
1753}
1754
Zhang Qiana6e9c102016-12-22 16:47:24 +08001755#ifdef WLAN_PEER_PS_NOTIFICATION
1756/**
1757 * wma_peer_ps_evt_handler() - handler for PEER power state change.
1758 * @handle: wma handle
1759 * @event: FW event
1760 * @len: length of FW event
1761 *
1762 * Once peer STA power state changes, an event will be indicated by
1763 * FW. This function send a link layer state change msg to HDD. HDD
1764 * link layer callback will converts the event to NL msg.
1765 *
1766 * Return: 0 Success. Others fail.
1767 */
1768static int wma_peer_ps_evt_handler(void *handle, u_int8_t *event,
1769 u_int32_t len)
1770{
1771 WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *param_buf;
1772 wmi_peer_sta_ps_statechange_event_fixed_param *fixed_param;
1773 tSirWifiPeerStat *peer_stat;
1774 tSirWifiPeerInfo *peer_info;
1775 tSirLLStatsResults *link_stats_results;
1776 tSirMacAddr mac_address;
1777 uint32_t result_len;
1778 cds_msg_t sme_msg = { 0 };
1779 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
1780
1781 tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE);
1782
1783 if (!mac) {
1784 WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1785 return -EINVAL;
1786 }
1787
1788 if (!mac->sme.link_layer_stats_ext_cb) {
1789 WMA_LOGD("%s: HDD callback is null", __func__);
1790 return -EINVAL;
1791 }
1792
1793 WMA_LOGD("%s: Posting Peer Stats PS event to HDD", __func__);
1794
1795 param_buf = (WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *)event;
1796 fixed_param = param_buf->fixed_param;
1797
1798 result_len = sizeof(tSirLLStatsResults) +
1799 sizeof(tSirWifiPeerStat) +
1800 sizeof(tSirWifiPeerInfo);
1801 link_stats_results = qdf_mem_malloc(result_len);
1802 if (link_stats_results == NULL) {
1803 WMA_LOGE("%s: Cannot allocate link layer stats.", __func__);
1804 return -EINVAL;
1805 }
1806
1807 WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_param->peer_macaddr, &mac_address[0]);
1808 WMA_LOGD("Peer power state change event from FW");
1809 WMA_LOGD("Fixed Param:");
1810 WMA_LOGD("MAC address: %2x:%2x:%2x:%2x:%2x:%2x, Power state: %d",
1811 mac_address[0], mac_address[1], mac_address[2],
1812 mac_address[3], mac_address[4], mac_address[5],
1813 fixed_param->peer_ps_state);
1814
1815 link_stats_results->paramId = WMI_LL_STATS_EXT_PS_CHG;
1816 link_stats_results->num_peers = 1;
1817 link_stats_results->peer_event_number = 1;
1818 link_stats_results->moreResultToFollow = 0;
1819
1820 peer_stat = (tSirWifiPeerStat *)link_stats_results->results;
1821 peer_stat->numPeers = 1;
1822 peer_info = (tSirWifiPeerInfo *)peer_stat->peerInfo;
1823 qdf_mem_copy(&peer_info->peerMacAddress,
1824 &mac_address,
1825 sizeof(tSirMacAddr));
1826 peer_info->power_saving = fixed_param->peer_ps_state;
1827
1828 sme_msg.type = eWMI_SME_LL_STATS_IND;
1829 sme_msg.bodyptr = link_stats_results;
1830 sme_msg.bodyval = 0;
1831
Zhang Qian73c348a2017-03-13 16:15:55 +08001832 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
Zhang Qiana6e9c102016-12-22 16:47:24 +08001833 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1834 WMA_LOGE("%s: Fail to post ps change ind msg", __func__);
1835 qdf_mem_free(link_stats_results);
1836 }
1837
1838 return 0;
1839}
1840#else
1841/**
1842 * wma_peer_ps_evt_handler() - handler for PEER power state change.
1843 * @handle: wma handle
1844 * @event: FW event
1845 * @len: length of FW event
1846 *
1847 * Once peer STA power state changes, an event will be indicated by
1848 * FW. This function send a link layer state change msg to HDD. HDD
1849 * link layer callback will converts the event to NL msg.
1850 *
1851 * Return: 0 Success. Others fail.
1852 */
1853static inline int wma_peer_ps_evt_handler(void *handle, u_int8_t *event,
1854 u_int32_t len)
1855{
1856 return 0;
1857}
1858#endif
1859
1860/**
1861 * wma_tx_failure_cb() - TX failure callback
1862 * @ctx: txrx context
1863 * @num_msdu: number of msdu with the same status
1864 * @tid: TID number
1865 * @status: failure status
1866 */
1867void wma_tx_failure_cb(void *ctx, uint32_t num_msdu,
1868 uint8_t tid, enum htt_tx_status status)
1869{
1870 tSirLLStatsResults *results;
1871 struct sir_wifi_iface_tx_fail *tx_fail;
1872 struct scheduler_msg sme_msg = { 0 };
1873 QDF_STATUS qdf_status;
1874 tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE);
1875
1876 if (!mac) {
1877 WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1878 return;
1879 }
1880
1881 if (!mac->sme.link_layer_stats_ext_cb) {
1882 WMA_LOGD("%s: HDD callback is null", __func__);
1883 return;
1884 }
1885
1886 results = qdf_mem_malloc(sizeof(tSirLLStatsResults) +
1887 sizeof(struct sir_wifi_iface_tx_fail));
1888 if (results == NULL) {
1889 WMA_LOGE("%s: Cannot allocate link layer stats.", __func__);
1890 return;
1891 }
1892
1893 results->paramId = WMI_LL_STATS_EXT_TX_FAIL;
1894 results->num_peers = 1;
1895 results->peer_event_number = 1;
1896 results->moreResultToFollow = 0;
1897
1898 tx_fail = (struct sir_wifi_iface_tx_fail *)results->results;
1899 tx_fail->tid = tid;
1900 tx_fail->msdu_num = num_msdu;
1901 tx_fail->status = status;
1902
1903 sme_msg.type = eWMI_SME_LL_STATS_IND;
1904 sme_msg.bodyptr = results;
1905 sme_msg.bodyval = 0;
1906
1907 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
1908 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1909 WMA_LOGE("%s: Fail to post TX failure ind msg", __func__);
1910 qdf_mem_free(results);
1911 }
1912}
1913
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001914/**
1915 * wma_register_ll_stats_event_handler() - register link layer stats related
1916 * event handler
1917 * @wma_handle: wma handle
1918 *
1919 * Return: none
1920 */
1921void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle)
1922{
1923 if (NULL == wma_handle) {
1924 WMA_LOGE("%s: wma_handle is NULL", __func__);
1925 return;
1926 }
1927
1928 wmi_unified_register_event_handler(wma_handle->wmi_handle,
Govind Singhd76a5b02016-03-08 15:12:14 +05301929 WMI_IFACE_LINK_STATS_EVENTID,
1930 wma_unified_link_iface_stats_event_handler,
1931 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001932 wmi_unified_register_event_handler(wma_handle->wmi_handle,
Govind Singhd76a5b02016-03-08 15:12:14 +05301933 WMI_PEER_LINK_STATS_EVENTID,
1934 wma_unified_link_peer_stats_event_handler,
1935 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936 wmi_unified_register_event_handler(wma_handle->wmi_handle,
Govind Singhd76a5b02016-03-08 15:12:14 +05301937 WMI_RADIO_LINK_STATS_EVENTID,
1938 wma_unified_link_radio_stats_event_handler,
1939 WMA_RX_SERIALIZER_CTX);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001940 wmi_unified_register_event_handler(wma_handle->wmi_handle,
1941 WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID,
1942 wma_unified_radio_tx_power_level_stats_event_handler,
1943 WMA_RX_SERIALIZER_CTX);
Zhang Qiana6e9c102016-12-22 16:47:24 +08001944 wmi_unified_register_event_handler(wma_handle->wmi_handle,
1945 WMI_PEER_STA_PS_STATECHG_EVENTID,
1946 wma_peer_ps_evt_handler,
1947 WMA_RX_SERIALIZER_CTX);
Zhang Qian73c348a2017-03-13 16:15:55 +08001948 wmi_unified_register_event_handler(wma_handle->wmi_handle,
1949 WMI_REPORT_STATS_EVENTID,
1950 wma_ll_stats_evt_handler,
1951 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001952
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953}
1954
1955
1956/**
1957 * wma_process_ll_stats_clear_req() - clear link layer stats
1958 * @wma: wma handle
1959 * @clearReq: ll stats clear request command params
1960 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301961 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962 */
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001963QDF_STATUS wma_process_ll_stats_clear_req(tp_wma_handle wma,
1964 const tpSirLLStatsClearReq clearReq)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965{
Govind Singh4863da42016-03-08 11:45:00 +05301966 struct ll_stats_clear_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001967 int ret;
1968
1969 if (!clearReq || !wma) {
1970 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301971 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972 }
1973
Deepak Dhamdhere6adc08e2017-07-27 09:33:22 -07001974 if (!wma->interfaces[clearReq->staId].handle) {
1975 WMA_LOGE("%s: vdev_id %d handle is NULL",
1976 __func__, clearReq->staId);
1977 return QDF_STATUS_E_FAILURE;
1978 }
1979
Govind Singh4863da42016-03-08 11:45:00 +05301980 cmd.stop_req = clearReq->stopReq;
1981 cmd.sta_id = clearReq->staId;
1982 cmd.stats_clear_mask = clearReq->statsClearReqMask;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983
Govind Singh4863da42016-03-08 11:45:00 +05301984 ret = wmi_unified_process_ll_stats_clear_cmd(wma->wmi_handle, &cmd,
1985 wma->interfaces[clearReq->staId].addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986 if (ret) {
1987 WMA_LOGE("%s: Failed to send clear link stats req", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301988 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001989 }
1990
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301991 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001992}
1993
1994/**
1995 * wma_process_ll_stats_set_req() - link layer stats set request
1996 * @wma: wma handle
1997 * @setReq: ll stats set request command params
1998 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301999 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002000 */
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002001QDF_STATUS wma_process_ll_stats_set_req(tp_wma_handle wma,
2002 const tpSirLLStatsSetReq setReq)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002003{
Govind Singh4863da42016-03-08 11:45:00 +05302004 struct ll_stats_set_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002005 int ret;
2006
2007 if (!setReq || !wma) {
2008 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302009 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002010 }
2011
Govind Singh4863da42016-03-08 11:45:00 +05302012 cmd.mpdu_size_threshold = setReq->mpduSizeThreshold;
2013 cmd.aggressive_statistics_gathering =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002014 setReq->aggressiveStatisticsGathering;
2015
Govind Singh4863da42016-03-08 11:45:00 +05302016 ret = wmi_unified_process_ll_stats_set_cmd(wma->wmi_handle,
2017 &cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002018 if (ret) {
2019 WMA_LOGE("%s: Failed to send set link stats request", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302020 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021 }
2022
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302023 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024}
2025
2026/**
2027 * wma_process_ll_stats_get_req() - link layer stats get request
2028 * @wma:wma handle
2029 * @getReq:ll stats get request command params
2030 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302031 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002032 */
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002033QDF_STATUS wma_process_ll_stats_get_req(tp_wma_handle wma,
2034 const tpSirLLStatsGetReq getReq)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002035{
Govind Singh4863da42016-03-08 11:45:00 +05302036 struct ll_stats_get_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002037 int ret;
2038
2039 if (!getReq || !wma) {
2040 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302041 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042 }
2043
Selvaraj, Sridhar171e2252016-06-22 22:33:26 +05302044 if (!wma->interfaces[getReq->staId].vdev_active) {
2045 WMA_LOGE("%s: vdev not created yet", __func__);
2046 return QDF_STATUS_E_FAILURE;
2047 }
2048
Govind Singh4863da42016-03-08 11:45:00 +05302049 cmd.req_id = getReq->reqId;
2050 cmd.param_id_mask = getReq->paramIdMask;
2051 cmd.sta_id = getReq->staId;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052
Govind Singh4863da42016-03-08 11:45:00 +05302053 ret = wmi_unified_process_ll_stats_get_cmd(wma->wmi_handle, &cmd,
2054 wma->interfaces[getReq->staId].addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 if (ret) {
2056 WMA_LOGE("%s: Failed to send get link stats request", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302057 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002058 }
2059
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302060 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002061}
2062
2063/**
2064 * wma_unified_link_iface_stats_event_handler() - link iface stats event handler
2065 * @wma:wma handle
2066 * @cmd_param_info: data from event
2067 * @len: length
2068 *
2069 * Return: 0 for success or error code
2070 */
2071int wma_unified_link_iface_stats_event_handler(void *handle,
2072 uint8_t *cmd_param_info,
2073 uint32_t len)
2074{
2075 WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
2076 wmi_iface_link_stats_event_fixed_param *fixed_param;
2077 wmi_iface_link_stats *link_stats;
2078 wmi_wmm_ac_stats *ac_stats;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002079 wmi_iface_offload_stats *offload_stats;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002080 tSirLLStatsResults *link_stats_results;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002081 uint8_t *results, *t_link_stats, *t_ac_stats, *t_offload_stats;
2082 uint32_t next_res_offset, next_ac_offset, next_offload_offset, count;
2083 uint32_t roaming_offset, size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084 size_t link_stats_size, ac_stats_size, iface_info_size;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002085 size_t link_stats_results_size, offload_stats_size;
2086 size_t total_ac_size, total_offload_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087
Anurag Chouhan6d760662016-02-20 16:05:43 +05302088 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002089
2090 if (!pMac) {
2091 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
2092 return -EINVAL;
2093 }
2094
2095 if (!pMac->sme.pLinkLayerStatsIndCallback) {
2096 WMA_LOGD("%s: HDD callback is null", __func__);
2097 return -EINVAL;
2098 }
2099
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100 param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
2101 if (!param_tlvs) {
2102 WMA_LOGA("%s: Invalid stats event", __func__);
2103 return -EINVAL;
2104 }
2105
2106 /*
2107 * cmd_param_info contains
2108 * wmi_iface_link_stats_event_fixed_param fixed_param;
2109 * wmi_iface_link_stats iface_link_stats;
2110 * iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats)
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002111 * fixed_param->num_offload_stats * size of(wmi_iface_offload_stats);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002112 */
2113 fixed_param = param_tlvs->fixed_param;
2114 link_stats = param_tlvs->iface_link_stats;
2115 ac_stats = param_tlvs->ac;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002116 offload_stats = param_tlvs->iface_offload_stats;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002117
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002118 if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats) ||
2119 (fixed_param->num_offload_stats && !offload_stats)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002120 WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__);
2121 return -EINVAL;
2122 }
2123
Vignesh Viswanathan37794ae2017-09-28 15:26:56 +05302124 if (link_stats->num_ac > WIFI_AC_MAX) {
2125 WMA_LOGE("%s: Excess data received from firmware num_ac %d",
2126 __func__, link_stats->num_ac);
2127 return -EINVAL;
2128 }
2129 if (fixed_param->num_offload_stats > WMI_OFFLOAD_STATS_TYPE_MAX) {
2130 WMA_LOGE("%s: Excess num offload stats recvd from fw: %d",
2131 __func__, fixed_param->num_offload_stats);
2132 return -EINVAL;
2133 }
2134
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002135 link_stats_size = sizeof(tSirWifiIfaceStat);
2136 iface_info_size = sizeof(tSirWifiInterfaceInfo);
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002137
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002138 ac_stats_size = sizeof(tSirWifiWmmAcStat);
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002139 offload_stats_size = sizeof(struct wifi_iface_offload_stat);
2140
2141 total_ac_size = ac_stats_size * WIFI_AC_MAX;
2142 total_offload_size = offload_stats_size * WMI_OFFLOAD_STATS_TYPE_MAX +
2143 member_size(tSirWifiIfaceStat, num_offload_stats);
2144
2145 link_stats_results_size = sizeof(*link_stats_results) + link_stats_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002146
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302147 link_stats_results = qdf_mem_malloc(link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002148 if (!link_stats_results) {
2149 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
2150 __func__, link_stats_results_size);
2151 return -ENOMEM;
2152 }
2153
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302154 qdf_mem_zero(link_stats_results, link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002155
2156 link_stats_results->paramId = WMI_LINK_STATS_IFACE;
2157 link_stats_results->rspId = fixed_param->request_id;
2158 link_stats_results->ifaceId = fixed_param->vdev_id;
2159 link_stats_results->num_peers = link_stats->num_peers;
2160 link_stats_results->peer_event_number = 0;
2161 link_stats_results->moreResultToFollow = 0;
2162
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002163 /* results is copied to tSirWifiIfaceStat in upper layer
2164 * tSirWifiIfaceStat
2165 * - tSirWifiInterfaceInfo (all fields except roaming is
2166 * filled by host in the upper layer)
2167 * - various members of tSirWifiIfaceStat (from wmi_iface_link_stats)
2168 * - ACs information (from wmi_wmm_ac_stats)
2169 * - num_offload_stats (from fixed param)
2170 * - offload stats (from wmi_iface_offload_stats)
2171 */
2172
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002173 results = (uint8_t *) link_stats_results->results;
2174 t_link_stats = (uint8_t *) link_stats;
2175 t_ac_stats = (uint8_t *) ac_stats;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002176 t_offload_stats = (uint8_t *) offload_stats;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002177
2178 /* Copy roaming state */
2179 roaming_offset = offsetof(tSirWifiInterfaceInfo, roaming);
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002180 size = member_size(tSirWifiInterfaceInfo, roaming);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002181
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002182 qdf_mem_copy(results + roaming_offset, &link_stats->roam_state, size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002183
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002184 next_res_offset = iface_info_size;
2185 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002186 t_link_stats + WMI_TLV_HDR_SIZE,
2187 link_stats_size - iface_info_size -
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002188 total_ac_size - total_offload_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002189
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002190 next_res_offset = link_stats_size - total_ac_size - total_offload_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002191 next_ac_offset = WMI_TLV_HDR_SIZE;
2192
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002193 for (count = 0; count < link_stats->num_ac; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 ac_stats++;
2195
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302196 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002197 t_ac_stats + next_ac_offset, ac_stats_size);
2198 next_res_offset += ac_stats_size;
2199 next_ac_offset += sizeof(*ac_stats);
2200 }
2201
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002202 next_res_offset = link_stats_size - total_offload_size;
2203 /* copy num_offload_stats into result */
2204 size = member_size(tSirWifiIfaceStat, num_offload_stats);
2205 qdf_mem_copy(results + next_res_offset, &fixed_param->num_offload_stats,
2206 size);
2207
2208 next_res_offset += size;
2209 next_offload_offset = WMI_TLV_HDR_SIZE;
2210
2211 for (count = 0; count < fixed_param->num_offload_stats; count++) {
2212 qdf_mem_copy(results + next_res_offset,
2213 t_offload_stats + next_offload_offset,
2214 offload_stats_size);
2215 next_res_offset += offload_stats_size;
2216 next_offload_offset += sizeof(*offload_stats);
2217 }
2218
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002219 /* call hdd callback with Link Layer Statistics
2220 * vdev_id/ifacId in link_stats_results will be
2221 * used to retrieve the correct HDD context
2222 */
2223 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
2224 WMA_LINK_LAYER_STATS_RESULTS_RSP,
2225 link_stats_results);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302226 qdf_mem_free(link_stats_results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002227
2228 return 0;
2229}
2230
Zhang Qian73c348a2017-03-13 16:15:55 +08002231/**
2232 * wma_config_stats_ext_threshold - set threthold for MAC counters
2233 * @wma: wma handler
2234 * @threshold: threhold for MAC counters
2235 *
2236 * For each MAC layer counter, FW holds two copies. One is the current value.
2237 * The other is the last report. Once a current counter's increment is larger
2238 * than the threshold, FW will indicate that counter to host even if the
2239 * monitoring timer does not expire.
2240 *
2241 * Return: None
2242 */
2243void wma_config_stats_ext_threshold(tp_wma_handle wma,
2244 struct sir_ll_ext_stats_threshold *thresh)
2245{
2246 uint32_t len, tag, hdr_len;
2247 uint8_t *buf_ptr;
2248 wmi_buf_t buf;
2249 wmi_pdev_set_stats_threshold_cmd_fixed_param *cmd;
2250 wmi_chan_cca_stats_thresh *cca;
2251 wmi_peer_signal_stats_thresh *signal;
2252 wmi_tx_stats_thresh *tx;
2253 wmi_rx_stats_thresh *rx;
2254
2255 if (!thresh) {
2256 WMA_LOGE(FL("Invalid threshold input."));
2257 return;
2258 }
2259
2260 len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param) +
2261 sizeof(wmi_chan_cca_stats_thresh) +
2262 sizeof(wmi_peer_signal_stats_thresh) +
2263 sizeof(wmi_tx_stats_thresh) +
2264 sizeof(wmi_rx_stats_thresh) +
2265 5 * WMI_TLV_HDR_SIZE;
2266 buf = wmi_buf_alloc(wma->wmi_handle, len);
2267 if (!buf) {
2268 WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
2269 return;
2270 }
2271
2272 buf_ptr = (u_int8_t *)wmi_buf_data(buf);
2273 tag = WMITLV_TAG_STRUC_wmi_pdev_set_stats_threshold_cmd_fixed_param;
2274 hdr_len = WMITLV_GET_STRUCT_TLVLEN(
2275 wmi_pdev_set_stats_threshold_cmd_fixed_param);
2276 WMA_LOGD(FL("Setting fixed parameters. tag=%d, len=%d"), tag, hdr_len);
2277 cmd = (wmi_pdev_set_stats_threshold_cmd_fixed_param *)buf_ptr;
2278 WMITLV_SET_HDR(&cmd->tlv_header, tag, hdr_len);
2279 cmd->enable_thresh = thresh->enable;
2280 cmd->use_thresh_bitmap = thresh->enable_bitmap;
2281 cmd->gbl_thresh = thresh->global_threshold;
2282 cmd->cca_thresh_enable_bitmap = thresh->cca_bitmap;
2283 cmd->signal_thresh_enable_bitmap = thresh->signal_bitmap;
2284 cmd->tx_thresh_enable_bitmap = thresh->tx_bitmap;
2285 cmd->rx_thresh_enable_bitmap = thresh->rx_bitmap;
2286 len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param);
2287
2288 tag = WMITLV_TAG_STRUC_wmi_chan_cca_stats_thresh,
2289 hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_chan_cca_stats_thresh);
2290 cca = (wmi_chan_cca_stats_thresh *)(buf_ptr + len);
2291 WMITLV_SET_HDR(&cca->tlv_header, tag, hdr_len);
2292 WMA_LOGD(FL("Setting cca parameters. tag=%d, len=%d"), tag, hdr_len);
2293 cca->idle_time = thresh->cca.idle_time;
2294 cca->tx_time = thresh->cca.tx_time;
2295 cca->rx_in_bss_time = thresh->cca.rx_in_bss_time;
2296 cca->rx_out_bss_time = thresh->cca.rx_out_bss_time;
2297 cca->rx_busy_time = thresh->cca.rx_busy_time;
2298 cca->rx_in_bad_cond_time = thresh->cca.rx_in_bad_cond_time;
2299 cca->tx_in_bad_cond_time = thresh->cca.tx_in_bad_cond_time;
2300 cca->wlan_not_avail_time = thresh->cca.wlan_not_avail_time;
2301 WMA_LOGD(FL("idle time=%d, tx_time=%d, in_bss=%d, out_bss=%d"),
2302 cca->idle_time, cca->tx_time,
2303 cca->rx_in_bss_time, cca->rx_out_bss_time);
2304 WMA_LOGD(FL("rx_busy=%d, rx_bad=%d, tx_bad=%d, not_avail=%d"),
2305 cca->rx_busy_time, cca->rx_in_bad_cond_time,
2306 cca->tx_in_bad_cond_time, cca->wlan_not_avail_time);
2307 len += sizeof(wmi_chan_cca_stats_thresh);
2308
2309 signal = (wmi_peer_signal_stats_thresh *)(buf_ptr + len);
2310 tag = WMITLV_TAG_STRUC_wmi_peer_signal_stats_thresh;
2311 hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_peer_signal_stats_thresh);
2312 WMA_LOGD(FL("Setting signal parameters. tag=%d, len=%d"), tag, hdr_len);
2313 WMITLV_SET_HDR(&signal->tlv_header, tag, hdr_len);
2314 signal->per_chain_snr = thresh->signal.snr;
2315 signal->per_chain_nf = thresh->signal.nf;
2316 WMA_LOGD(FL("snr=%d, nf=%d"), signal->per_chain_snr,
2317 signal->per_chain_nf);
2318 len += sizeof(wmi_peer_signal_stats_thresh);
2319
2320 tx = (wmi_tx_stats_thresh *)(buf_ptr + len);
2321 tag = WMITLV_TAG_STRUC_wmi_tx_stats_thresh;
2322 hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_tx_stats_thresh);
2323 WMA_LOGD(FL("Setting TX parameters. tag=%d, len=%d"), tag, len);
2324 WMITLV_SET_HDR(&tx->tlv_header, tag, hdr_len);
2325 tx->tx_msdu_cnt = thresh->tx.msdu;
2326 tx->tx_mpdu_cnt = thresh->tx.mpdu;
2327 tx->tx_ppdu_cnt = thresh->tx.ppdu;
2328 tx->tx_bytes = thresh->tx.bytes;
2329 tx->tx_msdu_drop_cnt = thresh->tx.msdu_drop;
2330 tx->tx_drop_bytes = thresh->tx.byte_drop;
2331 tx->tx_mpdu_retry_cnt = thresh->tx.mpdu_retry;
2332 tx->tx_mpdu_fail_cnt = thresh->tx.mpdu_fail;
2333 tx->tx_ppdu_fail_cnt = thresh->tx.ppdu_fail;
2334 tx->tx_mpdu_aggr = thresh->tx.aggregation;
2335 tx->tx_succ_mcs = thresh->tx.succ_mcs;
2336 tx->tx_fail_mcs = thresh->tx.fail_mcs;
2337 tx->tx_ppdu_delay = thresh->tx.delay;
2338 WMA_LOGD(FL("msdu=%d, mpdu=%d, ppdu=%d, bytes=%d, msdu_drop=%d"),
2339 tx->tx_msdu_cnt, tx->tx_mpdu_cnt, tx->tx_ppdu_cnt,
2340 tx->tx_bytes, tx->tx_msdu_drop_cnt);
2341 WMA_LOGD(FL("byte_drop=%d, mpdu_retry=%d, mpdu_fail=%d, ppdu_fail=%d"),
2342 tx->tx_drop_bytes, tx->tx_mpdu_retry_cnt,
2343 tx->tx_mpdu_fail_cnt, tx->tx_ppdu_fail_cnt);
2344 WMA_LOGD(FL("aggr=%d, succ_mcs=%d, fail_mcs=%d, delay=%d"),
2345 tx->tx_mpdu_aggr, tx->tx_succ_mcs, tx->tx_fail_mcs,
2346 tx->tx_ppdu_delay);
2347 len += sizeof(wmi_tx_stats_thresh);
2348
2349 rx = (wmi_rx_stats_thresh *)(buf_ptr + len);
2350 tag = WMITLV_TAG_STRUC_wmi_rx_stats_thresh,
2351 hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_rx_stats_thresh);
2352 WMITLV_SET_HDR(&rx->tlv_header, tag, hdr_len);
2353 WMA_LOGD(FL("Setting RX parameters. tag=%d, len=%d"), tag, hdr_len);
2354 rx->mac_rx_mpdu_cnt = thresh->rx.mpdu;
2355 rx->mac_rx_bytes = thresh->rx.bytes;
2356 rx->phy_rx_ppdu_cnt = thresh->rx.ppdu;
2357 rx->phy_rx_bytes = thresh->rx.ppdu_bytes;
2358 rx->rx_disorder_cnt = thresh->rx.disorder;
2359 rx->rx_mpdu_retry_cnt = thresh->rx.mpdu_retry;
2360 rx->rx_mpdu_dup_cnt = thresh->rx.mpdu_dup;
2361 rx->rx_mpdu_discard_cnt = thresh->rx.mpdu_discard;
2362 rx->rx_mpdu_aggr = thresh->rx.aggregation;
2363 rx->rx_mcs = thresh->rx.mcs;
2364 rx->sta_ps_inds = thresh->rx.ps_inds;
2365 rx->sta_ps_durs = thresh->rx.ps_durs;
2366 rx->rx_probe_reqs = thresh->rx.probe_reqs;
2367 rx->rx_oth_mgmts = thresh->rx.other_mgmt;
2368 WMA_LOGD(FL("rx_mpdu=%d, rx_bytes=%d, rx_ppdu=%d, rx_pbytes=%d"),
2369 rx->mac_rx_mpdu_cnt, rx->mac_rx_bytes,
2370 rx->phy_rx_ppdu_cnt, rx->phy_rx_bytes);
2371 WMA_LOGD(FL("disorder=%d, rx_dup=%d, rx_aggr=%d, rx_mcs=%d"),
2372 rx->rx_disorder_cnt, rx->rx_mpdu_dup_cnt,
2373 rx->rx_mpdu_aggr, rx->rx_mcs);
2374 WMA_LOGD(FL("rx_ind=%d, rx_dur=%d, rx_probe=%d, rx_mgmt=%d"),
2375 rx->sta_ps_inds, rx->sta_ps_durs,
2376 rx->rx_probe_reqs, rx->rx_oth_mgmts);
2377 len += sizeof(wmi_rx_stats_thresh);
2378
2379 WMA_LOGA("WMA --> WMI_PDEV_SET_STATS_THRESHOLD_CMDID(0x%x), length=%d",
2380 WMI_PDEV_SET_STATS_THRESHOLD_CMDID, len);
2381 if (EOK != wmi_unified_cmd_send(wma->wmi_handle,
2382 buf, len,
2383 WMI_PDEV_SET_STATS_THRESHOLD_CMDID)) {
2384 WMA_LOGE("Failed to send WMI_PDEV_SET_STATS_THRESHOLD_CMDID");
2385 wmi_buf_free(buf);
2386 }
2387}
2388
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002389#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
2390
2391/**
2392 * wma_update_pdev_stats() - update pdev stats
2393 * @wma: wma handle
2394 * @pdev_stats: pdev stats
2395 *
2396 * Return: none
2397 */
2398static void wma_update_pdev_stats(tp_wma_handle wma,
2399 wmi_pdev_stats *pdev_stats)
2400{
2401 tAniGetPEStatsRsp *stats_rsp_params;
2402 uint32_t temp_mask;
2403 uint8_t *stats_buf;
2404 tCsrGlobalClassAStatsInfo *classa_stats = NULL;
2405 struct wma_txrx_node *node;
2406 uint8_t i;
2407
2408 for (i = 0; i < wma->max_bssid; i++) {
2409 node = &wma->interfaces[i];
2410 stats_rsp_params = node->stats_rsp;
2411 if (stats_rsp_params) {
2412 node->fw_stats_set |= FW_PDEV_STATS_SET;
2413 WMA_LOGD("<---FW PDEV STATS received for vdevId:%d", i);
2414 stats_buf = (uint8_t *) (stats_rsp_params + 1);
2415 temp_mask = stats_rsp_params->statsMask;
2416 if (temp_mask & (1 << eCsrSummaryStats))
2417 stats_buf += sizeof(tCsrSummaryStatsInfo);
2418
2419 if (temp_mask & (1 << eCsrGlobalClassAStats)) {
2420 classa_stats =
2421 (tCsrGlobalClassAStatsInfo *) stats_buf;
2422 classa_stats->max_pwr = pdev_stats->chan_tx_pwr;
2423 }
2424 }
2425 }
2426}
2427
2428/**
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302429 * wma_vdev_stats_lost_link_helper() - helper function to extract
2430 * lost link information from vdev statistics event while deleting BSS.
2431 * @wma: WMA handle
2432 * @vdev_stats: statistics information from firmware
2433 *
2434 * This is for informing HDD to collect lost link information while
2435 * disconnection. Following conditions to check
2436 * 1. vdev is up
2437 * 2. bssid is zero. When handling DELETE_BSS request message, it sets bssid to
2438 * zero, hence add the check here to indicate the event comes during deleting
2439 * BSS
2440 * 3. DELETE_BSS is the request message queued. Put this condition check on the
2441 * last one as it consumes more resource searching entries in the list
2442 *
2443 * Return: none
2444 */
2445static void wma_vdev_stats_lost_link_helper(tp_wma_handle wma,
2446 wmi_vdev_stats *vdev_stats)
2447{
2448 struct wma_txrx_node *node;
2449 int32_t rssi;
2450 struct wma_target_req *req_msg;
2451 static const uint8_t zero_mac[QDF_MAC_ADDR_SIZE] = {0};
Naveen Rawatf440a132017-05-05 12:27:39 -07002452 int32_t bcn_snr, dat_snr;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302453
2454 node = &wma->interfaces[vdev_stats->vdev_id];
Mukul Sharmaf9047232017-03-02 16:58:56 +05302455 if (wma_is_vdev_up(vdev_stats->vdev_id) &&
Hanumanth Reddy Pothulaaef3c7f2017-05-18 12:19:23 +05302456 !qdf_mem_cmp(node->bssid, zero_mac, QDF_MAC_ADDR_SIZE)) {
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302457 req_msg = wma_peek_vdev_req(wma, vdev_stats->vdev_id,
2458 WMA_TARGET_REQ_TYPE_VDEV_STOP);
2459 if ((NULL == req_msg) ||
2460 (WMA_DELETE_BSS_REQ != req_msg->msg_type)) {
2461 WMA_LOGD(FL("cannot find DELETE_BSS request message"));
2462 return;
2463 }
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002464 bcn_snr = vdev_stats->vdev_snr.bcn_snr;
2465 dat_snr = vdev_stats->vdev_snr.dat_snr;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302466 WMA_LOGD(FL("get vdev id %d, beancon snr %d, data snr %d"),
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002467 vdev_stats->vdev_id, bcn_snr, dat_snr);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302468
2469 if (WMA_TGT_IS_VALID_SNR(bcn_snr))
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002470 rssi = bcn_snr;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302471 else if (WMA_TGT_IS_VALID_SNR(dat_snr))
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002472 rssi = dat_snr;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302473 else
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302474 rssi = WMA_TGT_INVALID_SNR;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302475
2476 /* Get the absolute rssi value from the current rssi value */
2477 rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
2478 wma_lost_link_info_handler(wma, vdev_stats->vdev_id, rssi);
2479 }
2480}
2481
2482/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002483 * wma_update_vdev_stats() - update vdev stats
2484 * @wma: wma handle
2485 * @vdev_stats: vdev stats
2486 *
2487 * Return: none
2488 */
2489static void wma_update_vdev_stats(tp_wma_handle wma,
2490 wmi_vdev_stats *vdev_stats)
2491{
2492 tAniGetPEStatsRsp *stats_rsp_params;
2493 tCsrSummaryStatsInfo *summary_stats = NULL;
2494 uint8_t *stats_buf;
2495 struct wma_txrx_node *node;
2496 uint8_t i;
Naveen Rawatf440a132017-05-05 12:27:39 -07002497 int32_t rssi = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302498 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002499 tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) wma->pGetRssiReq;
Rajeev Kumarb60abe42017-01-21 15:39:31 -08002500 struct scheduler_msg sme_msg = { 0 };
Naveen Rawatf440a132017-05-05 12:27:39 -07002501 int32_t bcn_snr, dat_snr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002502
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002503 bcn_snr = vdev_stats->vdev_snr.bcn_snr;
2504 dat_snr = vdev_stats->vdev_snr.dat_snr;
2505 WMA_LOGD("vdev id %d beancon snr %d data snr %d",
2506 vdev_stats->vdev_id, bcn_snr, dat_snr);
2507
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002508 node = &wma->interfaces[vdev_stats->vdev_id];
2509 stats_rsp_params = node->stats_rsp;
2510 if (stats_rsp_params) {
2511 stats_buf = (uint8_t *) (stats_rsp_params + 1);
2512 node->fw_stats_set |= FW_VDEV_STATS_SET;
2513 WMA_LOGD("<---FW VDEV STATS received for vdevId:%d",
2514 vdev_stats->vdev_id);
2515 if (stats_rsp_params->statsMask & (1 << eCsrSummaryStats)) {
2516 summary_stats = (tCsrSummaryStatsInfo *) stats_buf;
2517 for (i = 0; i < 4; i++) {
2518 summary_stats->tx_frm_cnt[i] =
2519 vdev_stats->tx_frm_cnt[i];
2520 summary_stats->fail_cnt[i] =
2521 vdev_stats->fail_cnt[i];
2522 summary_stats->multiple_retry_cnt[i] =
2523 vdev_stats->multiple_retry_cnt[i];
2524 }
2525
2526 summary_stats->rx_frm_cnt = vdev_stats->rx_frm_cnt;
2527 summary_stats->rx_error_cnt = vdev_stats->rx_err_cnt;
2528 summary_stats->rx_discard_cnt =
2529 vdev_stats->rx_discard_cnt;
2530 summary_stats->ack_fail_cnt = vdev_stats->ack_fail_cnt;
2531 summary_stats->rts_succ_cnt = vdev_stats->rts_succ_cnt;
2532 summary_stats->rts_fail_cnt = vdev_stats->rts_fail_cnt;
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002533 /* Update SNR and RSSI in SummaryStats */
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302534 if (WMA_TGT_IS_VALID_SNR(bcn_snr)) {
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002535 summary_stats->snr = bcn_snr;
2536 summary_stats->rssi =
2537 bcn_snr + WMA_TGT_NOISE_FLOOR_DBM;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302538 } else if (WMA_TGT_IS_VALID_SNR(dat_snr)) {
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002539 summary_stats->snr = dat_snr;
2540 summary_stats->rssi =
Naveen Rawatf440a132017-05-05 12:27:39 -07002541 dat_snr + WMA_TGT_NOISE_FLOOR_DBM;
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002542 } else {
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302543 summary_stats->snr = WMA_TGT_INVALID_SNR;
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002544 summary_stats->rssi = 0;
2545 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002546 }
2547 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002548
2549 if (pGetRssiReq && pGetRssiReq->sessionId == vdev_stats->vdev_id) {
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302550 if (WMA_TGT_IS_VALID_SNR(bcn_snr)) {
2551 rssi = bcn_snr;
2552 rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
2553 } else if (WMA_TGT_IS_VALID_SNR(dat_snr)) {
2554 rssi = dat_snr;
2555 rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
2556 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002557 /*
2558 * Firmware sends invalid snr till it sees
2559 * Beacon/Data after connection since after
2560 * vdev up fw resets the snr to invalid.
2561 * In this duartion Host will return the last know
2562 * rssi during connection.
2563 */
2564 WMA_LOGE("Invalid SNR from firmware");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002565 }
2566
2567 WMA_LOGD("Average Rssi = %d, vdev id= %d", rssi,
2568 pGetRssiReq->sessionId);
2569
2570 /* update the average rssi value to UMAC layer */
2571 if (NULL != pGetRssiReq->rssiCallback) {
2572 ((tCsrRssiCallback) (pGetRssiReq->rssiCallback))(rssi,
2573 pGetRssiReq->staId,
2574 pGetRssiReq->pDevContext);
2575 }
2576
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302577 qdf_mem_free(pGetRssiReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002578 wma->pGetRssiReq = NULL;
2579 }
2580
2581 if (node->psnr_req) {
2582 tAniGetSnrReq *p_snr_req = node->psnr_req;
2583
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302584 if (WMA_TGT_IS_VALID_SNR(bcn_snr))
Varun Reddy Yeturu83ccb9b2016-06-29 11:55:41 -07002585 p_snr_req->snr = bcn_snr;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302586 else if (WMA_TGT_IS_VALID_SNR(dat_snr))
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002587 p_snr_req->snr = dat_snr;
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002588 else
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302589 p_snr_req->snr = WMA_TGT_INVALID_SNR;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002590
2591 sme_msg.type = eWNI_SME_SNR_IND;
2592 sme_msg.bodyptr = p_snr_req;
2593 sme_msg.bodyval = 0;
2594
Rajeev Kumarb60abe42017-01-21 15:39:31 -08002595 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302596 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002597 WMA_LOGE("%s: Fail to post snr ind msg", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302598 qdf_mem_free(p_snr_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002599 }
2600
2601 node->psnr_req = NULL;
2602 }
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302603 wma_vdev_stats_lost_link_helper(wma, vdev_stats);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002604}
2605
2606/**
2607 * wma_post_stats() - update stats to PE
2608 * @wma: wma handle
2609 * @node: txrx node
2610 *
2611 * Return: none
2612 */
2613static void wma_post_stats(tp_wma_handle wma, struct wma_txrx_node *node)
2614{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002615 /* send response to UMAC */
Naveen Rawat3c49d192017-03-02 18:43:16 -08002616 wma_send_msg(wma, WMA_GET_STATISTICS_RSP, node->stats_rsp, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002617 node->stats_rsp = NULL;
2618 node->fw_stats_set = 0;
2619}
2620
2621/**
2622 * wma_update_peer_stats() - update peer stats
2623 * @wma: wma handle
2624 * @peer_stats: peer stats
2625 *
2626 * Return: none
2627 */
2628static void wma_update_peer_stats(tp_wma_handle wma,
2629 wmi_peer_stats *peer_stats)
2630{
2631 tAniGetPEStatsRsp *stats_rsp_params;
2632 tCsrGlobalClassAStatsInfo *classa_stats = NULL;
2633 struct wma_txrx_node *node;
2634 uint8_t *stats_buf, vdev_id, macaddr[IEEE80211_ADDR_LEN], mcsRateFlags;
2635 uint32_t temp_mask;
2636
2637 WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, &macaddr[0]);
2638 if (!wma_find_vdev_by_bssid(wma, macaddr, &vdev_id))
2639 return;
2640
2641 node = &wma->interfaces[vdev_id];
Naveen Rawat3c49d192017-03-02 18:43:16 -08002642 stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp;
2643 if (stats_rsp_params) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002644 node->fw_stats_set |= FW_PEER_STATS_SET;
2645 WMA_LOGD("<-- FW PEER STATS received for vdevId:%d", vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002646 stats_buf = (uint8_t *) (stats_rsp_params + 1);
2647 temp_mask = stats_rsp_params->statsMask;
2648 if (temp_mask & (1 << eCsrSummaryStats))
2649 stats_buf += sizeof(tCsrSummaryStatsInfo);
2650
2651 if (temp_mask & (1 << eCsrGlobalClassAStats)) {
2652 classa_stats = (tCsrGlobalClassAStatsInfo *) stats_buf;
2653 WMA_LOGD("peer tx rate:%d", peer_stats->peer_tx_rate);
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002654 /* The linkspeed returned by fw is in kbps so convert
2655 * it in to units of 500kbps which is expected by UMAC
2656 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002657 if (peer_stats->peer_tx_rate) {
2658 classa_stats->tx_rate =
2659 peer_stats->peer_tx_rate / 500;
2660 }
2661
2662 classa_stats->tx_rate_flags = node->rate_flags;
2663 if (!(node->rate_flags & eHAL_TX_RATE_LEGACY)) {
2664 classa_stats->mcs_index =
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002665 wma_get_mcs_idx(
2666 (peer_stats->peer_tx_rate /
2667 100), node->rate_flags,
2668 node->nss, &mcsRateFlags);
Jeff Johnsonad0b2c62017-03-16 14:37:38 -07002669 classa_stats->nss = node->nss;
2670 classa_stats->mcs_rate_flags = mcsRateFlags;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002671 }
2672 /* FW returns tx power in intervals of 0.5 dBm
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002673 * Convert it back to intervals of 1 dBm
2674 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002675 classa_stats->max_pwr =
2676 roundup(classa_stats->max_pwr, 2) >> 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002677 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002678 }
2679}
2680
2681/**
2682 * wma_post_link_status() - post link status to SME
2683 * @pGetLinkStatus: SME Link status
2684 * @link_status: Link status
2685 *
2686 * Return: none
2687 */
2688void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus,
2689 uint8_t link_status)
2690{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302691 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Rajeev Kumarb60abe42017-01-21 15:39:31 -08002692 struct scheduler_msg sme_msg = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002693
2694 pGetLinkStatus->linkStatus = link_status;
2695 sme_msg.type = eWNI_SME_LINK_STATUS_IND;
2696 sme_msg.bodyptr = pGetLinkStatus;
2697 sme_msg.bodyval = 0;
2698
Rajeev Kumarb60abe42017-01-21 15:39:31 -08002699 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302700 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002701 WMA_LOGE("%s: Fail to post link status ind msg", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302702 qdf_mem_free(pGetLinkStatus);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002703 }
2704}
2705
2706/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302707 * wma_update_per_chain_rssi_stats() - to store per chain rssi stats
2708 * @wma: wma handle
2709 * @rssi_stats: rssi stats
2710 * @rssi_per_chain_stats: buffer where rssi stats to be stored
2711 *
2712 * This function stores per chain rssi stats received from fw for all vdevs for
2713 * which the stats were requested into a csr stats structure.
2714 *
2715 * Return: void
2716 */
2717static void wma_update_per_chain_rssi_stats(tp_wma_handle wma,
2718 wmi_rssi_stats *rssi_stats,
2719 struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats)
2720{
2721 int i;
Naveen Rawatf440a132017-05-05 12:27:39 -07002722 int32_t bcn_snr, dat_snr;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302723
2724 for (i = 0; i < NUM_CHAINS_MAX; i++) {
2725 bcn_snr = rssi_stats->rssi_avg_beacon[i];
2726 dat_snr = rssi_stats->rssi_avg_data[i];
2727 WMA_LOGD("chain %d beacon snr %d data snr %d",
2728 i, bcn_snr, dat_snr);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302729 if (WMA_TGT_IS_VALID_SNR(bcn_snr))
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302730 rssi_per_chain_stats->rssi[i] = bcn_snr;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302731 else if (WMA_TGT_IS_VALID_SNR(dat_snr))
2732 rssi_per_chain_stats->rssi[i] = dat_snr;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302733 else
2734 /*
2735 * Firmware sends invalid snr till it sees
2736 * Beacon/Data after connection since after
2737 * vdev up fw resets the snr to invalid.
2738 * In this duartion Host will return an invalid rssi
2739 * value.
2740 */
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302741 rssi_per_chain_stats->rssi[i] = WMA_TGT_INVALID_SNR;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302742
2743 /*
2744 * Get the absolute rssi value from the current rssi value the
2745 * sinr value is hardcoded into 0 in the qcacld-new/CORE stack
2746 */
2747 rssi_per_chain_stats->rssi[i] += WMA_TGT_NOISE_FLOOR_DBM;
2748 WMI_MAC_ADDR_TO_CHAR_ARRAY(&(rssi_stats->peer_macaddr),
2749 rssi_per_chain_stats->peer_mac_addr);
2750 }
2751}
2752
2753/**
2754 * wma_update_rssi_stats() - to update rssi stats for all vdevs
2755 * for which the stats were requested.
2756 * @wma: wma handle
2757 * @rssi_stats: rssi stats
2758 *
2759 * This function updates the rssi stats for all vdevs for which
2760 * the stats were requested.
2761 *
2762 * Return: void
2763 */
2764static void wma_update_rssi_stats(tp_wma_handle wma,
2765 wmi_rssi_stats *rssi_stats)
2766{
2767 tAniGetPEStatsRsp *stats_rsp_params;
2768 struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats = NULL;
2769 struct wma_txrx_node *node;
2770 uint8_t *stats_buf;
2771 uint32_t temp_mask;
2772 uint8_t vdev_id;
2773
2774 vdev_id = rssi_stats->vdev_id;
2775 node = &wma->interfaces[vdev_id];
Naveen Rawat3c49d192017-03-02 18:43:16 -08002776 stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp;
2777 if (stats_rsp_params) {
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302778 node->fw_stats_set |= FW_RSSI_PER_CHAIN_STATS_SET;
2779 WMA_LOGD("<-- FW RSSI PER CHAIN STATS received for vdevId:%d",
2780 vdev_id);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302781 stats_buf = (uint8_t *) (stats_rsp_params + 1);
2782 temp_mask = stats_rsp_params->statsMask;
2783
2784 if (temp_mask & (1 << eCsrSummaryStats))
2785 stats_buf += sizeof(tCsrSummaryStatsInfo);
2786 if (temp_mask & (1 << eCsrGlobalClassAStats))
2787 stats_buf += sizeof(tCsrGlobalClassAStatsInfo);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302788 if (temp_mask & (1 << eCsrGlobalClassDStats))
2789 stats_buf += sizeof(tCsrGlobalClassDStatsInfo);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302790
2791 if (temp_mask & (1 << csr_per_chain_rssi_stats)) {
2792 rssi_per_chain_stats =
2793 (struct csr_per_chain_rssi_stats_info *)stats_buf;
2794 wma_update_per_chain_rssi_stats(wma, rssi_stats,
2795 rssi_per_chain_stats);
2796 }
2797 }
2798}
2799
2800
2801/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002802 * wma_link_status_event_handler() - link status event handler
2803 * @handle: wma handle
2804 * @cmd_param_info: data from event
2805 * @len: length
2806 *
2807 * Return: 0 for success or error code
2808 */
2809int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info,
2810 uint32_t len)
2811{
2812 tp_wma_handle wma = (tp_wma_handle) handle;
2813 WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf;
2814 wmi_vdev_rate_stats_event_fixed_param *event;
2815 wmi_vdev_rate_ht_info *ht_info;
2816 struct wma_txrx_node *intr = wma->interfaces;
2817 uint8_t link_status = LINK_STATUS_LEGACY;
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07002818 uint32_t i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002819
2820 param_buf =
2821 (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *) cmd_param_info;
2822 if (!param_buf) {
2823 WMA_LOGA("%s: Invalid stats event", __func__);
2824 return -EINVAL;
2825 }
2826
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002827 event = (wmi_vdev_rate_stats_event_fixed_param *)
2828 param_buf->fixed_param;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002829 ht_info = (wmi_vdev_rate_ht_info *) param_buf->ht_info;
2830
2831 WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats);
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07002832
2833 if (event->num_vdev_stats > ((WMI_SVC_MSG_MAX_SIZE -
2834 sizeof(*event)) / sizeof(*ht_info))) {
2835 WMA_LOGE("%s: excess vdev_stats buffers:%d", __func__,
2836 event->num_vdev_stats);
2837 QDF_ASSERT(0);
2838 return -EINVAL;
2839 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002840 for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) {
2841 WMA_LOGD("%s vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d",
2842 __func__, ht_info->vdevid, ht_info->tx_nss,
2843 ht_info->rx_nss, ht_info->tx_preamble,
2844 ht_info->rx_preamble);
2845 if (ht_info->vdevid < wma->max_bssid
2846 && intr[ht_info->vdevid].plink_status_req) {
2847 if (ht_info->tx_nss || ht_info->rx_nss)
2848 link_status = LINK_STATUS_MIMO;
2849
2850 if ((ht_info->tx_preamble == LINK_RATE_VHT) ||
2851 (ht_info->rx_preamble == LINK_RATE_VHT))
2852 link_status |= LINK_STATUS_VHT;
2853
2854 if (intr[ht_info->vdevid].nss == 2)
2855 link_status |= LINK_SUPPORT_MIMO;
2856
2857 if (intr[ht_info->vdevid].rate_flags &
2858 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
2859 eHAL_TX_RATE_VHT80))
2860 link_status |= LINK_SUPPORT_VHT;
2861
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002862 wma_post_link_status(
2863 intr[ht_info->vdevid].plink_status_req,
2864 link_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002865 intr[ht_info->vdevid].plink_status_req = NULL;
2866 link_status = LINK_STATUS_LEGACY;
2867 }
2868
2869 ht_info++;
2870 }
2871
2872 return 0;
2873}
2874
Sreelakshmi Konamki88a2a412017-04-14 15:11:55 +05302875int wma_rso_cmd_status_event_handler(wmi_roam_event_fixed_param *wmi_event)
2876{
2877 struct rso_cmd_status *rso_status;
Rajeev Kumarcf7bd802017-04-18 11:11:42 -07002878 struct scheduler_msg sme_msg = {0};
Sreelakshmi Konamki88a2a412017-04-14 15:11:55 +05302879 QDF_STATUS qdf_status;
2880
2881 rso_status = qdf_mem_malloc(sizeof(*rso_status));
2882 if (!rso_status) {
2883 WMA_LOGE("%s: malloc fails for rso cmd status", __func__);
2884 return -ENOMEM;
2885 }
2886
2887 rso_status->vdev_id = wmi_event->vdev_id;
2888 if (WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS == wmi_event->notif)
2889 rso_status->status = true;
2890 else if (WMI_ROAM_NOTIF_SCAN_MODE_FAIL == wmi_event->notif)
2891 rso_status->status = false;
2892 sme_msg.type = eWNI_SME_RSO_CMD_STATUS_IND;
2893 sme_msg.bodyptr = rso_status;
2894 sme_msg.bodyval = 0;
2895 WMA_LOGI("%s: Post RSO cmd status to SME", __func__);
2896
2897 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
2898 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
2899 WMA_LOGE("%s: fail to post RSO cmd status to SME", __func__);
2900 qdf_mem_free(rso_status);
2901 }
2902 return 0;
2903}
2904
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002905/**
Will Huanga9814592017-05-24 15:47:58 +08002906 * wma_handle_sta_peer_info() - handle peer information in
2907 * peer stats
2908 * @num_peer_stats: peer number
2909 * @peer_stats: peer stats received from firmware
2910 * @peer_macaddr: the specified mac address
2911 * @sapaddr: sap mac address
2912 *
2913 * This function will send eWNI_SME_GET_PEER_INFO_IND
2914 * to sme with stations' information
2915 *
2916 */
2917static void wma_handle_sta_peer_info(uint32_t num_peer_stats,
2918 wmi_peer_stats *peer_stats,
2919 struct qdf_mac_addr peer_macaddr,
2920 uint8_t *sapaddr)
2921{
2922 QDF_STATUS qdf_status;
2923 wmi_mac_addr temp_addr;
2924 struct sir_peer_info_resp *peer_info;
2925 struct scheduler_msg sme_msg = {0};
2926 uint32_t i;
2927 uint32_t j = 0;
2928
2929 if (!qdf_is_macaddr_broadcast(&peer_macaddr)) {
2930 WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_macaddr.bytes, &temp_addr);
2931 for (i = 0; i < num_peer_stats; i++) {
2932 if ((((temp_addr.mac_addr47to32) & 0x0000ffff) ==
2933 ((peer_stats->peer_macaddr.mac_addr47to32) &
2934 0x0000ffff))
2935 && (temp_addr.mac_addr31to0 ==
2936 peer_stats->peer_macaddr.mac_addr31to0)) {
2937
2938 break;
2939 }
2940 peer_stats = peer_stats + 1;
2941 }
2942 peer_info = qdf_mem_malloc(sizeof(*peer_info) +
2943 sizeof(peer_info->info[0]));
2944 if (NULL == peer_info) {
2945 WMA_LOGE("%s: Memory allocation failed.", __func__);
2946 return;
2947 }
2948 if (i < num_peer_stats) {
2949 peer_info->count = 1;
2950 WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
2951 peer_info->info[0].peer_macaddr.bytes);
2952 peer_info->info[0].rssi = peer_stats->peer_rssi;
2953 peer_info->info[0].tx_rate = peer_stats->peer_tx_rate;
2954 peer_info->info[0].rx_rate = peer_stats->peer_rx_rate;
2955 WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d",
2956 __func__,
2957 peer_info->info[0].peer_macaddr.bytes,
2958 peer_stats->peer_rssi,
2959 peer_stats->peer_tx_rate,
2960 peer_stats->peer_rx_rate);
2961 } else {
2962 WMA_LOGE("%s: no match mac address", __func__);
2963 peer_info->count = 0;
2964 }
2965 } else {
2966 peer_info = qdf_mem_malloc(sizeof(*peer_info) +
2967 num_peer_stats * sizeof(peer_info->info[0]));
2968 if (NULL == peer_info) {
2969 WMA_LOGE("%s: Memory allocation failed.", __func__);
2970 return;
2971 }
2972 peer_info->count = num_peer_stats;
2973
2974 for (i = 0; i < num_peer_stats; i++) {
2975 WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
2976 peer_info->info[j].peer_macaddr.bytes);
2977 peer_info->info[j].rssi = peer_stats->peer_rssi;
2978 peer_info->info[j].tx_rate = peer_stats->peer_tx_rate;
2979 peer_info->info[j].rx_rate = peer_stats->peer_rx_rate;
2980 WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d",
2981 __func__,
2982 peer_info->info[j].peer_macaddr.bytes,
2983 peer_stats->peer_rssi,
2984 peer_stats->peer_tx_rate,
2985 peer_stats->peer_rx_rate);
2986 if (!qdf_mem_cmp(peer_info->info[j].peer_macaddr.bytes,
2987 sapaddr, QDF_MAC_ADDR_SIZE)) {
2988 peer_info->count = peer_info->count - 1;
2989 } else {
2990 j++;
2991 }
2992 peer_stats = peer_stats + 1;
2993 }
2994 WMA_LOGD("WDA send peer num %d", peer_info->count);
2995 }
2996
2997 sme_msg.type = eWNI_SME_GET_PEER_INFO_IND;
2998 sme_msg.bodyptr = peer_info;
2999 sme_msg.bodyval = 0;
3000
3001 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
3002 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
3003 WMA_LOGE("%s: Fail to post get rssi msg", __func__);
3004 qdf_mem_free(peer_info);
3005 }
3006
3007 return;
3008}
3009
3010/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003011 * wma_stats_event_handler() - stats event handler
3012 * @handle: wma handle
3013 * @cmd_param_info: data from event
3014 * @len: length
3015 *
3016 * Return: 0 for success or error code
3017 */
3018int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info,
3019 uint32_t len)
3020{
3021 tp_wma_handle wma = (tp_wma_handle) handle;
3022 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
3023 wmi_stats_event_fixed_param *event;
3024 wmi_pdev_stats *pdev_stats;
3025 wmi_vdev_stats *vdev_stats;
3026 wmi_peer_stats *peer_stats;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303027 wmi_rssi_stats *rssi_stats;
3028 wmi_per_chain_rssi_stats *rssi_event;
3029 struct wma_txrx_node *node;
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07003030 uint8_t *temp;
3031 uint32_t i;
3032 uint32_t buf_len = 0;
3033 bool excess_data = false;
Padma, Santhosh Kumar16dacfb2017-03-21 19:05:40 +05303034 wmi_congestion_stats *congestion_stats;
3035 tpAniSirGlobal mac;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003036
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003037 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) cmd_param_info;
3038 if (!param_buf) {
3039 WMA_LOGA("%s: Invalid stats event", __func__);
3040 return -EINVAL;
3041 }
3042 event = param_buf->fixed_param;
3043 temp = (uint8_t *) param_buf->data;
3044
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07003045 do {
3046 if (event->num_pdev_stats > ((WMI_SVC_MSG_MAX_SIZE -
3047 sizeof(*event)) / sizeof(*pdev_stats))) {
3048 excess_data = true;
3049 break;
3050 } else {
3051 buf_len += event->num_pdev_stats * sizeof(*pdev_stats);
3052 }
3053
3054 if (event->num_vdev_stats > ((WMI_SVC_MSG_MAX_SIZE -
3055 sizeof(*event)) / sizeof(*vdev_stats))) {
3056 excess_data = true;
3057 break;
3058 } else {
3059 buf_len += event->num_vdev_stats * sizeof(*vdev_stats);
3060 }
3061
3062 if (event->num_peer_stats > ((WMI_SVC_MSG_MAX_SIZE -
3063 sizeof(*event)) / sizeof(*peer_stats))) {
3064 excess_data = true;
3065 break;
3066 } else {
3067 buf_len += event->num_peer_stats * sizeof(*peer_stats);
3068 }
3069
3070 rssi_event =
3071 (wmi_per_chain_rssi_stats *) param_buf->chain_stats;
bingsf9047652017-08-31 08:05:54 +08003072 if (rssi_event) {
3073 if (rssi_event->num_per_chain_rssi_stats >
3074 ((WMI_SVC_MSG_MAX_SIZE - sizeof(*event)) /
3075 sizeof(*rssi_event))) {
3076 excess_data = true;
3077 break;
3078 } else {
3079 buf_len += sizeof(*rssi_event) *
3080 rssi_event->num_per_chain_rssi_stats;
3081 }
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07003082 }
3083 } while (0);
3084
3085 if (excess_data ||
3086 (sizeof(*event) > WMI_SVC_MSG_MAX_SIZE - buf_len)) {
3087 WMA_LOGE("excess wmi buffer: stats pdev %d vdev %d peer %d",
3088 event->num_pdev_stats, event->num_vdev_stats,
3089 event->num_peer_stats);
3090 QDF_ASSERT(0);
3091 return -EINVAL;
3092 }
3093
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003094 if (event->num_pdev_stats > 0) {
3095 for (i = 0; i < event->num_pdev_stats; i++) {
3096 pdev_stats = (wmi_pdev_stats *) temp;
3097 wma_update_pdev_stats(wma, pdev_stats);
3098 temp += sizeof(wmi_pdev_stats);
3099 }
3100 }
3101
3102 if (event->num_vdev_stats > 0) {
3103 for (i = 0; i < event->num_vdev_stats; i++) {
3104 vdev_stats = (wmi_vdev_stats *) temp;
3105 wma_update_vdev_stats(wma, vdev_stats);
3106 temp += sizeof(wmi_vdev_stats);
3107 }
3108 }
3109
3110 if (event->num_peer_stats > 0) {
Will Huanga9814592017-05-24 15:47:58 +08003111 if (wma->get_sta_peer_info == true) {
3112 wma_handle_sta_peer_info(event->num_peer_stats,
3113 (wmi_peer_stats *)temp,
3114 wma->peer_macaddr,
3115 wma->myaddr);
3116 } else {
3117 for (i = 0; i < event->num_peer_stats; i++) {
3118 peer_stats = (wmi_peer_stats *) temp;
3119 wma_update_peer_stats(wma, peer_stats);
3120 temp += sizeof(wmi_peer_stats);
3121 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003122 }
3123 }
3124
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303125 rssi_event = (wmi_per_chain_rssi_stats *) param_buf->chain_stats;
3126 if (rssi_event) {
Himanshu Agarwalcd8a84a2016-07-21 14:59:50 +05303127 if (((rssi_event->tlv_header & 0xFFFF0000) >> 16 ==
3128 WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats) &&
3129 ((rssi_event->tlv_header & 0x0000FFFF) ==
3130 WMITLV_GET_STRUCT_TLVLEN(wmi_per_chain_rssi_stats))) {
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303131 if (rssi_event->num_per_chain_rssi_stats > 0) {
3132 temp = (uint8_t *) rssi_event;
3133 temp += sizeof(*rssi_event);
Dustin Brownc4a5ba22016-11-10 17:21:18 -08003134
3135 /* skip past struct array tlv header */
3136 temp += WMI_TLV_HDR_SIZE;
3137
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303138 for (i = 0;
3139 i < rssi_event->num_per_chain_rssi_stats;
3140 i++) {
3141 rssi_stats = (wmi_rssi_stats *)temp;
3142 wma_update_rssi_stats(wma, rssi_stats);
3143 temp += sizeof(wmi_rssi_stats);
3144 }
3145 }
3146 }
3147 }
3148
Padma, Santhosh Kumar16dacfb2017-03-21 19:05:40 +05303149 congestion_stats = (wmi_congestion_stats *) param_buf->congestion_stats;
3150 if (congestion_stats) {
3151 if (((congestion_stats->tlv_header & 0xFFFF0000) >> 16 ==
3152 WMITLV_TAG_STRUC_wmi_congestion_stats) &&
3153 ((congestion_stats->tlv_header & 0x0000FFFF) ==
3154 WMITLV_GET_STRUCT_TLVLEN(wmi_congestion_stats))) {
3155 mac = cds_get_context(QDF_MODULE_ID_PE);
3156 if (!mac) {
3157 WMA_LOGE("%s: Invalid mac", __func__);
3158 return -EINVAL;
3159 }
3160 if (!mac->sme.congestion_cb) {
3161 WMA_LOGE("%s: Callback not registered",
3162 __func__);
3163 return -EINVAL;
3164 }
3165 WMA_LOGI("%s: congestion %d", __func__,
3166 congestion_stats->congestion);
3167 mac->sme.congestion_cb(mac->hHdd,
3168 congestion_stats->congestion,
3169 congestion_stats->vdev_id);
3170 }
3171 }
3172
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303173 for (i = 0; i < wma->max_bssid; i++) {
3174 node = &wma->interfaces[i];
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003175 if (node->fw_stats_set & FW_PEER_STATS_SET)
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303176 wma_post_stats(wma, node);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303177 }
3178
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003179 return 0;
3180}
3181
3182/**
Will Huanga9814592017-05-24 15:47:58 +08003183 * wma_fill_peer_info() - fill SIR peer info from WMI peer info struct
3184 * @wma: wma interface
3185 * @stats_info: WMI peer info pointer
3186 * @peer_info: SIR peer info pointer
3187 *
3188 * This function will fill SIR peer info from WMI peer info struct
3189 *
3190 * Return: None
3191 */
3192static void wma_fill_peer_info(tp_wma_handle wma,
3193 wmi_peer_stats_info *stats_info,
3194 struct sir_peer_info_ext *peer_info)
3195{
3196 peer_info->tx_packets = stats_info->tx_packets.low_32;
3197 peer_info->tx_bytes = stats_info->tx_bytes.high_32;
3198 peer_info->tx_bytes <<= 32;
3199 peer_info->tx_bytes += stats_info->tx_bytes.low_32;
3200 peer_info->rx_packets = stats_info->rx_packets.low_32;
3201 peer_info->rx_bytes = stats_info->rx_bytes.high_32;
3202 peer_info->rx_bytes <<= 32;
3203 peer_info->rx_bytes += stats_info->rx_bytes.low_32;
3204 peer_info->tx_retries = stats_info->tx_retries;
3205 peer_info->tx_failed = stats_info->tx_failed;
3206 peer_info->rssi = stats_info->peer_rssi;
3207 peer_info->tx_rate = stats_info->last_tx_bitrate_kbps;
3208 peer_info->tx_rate_code = stats_info->last_tx_rate_code;
3209 peer_info->rx_rate = stats_info->last_rx_bitrate_kbps;
3210 peer_info->rx_rate_code = stats_info->last_rx_rate_code;
3211}
3212
3213/**
3214 * wma_peer_info_ext_rsp() - process peer ext info ext
3215 * @handle: wma interface
3216 * @buf: wmi event buf pointer
3217 *
3218 * This function will send eWNI_SME_GET_PEER_INFO_EXT_IND to SME
3219 *
3220 * Return: 0 on success, error code otherwise
3221 */
3222static QDF_STATUS wma_peer_info_ext_rsp(tp_wma_handle wma, u_int8_t *buf)
3223{
3224 wmi_peer_stats_info_event_fixed_param *event;
3225 wmi_peer_stats_info *stats_info;
3226 struct sir_peer_info_ext_resp *resp;
3227 struct sir_peer_info_ext *peer_info;
3228 struct scheduler_msg sme_msg = {0};
3229 int i, j = 0;
3230 QDF_STATUS qdf_status;
3231
3232 event = (wmi_peer_stats_info_event_fixed_param *)buf;
3233 stats_info = (wmi_peer_stats_info *)(buf +
3234 sizeof(wmi_peer_stats_info_event_fixed_param));
3235
3236 if (wma->get_one_peer_info) {
3237 resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
3238 sizeof(resp->info[0]));
3239 if (!resp) {
3240 WMA_LOGE(FL("resp allocation failed."));
3241 return QDF_STATUS_E_NOMEM;
3242 }
3243 resp->count = 0;
3244 peer_info = &resp->info[0];
3245 for (i = 0; i < event->num_peers; i++) {
3246 WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
3247 peer_info->peer_macaddr.bytes);
3248
3249 if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes,
3250 wma->peer_macaddr.bytes,
3251 QDF_MAC_ADDR_SIZE)) {
3252 wma_fill_peer_info(wma, stats_info, peer_info);
3253 resp->count++;
3254 break;
3255 }
3256
3257 stats_info = stats_info + 1;
3258 }
3259 } else {
3260 resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
3261 event->num_peers * sizeof(resp->info[0]));
3262 if (!resp) {
3263 WMA_LOGE(FL("resp allocation failed."));
3264 return QDF_STATUS_E_NOMEM;
3265 }
3266 resp->count = event->num_peers;
3267 for (i = 0; i < event->num_peers; i++) {
3268 peer_info = &resp->info[j];
3269 WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
3270 peer_info->peer_macaddr.bytes);
3271
3272 if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes,
3273 wma->myaddr, QDF_MAC_ADDR_SIZE)) {
3274 resp->count = resp->count - 1;
3275 } else {
3276 wma_fill_peer_info(wma, stats_info, peer_info);
3277 j++;
3278 }
3279 stats_info = stats_info + 1;
3280 }
3281 }
3282
3283 sme_msg.type = eWNI_SME_GET_PEER_INFO_EXT_IND;
3284 sme_msg.bodyptr = resp;
3285 sme_msg.bodyval = 0;
3286
3287 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
3288 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
3289 WMA_LOGE("%s: Fail to post get peer info msg", __func__);
3290 qdf_mem_free(resp);
3291 }
3292
3293 return qdf_status;
3294}
3295
3296/**
3297 * dump_peer_stats_info() - dump wmi peer info struct
3298 * @event: wmi peer info fixed param pointer
3299 * @peer_stats: wmi peer stats info pointer
3300 *
3301 * This function will dump wmi peer info struct
3302 *
3303 * Return: None
3304 */
3305static void dump_peer_stats_info(wmi_peer_stats_info_event_fixed_param *event,
3306 wmi_peer_stats_info *peer_stats)
3307{
3308 int i;
3309 wmi_peer_stats_info *stats = peer_stats;
3310 u_int8_t mac[6];
3311
3312 WMA_LOGI("%s vdev_id %d, num_peers %d more_data %d",
3313 __func__, event->vdev_id,
3314 event->num_peers, event->more_data);
3315
3316 for (i = 0; i < event->num_peers; i++) {
3317 WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats->peer_macaddr, mac);
3318 WMA_LOGI("%s mac %pM", __func__, mac);
3319 WMA_LOGI("%s tx_bytes %d %d tx_packets %d %d",
3320 __func__,
3321 stats->tx_bytes.low_32,
3322 stats->tx_bytes.high_32,
3323 stats->tx_packets.low_32,
3324 stats->tx_packets.high_32);
3325 WMA_LOGI("%s rx_bytes %d %d rx_packets %d %d",
3326 __func__,
3327 stats->rx_bytes.low_32,
3328 stats->rx_bytes.high_32,
3329 stats->rx_packets.low_32,
3330 stats->rx_packets.high_32);
3331 WMA_LOGI("%s tx_retries %d tx_failed %d",
3332 __func__, stats->tx_retries, stats->tx_failed);
3333 WMA_LOGI("%s tx_rate_code %x rx_rate_code %x",
3334 __func__,
3335 stats->last_tx_rate_code,
3336 stats->last_rx_rate_code);
3337 WMA_LOGI("%s tx_rate %x rx_rate %x",
3338 __func__,
3339 stats->last_tx_bitrate_kbps,
3340 stats->last_rx_bitrate_kbps);
3341 WMA_LOGI("%s peer_rssi %d", __func__, stats->peer_rssi);
3342 stats++;
3343 }
3344}
3345
3346int wma_peer_info_event_handler(void *handle, u_int8_t *cmd_param_info,
3347 u_int32_t len)
3348{
3349 tp_wma_handle wma = (tp_wma_handle) handle;
3350 WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf;
3351 wmi_peer_stats_info_event_fixed_param *event;
3352 u_int32_t buf_size;
3353 u_int8_t *buf;
3354
3355 param_buf =
3356 (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)cmd_param_info;
3357 if (!param_buf) {
3358 WMA_LOGA("%s: Invalid stats event", __func__);
3359 return -EINVAL;
3360 }
3361
3362 WMA_LOGI("%s Recv WMI_PEER_STATS_INFO_EVENTID", __func__);
3363 event = param_buf->fixed_param;
Varun Reddy Yeturue4e2f292017-09-26 15:51:07 -07003364 if (event->num_peers >
3365 ((WMI_SVC_MSG_MAX_SIZE -
3366 sizeof(wmi_peer_stats_info_event_fixed_param))/
3367 sizeof(wmi_peer_stats_info))) {
3368 WMA_LOGE("Excess num of peers from fw %d", event->num_peers);
3369 return -EINVAL;
3370 }
Will Huanga9814592017-05-24 15:47:58 +08003371 buf_size = sizeof(wmi_peer_stats_info_event_fixed_param) +
3372 sizeof(wmi_peer_stats_info) * event->num_peers;
3373 buf = qdf_mem_malloc(buf_size);
3374 if (!buf) {
3375 WMA_LOGE("%s: Failed alloc memory for buf", __func__);
3376 return -ENOMEM;
3377 }
3378
3379 qdf_mem_copy(buf, param_buf->fixed_param,
3380 sizeof(wmi_peer_stats_info_event_fixed_param));
3381 qdf_mem_copy((buf + sizeof(wmi_peer_stats_info_event_fixed_param)),
3382 param_buf->peer_stats_info,
3383 sizeof(wmi_peer_stats_info) * event->num_peers);
3384 WMA_LOGI("%s dump peer stats info", __func__);
3385 dump_peer_stats_info(event, param_buf->peer_stats_info);
3386
3387 wma_peer_info_ext_rsp(wma, buf);
3388 qdf_mem_free(buf);
3389
3390 return 0;
3391}
3392
3393/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003394 * wma_send_link_speed() - send link speed to SME
3395 * @link_speed: link speed
3396 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303397 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003398 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303399QDF_STATUS wma_send_link_speed(uint32_t link_speed)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003400{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303401 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Mukul Sharmac3886aa2017-05-04 17:53:22 +05303402 tpAniSirGlobal mac_ctx;
3403 tSirLinkSpeedInfo *ls_ind;
3404
3405 mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
3406 if (!mac_ctx) {
3407 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
3408 return QDF_STATUS_E_INVAL;
3409 }
3410
3411 ls_ind = (tSirLinkSpeedInfo *)qdf_mem_malloc(sizeof(tSirLinkSpeedInfo));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003412 if (!ls_ind) {
3413 WMA_LOGE("%s: Memory allocation failed.", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303414 qdf_status = QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003415 } else {
3416 ls_ind->estLinkSpeed = link_speed;
Mukul Sharmac3886aa2017-05-04 17:53:22 +05303417 if (mac_ctx->sme.pLinkSpeedIndCb)
3418 mac_ctx->sme.pLinkSpeedIndCb(ls_ind,
3419 mac_ctx->sme.pLinkSpeedCbContext);
3420 else
3421 WMA_LOGD("%s: pLinkSpeedIndCb is null", __func__);
3422 qdf_mem_free(ls_ind);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003424 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303425 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003426}
3427
3428/**
3429 * wma_link_speed_event_handler() - link speed event handler
3430 * @handle: wma handle
3431 * @cmd_param_info: event data
3432 * @len: length
3433 *
3434 * Return: 0 for success or error code
3435 */
3436int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info,
3437 uint32_t len)
3438{
3439 WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *param_buf;
3440 wmi_peer_estimated_linkspeed_event_fixed_param *event;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303441 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003442
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003443 param_buf = (WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *)
3444 cmd_param_info;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003445 if (!param_buf) {
3446 WMA_LOGE("%s: Invalid linkspeed event", __func__);
3447 return -EINVAL;
3448 }
3449 event = param_buf->fixed_param;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303450 qdf_status = wma_send_link_speed(event->est_linkspeed_kbps);
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003451 if (!QDF_IS_STATUS_SUCCESS(qdf_status))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003452 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003453 return 0;
3454}
3455
3456/**
3457 * wma_wni_cfg_dnld() - cfg download request
3458 * @handle: wma handle
3459 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303460 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003461 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303462QDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003463{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303464 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Anurag Chouhan6d760662016-02-20 16:05:43 +05303465 void *mac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003466
3467 WMA_LOGD("%s: Enter", __func__);
3468
3469 if (NULL == mac) {
Srinivas Girigowdad1a07a52017-03-06 22:48:16 -08003470 WMA_LOGE("%s: Invalid context", __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303471 QDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303472 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003473 }
3474
3475 process_cfg_download_req(mac);
3476
3477 WMA_LOGD("%s: Exit", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303478 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003479}
3480
3481/**
3482 * wma_unified_debug_print_event_handler() - debug print event handler
3483 * @handle: wma handle
3484 * @datap: data pointer
3485 * @len: length
3486 *
3487 * Return: 0 for success or error code
3488 */
3489int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap,
3490 uint32_t len)
3491{
3492 WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf;
3493 uint8_t *data;
3494 uint32_t datalen;
3495
3496 param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap;
3497 if (!param_buf) {
3498 WMA_LOGE("Get NULL point message from FW");
3499 return -ENOMEM;
3500 }
3501 data = param_buf->data;
3502 datalen = param_buf->num_data;
3503
3504#ifdef BIG_ENDIAN_HOST
3505 {
3506 char dbgbuf[500] = { 0 };
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003507
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003508 memcpy(dbgbuf, data, datalen);
3509 SWAPME(dbgbuf, datalen);
3510 WMA_LOGD("FIRMWARE:%s", dbgbuf);
3511 return 0;
3512 }
3513#else
3514 WMA_LOGD("FIRMWARE:%s", data);
3515 return 0;
3516#endif /* BIG_ENDIAN_HOST */
3517}
3518
3519/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003520 * wma_is_sap_active() - check sap is active or not
3521 * @handle: wma handle
3522 *
3523 * Return: true/false
3524 */
3525bool wma_is_sap_active(tp_wma_handle wma_handle)
3526{
3527 int i;
3528
3529 for (i = 0; i < wma_handle->max_bssid; i++) {
Mukul Sharmaf9047232017-03-02 16:58:56 +05303530 if (!wma_is_vdev_up(i))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003531 continue;
3532 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
3533 wma_handle->interfaces[i].sub_type == 0)
3534 return true;
3535 }
3536 return false;
3537}
3538
3539/**
3540 * wma_is_p2p_go_active() - check p2p go is active or not
3541 * @handle: wma handle
3542 *
3543 * Return: true/false
3544 */
3545bool wma_is_p2p_go_active(tp_wma_handle wma_handle)
3546{
3547 int i;
3548
3549 for (i = 0; i < wma_handle->max_bssid; i++) {
Mukul Sharmaf9047232017-03-02 16:58:56 +05303550 if (!wma_is_vdev_up(i))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003551 continue;
3552 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
3553 wma_handle->interfaces[i].sub_type ==
3554 WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO)
3555 return true;
3556 }
3557 return false;
3558}
3559
3560/**
3561 * wma_is_p2p_cli_active() - check p2p cli is active or not
3562 * @handle: wma handle
3563 *
3564 * Return: true/false
3565 */
3566bool wma_is_p2p_cli_active(tp_wma_handle wma_handle)
3567{
3568 int i;
3569
3570 for (i = 0; i < wma_handle->max_bssid; i++) {
Mukul Sharmaf9047232017-03-02 16:58:56 +05303571 if (!wma_is_vdev_up(i))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003572 continue;
3573 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
3574 wma_handle->interfaces[i].sub_type ==
3575 WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT)
3576 return true;
3577 }
3578 return false;
3579}
3580
3581/**
3582 * wma_is_sta_active() - check sta is active or not
3583 * @handle: wma handle
3584 *
3585 * Return: true/false
3586 */
3587bool wma_is_sta_active(tp_wma_handle wma_handle)
3588{
3589 int i;
3590
3591 for (i = 0; i < wma_handle->max_bssid; i++) {
Mukul Sharmaf9047232017-03-02 16:58:56 +05303592 if (!wma_is_vdev_up(i))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003593 continue;
3594 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
3595 wma_handle->interfaces[i].sub_type == 0)
3596 return true;
3597 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_IBSS)
3598 return true;
3599 }
3600 return false;
3601}
3602
3603/**
3604 * wma_peer_phymode() - get phymode
3605 * @nw_type: nw type
3606 * @sta_type: sta type
3607 * @is_ht: is ht supported
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003608 * @ch_width: supported channel width
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003609 * @is_vht: is vht supported
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003610 * @is_he: is HE supported
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003611 *
3612 * Return: WLAN_PHY_MODE
3613 */
3614WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type,
3615 uint8_t is_ht, uint8_t ch_width,
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003616 uint8_t is_vht, bool is_he)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003617{
3618 WLAN_PHY_MODE phymode = MODE_UNKNOWN;
3619
3620 switch (nw_type) {
3621 case eSIR_11B_NW_TYPE:
Kabilan Kannanedff06d2017-08-23 16:55:13 -07003622#ifdef FEATURE_WLAN_TDLS
3623 if (STA_ENTRY_TDLS_PEER == sta_type) {
3624 if (is_vht) {
3625 if (CH_WIDTH_80MHZ == ch_width)
3626 phymode = MODE_11AC_VHT80;
3627 else
3628 phymode = (CH_WIDTH_40MHZ == ch_width) ?
3629 MODE_11AC_VHT40 :
3630 MODE_11AC_VHT20;
3631 } else if (is_ht) {
3632 phymode = (CH_WIDTH_40MHZ == ch_width) ?
3633 MODE_11NG_HT40 : MODE_11NG_HT20;
3634 } else
3635 phymode = MODE_11B;
3636 } else
3637#endif /* FEATURE_WLAN_TDLS */
3638 {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003639 phymode = MODE_11B;
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003640 if (is_ht || is_vht || is_he)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003641 WMA_LOGE("HT/VHT is enabled with 11B NW type");
Kabilan Kannanedff06d2017-08-23 16:55:13 -07003642 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003643 break;
3644 case eSIR_11G_NW_TYPE:
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003645 if (!(is_ht || is_vht || is_he)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003646 phymode = MODE_11G;
3647 break;
3648 }
3649 if (CH_WIDTH_40MHZ < ch_width)
3650 WMA_LOGE("80/160 MHz BW sent in 11G, configured 40MHz");
3651 if (ch_width)
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003652 phymode = (is_he) ? MODE_11AX_HE40_2G : (is_vht) ?
3653 MODE_11AC_VHT40_2G : MODE_11NG_HT40;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003654 else
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003655 phymode = (is_he) ? MODE_11AX_HE20_2G : (is_vht) ?
3656 MODE_11AC_VHT20_2G : MODE_11NG_HT20;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003657 break;
3658 case eSIR_11A_NW_TYPE:
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003659 if (!(is_ht || is_vht || is_he)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003660 phymode = MODE_11A;
3661 break;
3662 }
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003663 if (is_he) {
3664 if (ch_width == CH_WIDTH_160MHZ)
3665 phymode = MODE_11AX_HE160;
3666 else if (ch_width == CH_WIDTH_80P80MHZ)
3667 phymode = MODE_11AX_HE80_80;
3668 else if (ch_width == CH_WIDTH_80MHZ)
3669 phymode = MODE_11AX_HE80;
3670 else
3671 phymode = (ch_width) ?
3672 MODE_11AX_HE40 : MODE_11AX_HE20;
3673 } else if (is_vht) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003674 if (ch_width == CH_WIDTH_160MHZ)
3675 phymode = MODE_11AC_VHT160;
3676 else if (ch_width == CH_WIDTH_80P80MHZ)
3677 phymode = MODE_11AC_VHT80_80;
Amar Singhal046eb8a2016-05-05 12:50:15 -07003678 else if (ch_width == CH_WIDTH_80MHZ)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003679 phymode = MODE_11AC_VHT80;
3680 else
3681 phymode = (ch_width) ?
3682 MODE_11AC_VHT40 : MODE_11AC_VHT20;
3683 } else
3684 phymode = (ch_width) ? MODE_11NA_HT40 : MODE_11NA_HT20;
3685 break;
3686 default:
Srinivas Girigowdad1a07a52017-03-06 22:48:16 -08003687 WMA_LOGE("%s: Invalid nw type %d", __func__, nw_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003688 break;
3689 }
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003690 WMA_LOGD(FL("nw_type %d is_ht %d ch_width %d is_vht %d is_he %d phymode %d"),
3691 nw_type, is_ht, ch_width, is_vht, is_he, phymode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003692
3693 return phymode;
3694}
3695
3696/**
3697 * wma_txrx_fw_stats_reset() - reset txrx fw statistics
3698 * @wma_handle: wma handle
3699 * @vdev_id: vdev id
3700 * @value: value
3701 *
3702 * Return: 0 for success or return error
3703 */
3704int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle,
3705 uint8_t vdev_id, uint32_t value)
3706{
3707 struct ol_txrx_stats_req req;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003708 struct cdp_vdev *vdev;
Nishank Aggarwala13b61d2016-12-01 12:53:58 +05303709 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3710
3711 if (!soc) {
3712 WMA_LOGE("%s:SOC context is NULL", __func__);
3713 return -EINVAL;
3714 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003715
3716 vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
3717 if (!vdev) {
3718 WMA_LOGE("%s:Invalid vdev handle", __func__);
3719 return -EINVAL;
3720 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303721 qdf_mem_zero(&req, sizeof(req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003722 req.stats_type_reset_mask = value;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003723 cdp_fw_stats_get(soc, vdev, &req, false, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003724
3725 return 0;
3726}
3727
3728#ifdef HELIUMPLUS
Jeff Johnson560dc562017-03-17 15:19:31 -07003729#define SET_UPLOAD_MASK(_mask, _rate_info) \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003730 ((_mask) = 1 << (_rate_info ## _V2))
3731#else /* !HELIUMPLUS */
Jeff Johnson560dc562017-03-17 15:19:31 -07003732#define SET_UPLOAD_MASK(_mask, _rate_info) \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003733 ((_mask) = 1 << (_rate_info))
3734#endif
3735
Nirav Shah93e789e2016-04-14 19:47:43 +05303736#ifdef HELIUMPLUS
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07003737static bool wma_is_valid_fw_stats_cmd(uint32_t value)
Nirav Shah93e789e2016-04-14 19:47:43 +05303738{
3739 if (value > (HTT_DBG_NUM_STATS + 1) ||
3740 value == (HTT_DBG_STATS_RX_RATE_INFO + 1) ||
3741 value == (HTT_DBG_STATS_TX_RATE_INFO + 1) ||
3742 value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) {
3743 WMA_LOGE("%s: Not supported", __func__);
3744 return false;
3745 }
3746 return true;
3747}
3748#else
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07003749static bool wma_is_valid_fw_stats_cmd(uint32_t value)
Nirav Shah93e789e2016-04-14 19:47:43 +05303750{
3751 if (value > (HTT_DBG_NUM_STATS + 1) ||
3752 value == (HTT_DBG_STATS_RX_RATE_INFO_V2 + 1) ||
3753 value == (HTT_DBG_STATS_TX_RATE_INFO_V2 + 1) ||
3754 value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) {
3755 WMA_LOGE("%s: Not supported", __func__);
3756 return false;
3757 }
3758 return true;
3759}
3760#endif
3761
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003762/**
3763 * wma_set_txrx_fw_stats_level() - set txrx fw stats level
3764 * @wma_handle: wma handle
3765 * @vdev_id: vdev id
3766 * @value: value
3767 *
3768 * Return: 0 for success or return error
3769 */
3770int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle,
3771 uint8_t vdev_id, uint32_t value)
3772{
3773 struct ol_txrx_stats_req req;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003774 struct cdp_vdev *vdev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003775 uint32_t l_up_mask;
Nishank Aggarwala13b61d2016-12-01 12:53:58 +05303776 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3777
3778 if (!soc) {
3779 WMA_LOGE("%s:SOC context is NULL", __func__);
3780 return -EINVAL;
3781 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003782
3783 vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
3784 if (!vdev) {
3785 WMA_LOGE("%s:Invalid vdev handle", __func__);
3786 return -EINVAL;
3787 }
Nirav Shah93e789e2016-04-14 19:47:43 +05303788
3789 if (wma_is_valid_fw_stats_cmd(value) == false)
3790 return -EINVAL;
3791
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303792 qdf_mem_zero(&req, sizeof(req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003793 req.print.verbose = 1;
3794
Nirav Shah93e789e2016-04-14 19:47:43 +05303795 /* TODO: Need to check how to avoid mem leak*/
3796 l_up_mask = 1 << (value - 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003797 req.stats_type_upload_mask = l_up_mask;
3798
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003799 cdp_fw_stats_get(soc, vdev, &req, false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003800
3801 return 0;
3802}
3803
3804/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003805 * wma_get_stats_rsp_buf() - fill get stats response buffer
3806 * @get_stats_param: get stats parameters
3807 *
3808 * Return: stats response buffer
3809 */
3810static tAniGetPEStatsRsp *wma_get_stats_rsp_buf
3811 (tAniGetPEStatsReq *get_stats_param)
3812{
3813 tAniGetPEStatsRsp *stats_rsp_params;
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003814 uint32_t len, temp_mask;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003815
3816 len = sizeof(tAniGetPEStatsRsp);
3817 temp_mask = get_stats_param->statsMask;
3818
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003819 if (temp_mask & (1 << eCsrSummaryStats))
3820 len += sizeof(tCsrSummaryStatsInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003821
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003822 if (temp_mask & (1 << eCsrGlobalClassAStats))
3823 len += sizeof(tCsrGlobalClassAStatsInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003824
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003825 if (temp_mask & (1 << eCsrGlobalClassDStats))
3826 len += sizeof(tCsrGlobalClassDStatsInfo);
3827
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003828 if (temp_mask & (1 << csr_per_chain_rssi_stats))
3829 len += sizeof(struct csr_per_chain_rssi_stats_info);
3830
3831 stats_rsp_params = qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003832 if (!stats_rsp_params) {
3833 WMA_LOGE("memory allocation failed for tAniGetPEStatsRsp");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303834 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003835 return NULL;
3836 }
3837
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003838 stats_rsp_params->staId = get_stats_param->staId;
3839 stats_rsp_params->statsMask = get_stats_param->statsMask;
3840 stats_rsp_params->msgType = WMA_GET_STATISTICS_RSP;
3841 stats_rsp_params->msgLen = len - sizeof(tAniGetPEStatsRsp);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303842 stats_rsp_params->rc = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003843 return stats_rsp_params;
3844}
3845
3846/**
3847 * wma_get_stats_req() - get stats request
3848 * @handle: wma handle
3849 * @get_stats_param: stats params
3850 *
3851 * Return: none
3852 */
3853void wma_get_stats_req(WMA_HANDLE handle,
3854 tAniGetPEStatsReq *get_stats_param)
3855{
3856 tp_wma_handle wma_handle = (tp_wma_handle) handle;
3857 struct wma_txrx_node *node;
Dustin Brown35619492017-10-03 15:16:12 -07003858 struct stats_request_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003859 tAniGetPEStatsRsp *pGetPEStatsRspParams;
Govind Singh4863da42016-03-08 11:45:00 +05303860
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003861
3862 WMA_LOGD("%s: Enter", __func__);
3863 node = &wma_handle->interfaces[get_stats_param->sessionId];
3864 if (node->stats_rsp) {
3865 pGetPEStatsRspParams = node->stats_rsp;
3866 if (pGetPEStatsRspParams->staId == get_stats_param->staId &&
3867 pGetPEStatsRspParams->statsMask ==
3868 get_stats_param->statsMask) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003869 WMA_LOGD("Stats for staId %d with stats mask %d is pending.. ignore new request",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003870 get_stats_param->staId,
3871 get_stats_param->statsMask);
Ganesh Kondabattini5bcc3e72017-05-17 15:20:31 +05303872 pGetPEStatsRspParams =
3873 wma_get_stats_rsp_buf(get_stats_param);
3874 if (!pGetPEStatsRspParams) {
3875 WMA_LOGE("failed to allocate memory for stats response");
3876 goto end;
3877 }
3878 goto req_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003879 } else {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303880 qdf_mem_free(node->stats_rsp);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003881 node->stats_rsp = NULL;
3882 node->fw_stats_set = 0;
3883 }
3884 }
3885
3886 pGetPEStatsRspParams = wma_get_stats_rsp_buf(get_stats_param);
3887 if (!pGetPEStatsRspParams)
3888 goto end;
3889
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003890 node->fw_stats_set = 0;
Naveen Rawat3c49d192017-03-02 18:43:16 -08003891 if (node->stats_rsp) {
Jeff Johnsonadba3962017-09-18 08:12:35 -07003892 WMA_LOGD(FL("stats_rsp is not null, prev_value: %pK"),
Naveen Rawat3c49d192017-03-02 18:43:16 -08003893 node->stats_rsp);
3894 qdf_mem_free(node->stats_rsp);
3895 node->stats_rsp = NULL;
3896 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003897 node->stats_rsp = pGetPEStatsRspParams;
Will Huanga9814592017-05-24 15:47:58 +08003898 wma_handle->get_sta_peer_info = false;
Jeff Johnsonadba3962017-09-18 08:12:35 -07003899 WMA_LOGD("stats_rsp allocated: %pK, sta_id: %d, mask: %d, vdev_id: %d",
Naveen Rawat3c49d192017-03-02 18:43:16 -08003900 node->stats_rsp, node->stats_rsp->staId,
3901 node->stats_rsp->statsMask, get_stats_param->sessionId);
Govind Singh4863da42016-03-08 11:45:00 +05303902
Dustin Brown35619492017-10-03 15:16:12 -07003903 cmd.vdev_id = get_stats_param->sessionId;
3904 cmd.stats_id = get_stats_param->statsMask;
3905 if (wmi_unified_stats_request_send(wma_handle->wmi_handle,
3906 node->bssid,
3907 &cmd)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003908 WMA_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID",
3909 __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003910 goto failed;
3911 }
3912
3913 goto end;
3914failed:
Ganesh Kondabattini5bcc3e72017-05-17 15:20:31 +05303915 node->stats_rsp = NULL;
3916req_pending:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303917 pGetPEStatsRspParams->rc = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918 /* send response to UMAC */
3919 wma_send_msg(wma_handle, WMA_GET_STATISTICS_RSP, pGetPEStatsRspParams,
3920 0);
3921end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303922 qdf_mem_free(get_stats_param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923 WMA_LOGD("%s: Exit", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003924}
3925
3926/**
Padma, Santhosh Kumar16dacfb2017-03-21 19:05:40 +05303927 * wma_get_cca_stats() - send request to fw to get CCA
3928 * @wma_handle: wma handle
3929 * @vdev_id: vdev id
3930 *
3931 * Return: QDF status
3932 */
3933QDF_STATUS wma_get_cca_stats(tp_wma_handle wma_handle,
3934 uint8_t vdev_id)
3935{
3936 if (wmi_unified_congestion_request_cmd(wma_handle->wmi_handle,
3937 vdev_id)) {
3938 WMA_LOGE("Failed to congestion request to fw");
3939 return QDF_STATUS_E_FAILURE;
3940 }
3941 return QDF_STATUS_SUCCESS;
3942}
3943
3944/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003945 * wma_get_beacon_buffer_by_vdev_id() - get the beacon buffer from vdev ID
3946 * @vdev_id: vdev id
3947 * @buffer_size: size of buffer
3948 *
3949 * Return: none
3950 */
3951void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size)
3952{
3953 tp_wma_handle wma;
3954 struct beacon_info *beacon;
3955 uint8_t *buf;
3956 uint32_t buf_size;
3957
Anurag Chouhan6d760662016-02-20 16:05:43 +05303958 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003959 if (!wma) {
3960 WMA_LOGE("%s: Invalid WMA handle", __func__);
3961 return NULL;
3962 }
3963
3964 if (vdev_id >= wma->max_bssid) {
3965 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
3966 return NULL;
3967 }
3968
3969 if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) {
3970 WMA_LOGE("%s: vdevid %d is not in AP mode", __func__, vdev_id);
3971 return NULL;
3972 }
3973
3974 beacon = wma->interfaces[vdev_id].beacon;
3975
3976 if (!beacon) {
3977 WMA_LOGE("%s: beacon invalid", __func__);
3978 return NULL;
3979 }
3980
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303981 qdf_spin_lock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982
Nirav Shahcbc6d722016-03-01 16:24:53 +05303983 buf_size = qdf_nbuf_len(beacon->buf);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303984 buf = qdf_mem_malloc(buf_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003985
3986 if (!buf) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303987 qdf_spin_unlock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003988 WMA_LOGE("%s: alloc failed for beacon buf", __func__);
3989 return NULL;
3990 }
3991
Nirav Shahcbc6d722016-03-01 16:24:53 +05303992 qdf_mem_copy(buf, qdf_nbuf_data(beacon->buf), buf_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003993
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303994 qdf_spin_unlock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003995
3996 if (buffer_size)
3997 *buffer_size = buf_size;
3998
3999 return buf;
4000}
4001
4002/**
4003 * wma_get_vdev_address_by_vdev_id() - lookup MAC address from vdev ID
4004 * @vdev_id: vdev id
4005 *
4006 * Return: mac address
4007 */
4008uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id)
4009{
4010 tp_wma_handle wma;
4011
Anurag Chouhan6d760662016-02-20 16:05:43 +05304012 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004013 if (!wma) {
4014 WMA_LOGE("%s: Invalid WMA handle", __func__);
4015 return NULL;
4016 }
4017
4018 if (vdev_id >= wma->max_bssid) {
4019 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
4020 return NULL;
4021 }
4022
4023 return wma->interfaces[vdev_id].addr;
4024}
4025
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08004026QDF_STATUS wma_get_connection_info(uint8_t vdev_id,
4027 struct policy_mgr_vdev_entry_info *conn_table_entry)
4028{
4029 struct wma_txrx_node *wma_conn_table_entry;
4030
4031 wma_conn_table_entry = wma_get_interface_by_vdev_id(vdev_id);
4032 if (NULL == wma_conn_table_entry) {
4033 WMA_LOGE("%s: can't find vdev_id %d in WMA table", __func__, vdev_id);
4034 return QDF_STATUS_E_FAILURE;
4035 }
4036 conn_table_entry->chan_width = wma_conn_table_entry->chan_width;
4037 conn_table_entry->mac_id = wma_conn_table_entry->mac_id;
4038 conn_table_entry->mhz = wma_conn_table_entry->mhz;
4039 conn_table_entry->sub_type = wma_conn_table_entry->sub_type;
4040 conn_table_entry->type = wma_conn_table_entry->type;
4041
4042 return QDF_STATUS_SUCCESS;
4043}
4044
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004045/**
4046 * wma_get_interface_by_vdev_id() - lookup interface entry using vdev ID
4047 * @vdev_id: vdev id
4048 *
4049 * Return: entry from vdev table
4050 */
4051struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id)
4052{
4053 tp_wma_handle wma;
4054
Anurag Chouhan6d760662016-02-20 16:05:43 +05304055 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004056 if (!wma) {
4057 WMA_LOGE("%s: Invalid WMA handle", __func__);
4058 return NULL;
4059 }
4060
4061 if (vdev_id >= wma->max_bssid) {
4062 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
4063 return NULL;
4064 }
4065
4066 return &wma->interfaces[vdev_id];
4067}
4068
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004069#if defined(QCA_WIFI_FTM)
4070/**
4071 * wma_utf_rsp() - utf response
4072 * @wma_handle: wma handle
4073 * @payload: payload
4074 * @len: length of payload
4075 *
4076 * Return: 0 for success or error code
4077 */
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07004078static int wma_utf_rsp(tp_wma_handle wma_handle, uint8_t **payload,
4079 uint32_t *len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004080{
4081 int ret = -1;
4082 uint32_t payload_len;
4083
4084 payload_len = wma_handle->utf_event_info.length;
4085 if (payload_len) {
4086 ret = 0;
4087
4088 /*
4089 * The first 4 bytes holds the payload size
4090 * and the actual payload sits next to it
4091 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304092 *payload = (uint8_t *) qdf_mem_malloc((uint32_t) payload_len
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004093 + sizeof(A_UINT32));
4094 *(A_UINT32 *) &(*payload[0]) =
4095 wma_handle->utf_event_info.length;
4096 memcpy(*payload + sizeof(A_UINT32),
4097 wma_handle->utf_event_info.data, payload_len);
4098 wma_handle->utf_event_info.length = 0;
4099 *len = payload_len;
4100 }
4101
4102 return ret;
4103}
4104
4105/**
4106 * wma_post_ftm_response() - post ftm response to upper layer
4107 * @wma_handle: wma handle
4108 *
4109 * Return: none
4110 */
4111static void wma_post_ftm_response(tp_wma_handle wma_handle)
4112{
4113 int ret;
4114 uint8_t *payload;
4115 uint32_t data_len;
Rajeev Kumarb60abe42017-01-21 15:39:31 -08004116 struct scheduler_msg msg = { 0 };
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304117 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004118
4119 ret = wma_utf_rsp(wma_handle, &payload, &data_len);
4120
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004121 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004122 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004123
4124 sys_build_message_header(SYS_MSG_ID_FTM_RSP, &msg);
4125 msg.bodyptr = payload;
4126 msg.bodyval = 0;
4127
Rajeev Kumarb60abe42017-01-21 15:39:31 -08004128 status = scheduler_post_msg(QDF_MODULE_ID_SYS, &msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004129
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304130 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004131 WMA_LOGE("failed to post ftm response to SYS");
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304132 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004133 }
4134}
4135
4136/**
4137 * wma_process_utf_event() - process utf event
4138 * @handle: wma handle
4139 * @datap: data buffer
4140 * @dataplen: data length
4141 *
4142 * Return: 0 for success or error code
4143 */
4144static int
4145wma_process_utf_event(WMA_HANDLE handle, uint8_t *datap, uint32_t dataplen)
4146{
4147 tp_wma_handle wma_handle = (tp_wma_handle) handle;
Govind Singhd76a5b02016-03-08 15:12:14 +05304148 struct seg_hdr_info segHdrInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004149 uint8_t totalNumOfSegments, currentSeq;
4150 WMI_PDEV_UTF_EVENTID_param_tlvs *param_buf;
4151 uint8_t *data;
4152 uint32_t datalen;
4153
4154 param_buf = (WMI_PDEV_UTF_EVENTID_param_tlvs *) datap;
4155 if (!param_buf) {
4156 WMA_LOGE("Get NULL point message from FW");
4157 return -EINVAL;
4158 }
4159 data = param_buf->data;
4160 datalen = param_buf->num_data;
4161
Amar Singhal4aaa6c42017-10-03 09:48:02 -07004162 if (datalen < sizeof(segHdrInfo)) {
4163 WMA_LOGE("message size %d is smaller than struct seg_hdr_info",
4164 datalen);
4165 return -EINVAL;
4166 }
4167
Govind Singhd76a5b02016-03-08 15:12:14 +05304168 segHdrInfo = *(struct seg_hdr_info *) &(data[0]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004169
4170 wma_handle->utf_event_info.currentSeq = (segHdrInfo.segmentInfo & 0xF);
4171
4172 currentSeq = (segHdrInfo.segmentInfo & 0xF);
4173 totalNumOfSegments = (segHdrInfo.segmentInfo >> 4) & 0xF;
4174
4175 datalen = datalen - sizeof(segHdrInfo);
4176
4177 if (currentSeq == 0) {
4178 wma_handle->utf_event_info.expectedSeq = 0;
4179 wma_handle->utf_event_info.offset = 0;
4180 } else {
4181 if (wma_handle->utf_event_info.expectedSeq != currentSeq)
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004182 WMA_LOGE("Mismatch in expecting seq expected Seq %d got seq %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004183 wma_handle->utf_event_info.expectedSeq,
4184 currentSeq);
4185 }
4186
Varun Reddy Yeturud4c523d2017-09-26 15:28:42 -07004187 if ((datalen > MAX_UTF_EVENT_LENGTH) ||
4188 (wma_handle->utf_event_info.offset >
4189 (MAX_UTF_EVENT_LENGTH - datalen))) {
4190 WMA_LOGE("Excess data from firmware, offset:%zu, len:%d",
4191 wma_handle->utf_event_info.offset, datalen);
4192 return -EINVAL;
4193 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004194 memcpy(&wma_handle->utf_event_info.
4195 data[wma_handle->utf_event_info.offset],
4196 &data[sizeof(segHdrInfo)], datalen);
4197 wma_handle->utf_event_info.offset =
4198 wma_handle->utf_event_info.offset + datalen;
4199 wma_handle->utf_event_info.expectedSeq++;
4200
4201 if (wma_handle->utf_event_info.expectedSeq == totalNumOfSegments) {
4202 if (wma_handle->utf_event_info.offset != segHdrInfo.len)
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004203 WMA_LOGE("All segs received total len mismatch.. len %zu total len %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004204 wma_handle->utf_event_info.offset,
4205 segHdrInfo.len);
4206
4207 wma_handle->utf_event_info.length =
4208 wma_handle->utf_event_info.offset;
4209 }
4210
4211 wma_post_ftm_response(wma_handle);
4212
4213 return 0;
4214}
4215
4216/**
4217 * wma_utf_detach() - utf detach
4218 * @wma_handle: wma handle
4219 *
4220 * Return: none
4221 */
4222void wma_utf_detach(tp_wma_handle wma_handle)
4223{
4224 if (wma_handle->utf_event_info.data) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304225 qdf_mem_free(wma_handle->utf_event_info.data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004226 wma_handle->utf_event_info.data = NULL;
4227 wma_handle->utf_event_info.length = 0;
4228 wmi_unified_unregister_event_handler(wma_handle->wmi_handle,
4229 WMI_PDEV_UTF_EVENTID);
4230 }
4231}
4232
4233/**
4234 * wma_utf_attach() - utf attach
4235 * @wma_handle: wma handle
4236 *
4237 * Return: none
4238 */
4239void wma_utf_attach(tp_wma_handle wma_handle)
4240{
4241 int ret;
4242
4243 wma_handle->utf_event_info.data = (unsigned char *)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304244 qdf_mem_malloc(MAX_UTF_EVENT_LENGTH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004245 wma_handle->utf_event_info.length = 0;
4246
4247 ret = wmi_unified_register_event_handler(wma_handle->wmi_handle,
4248 WMI_PDEV_UTF_EVENTID,
Govind Singhd76a5b02016-03-08 15:12:14 +05304249 wma_process_utf_event,
4250 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251
4252 if (ret)
Srinivas Girigowdad1a07a52017-03-06 22:48:16 -08004253 WMA_LOGE("%s: Failed to register UTF event callback", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254}
4255
4256/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257 * wma_utf_cmd() - utf command
4258 * @wma_handle: wma handle
4259 * @data: data
4260 * @len: length
4261 *
Govind Singhd76a5b02016-03-08 15:12:14 +05304262 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004263 */
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07004264static QDF_STATUS wma_utf_cmd(tp_wma_handle wma_handle, uint8_t *data,
4265 uint16_t len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004266{
Govind Singhd76a5b02016-03-08 15:12:14 +05304267 struct pdev_utf_params param = {0};
4268
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004269 wma_handle->utf_event_info.length = 0;
Govind Singhd76a5b02016-03-08 15:12:14 +05304270 param.utf_payload = data;
4271 param.len = len;
4272
4273 return wmi_unified_pdev_utf_cmd_send(wma_handle->wmi_handle, &param,
4274 WMA_WILDCARD_PDEV_ID);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004275}
4276
4277/**
4278 * wma_process_ftm_command() - process ftm command
4279 * @wma_handle: wma handle
4280 * @msg_buffer: message buffer
4281 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304282 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004283 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304284QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004285wma_process_ftm_command(tp_wma_handle wma_handle,
4286 struct ar6k_testmode_cmd_data *msg_buffer)
4287{
4288 uint8_t *data = NULL;
4289 uint16_t len = 0;
4290 int ret;
4291
4292 if (!msg_buffer)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304293 return QDF_STATUS_E_INVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004294
Anurag Chouhan6d760662016-02-20 16:05:43 +05304295 if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004296 WMA_LOGE("FTM command issued in non-FTM mode");
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304297 qdf_mem_free(msg_buffer->data);
4298 qdf_mem_free(msg_buffer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304299 return QDF_STATUS_E_NOSUPPORT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004300 }
4301
4302 data = msg_buffer->data;
4303 len = msg_buffer->len;
4304
4305 ret = wma_utf_cmd(wma_handle, data, len);
4306
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304307 qdf_mem_free(msg_buffer->data);
4308 qdf_mem_free(msg_buffer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004309
4310 if (ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304311 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004312
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304313 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004314}
4315#endif /* QCA_WIFI_FTM */
4316
Jeff Johnsonabb74042017-08-31 11:44:55 -07004317QDF_STATUS wma_get_wcnss_software_version(uint8_t *version,
4318 uint32_t version_buffer_size)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004319{
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004320 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004321
4322 if (NULL == wma_handle) {
4323 WMA_LOGE("%s: Failed to get wma", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304324 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004325 }
4326
Jeff Johnsonabb74042017-08-31 11:44:55 -07004327 snprintf(version, version_buffer_size, "%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004328 (unsigned int)wma_handle->target_fw_version);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304329 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004330}
4331
Aravind Narasimhan5b7c2cd2016-12-08 21:04:26 -08004332/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004333 * wma_get_mac_id_of_vdev() - Get MAC id corresponding to a vdev
4334 * @vdev_id: VDEV whose MAC ID is required
4335 *
4336 * Get MAC id corresponding to a vdev id from the WMA structure
4337 *
4338 * Return: Negative value on failure and MAC id on success
4339 */
4340int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id)
4341{
4342 tp_wma_handle wma;
4343
Anurag Chouhan6d760662016-02-20 16:05:43 +05304344 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004345 if (!wma) {
4346 WMA_LOGE("%s: Invalid WMA handle", __func__);
4347 return -EINVAL;
4348 }
4349
4350 if (wma->interfaces)
4351 return wma->interfaces[vdev_id].mac_id;
4352
4353 return -EINVAL;
4354}
4355
4356/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004357 * wma_update_intf_hw_mode_params() - Update WMA params
4358 * @vdev_id: VDEV id whose params needs to be updated
4359 * @mac_id: MAC id to be updated
4360 * @cfgd_hw_mode_index: HW mode index from which Tx and Rx SS will be updated
4361 *
4362 * Updates the MAC id, tx spatial stream, rx spatial stream in WMA
4363 *
4364 * Return: None
4365 */
4366void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id,
4367 uint32_t cfgd_hw_mode_index)
4368{
4369 tp_wma_handle wma;
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08004370 uint32_t param;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004371
Anurag Chouhan6d760662016-02-20 16:05:43 +05304372 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004373 if (!wma) {
4374 WMA_LOGE("%s: Invalid WMA handle", __func__);
4375 return;
4376 }
4377
4378 if (!wma->interfaces) {
4379 WMA_LOGE("%s: Interface is NULL", __func__);
4380 return;
4381 }
4382
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08004383 if (cfgd_hw_mode_index > wma->num_dbs_hw_modes) {
4384 WMA_LOGE("%s: Invalid index", __func__);
4385 return;
4386 }
4387
4388 param = wma->hw_mode.hw_mode_list[cfgd_hw_mode_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004389 wma->interfaces[vdev_id].mac_id = mac_id;
4390 if (mac_id == 0) {
4391 wma->interfaces[vdev_id].tx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05304392 WMA_HW_MODE_MAC0_TX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004393 wma->interfaces[vdev_id].rx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05304394 WMA_HW_MODE_MAC0_RX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004395 } else {
4396 wma->interfaces[vdev_id].tx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05304397 WMA_HW_MODE_MAC1_TX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004398 wma->interfaces[vdev_id].rx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05304399 WMA_HW_MODE_MAC1_RX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004400 }
4401}
4402
4403/**
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08004404 * wma_get_vht_ch_width - return vht channel width
4405 *
4406 * Return: return vht channel width
4407 */
4408uint32_t wma_get_vht_ch_width(void)
4409{
4410 uint32_t fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ;
Anurag Chouhan6d760662016-02-20 16:05:43 +05304411 tp_wma_handle wm_hdl = cds_get_context(QDF_MODULE_ID_WMA);
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08004412
4413 if (NULL == wm_hdl)
4414 return fw_ch_wd;
4415
Kiran Kumar Lokere02b9aa42016-05-26 14:54:49 -07004416 if (wm_hdl->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ)
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08004417 fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ;
Kiran Kumar Lokere02b9aa42016-05-26 14:54:49 -07004418 else if (wm_hdl->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_160MHZ)
4419 fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ;
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08004420
4421 return fw_ch_wd;
4422}
Govind Singhd76a5b02016-03-08 15:12:14 +05304423
4424/**
Krunal Soniaa664da2016-06-15 23:46:40 -07004425 * wma_get_num_of_setbits_from_bitmask() - to get num of setbits from bitmask
4426 * @mask: given bitmask
4427 *
4428 * This helper function should return number of setbits from bitmask
4429 *
4430 * Return: number of setbits from bitmask
4431 */
4432uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask)
4433{
4434 uint32_t num_of_setbits = 0;
4435
4436 while (mask) {
4437 mask &= (mask - 1);
4438 num_of_setbits++;
4439 }
4440 return num_of_setbits;
4441}
4442
4443/**
Kiran Kumar Lokered0fad462017-06-13 18:23:48 -07004444 * wma_is_csa_offload_enabled - checks fw CSA offload capability
4445 *
4446 * Return: true or false
4447 */
4448
4449bool wma_is_csa_offload_enabled(void)
4450{
4451 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4452
4453 if (!wma)
4454 return false;
4455
4456 return WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
4457 WMI_SERVICE_CSA_OFFLOAD);
4458}
4459/**
Govind Singhd76a5b02016-03-08 15:12:14 +05304460 * wma_config_debug_module_cmd - set debug log config
4461 * @wmi_handle: wmi layer handle
4462 * @param: debug log parameter
4463 * @val: debug log value
4464 * @module_id_bitmap: debug module id bitmap
4465 * @bitmap_len: debug module bitmap length
4466 *
4467 * Return: QDF_STATUS_SUCCESS for success or error code
4468 */
4469QDF_STATUS
4470wma_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param,
4471 A_UINT32 val, A_UINT32 *module_id_bitmap,
4472 A_UINT32 bitmap_len)
4473{
4474 struct dbglog_params dbg_param;
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004475
Govind Singhd76a5b02016-03-08 15:12:14 +05304476 dbg_param.param = param;
4477 dbg_param.val = val;
4478 dbg_param.module_id_bitmap = module_id_bitmap;
4479 dbg_param.bitmap_len = bitmap_len;
4480
4481 return wmi_unified_dbglog_cmd_send(wmi_handle, &dbg_param);
4482}
Peng Xu8fdaa492016-06-22 10:20:47 -07004483
4484/**
4485 * wma_is_p2p_lo_capable() - if driver is capable of p2p listen offload
4486 *
4487 * This function checks if driver is capable of p2p listen offload
4488 * true: capable of p2p offload
4489 * false: not capable
4490 *
4491 * Return: true - capable, false - not capable
4492 */
4493bool wma_is_p2p_lo_capable(void)
4494{
Dustin Brown8d8d9fe2017-07-18 16:01:25 -07004495 return wma_is_service_enabled(WMI_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT);
Peng Xu8fdaa492016-06-22 10:20:47 -07004496}
Aravind Narasimhan5b7c2cd2016-12-08 21:04:26 -08004497
Dustin Brown8d8d9fe2017-07-18 16:01:25 -07004498bool wma_capability_enhanced_mcast_filter(void)
4499{
4500 return wma_is_service_enabled(WMI_SERVICE_ENHANCED_MCAST_FILTER);
4501}
4502
4503
Mukul Sharmaf9047232017-03-02 16:58:56 +05304504bool wma_is_vdev_up(uint8_t vdev_id)
4505{
4506 struct wlan_objmgr_vdev *vdev;
4507 tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA);
4508 enum wlan_vdev_state state = WLAN_VDEV_S_INIT;
4509
4510 if (!wma) {
4511 WMA_LOGE("%s: WMA context is invald!", __func__);
4512 return false;
4513 }
4514
4515 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id,
4516 WLAN_LEGACY_WMA_ID);
4517 if (vdev) {
4518 wlan_vdev_obj_lock(vdev);
4519 state = wlan_vdev_mlme_get_state(vdev);
4520 wlan_vdev_obj_unlock(vdev);
4521 wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID);
4522 }
Mukul Sharmaf9047232017-03-02 16:58:56 +05304523 return (state == WLAN_VDEV_S_RUN) ? true : false;
4524}
4525
Dustin Brownec2c92e2017-07-26 11:13:49 -07004526void wma_acquire_wakelock(qdf_wake_lock_t *wl, uint32_t msec)
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004527{
Dustin Brownec2c92e2017-07-26 11:13:49 -07004528 t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA);
4529
4530 cds_host_diag_log_work(wl, msec, WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
4531 qdf_wake_lock_timeout_acquire(wl, msec);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -08004532 qdf_runtime_pm_prevent_suspend(&wma->wmi_cmd_rsp_runtime_lock);
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004533}
4534
Dustin Brownec2c92e2017-07-26 11:13:49 -07004535void wma_release_wakelock(qdf_wake_lock_t *wl)
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004536{
Dustin Brownec2c92e2017-07-26 11:13:49 -07004537 t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA);
4538
4539 qdf_wake_lock_release(wl, WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -08004540 qdf_runtime_pm_allow_suspend(&wma->wmi_cmd_rsp_runtime_lock);
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004541}
4542
Dustin Brownd5f12942017-03-10 11:06:25 -08004543QDF_STATUS
4544wma_send_vdev_start_to_fw(t_wma_handle *wma, struct vdev_start_params *params)
4545{
4546 QDF_STATUS status;
Dustin Brownec2c92e2017-07-26 11:13:49 -07004547 struct wma_txrx_node *vdev = &wma->interfaces[params->vdev_id];
Dustin Brownd5f12942017-03-10 11:06:25 -08004548
Dustin Brownec2c92e2017-07-26 11:13:49 -07004549 wma_acquire_wakelock(&vdev->vdev_start_wakelock,
4550 WMA_VDEV_START_REQUEST_TIMEOUT);
Dustin Brownd5f12942017-03-10 11:06:25 -08004551 status = wmi_unified_vdev_start_send(wma->wmi_handle, params);
4552 if (QDF_IS_STATUS_ERROR(status))
Dustin Brownec2c92e2017-07-26 11:13:49 -07004553 wma_release_wakelock(&vdev->vdev_start_wakelock);
Dustin Brownd5f12942017-03-10 11:06:25 -08004554
4555 return status;
4556}
4557
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004558QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id)
4559{
4560 QDF_STATUS status;
Dustin Brownec2c92e2017-07-26 11:13:49 -07004561 struct wma_txrx_node *vdev = &wma->interfaces[vdev_id];
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004562
Dustin Brownec2c92e2017-07-26 11:13:49 -07004563 wma_acquire_wakelock(&vdev->vdev_stop_wakelock,
4564 WMA_VDEV_STOP_REQUEST_TIMEOUT);
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004565 status = wmi_unified_vdev_stop_send(wma->wmi_handle, vdev_id);
4566 if (QDF_IS_STATUS_ERROR(status))
Dustin Brownec2c92e2017-07-26 11:13:49 -07004567 wma_release_wakelock(&vdev->vdev_stop_wakelock);
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004568
4569 return status;
4570}
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08004571
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05304572QDF_STATUS wma_get_rcpi_req(WMA_HANDLE handle,
4573 struct sme_rcpi_req *rcpi_request)
4574{
4575 tp_wma_handle wma_handle = (tp_wma_handle) handle;
4576 struct rcpi_req cmd = {0};
4577 struct wma_txrx_node *iface;
4578 struct sme_rcpi_req *node_rcpi_req;
4579
4580 WMA_LOGD("%s: Enter", __func__);
4581 iface = &wma_handle->interfaces[rcpi_request->session_id];
4582 /* command is in progress */
4583 if (iface->rcpi_req != NULL) {
4584 WMA_LOGE("%s : previous rcpi request is pending", __func__);
4585 return QDF_STATUS_SUCCESS;
4586 }
4587
4588 node_rcpi_req = qdf_mem_malloc(sizeof(*node_rcpi_req));
4589 if (!node_rcpi_req) {
4590 WMA_LOGE("Failed to allocate memory for rcpi_request");
4591 return QDF_STATUS_E_NOMEM;
4592 }
4593
4594 *node_rcpi_req = *rcpi_request;
4595 iface->rcpi_req = node_rcpi_req;
4596
4597 cmd.vdev_id = rcpi_request->session_id;
4598 qdf_mem_copy(cmd.mac_addr, &rcpi_request->mac_addr, QDF_MAC_ADDR_SIZE);
4599
4600 switch (rcpi_request->measurement_type) {
4601
4602 case RCPI_MEASUREMENT_TYPE_AVG_MGMT:
4603 cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_AVG_MGMT;
4604 break;
4605
4606 case RCPI_MEASUREMENT_TYPE_AVG_DATA:
4607 cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_AVG_DATA;
4608 break;
4609
4610 case RCPI_MEASUREMENT_TYPE_LAST_MGMT:
4611 cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_LAST_MGMT;
4612 break;
4613
4614 case RCPI_MEASUREMENT_TYPE_LAST_DATA:
4615 cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_LAST_DATA;
4616 break;
4617
4618 default:
4619 /*
4620 * invalid rcpi measurement type, fall back to
4621 * RCPI_MEASUREMENT_TYPE_AVG_MGMT
4622 */
4623 cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_AVG_MGMT;
4624 break;
4625 }
4626
4627 if (wmi_unified_send_request_get_rcpi_cmd(wma_handle->wmi_handle,
4628 &cmd)) {
4629 WMA_LOGE("%s: Failed to send WMI_REQUEST_RCPI_CMDID",
4630 __func__);
4631 iface->rcpi_req = NULL;
4632 qdf_mem_free(node_rcpi_req);
4633 return QDF_STATUS_E_FAILURE;
4634 }
4635
4636 WMA_LOGD("%s: Exit", __func__);
4637
4638 return QDF_STATUS_SUCCESS;
4639}
4640
4641int wma_rcpi_event_handler(void *handle, uint8_t *cmd_param_info,
4642 uint32_t len)
4643{
4644 struct rcpi_res res = {0};
4645 struct sme_rcpi_req *rcpi_req;
4646 struct qdf_mac_addr qdf_mac;
4647 struct wma_txrx_node *iface;
4648 QDF_STATUS status = QDF_STATUS_SUCCESS;
4649 tp_wma_handle wma_handle = (tp_wma_handle)handle;
4650
4651 status = wmi_extract_rcpi_response_event(wma_handle->wmi_handle,
4652 cmd_param_info, &res);
4653 if (status == QDF_STATUS_E_INVAL)
4654 return -EINVAL;
4655
4656 iface = &wma_handle->interfaces[res.vdev_id];
4657 if (!iface->rcpi_req) {
4658 WMI_LOGE("rcpi_req buffer not available");
4659 return 0;
4660 }
4661
4662 rcpi_req = iface->rcpi_req;
4663 if (!rcpi_req->rcpi_callback) {
4664 iface->rcpi_req = NULL;
4665 qdf_mem_free(rcpi_req);
4666 return 0;
4667 }
4668
4669 if ((res.measurement_type == RCPI_MEASUREMENT_TYPE_INVALID) ||
4670 (res.vdev_id != rcpi_req->session_id) ||
4671 (res.measurement_type != rcpi_req->measurement_type) ||
4672 (qdf_mem_cmp(res.mac_addr, &rcpi_req->mac_addr,
4673 QDF_MAC_ADDR_SIZE))) {
4674 WMI_LOGE("invalid rcpi_response");
4675 iface->rcpi_req = NULL;
4676 qdf_mem_free(rcpi_req);
4677 return 0;
4678 }
4679
4680 qdf_mem_copy(&qdf_mac, res.mac_addr, QDF_MAC_ADDR_SIZE);
4681 (rcpi_req->rcpi_callback)(rcpi_req->rcpi_context, qdf_mac,
4682 res.rcpi_value, status);
4683 iface->rcpi_req = NULL;
4684 qdf_mem_free(rcpi_req);
4685
4686 return 0;
4687}
4688
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08004689bool wma_is_service_enabled(WMI_SERVICE service_type)
4690{
4691 tp_wma_handle wma;
Srinivas Girigowda4d65ebe2017-10-13 21:41:42 -07004692
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08004693 wma = cds_get_context(QDF_MODULE_ID_WMA);
4694 if (!wma) {
4695 WMA_LOGE("%s: Invalid WMA handle", __func__);
4696 return false;
4697 }
4698
4699 return WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, service_type);
4700}
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08004701
Dustin Brownec2c92e2017-07-26 11:13:49 -07004702QDF_STATUS wma_send_vdev_up_to_fw(t_wma_handle *wma,
4703 struct vdev_up_params *params,
4704 uint8_t bssid[IEEE80211_ADDR_LEN])
4705{
4706 QDF_STATUS status;
4707 struct wma_txrx_node *vdev = &wma->interfaces[params->vdev_id];
4708
Varun Reddy Yeturu5303e082017-10-24 14:20:00 -07004709 if (wma_is_vdev_up(params->vdev_id)) {
4710 WMA_LOGD("vdev %d is already up for bssid %pM. Do not send",
4711 params->vdev_id, bssid);
4712 return QDF_STATUS_SUCCESS;
4713 }
Dustin Brownec2c92e2017-07-26 11:13:49 -07004714 status = wmi_unified_vdev_up_send(wma->wmi_handle, bssid, params);
4715 wma_release_wakelock(&vdev->vdev_start_wakelock);
4716
4717 return status;
4718}
4719
4720QDF_STATUS wma_send_vdev_down_to_fw(t_wma_handle *wma, uint8_t vdev_id)
4721{
4722 QDF_STATUS status;
4723 struct wma_txrx_node *vdev = &wma->interfaces[vdev_id];
4724
4725 status = wmi_unified_vdev_down_send(wma->wmi_handle, vdev_id);
4726 wma_release_wakelock(&vdev->vdev_start_wakelock);
4727
4728 return status;
4729}
4730
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08004731tSirWifiPeerType wmi_to_sir_peer_type(enum wmi_peer_type type)
4732{
4733 switch (type) {
4734 case WMI_PEER_TYPE_DEFAULT:
4735 return WIFI_PEER_STA;
4736 case WMI_PEER_TYPE_BSS:
4737 return WIFI_PEER_AP;
4738 case WMI_PEER_TYPE_TDLS:
4739 return WIFI_PEER_TDLS;
4740 case WMI_PEER_TYPE_NAN_DATA:
4741 return WIFI_PEER_NAN;
4742 default:
4743 WMA_LOGE("Cannot map wmi_peer_type %d to HAL peer type", type);
4744 return WIFI_PEER_INVALID;
4745 }
4746}
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05304747
Nachiket Kukade8983cf62017-10-12 18:14:48 +05304748/**
4749 * wma_set_vc_mode_config() - set voltage corner mode config to FW.
4750 * @wma_handle: pointer to wma handle.
4751 * @vc_bitmap: value needs to set to firmware.
4752 *
4753 * At the time of driver startup, set operating voltage corner mode
4754 * for differenet phymode and bw configurations.
4755 *
4756 * Return: QDF_STATUS.
4757 */
4758QDF_STATUS wma_set_vc_mode_config(void *wma_handle,
4759 uint32_t vc_bitmap)
4760{
4761 int32_t ret;
4762 tp_wma_handle wma = (tp_wma_handle)wma_handle;
4763 struct pdev_params pdevparam;
4764
4765 pdevparam.param_id = WMI_PDEV_UPDATE_WDCVS_ALGO;
4766 pdevparam.param_value = vc_bitmap;
4767
4768 ret = wmi_unified_pdev_param_send(wma->wmi_handle,
4769 &pdevparam,
4770 WMA_WILDCARD_PDEV_ID);
4771 if (ret) {
4772 WMA_LOGE("Fail to Set Voltage Corner config (0x%x)",
4773 vc_bitmap);
4774 return QDF_STATUS_E_FAILURE;
4775 }
4776
4777 WMA_LOGD("Successfully Set Voltage Corner config (0x%x)",
4778 vc_bitmap);
4779
4780 return QDF_STATUS_SUCCESS;
4781}
4782
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05304783int wma_chip_power_save_failure_detected_handler(void *handle,
4784 uint8_t *cmd_param_info,
4785 uint32_t len)
4786{
4787 tp_wma_handle wma = (tp_wma_handle)handle;
4788 WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *param_buf;
4789 wmi_chip_power_save_failure_detected_fixed_param *event;
4790 struct chip_pwr_save_fail_detected_params pwr_save_fail_params;
4791 tpAniSirGlobal mac = (tpAniSirGlobal)cds_get_context(
4792 QDF_MODULE_ID_PE);
4793 if (wma == NULL) {
4794 WMA_LOGE("%s: wma_handle is NULL", __func__);
4795 return -EINVAL;
4796 }
4797 if (!mac) {
4798 WMA_LOGE("%s: Invalid mac context", __func__);
4799 return -EINVAL;
4800 }
4801 if (!mac->sme.chip_power_save_fail_cb) {
4802 WMA_LOGE("%s: Callback not registered", __func__);
4803 return -EINVAL;
4804 }
4805
4806 param_buf =
4807 (WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *)
4808 cmd_param_info;
4809 if (!param_buf) {
4810 WMA_LOGE("%s: Invalid pwr_save_fail_params breached event",
4811 __func__);
4812 return -EINVAL;
4813 }
4814 event = param_buf->fixed_param;
4815 pwr_save_fail_params.failure_reason_code =
4816 event->power_save_failure_reason_code;
4817 pwr_save_fail_params.wake_lock_bitmap[0] =
4818 event->protocol_wake_lock_bitmap[0];
4819 pwr_save_fail_params.wake_lock_bitmap[1] =
4820 event->protocol_wake_lock_bitmap[1];
4821 pwr_save_fail_params.wake_lock_bitmap[2] =
4822 event->protocol_wake_lock_bitmap[2];
4823 pwr_save_fail_params.wake_lock_bitmap[3] =
4824 event->protocol_wake_lock_bitmap[3];
4825 mac->sme.chip_power_save_fail_cb(mac->hHdd,
4826 &pwr_save_fail_params);
4827
4828 WMA_LOGD("%s: Invoke HDD pwr_save_fail callback", __func__);
4829 return 0;
4830}