blob: 6722136f90ffb4ddb4035d6b52c92a94df4980dd [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 }
770 if (peer_num > (WMI_SVC_MSG_MAX_SIZE /
771 (sizeof(struct sir_wifi_ll_ext_peer_stats) +
772 total_peer_len))) {
773 excess_data = true;
774 break;
775 } else {
776 buf_len += peer_num *
777 (sizeof(struct sir_wifi_ll_ext_peer_stats) +
778 total_peer_len);
779 }
780 } while (0);
781
782 if (excess_data || (buf_len > WMI_SVC_MSG_MAX_SIZE)) {
783 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",
784 __func__, peer_num, fixed_param->num_chan_cca_stats,
785 fixed_param->tx_mpdu_aggr_array_len,
786 fixed_param->tx_succ_mcs_array_len,
787 fixed_param->tx_fail_mcs_array_len,
788 fixed_param->tx_ppdu_delay_array_len,
789 fixed_param->rx_mpdu_aggr_array_len,
790 fixed_param->rx_mcs_array_len);
Vignesh Viswanathan9f090ad2017-09-27 20:33:55 +0530791 return NULL;
792 }
Zhang Qian73c348a2017-03-13 16:15:55 +0800793
794 buf = (tSirLLStatsResults *)qdf_mem_malloc(buf_len);
795 if (buf == NULL) {
796 WMA_LOGE("%s: Cannot allocate link layer stats.", __func__);
797 buf_len = 0;
798 return NULL;
799 }
800
801 *len = buf_len;
802 return buf;
803}
804
805/**
806 * wma_fill_tx_stats() - Fix TX stats into result buffer
807 * @ll_stats: LL stats buffer
808 * @fix_param: parameters with fixed length in WMI event
809 * @param_buf: parameters without fixed length in WMI event
810 * @buf: buffer for TLV parameters
811 *
812 * Return: None
813 */
814static void wma_fill_tx_stats(struct sir_wifi_ll_ext_stats *ll_stats,
815 wmi_report_stats_event_fixed_param *fix_param,
816 WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf,
817 uint8_t **buf, uint32_t *buf_length)
818{
819 uint8_t *result;
820 uint32_t i, j, k;
821 wmi_peer_ac_tx_stats *wmi_peer_tx;
822 wmi_tx_stats *wmi_tx;
823 struct sir_wifi_tx *tx_stats;
824 struct sir_wifi_ll_ext_peer_stats *peer_stats;
825 uint32_t *tx_mpdu_aggr, *tx_succ_mcs, *tx_fail_mcs, *tx_delay;
826 uint32_t len, dst_len, tx_mpdu_aggr_array_len, tx_succ_mcs_array_len,
827 tx_fail_mcs_array_len, tx_delay_array_len;
828
829 result = *buf;
830 dst_len = *buf_length;
831 tx_mpdu_aggr_array_len = fix_param->tx_mpdu_aggr_array_len;
832 ll_stats->tx_mpdu_aggr_array_len = tx_mpdu_aggr_array_len;
833 tx_succ_mcs_array_len = fix_param->tx_succ_mcs_array_len;
834 ll_stats->tx_succ_mcs_array_len = tx_succ_mcs_array_len;
835 tx_fail_mcs_array_len = fix_param->tx_fail_mcs_array_len;
836 ll_stats->tx_fail_mcs_array_len = tx_fail_mcs_array_len;
837 tx_delay_array_len = fix_param->tx_ppdu_delay_array_len;
838 ll_stats->tx_delay_array_len = tx_delay_array_len;
839 wmi_peer_tx = param_buf->peer_ac_tx_stats;
840 wmi_tx = param_buf->tx_stats;
841
842 len = fix_param->num_peer_ac_tx_stats *
843 WLAN_MAX_AC * tx_mpdu_aggr_array_len * sizeof(uint32_t);
844 if (len <= dst_len) {
845 tx_mpdu_aggr = (uint32_t *)result;
846 qdf_mem_copy(tx_mpdu_aggr, param_buf->tx_mpdu_aggr, len);
847 result += len;
848 dst_len -= len;
849 } else {
850 WMA_LOGE(FL("TX_MPDU_AGGR buffer length is wrong."));
851 tx_mpdu_aggr = NULL;
852 }
853
854 len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC *
855 tx_succ_mcs_array_len * sizeof(uint32_t);
856 if (len <= dst_len) {
857 tx_succ_mcs = (uint32_t *)result;
858 qdf_mem_copy(tx_succ_mcs, param_buf->tx_succ_mcs, len);
859 result += len;
860 dst_len -= len;
861 } else {
862 WMA_LOGE(FL("TX_SUCC_MCS buffer length is wrong."));
863 tx_succ_mcs = NULL;
864 }
865
866 len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC *
867 tx_fail_mcs_array_len * sizeof(uint32_t);
868 if (len <= dst_len) {
869 tx_fail_mcs = (uint32_t *)result;
870 qdf_mem_copy(tx_fail_mcs, param_buf->tx_fail_mcs, len);
871 result += len;
872 dst_len -= len;
873 } else {
874 WMA_LOGE(FL("TX_FAIL_MCS buffer length is wrong."));
875 tx_fail_mcs = NULL;
876 }
877
878 len = fix_param->num_peer_ac_tx_stats *
879 WLAN_MAX_AC * tx_delay_array_len * sizeof(uint32_t);
880 if (len <= dst_len) {
881 tx_delay = (uint32_t *)result;
882 qdf_mem_copy(tx_delay, param_buf->tx_ppdu_delay, len);
883 result += len;
884 dst_len -= len;
885 } else {
886 WMA_LOGE(FL("TX_DELAY buffer length is wrong."));
887 tx_delay = NULL;
888 }
889
890 /* per peer tx stats */
891 peer_stats = ll_stats->peer_stats;
892
893 for (i = 0; i < fix_param->num_peer_ac_tx_stats; i++) {
894 uint32_t peer_id = wmi_peer_tx[i].peer_id;
895 struct sir_wifi_tx *ac;
896 wmi_tx_stats *wmi_tx_stats;
897
898 for (j = 0; j < ll_stats->peer_num; j++) {
899 peer_stats += j;
900 if (peer_stats->peer_id == WIFI_INVALID_PEER_ID ||
901 peer_stats->peer_id == peer_id)
902 break;
903 }
904
905 if (j < ll_stats->peer_num) {
906 peer_stats->peer_id = wmi_peer_tx[i].peer_id;
907 peer_stats->vdev_id = wmi_peer_tx[i].vdev_id;
908 tx_stats = (struct sir_wifi_tx *)result;
909 for (k = 0; k < WLAN_MAX_AC; k++) {
910 wmi_tx_stats = &wmi_tx[i * WLAN_MAX_AC + k];
911 ac = &tx_stats[k];
912 WMA_FILL_TX_STATS(wmi_tx_stats, ac);
913 ac->mpdu_aggr_size = tx_mpdu_aggr;
914 ac->aggr_len = tx_mpdu_aggr_array_len *
915 sizeof(uint32_t);
916 ac->success_mcs_len = tx_succ_mcs_array_len *
917 sizeof(uint32_t);
918 ac->success_mcs = tx_succ_mcs;
919 ac->fail_mcs = tx_fail_mcs;
920 ac->fail_mcs_len = tx_fail_mcs_array_len *
921 sizeof(uint32_t);
922 ac->delay = tx_delay;
923 ac->delay_len = tx_delay_array_len *
924 sizeof(uint32_t);
925 peer_stats->ac_stats[k].tx_stats = ac;
926 peer_stats->ac_stats[k].type = k;
927 tx_mpdu_aggr += tx_mpdu_aggr_array_len;
928 tx_succ_mcs += tx_succ_mcs_array_len;
929 tx_fail_mcs += tx_fail_mcs_array_len;
930 tx_delay += tx_delay_array_len;
931 }
932 result += WLAN_MAX_AC * sizeof(struct sir_wifi_tx);
933 } else {
934 /*
935 * Buffer for Peer TX counter overflow.
936 * There is peer ID mismatch between TX, RX,
937 * signal counters.
938 */
939 WMA_LOGE(FL("One peer TX info is dropped."));
940
941 tx_mpdu_aggr += tx_mpdu_aggr_array_len * WLAN_MAX_AC;
942 tx_succ_mcs += tx_succ_mcs_array_len * WLAN_MAX_AC;
943 tx_fail_mcs += tx_fail_mcs_array_len * WLAN_MAX_AC;
944 tx_delay += tx_delay_array_len * WLAN_MAX_AC;
945 }
946 }
947 *buf = result;
948 *buf_length = dst_len;
949}
950
951/**
952 * wma_fill_rx_stats() - Fix RX stats into result buffer
953 * @ll_stats: LL stats buffer
954 * @fix_param: parameters with fixed length in WMI event
955 * @param_buf: parameters without fixed length in WMI event
956 * @buf: buffer for TLV parameters
957 *
958 * Return: None
959 */
960static void wma_fill_rx_stats(struct sir_wifi_ll_ext_stats *ll_stats,
961 wmi_report_stats_event_fixed_param *fix_param,
962 WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf,
963 uint8_t **buf, uint32_t *buf_length)
964{
965 uint8_t *result;
966 uint32_t i, j, k;
967 uint32_t *rx_mpdu_aggr, *rx_mcs;
968 wmi_rx_stats *wmi_rx;
969 wmi_peer_ac_rx_stats *wmi_peer_rx;
970 struct sir_wifi_rx *rx_stats;
971 struct sir_wifi_ll_ext_peer_stats *peer_stats;
972 uint32_t len, dst_len, rx_mpdu_aggr_array_len, rx_mcs_array_len;
973
974 rx_mpdu_aggr_array_len = fix_param->rx_mpdu_aggr_array_len;
975 ll_stats->rx_mpdu_aggr_array_len = rx_mpdu_aggr_array_len;
976 rx_mcs_array_len = fix_param->rx_mcs_array_len;
977 ll_stats->rx_mcs_array_len = rx_mcs_array_len;
978 wmi_peer_rx = param_buf->peer_ac_rx_stats;
979 wmi_rx = param_buf->rx_stats;
980
981 result = *buf;
982 dst_len = *buf_length;
983 len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats *
984 WLAN_MAX_AC * rx_mpdu_aggr_array_len);
985 if (len <= dst_len) {
986 rx_mpdu_aggr = (uint32_t *)result;
987 qdf_mem_copy(rx_mpdu_aggr, param_buf->rx_mpdu_aggr, len);
988 result += len;
989 dst_len -= len;
990 } else {
991 WMA_LOGE(FL("RX_MPDU_AGGR array length is wrong."));
992 rx_mpdu_aggr = NULL;
993 }
994
995 len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats *
996 WLAN_MAX_AC * rx_mcs_array_len);
997 if (len <= dst_len) {
998 rx_mcs = (uint32_t *)result;
999 qdf_mem_copy(rx_mcs, param_buf->rx_mcs, len);
1000 result += len;
1001 dst_len -= len;
1002 } else {
1003 WMA_LOGE(FL("RX_MCS array length is wrong."));
1004 rx_mcs = NULL;
1005 }
1006
1007 /* per peer rx stats */
1008 peer_stats = ll_stats->peer_stats;
1009 for (i = 0; i < fix_param->num_peer_ac_rx_stats; i++) {
1010 uint32_t peer_id = wmi_peer_rx[i].peer_id;
1011 struct sir_wifi_rx *ac;
1012 wmi_rx_stats *wmi_rx_stats;
1013
1014 for (j = 0; j < ll_stats->peer_num; j++) {
1015 peer_stats += j;
1016 if ((peer_stats->peer_id == WIFI_INVALID_PEER_ID) ||
1017 (peer_stats->peer_id == peer_id))
1018 break;
1019 }
1020
1021 if (j < ll_stats->peer_num) {
1022 peer_stats->peer_id = wmi_peer_rx[i].peer_id;
1023 peer_stats->vdev_id = wmi_peer_rx[i].vdev_id;
1024 peer_stats->sta_ps_inds = wmi_peer_rx[i].sta_ps_inds;
1025 peer_stats->sta_ps_durs = wmi_peer_rx[i].sta_ps_durs;
1026 peer_stats->rx_probe_reqs =
1027 wmi_peer_rx[i].rx_probe_reqs;
1028 peer_stats->rx_oth_mgmts = wmi_peer_rx[i].rx_oth_mgmts;
1029 rx_stats = (struct sir_wifi_rx *)result;
1030
1031 for (k = 0; k < WLAN_MAX_AC; k++) {
1032 wmi_rx_stats = &wmi_rx[i * WLAN_MAX_AC + k];
1033 ac = &rx_stats[k];
1034 WMA_FILL_RX_STATS(wmi_rx_stats, ac);
1035 ac->mpdu_aggr = rx_mpdu_aggr;
1036 ac->aggr_len = rx_mpdu_aggr_array_len *
1037 sizeof(uint32_t);
1038 ac->mcs = rx_mcs;
1039 ac->mcs_len = rx_mcs_array_len *
1040 sizeof(uint32_t);
1041 peer_stats->ac_stats[k].rx_stats = ac;
1042 peer_stats->ac_stats[k].type = k;
1043 rx_mpdu_aggr += rx_mpdu_aggr_array_len;
1044 rx_mcs += rx_mcs_array_len;
1045 }
1046 result += WLAN_MAX_AC * sizeof(struct sir_wifi_rx);
1047 } else {
1048 /*
1049 * Buffer for Peer RX counter overflow.
1050 * There is peer ID mismatch between TX, RX,
1051 * signal counters.
1052 */
1053 WMA_LOGE(FL("One peer RX info is dropped."));
1054 rx_mpdu_aggr += rx_mpdu_aggr_array_len * WLAN_MAX_AC;
1055 rx_mcs += rx_mcs_array_len * WLAN_MAX_AC;
1056 }
1057 }
1058 *buf = result;
1059 *buf_length = dst_len;
1060}
1061
1062/**
1063 * wma_ll_stats_evt_handler() - handler for MAC layer counters.
1064 * @handle - wma handle
1065 * @event - FW event
1066 * @len - length of FW event
1067 *
1068 * return: 0 success.
1069 */
1070static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
1071 u_int32_t len)
1072{
1073 WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf;
1074 wmi_report_stats_event_fixed_param *fixed_param;
1075 tSirLLStatsResults *link_stats_results;
1076 wmi_chan_cca_stats *wmi_cca_stats;
1077 wmi_peer_signal_stats *wmi_peer_signal;
1078 wmi_peer_ac_rx_stats *wmi_peer_rx;
1079 struct sir_wifi_ll_ext_stats *ll_stats;
1080 struct sir_wifi_ll_ext_peer_stats *peer_stats;
1081 struct sir_wifi_chan_cca_stats *cca_stats;
1082 struct sir_wifi_peer_signal_stats *peer_signal;
1083 uint8_t *result;
1084 uint32_t i, peer_num, result_size, dst_len;
1085 tpAniSirGlobal mac;
1086 struct scheduler_msg sme_msg = { 0 };
1087 QDF_STATUS qdf_status;
1088
1089 mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE);
1090 if (!mac) {
1091 WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1092 return -EINVAL;
1093 }
1094
1095 if (!mac->sme.link_layer_stats_ext_cb) {
1096 WMA_LOGD("%s: HDD callback is null", __func__);
1097 return -EINVAL;
1098 }
1099
1100 WMA_LOGD("%s: Posting MAC counters event to HDD", __func__);
1101
1102 param_buf = (WMI_REPORT_STATS_EVENTID_param_tlvs *)event;
1103 fixed_param = param_buf->fixed_param;
1104 wmi_cca_stats = param_buf->chan_cca_stats;
1105 wmi_peer_signal = param_buf->peer_signal_stats;
1106 wmi_peer_rx = param_buf->peer_ac_rx_stats;
1107
1108 /* Get the MAX of three peer numbers */
1109 peer_num = fixed_param->num_peer_signal_stats >
1110 fixed_param->num_peer_ac_tx_stats ?
1111 fixed_param->num_peer_signal_stats :
1112 fixed_param->num_peer_ac_tx_stats;
1113 peer_num = peer_num > fixed_param->num_peer_ac_rx_stats ?
1114 peer_num : fixed_param->num_peer_ac_rx_stats;
1115
1116 if (peer_num == 0)
1117 return -EINVAL;
1118
1119 link_stats_results = wma_get_ll_stats_ext_buf(&result_size,
1120 peer_num,
1121 fixed_param);
1122 if (!link_stats_results) {
1123 WMA_LOGE("%s: Fail to allocate stats buffer", __func__);
1124 return -EINVAL;
1125 }
1126 link_stats_results->paramId = WMI_LL_STATS_EXT_MAC_COUNTER;
1127 link_stats_results->num_peers = peer_num;
1128 link_stats_results->peer_event_number = 1;
1129 link_stats_results->moreResultToFollow = 0;
1130
1131 ll_stats = (struct sir_wifi_ll_ext_stats *)link_stats_results->results;
1132 ll_stats->trigger_cond_id = fixed_param->trigger_cond_id;
1133 ll_stats->cca_chgd_bitmap = fixed_param->cca_chgd_bitmap;
1134 ll_stats->sig_chgd_bitmap = fixed_param->sig_chgd_bitmap;
1135 ll_stats->tx_chgd_bitmap = fixed_param->tx_chgd_bitmap;
1136 ll_stats->rx_chgd_bitmap = fixed_param->rx_chgd_bitmap;
1137 ll_stats->channel_num = fixed_param->num_chan_cca_stats;
1138 ll_stats->peer_num = peer_num;
1139
1140 result = (uint8_t *)ll_stats->stats;
1141 peer_stats = (struct sir_wifi_ll_ext_peer_stats *)result;
1142 ll_stats->peer_stats = peer_stats;
1143
1144 for (i = 0; i < peer_num; i++) {
1145 peer_stats[i].peer_id = WIFI_INVALID_PEER_ID;
1146 peer_stats[i].vdev_id = WIFI_INVALID_VDEV_ID;
1147 }
1148
1149 /* Per peer signal */
1150 result_size -= sizeof(struct sir_wifi_ll_ext_stats);
1151 dst_len = sizeof(struct sir_wifi_peer_signal_stats);
1152 for (i = 0; i < fixed_param->num_peer_signal_stats; i++) {
1153 peer_stats[i].peer_id = wmi_peer_signal->peer_id;
1154 peer_stats[i].vdev_id = wmi_peer_signal->vdev_id;
1155 peer_signal = &peer_stats[i].peer_signal_stats;
1156
Zhang Qian303ebe92017-05-18 13:59:07 +08001157 WMA_LOGD("%d antennas for peer %d",
1158 wmi_peer_signal->num_chains_valid,
1159 wmi_peer_signal->peer_id);
Zhang Qian73c348a2017-03-13 16:15:55 +08001160 if (dst_len <= result_size) {
Zhang Qian303ebe92017-05-18 13:59:07 +08001161 peer_signal->vdev_id = wmi_peer_signal->vdev_id;
1162 peer_signal->peer_id = wmi_peer_signal->peer_id;
1163 peer_signal->num_chain =
1164 wmi_peer_signal->num_chains_valid;
1165 qdf_mem_copy(peer_signal->per_ant_snr,
1166 wmi_peer_signal->per_chain_snr,
1167 sizeof(peer_signal->per_ant_snr));
1168 qdf_mem_copy(peer_signal->nf,
1169 wmi_peer_signal->per_chain_nf,
1170 sizeof(peer_signal->nf));
1171 qdf_mem_copy(peer_signal->per_ant_rx_mpdus,
1172 wmi_peer_signal->per_antenna_rx_mpdus,
1173 sizeof(peer_signal->per_ant_rx_mpdus));
1174 qdf_mem_copy(peer_signal->per_ant_tx_mpdus,
1175 wmi_peer_signal->per_antenna_tx_mpdus,
1176 sizeof(peer_signal->per_ant_tx_mpdus));
Zhang Qian73c348a2017-03-13 16:15:55 +08001177 result_size -= dst_len;
1178 } else {
1179 WMA_LOGE(FL("Invalid length of PEER signal."));
1180 }
1181 wmi_peer_signal++;
1182 }
1183
1184 result += peer_num * sizeof(struct sir_wifi_ll_ext_peer_stats);
1185 cca_stats = (struct sir_wifi_chan_cca_stats *)result;
1186 ll_stats->cca = cca_stats;
1187 dst_len = sizeof(struct sir_wifi_chan_cca_stats);
1188 for (i = 0; i < ll_stats->channel_num; i++) {
1189 if (dst_len <= result_size) {
1190 qdf_mem_copy(&cca_stats[i], &wmi_cca_stats->vdev_id,
1191 dst_len);
1192 result_size -= dst_len;
1193 } else {
1194 WMA_LOGE(FL("Invalid length of CCA."));
1195 }
1196 }
1197
1198 result += i * sizeof(struct sir_wifi_chan_cca_stats);
1199 wma_fill_tx_stats(ll_stats, fixed_param, param_buf,
1200 &result, &result_size);
1201 wma_fill_rx_stats(ll_stats, fixed_param, param_buf,
1202 &result, &result_size);
1203 sme_msg.type = eWMI_SME_LL_STATS_IND;
1204 sme_msg.bodyptr = (void *)link_stats_results;
1205 sme_msg.bodyval = 0;
1206 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
1207 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1208 WMA_LOGP(FL("Failed to post peer stat change msg!"));
1209 qdf_mem_free(link_stats_results);
1210 return -EINVAL;
1211 }
1212
1213 return 0;
1214}
1215
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001216/**
1217 * wma_unified_link_peer_stats_event_handler() - peer stats event handler
1218 * @handle: wma handle
1219 * @cmd_param_info: data received with event from fw
1220 * @len: length of data
1221 *
1222 * Return: 0 for success or error code
1223 */
1224static int wma_unified_link_peer_stats_event_handler(void *handle,
1225 uint8_t *cmd_param_info,
1226 uint32_t len)
1227{
1228 WMI_PEER_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
1229 wmi_peer_stats_event_fixed_param *fixed_param;
1230 wmi_peer_link_stats *peer_stats, *temp_peer_stats;
1231 wmi_rate_stats *rate_stats;
1232 tSirLLStatsResults *link_stats_results;
1233 uint8_t *results, *t_peer_stats, *t_rate_stats;
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301234 uint32_t count, rate_cnt;
1235 uint32_t total_num_rates = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 uint32_t next_res_offset, next_peer_offset, next_rate_offset;
1237 size_t peer_info_size, peer_stats_size, rate_stats_size;
1238 size_t link_stats_results_size;
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001239 bool excess_data = false;
1240 uint32_t buf_len;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001241
Anurag Chouhan6d760662016-02-20 16:05:43 +05301242 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001243
1244 if (!pMac) {
1245 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
1246 return -EINVAL;
1247 }
1248
1249 if (!pMac->sme.pLinkLayerStatsIndCallback) {
1250 WMA_LOGD("%s: HDD callback is null", __func__);
1251 return -EINVAL;
1252 }
1253
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254 param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
1255 if (!param_tlvs) {
1256 WMA_LOGA("%s: Invalid stats event", __func__);
1257 return -EINVAL;
1258 }
1259 /*
1260 * cmd_param_info contains
1261 * wmi_peer_stats_event_fixed_param fixed_param;
1262 * num_peers * size of(struct wmi_peer_link_stats)
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301263 * total_num_rates * size of(struct wmi_rate_stats)
1264 * total_num_rates is the sum of the rates of all the peers.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001265 */
1266 fixed_param = param_tlvs->fixed_param;
1267 peer_stats = param_tlvs->peer_stats;
1268 rate_stats = param_tlvs->peer_rate_stats;
1269
1270 if (!fixed_param || !peer_stats ||
1271 (peer_stats->num_rates && !rate_stats)) {
1272 WMA_LOGA("%s: Invalid param_tlvs for Peer Stats", __func__);
1273 return -EINVAL;
1274 }
1275
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001276 do {
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001277 if (fixed_param->num_peers >
1278 WMI_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats)) {
1279 excess_data = true;
1280 break;
1281 } else {
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301282 buf_len = fixed_param->num_peers *
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001283 sizeof(wmi_peer_link_stats);
1284 }
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301285 temp_peer_stats = (wmi_peer_link_stats *) peer_stats;
1286 for (count = 0; count < fixed_param->num_peers; count++) {
1287 if (temp_peer_stats->num_rates >
1288 WMI_SVC_MSG_MAX_SIZE / sizeof(wmi_rate_stats)) {
1289 excess_data = true;
1290 break;
1291 } else {
1292 total_num_rates += temp_peer_stats->num_rates;
1293 if (total_num_rates >
1294 WMI_SVC_MSG_MAX_SIZE /
1295 sizeof(wmi_rate_stats)) {
1296 excess_data = true;
1297 break;
1298 }
1299 buf_len += temp_peer_stats->num_rates *
1300 sizeof(wmi_rate_stats);
1301 }
1302 temp_peer_stats++;
1303 }
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001304 } while (0);
1305
1306 if (excess_data ||
1307 (sizeof(*fixed_param) > WMI_SVC_MSG_MAX_SIZE - buf_len)) {
1308 WMA_LOGE("excess wmi buffer: rates:%d, peers:%d",
1309 peer_stats->num_rates, fixed_param->num_peers);
1310 QDF_ASSERT(0);
1311 return -EINVAL;
1312 }
1313
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001314 peer_stats_size = sizeof(tSirWifiPeerStat);
1315 peer_info_size = sizeof(tSirWifiPeerInfo);
1316 rate_stats_size = sizeof(tSirWifiRateStat);
1317 link_stats_results_size =
1318 sizeof(*link_stats_results) + peer_stats_size +
1319 (fixed_param->num_peers * peer_info_size) +
Vignesh Viswanathan53d69c92017-09-26 15:27:16 +05301320 (total_num_rates * rate_stats_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001321
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301322 link_stats_results = qdf_mem_malloc(link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001323 if (NULL == link_stats_results) {
1324 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
1325 __func__, link_stats_results_size);
1326 return -ENOMEM;
1327 }
1328
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301329 qdf_mem_zero(link_stats_results, link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001330
1331 link_stats_results->paramId = WMI_LINK_STATS_ALL_PEER;
1332 link_stats_results->rspId = fixed_param->request_id;
1333 link_stats_results->ifaceId = 0;
1334 link_stats_results->num_peers = fixed_param->num_peers;
1335 link_stats_results->peer_event_number = fixed_param->peer_event_number;
1336 link_stats_results->moreResultToFollow = fixed_param->more_data;
1337
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301338 qdf_mem_copy(link_stats_results->results,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001339 &fixed_param->num_peers, peer_stats_size);
1340
1341 results = (uint8_t *) link_stats_results->results;
1342 t_peer_stats = (uint8_t *) peer_stats;
1343 t_rate_stats = (uint8_t *) rate_stats;
1344 next_res_offset = peer_stats_size;
1345 next_peer_offset = WMI_TLV_HDR_SIZE;
1346 next_rate_offset = WMI_TLV_HDR_SIZE;
Kondabattini, Ganesh32be0832016-08-09 15:19:50 +05301347 for (rate_cnt = 0; rate_cnt < fixed_param->num_peers; rate_cnt++) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301348 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001349 t_peer_stats + next_peer_offset, peer_info_size);
1350 next_res_offset += peer_info_size;
1351
1352 /* Copy rate stats associated with this peer */
1353 for (count = 0; count < peer_stats->num_rates; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354 rate_stats++;
1355
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301356 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001357 t_rate_stats + next_rate_offset,
1358 rate_stats_size);
1359 next_res_offset += rate_stats_size;
1360 next_rate_offset += sizeof(*rate_stats);
1361 }
1362 next_peer_offset += sizeof(*peer_stats);
1363 peer_stats++;
1364 }
1365
1366 /* call hdd callback with Link Layer Statistics
1367 * vdev_id/ifacId in link_stats_results will be
1368 * used to retrieve the correct HDD context
1369 */
1370 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
1371 WMA_LINK_LAYER_STATS_RESULTS_RSP,
1372 link_stats_results);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301373 qdf_mem_free(link_stats_results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001374
1375 return 0;
1376}
1377
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001378/**
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001379 * wma_unified_radio_tx_mem_free() - Free radio tx power stats memory
1380 * @handle: WMI handle
1381 *
1382 * Return: 0 on success, error number otherwise.
1383 */
yeshwanth sriram guntuka584c2332017-07-29 12:50:25 +05301384int wma_unified_radio_tx_mem_free(void *handle)
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001385{
1386 tp_wma_handle wma_handle = (tp_wma_handle) handle;
1387 tSirWifiRadioStat *rs_results;
1388 uint32_t i = 0;
1389
1390 if (!wma_handle->link_stats_results)
1391 return 0;
1392
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001393 rs_results = (tSirWifiRadioStat *)
1394 &wma_handle->link_stats_results->results[0];
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001395 for (i = 0; i < wma_handle->link_stats_results->num_radio; i++) {
1396 rs_results += i;
1397 if (rs_results->tx_time_per_power_level) {
1398 qdf_mem_free(rs_results->tx_time_per_power_level);
1399 rs_results->tx_time_per_power_level = NULL;
1400 }
1401
1402 if (rs_results->channels) {
1403 qdf_mem_free(rs_results->channels);
1404 rs_results->channels = NULL;
1405 }
1406 }
1407
1408 qdf_mem_free(wma_handle->link_stats_results);
1409 wma_handle->link_stats_results = NULL;
1410
1411 return 0;
1412}
1413
1414/**
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001415 * wma_unified_radio_tx_power_level_stats_event_handler() - tx power level stats
1416 * @handle: WMI handle
1417 * @cmd_param_info: command param info
1418 * @len: Length of @cmd_param_info
1419 *
1420 * This is the WMI event handler function to receive radio stats tx
1421 * power level stats.
1422 *
1423 * Return: 0 on success, error number otherwise.
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001424 */
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001425static int wma_unified_radio_tx_power_level_stats_event_handler(void *handle,
1426 u_int8_t *cmd_param_info, u_int32_t len)
1427{
1428 tp_wma_handle wma_handle = (tp_wma_handle) handle;
1429 WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *param_tlvs;
1430 wmi_tx_power_level_stats_evt_fixed_param *fixed_param;
1431 uint8_t *tx_power_level_values;
1432 tSirLLStatsResults *link_stats_results;
1433 tSirWifiRadioStat *rs_results;
1434
1435 tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE);
1436
1437 if (!mac) {
1438 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
1439 return -EINVAL;
1440 }
1441
1442 if (!mac->sme.pLinkLayerStatsIndCallback) {
1443 WMA_LOGD("%s: HDD callback is null", __func__);
1444 return -EINVAL;
1445 }
1446
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001447 param_tlvs = (WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *)
1448 cmd_param_info;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001449 if (!param_tlvs) {
1450 WMA_LOGA("%s: Invalid tx power level stats event", __func__);
1451 return -EINVAL;
1452 }
1453
1454 fixed_param = param_tlvs->fixed_param;
1455 if (!fixed_param) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001456 WMA_LOGA("%s:Invalid param_tlvs for Radio tx_power level Stats",
1457 __func__);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001458 return -EINVAL;
1459 }
1460
1461 link_stats_results = wma_handle->link_stats_results;
Srinivas Girigowda52cbce42016-10-25 14:11:58 -07001462 if (!link_stats_results) {
1463 WMA_LOGA("%s: link_stats_results is NULL", __func__);
1464 return -EINVAL;
1465 }
1466
Wu Gao478282a2017-09-19 15:45:29 +08001467 if (fixed_param->radio_id >= link_stats_results->num_radio) {
1468 WMA_LOGE("%s, invalid radio id:%d, num radio:%d",
1469 __func__, fixed_param->radio_id,
1470 link_stats_results->num_radio);
1471 return -EINVAL;
1472 }
1473
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001474 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 -07001475 __func__, fixed_param->total_num_tx_power_levels,
1476 fixed_param->num_tx_power_levels,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001477 fixed_param->power_level_offset,
1478 fixed_param->radio_id);
1479
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07001480 if (fixed_param->num_tx_power_levels > ((WMI_SVC_MSG_MAX_SIZE -
1481 sizeof(*fixed_param)) / sizeof(uint32_t))) {
1482 WMA_LOGE("%s: excess tx_power buffers:%d", __func__,
1483 fixed_param->num_tx_power_levels);
1484 QDF_ASSERT(0);
1485 return -EINVAL;
1486 }
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001487 rs_results = (tSirWifiRadioStat *) &link_stats_results->results[0] +
1488 fixed_param->radio_id;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001489 tx_power_level_values = (uint8_t *) param_tlvs->tx_time_per_power_level;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001490
1491 rs_results->total_num_tx_power_levels =
1492 fixed_param->total_num_tx_power_levels;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001493 if (!rs_results->total_num_tx_power_levels) {
1494 link_stats_results->nr_received++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001495 goto post_stats;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001496 }
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001497
1498 if (!rs_results->tx_time_per_power_level) {
1499 rs_results->tx_time_per_power_level = qdf_mem_malloc(
1500 sizeof(uint32_t) *
1501 rs_results->total_num_tx_power_levels);
1502 if (!rs_results->tx_time_per_power_level) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001503 WMA_LOGA("%s: Mem alloc fail for tx power level stats",
1504 __func__);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001505 /* In error case, atleast send the radio stats without
1506 * tx_power_level stats */
1507 rs_results->total_num_tx_power_levels = 0;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001508 link_stats_results->nr_received++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001509 goto post_stats;
1510 }
1511 }
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001512 qdf_mem_copy(&rs_results->tx_time_per_power_level[
1513 fixed_param->power_level_offset],
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001514 tx_power_level_values,
1515 sizeof(uint32_t) * fixed_param->num_tx_power_levels);
1516 if (rs_results->total_num_tx_power_levels ==
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001517 (fixed_param->num_tx_power_levels +
1518 fixed_param->power_level_offset)) {
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001519 link_stats_results->moreResultToFollow = 0;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001520 link_stats_results->nr_received++;
1521 }
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001522
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001523 WMA_LOGD("%s: moreResultToFollow: %u nr: %u nr_received: %u",
1524 __func__, link_stats_results->moreResultToFollow,
1525 link_stats_results->num_radio,
1526 link_stats_results->nr_received);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001527
1528 /* If still data to receive, return from here */
1529 if (link_stats_results->moreResultToFollow)
1530 return 0;
1531
1532post_stats:
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001533 if (link_stats_results->num_radio != link_stats_results->nr_received) {
1534 /* Not received all radio stats yet, don't post yet */
1535 return 0;
1536 }
1537
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001538 /* call hdd callback with Link Layer Statistics
1539 * vdev_id/ifacId in link_stats_results will be
1540 * used to retrieve the correct HDD context
1541 */
1542 mac->sme.pLinkLayerStatsIndCallback(mac->hHdd,
1543 WMA_LINK_LAYER_STATS_RESULTS_RSP,
1544 link_stats_results);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001545 wma_unified_radio_tx_mem_free(handle);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001546
1547 return 0;
1548}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549
1550/**
1551 * wma_unified_link_radio_stats_event_handler() - radio link stats event handler
1552 * @handle: wma handle
1553 * @cmd_param_info: data received with event from fw
1554 * @len: length of data
1555 *
1556 * Return: 0 for success or error code
1557 */
1558static int wma_unified_link_radio_stats_event_handler(void *handle,
1559 uint8_t *cmd_param_info,
1560 uint32_t len)
1561{
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001562 tp_wma_handle wma_handle = (tp_wma_handle) handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001563 WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
1564 wmi_radio_link_stats_event_fixed_param *fixed_param;
1565 wmi_radio_link_stats *radio_stats;
1566 wmi_channel_stats *channel_stats;
1567 tSirLLStatsResults *link_stats_results;
1568 uint8_t *results, *t_radio_stats, *t_channel_stats;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001569 uint32_t next_chan_offset, count;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001570 size_t radio_stats_size, chan_stats_size;
1571 size_t link_stats_results_size;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001572 tSirWifiRadioStat *rs_results;
1573 tSirWifiChannelStats *chn_results;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574
Anurag Chouhan6d760662016-02-20 16:05:43 +05301575 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001576
1577 if (!pMac) {
1578 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
1579 return -EINVAL;
1580 }
1581
1582 if (!pMac->sme.pLinkLayerStatsIndCallback) {
1583 WMA_LOGD("%s: HDD callback is null", __func__);
1584 return -EINVAL;
1585 }
1586
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001587 param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
1588 if (!param_tlvs) {
1589 WMA_LOGA("%s: Invalid stats event", __func__);
1590 return -EINVAL;
1591 }
1592
1593 /*
1594 * cmd_param_info contains
1595 * wmi_radio_link_stats_event_fixed_param fixed_param;
1596 * size of(struct wmi_radio_link_stats);
1597 * num_channels * size of(struct wmi_channel_stats)
1598 */
1599 fixed_param = param_tlvs->fixed_param;
1600 radio_stats = param_tlvs->radio_stats;
1601 channel_stats = param_tlvs->channel_stats;
1602
1603 if (!fixed_param || !radio_stats ||
1604 (radio_stats->num_channels && !channel_stats)) {
1605 WMA_LOGA("%s: Invalid param_tlvs for Radio Stats", __func__);
1606 return -EINVAL;
1607 }
Varun Reddy Yeturuc3139102017-09-27 20:38:39 -07001608 if (radio_stats->num_channels >
1609 (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS)) {
1610 WMA_LOGE("%s: Too many channels %d",
1611 __func__, radio_stats->num_channels);
1612 return -EINVAL;
1613 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614
1615 radio_stats_size = sizeof(tSirWifiRadioStat);
1616 chan_stats_size = sizeof(tSirWifiChannelStats);
Varun Reddy Yeturuc3139102017-09-27 20:38:39 -07001617 if (fixed_param->num_radio >
1618 (UINT_MAX - sizeof(*link_stats_results))/radio_stats_size) {
1619 WMA_LOGE("excess num_radio %d is leading to int overflow",
1620 fixed_param->num_radio);
1621 return -EINVAL;
1622 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001623 link_stats_results_size = sizeof(*link_stats_results) +
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001624 fixed_param->num_radio * radio_stats_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001626 if (!wma_handle->link_stats_results) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001627 wma_handle->link_stats_results = qdf_mem_malloc(
1628 link_stats_results_size);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001629 if (NULL == wma_handle->link_stats_results) {
1630 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
1631 __func__, link_stats_results_size);
1632 return -ENOMEM;
1633 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634 }
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001635 link_stats_results = wma_handle->link_stats_results;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001636
Paul Zhang05af1f62017-10-10 15:11:06 +08001637 if (radio_stats->radio_id >= link_stats_results->num_radio) {
1638 WMA_LOGE("%s, invalid radio id:%d, num radio:%d",
1639 __func__, radio_stats->radio_id,
1640 link_stats_results->num_radio);
1641 return -EINVAL;
1642 }
1643
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001644 WMA_LOGD("Radio stats Fixed Param:");
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001645 WMA_LOGD("req_id: %u num_radio: %u more_radio_events: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001646 fixed_param->request_id, fixed_param->num_radio,
1647 fixed_param->more_radio_events);
1648
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001649 WMA_LOGD("Radio Info: radio_id: %u on_time: %u tx_time: %u rx_time: %u on_time_scan: %u",
1650 radio_stats->radio_id, radio_stats->on_time,
1651 radio_stats->tx_time, radio_stats->rx_time,
1652 radio_stats->on_time_scan);
1653 WMA_LOGD("on_time_nbd: %u on_time_gscan: %u on_time_roam_scan: %u",
1654 radio_stats->on_time_nbd,
1655 radio_stats->on_time_gscan, radio_stats->on_time_roam_scan);
1656 WMA_LOGD("on_time_pno_scan: %u on_time_hs20: %u num_channels: %u",
1657 radio_stats->on_time_pno_scan, radio_stats->on_time_hs20,
1658 radio_stats->num_channels);
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08001659 WMA_LOGD("on_time_host_scan: %u, on_time_lpi_scan: %u",
1660 radio_stats->on_time_host_scan, radio_stats->on_time_lpi_scan);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001661
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001662 link_stats_results->paramId = WMI_LINK_STATS_RADIO;
1663 link_stats_results->rspId = fixed_param->request_id;
1664 link_stats_results->ifaceId = 0;
1665 link_stats_results->num_radio = fixed_param->num_radio;
1666 link_stats_results->peer_event_number = 0;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001667
1668 /*
1669 * Backward compatibility:
1670 * There are firmware(s) which will send Radio stats only with
1671 * more_radio_events set to 0 and firmware which sends Radio stats
1672 * followed by tx_power level stats with more_radio_events set to 1.
1673 * if more_radio_events is set to 1, buffer the radio stats and
1674 * wait for tx_power_level stats.
1675 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676 link_stats_results->moreResultToFollow = fixed_param->more_radio_events;
1677
1678 results = (uint8_t *) link_stats_results->results;
1679 t_radio_stats = (uint8_t *) radio_stats;
1680 t_channel_stats = (uint8_t *) channel_stats;
1681
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001682 rs_results = (tSirWifiRadioStat *) &results[0] + radio_stats->radio_id;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001683 rs_results->radio = radio_stats->radio_id;
1684 rs_results->onTime = radio_stats->on_time;
1685 rs_results->txTime = radio_stats->tx_time;
1686 rs_results->rxTime = radio_stats->rx_time;
1687 rs_results->onTimeScan = radio_stats->on_time_scan;
1688 rs_results->onTimeNbd = radio_stats->on_time_nbd;
1689 rs_results->onTimeGscan = radio_stats->on_time_gscan;
1690 rs_results->onTimeRoamScan = radio_stats->on_time_roam_scan;
1691 rs_results->onTimePnoScan = radio_stats->on_time_pno_scan;
1692 rs_results->onTimeHs20 = radio_stats->on_time_hs20;
1693 rs_results->total_num_tx_power_levels = 0;
1694 rs_results->tx_time_per_power_level = NULL;
1695 rs_results->numChannels = radio_stats->num_channels;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08001696 rs_results->on_time_host_scan = radio_stats->on_time_host_scan;
1697 rs_results->on_time_lpi_scan = radio_stats->on_time_lpi_scan;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001698 rs_results->channels = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001699
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001700 if (rs_results->numChannels) {
1701 rs_results->channels = (tSirWifiChannelStats *) qdf_mem_malloc(
1702 radio_stats->num_channels *
1703 chan_stats_size);
1704 if (rs_results->channels == NULL) {
1705 WMA_LOGD("%s: could not allocate mem for channel stats (size=%zu)",
1706 __func__, radio_stats->num_channels * chan_stats_size);
1707 wma_unified_radio_tx_mem_free(handle);
1708 return -ENOMEM;
1709 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001710
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001711 chn_results = (tSirWifiChannelStats *) &rs_results->channels[0];
1712 next_chan_offset = WMI_TLV_HDR_SIZE;
1713 WMA_LOGD("Channel Stats Info");
1714 for (count = 0; count < radio_stats->num_channels; count++) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001715 WMA_LOGD("channel_width %u center_freq %u center_freq0 %u",
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001716 channel_stats->channel_width,
1717 channel_stats->center_freq,
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001718 channel_stats->center_freq0);
1719 WMA_LOGD("center_freq1 %u radio_awake_time %u cca_busy_time %u",
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001720 channel_stats->center_freq1,
1721 channel_stats->radio_awake_time,
1722 channel_stats->cca_busy_time);
1723 channel_stats++;
1724
1725 qdf_mem_copy(chn_results,
1726 t_channel_stats + next_chan_offset,
1727 chan_stats_size);
1728 chn_results++;
1729 next_chan_offset += sizeof(*channel_stats);
1730 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731 }
1732
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001733 if (link_stats_results->moreResultToFollow) {
1734 /* More results coming, don't post yet */
1735 return 0;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001736 }
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001737 link_stats_results->nr_received++;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001738
1739 if (link_stats_results->num_radio != link_stats_results->nr_received) {
1740 /* Not received all radio stats yet, don't post yet */
1741 return 0;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001742 }
1743
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001744 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
1745 WMA_LINK_LAYER_STATS_RESULTS_RSP,
1746 link_stats_results);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001747 wma_unified_radio_tx_mem_free(handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001748
1749 return 0;
1750}
1751
Zhang Qiana6e9c102016-12-22 16:47:24 +08001752#ifdef WLAN_PEER_PS_NOTIFICATION
1753/**
1754 * wma_peer_ps_evt_handler() - handler for PEER power state change.
1755 * @handle: wma handle
1756 * @event: FW event
1757 * @len: length of FW event
1758 *
1759 * Once peer STA power state changes, an event will be indicated by
1760 * FW. This function send a link layer state change msg to HDD. HDD
1761 * link layer callback will converts the event to NL msg.
1762 *
1763 * Return: 0 Success. Others fail.
1764 */
1765static int wma_peer_ps_evt_handler(void *handle, u_int8_t *event,
1766 u_int32_t len)
1767{
1768 WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *param_buf;
1769 wmi_peer_sta_ps_statechange_event_fixed_param *fixed_param;
1770 tSirWifiPeerStat *peer_stat;
1771 tSirWifiPeerInfo *peer_info;
1772 tSirLLStatsResults *link_stats_results;
1773 tSirMacAddr mac_address;
1774 uint32_t result_len;
1775 cds_msg_t sme_msg = { 0 };
1776 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
1777
1778 tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE);
1779
1780 if (!mac) {
1781 WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1782 return -EINVAL;
1783 }
1784
1785 if (!mac->sme.link_layer_stats_ext_cb) {
1786 WMA_LOGD("%s: HDD callback is null", __func__);
1787 return -EINVAL;
1788 }
1789
1790 WMA_LOGD("%s: Posting Peer Stats PS event to HDD", __func__);
1791
1792 param_buf = (WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *)event;
1793 fixed_param = param_buf->fixed_param;
1794
1795 result_len = sizeof(tSirLLStatsResults) +
1796 sizeof(tSirWifiPeerStat) +
1797 sizeof(tSirWifiPeerInfo);
1798 link_stats_results = qdf_mem_malloc(result_len);
1799 if (link_stats_results == NULL) {
1800 WMA_LOGE("%s: Cannot allocate link layer stats.", __func__);
1801 return -EINVAL;
1802 }
1803
1804 WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_param->peer_macaddr, &mac_address[0]);
1805 WMA_LOGD("Peer power state change event from FW");
1806 WMA_LOGD("Fixed Param:");
1807 WMA_LOGD("MAC address: %2x:%2x:%2x:%2x:%2x:%2x, Power state: %d",
1808 mac_address[0], mac_address[1], mac_address[2],
1809 mac_address[3], mac_address[4], mac_address[5],
1810 fixed_param->peer_ps_state);
1811
1812 link_stats_results->paramId = WMI_LL_STATS_EXT_PS_CHG;
1813 link_stats_results->num_peers = 1;
1814 link_stats_results->peer_event_number = 1;
1815 link_stats_results->moreResultToFollow = 0;
1816
1817 peer_stat = (tSirWifiPeerStat *)link_stats_results->results;
1818 peer_stat->numPeers = 1;
1819 peer_info = (tSirWifiPeerInfo *)peer_stat->peerInfo;
1820 qdf_mem_copy(&peer_info->peerMacAddress,
1821 &mac_address,
1822 sizeof(tSirMacAddr));
1823 peer_info->power_saving = fixed_param->peer_ps_state;
1824
1825 sme_msg.type = eWMI_SME_LL_STATS_IND;
1826 sme_msg.bodyptr = link_stats_results;
1827 sme_msg.bodyval = 0;
1828
Zhang Qian73c348a2017-03-13 16:15:55 +08001829 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
Zhang Qiana6e9c102016-12-22 16:47:24 +08001830 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1831 WMA_LOGE("%s: Fail to post ps change ind msg", __func__);
1832 qdf_mem_free(link_stats_results);
1833 }
1834
1835 return 0;
1836}
1837#else
1838/**
1839 * wma_peer_ps_evt_handler() - handler for PEER power state change.
1840 * @handle: wma handle
1841 * @event: FW event
1842 * @len: length of FW event
1843 *
1844 * Once peer STA power state changes, an event will be indicated by
1845 * FW. This function send a link layer state change msg to HDD. HDD
1846 * link layer callback will converts the event to NL msg.
1847 *
1848 * Return: 0 Success. Others fail.
1849 */
1850static inline int wma_peer_ps_evt_handler(void *handle, u_int8_t *event,
1851 u_int32_t len)
1852{
1853 return 0;
1854}
1855#endif
1856
1857/**
1858 * wma_tx_failure_cb() - TX failure callback
1859 * @ctx: txrx context
1860 * @num_msdu: number of msdu with the same status
1861 * @tid: TID number
1862 * @status: failure status
1863 */
1864void wma_tx_failure_cb(void *ctx, uint32_t num_msdu,
1865 uint8_t tid, enum htt_tx_status status)
1866{
1867 tSirLLStatsResults *results;
1868 struct sir_wifi_iface_tx_fail *tx_fail;
1869 struct scheduler_msg sme_msg = { 0 };
1870 QDF_STATUS qdf_status;
1871 tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE);
1872
1873 if (!mac) {
1874 WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
1875 return;
1876 }
1877
1878 if (!mac->sme.link_layer_stats_ext_cb) {
1879 WMA_LOGD("%s: HDD callback is null", __func__);
1880 return;
1881 }
1882
1883 results = qdf_mem_malloc(sizeof(tSirLLStatsResults) +
1884 sizeof(struct sir_wifi_iface_tx_fail));
1885 if (results == NULL) {
1886 WMA_LOGE("%s: Cannot allocate link layer stats.", __func__);
1887 return;
1888 }
1889
1890 results->paramId = WMI_LL_STATS_EXT_TX_FAIL;
1891 results->num_peers = 1;
1892 results->peer_event_number = 1;
1893 results->moreResultToFollow = 0;
1894
1895 tx_fail = (struct sir_wifi_iface_tx_fail *)results->results;
1896 tx_fail->tid = tid;
1897 tx_fail->msdu_num = num_msdu;
1898 tx_fail->status = status;
1899
1900 sme_msg.type = eWMI_SME_LL_STATS_IND;
1901 sme_msg.bodyptr = results;
1902 sme_msg.bodyval = 0;
1903
1904 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
1905 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1906 WMA_LOGE("%s: Fail to post TX failure ind msg", __func__);
1907 qdf_mem_free(results);
1908 }
1909}
1910
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001911/**
1912 * wma_register_ll_stats_event_handler() - register link layer stats related
1913 * event handler
1914 * @wma_handle: wma handle
1915 *
1916 * Return: none
1917 */
1918void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle)
1919{
1920 if (NULL == wma_handle) {
1921 WMA_LOGE("%s: wma_handle is NULL", __func__);
1922 return;
1923 }
1924
1925 wmi_unified_register_event_handler(wma_handle->wmi_handle,
Govind Singhd76a5b02016-03-08 15:12:14 +05301926 WMI_IFACE_LINK_STATS_EVENTID,
1927 wma_unified_link_iface_stats_event_handler,
1928 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001929 wmi_unified_register_event_handler(wma_handle->wmi_handle,
Govind Singhd76a5b02016-03-08 15:12:14 +05301930 WMI_PEER_LINK_STATS_EVENTID,
1931 wma_unified_link_peer_stats_event_handler,
1932 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933 wmi_unified_register_event_handler(wma_handle->wmi_handle,
Govind Singhd76a5b02016-03-08 15:12:14 +05301934 WMI_RADIO_LINK_STATS_EVENTID,
1935 wma_unified_link_radio_stats_event_handler,
1936 WMA_RX_SERIALIZER_CTX);
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001937 wmi_unified_register_event_handler(wma_handle->wmi_handle,
1938 WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID,
1939 wma_unified_radio_tx_power_level_stats_event_handler,
1940 WMA_RX_SERIALIZER_CTX);
Zhang Qiana6e9c102016-12-22 16:47:24 +08001941 wmi_unified_register_event_handler(wma_handle->wmi_handle,
1942 WMI_PEER_STA_PS_STATECHG_EVENTID,
1943 wma_peer_ps_evt_handler,
1944 WMA_RX_SERIALIZER_CTX);
Zhang Qian73c348a2017-03-13 16:15:55 +08001945 wmi_unified_register_event_handler(wma_handle->wmi_handle,
1946 WMI_REPORT_STATS_EVENTID,
1947 wma_ll_stats_evt_handler,
1948 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001949
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001950}
1951
1952
1953/**
1954 * wma_process_ll_stats_clear_req() - clear link layer stats
1955 * @wma: wma handle
1956 * @clearReq: ll stats clear request command params
1957 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301958 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001959 */
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001960QDF_STATUS wma_process_ll_stats_clear_req(tp_wma_handle wma,
1961 const tpSirLLStatsClearReq clearReq)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962{
Govind Singh4863da42016-03-08 11:45:00 +05301963 struct ll_stats_clear_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001964 int ret;
1965
1966 if (!clearReq || !wma) {
1967 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301968 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001969 }
1970
Deepak Dhamdhere6adc08e2017-07-27 09:33:22 -07001971 if (!wma->interfaces[clearReq->staId].handle) {
1972 WMA_LOGE("%s: vdev_id %d handle is NULL",
1973 __func__, clearReq->staId);
1974 return QDF_STATUS_E_FAILURE;
1975 }
1976
Govind Singh4863da42016-03-08 11:45:00 +05301977 cmd.stop_req = clearReq->stopReq;
1978 cmd.sta_id = clearReq->staId;
1979 cmd.stats_clear_mask = clearReq->statsClearReqMask;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001980
Govind Singh4863da42016-03-08 11:45:00 +05301981 ret = wmi_unified_process_ll_stats_clear_cmd(wma->wmi_handle, &cmd,
1982 wma->interfaces[clearReq->staId].addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001983 if (ret) {
1984 WMA_LOGE("%s: Failed to send clear link stats req", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301985 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001986 }
1987
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301988 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001989}
1990
1991/**
1992 * wma_process_ll_stats_set_req() - link layer stats set request
1993 * @wma: wma handle
1994 * @setReq: ll stats set request command params
1995 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301996 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001997 */
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07001998QDF_STATUS wma_process_ll_stats_set_req(tp_wma_handle wma,
1999 const tpSirLLStatsSetReq setReq)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002000{
Govind Singh4863da42016-03-08 11:45:00 +05302001 struct ll_stats_set_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002002 int ret;
2003
2004 if (!setReq || !wma) {
2005 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302006 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002007 }
2008
Govind Singh4863da42016-03-08 11:45:00 +05302009 cmd.mpdu_size_threshold = setReq->mpduSizeThreshold;
2010 cmd.aggressive_statistics_gathering =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002011 setReq->aggressiveStatisticsGathering;
2012
Govind Singh4863da42016-03-08 11:45:00 +05302013 ret = wmi_unified_process_ll_stats_set_cmd(wma->wmi_handle,
2014 &cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015 if (ret) {
2016 WMA_LOGE("%s: Failed to send set link stats request", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302017 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002018 }
2019
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302020 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002021}
2022
2023/**
2024 * wma_process_ll_stats_get_req() - link layer stats get request
2025 * @wma:wma handle
2026 * @getReq:ll stats get request command params
2027 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302028 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029 */
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002030QDF_STATUS wma_process_ll_stats_get_req(tp_wma_handle wma,
2031 const tpSirLLStatsGetReq getReq)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002032{
Govind Singh4863da42016-03-08 11:45:00 +05302033 struct ll_stats_get_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002034 int ret;
2035
2036 if (!getReq || !wma) {
2037 WMA_LOGE("%s: input pointer is NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302038 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002039 }
2040
Selvaraj, Sridhar171e2252016-06-22 22:33:26 +05302041 if (!wma->interfaces[getReq->staId].vdev_active) {
2042 WMA_LOGE("%s: vdev not created yet", __func__);
2043 return QDF_STATUS_E_FAILURE;
2044 }
2045
Govind Singh4863da42016-03-08 11:45:00 +05302046 cmd.req_id = getReq->reqId;
2047 cmd.param_id_mask = getReq->paramIdMask;
2048 cmd.sta_id = getReq->staId;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002049
Govind Singh4863da42016-03-08 11:45:00 +05302050 ret = wmi_unified_process_ll_stats_get_cmd(wma->wmi_handle, &cmd,
2051 wma->interfaces[getReq->staId].addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052 if (ret) {
2053 WMA_LOGE("%s: Failed to send get link stats request", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302054 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 }
2056
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302057 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002058}
2059
2060/**
2061 * wma_unified_link_iface_stats_event_handler() - link iface stats event handler
2062 * @wma:wma handle
2063 * @cmd_param_info: data from event
2064 * @len: length
2065 *
2066 * Return: 0 for success or error code
2067 */
2068int wma_unified_link_iface_stats_event_handler(void *handle,
2069 uint8_t *cmd_param_info,
2070 uint32_t len)
2071{
2072 WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
2073 wmi_iface_link_stats_event_fixed_param *fixed_param;
2074 wmi_iface_link_stats *link_stats;
2075 wmi_wmm_ac_stats *ac_stats;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002076 wmi_iface_offload_stats *offload_stats;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002077 tSirLLStatsResults *link_stats_results;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002078 uint8_t *results, *t_link_stats, *t_ac_stats, *t_offload_stats;
2079 uint32_t next_res_offset, next_ac_offset, next_offload_offset, count;
2080 uint32_t roaming_offset, size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081 size_t link_stats_size, ac_stats_size, iface_info_size;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002082 size_t link_stats_results_size, offload_stats_size;
2083 size_t total_ac_size, total_offload_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002084
Anurag Chouhan6d760662016-02-20 16:05:43 +05302085 tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002086
2087 if (!pMac) {
2088 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
2089 return -EINVAL;
2090 }
2091
2092 if (!pMac->sme.pLinkLayerStatsIndCallback) {
2093 WMA_LOGD("%s: HDD callback is null", __func__);
2094 return -EINVAL;
2095 }
2096
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002097 param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info;
2098 if (!param_tlvs) {
2099 WMA_LOGA("%s: Invalid stats event", __func__);
2100 return -EINVAL;
2101 }
2102
2103 /*
2104 * cmd_param_info contains
2105 * wmi_iface_link_stats_event_fixed_param fixed_param;
2106 * wmi_iface_link_stats iface_link_stats;
2107 * iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats)
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002108 * fixed_param->num_offload_stats * size of(wmi_iface_offload_stats);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002109 */
2110 fixed_param = param_tlvs->fixed_param;
2111 link_stats = param_tlvs->iface_link_stats;
2112 ac_stats = param_tlvs->ac;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002113 offload_stats = param_tlvs->iface_offload_stats;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002114
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002115 if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats) ||
2116 (fixed_param->num_offload_stats && !offload_stats)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002117 WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__);
2118 return -EINVAL;
2119 }
2120
Vignesh Viswanathan37794ae2017-09-28 15:26:56 +05302121 if (link_stats->num_ac > WIFI_AC_MAX) {
2122 WMA_LOGE("%s: Excess data received from firmware num_ac %d",
2123 __func__, link_stats->num_ac);
2124 return -EINVAL;
2125 }
2126 if (fixed_param->num_offload_stats > WMI_OFFLOAD_STATS_TYPE_MAX) {
2127 WMA_LOGE("%s: Excess num offload stats recvd from fw: %d",
2128 __func__, fixed_param->num_offload_stats);
2129 return -EINVAL;
2130 }
2131
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002132 link_stats_size = sizeof(tSirWifiIfaceStat);
2133 iface_info_size = sizeof(tSirWifiInterfaceInfo);
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002134
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002135 ac_stats_size = sizeof(tSirWifiWmmAcStat);
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002136 offload_stats_size = sizeof(struct wifi_iface_offload_stat);
2137
2138 total_ac_size = ac_stats_size * WIFI_AC_MAX;
2139 total_offload_size = offload_stats_size * WMI_OFFLOAD_STATS_TYPE_MAX +
2140 member_size(tSirWifiIfaceStat, num_offload_stats);
2141
2142 link_stats_results_size = sizeof(*link_stats_results) + link_stats_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002143
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302144 link_stats_results = qdf_mem_malloc(link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002145 if (!link_stats_results) {
2146 WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
2147 __func__, link_stats_results_size);
2148 return -ENOMEM;
2149 }
2150
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302151 qdf_mem_zero(link_stats_results, link_stats_results_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002152
2153 link_stats_results->paramId = WMI_LINK_STATS_IFACE;
2154 link_stats_results->rspId = fixed_param->request_id;
2155 link_stats_results->ifaceId = fixed_param->vdev_id;
2156 link_stats_results->num_peers = link_stats->num_peers;
2157 link_stats_results->peer_event_number = 0;
2158 link_stats_results->moreResultToFollow = 0;
2159
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002160 /* results is copied to tSirWifiIfaceStat in upper layer
2161 * tSirWifiIfaceStat
2162 * - tSirWifiInterfaceInfo (all fields except roaming is
2163 * filled by host in the upper layer)
2164 * - various members of tSirWifiIfaceStat (from wmi_iface_link_stats)
2165 * - ACs information (from wmi_wmm_ac_stats)
2166 * - num_offload_stats (from fixed param)
2167 * - offload stats (from wmi_iface_offload_stats)
2168 */
2169
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002170 results = (uint8_t *) link_stats_results->results;
2171 t_link_stats = (uint8_t *) link_stats;
2172 t_ac_stats = (uint8_t *) ac_stats;
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002173 t_offload_stats = (uint8_t *) offload_stats;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002174
2175 /* Copy roaming state */
2176 roaming_offset = offsetof(tSirWifiInterfaceInfo, roaming);
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002177 size = member_size(tSirWifiInterfaceInfo, roaming);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002178
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002179 qdf_mem_copy(results + roaming_offset, &link_stats->roam_state, size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002180
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002181 next_res_offset = iface_info_size;
2182 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002183 t_link_stats + WMI_TLV_HDR_SIZE,
2184 link_stats_size - iface_info_size -
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002185 total_ac_size - total_offload_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002186
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002187 next_res_offset = link_stats_size - total_ac_size - total_offload_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002188 next_ac_offset = WMI_TLV_HDR_SIZE;
2189
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002190 for (count = 0; count < link_stats->num_ac; count++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002191 ac_stats++;
2192
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302193 qdf_mem_copy(results + next_res_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194 t_ac_stats + next_ac_offset, ac_stats_size);
2195 next_res_offset += ac_stats_size;
2196 next_ac_offset += sizeof(*ac_stats);
2197 }
2198
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -08002199 next_res_offset = link_stats_size - total_offload_size;
2200 /* copy num_offload_stats into result */
2201 size = member_size(tSirWifiIfaceStat, num_offload_stats);
2202 qdf_mem_copy(results + next_res_offset, &fixed_param->num_offload_stats,
2203 size);
2204
2205 next_res_offset += size;
2206 next_offload_offset = WMI_TLV_HDR_SIZE;
2207
2208 for (count = 0; count < fixed_param->num_offload_stats; count++) {
2209 qdf_mem_copy(results + next_res_offset,
2210 t_offload_stats + next_offload_offset,
2211 offload_stats_size);
2212 next_res_offset += offload_stats_size;
2213 next_offload_offset += sizeof(*offload_stats);
2214 }
2215
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002216 /* call hdd callback with Link Layer Statistics
2217 * vdev_id/ifacId in link_stats_results will be
2218 * used to retrieve the correct HDD context
2219 */
2220 pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
2221 WMA_LINK_LAYER_STATS_RESULTS_RSP,
2222 link_stats_results);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302223 qdf_mem_free(link_stats_results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002224
2225 return 0;
2226}
2227
Zhang Qian73c348a2017-03-13 16:15:55 +08002228/**
2229 * wma_config_stats_ext_threshold - set threthold for MAC counters
2230 * @wma: wma handler
2231 * @threshold: threhold for MAC counters
2232 *
2233 * For each MAC layer counter, FW holds two copies. One is the current value.
2234 * The other is the last report. Once a current counter's increment is larger
2235 * than the threshold, FW will indicate that counter to host even if the
2236 * monitoring timer does not expire.
2237 *
2238 * Return: None
2239 */
2240void wma_config_stats_ext_threshold(tp_wma_handle wma,
2241 struct sir_ll_ext_stats_threshold *thresh)
2242{
2243 uint32_t len, tag, hdr_len;
2244 uint8_t *buf_ptr;
2245 wmi_buf_t buf;
2246 wmi_pdev_set_stats_threshold_cmd_fixed_param *cmd;
2247 wmi_chan_cca_stats_thresh *cca;
2248 wmi_peer_signal_stats_thresh *signal;
2249 wmi_tx_stats_thresh *tx;
2250 wmi_rx_stats_thresh *rx;
2251
2252 if (!thresh) {
2253 WMA_LOGE(FL("Invalid threshold input."));
2254 return;
2255 }
2256
2257 len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param) +
2258 sizeof(wmi_chan_cca_stats_thresh) +
2259 sizeof(wmi_peer_signal_stats_thresh) +
2260 sizeof(wmi_tx_stats_thresh) +
2261 sizeof(wmi_rx_stats_thresh) +
2262 5 * WMI_TLV_HDR_SIZE;
2263 buf = wmi_buf_alloc(wma->wmi_handle, len);
2264 if (!buf) {
2265 WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
2266 return;
2267 }
2268
2269 buf_ptr = (u_int8_t *)wmi_buf_data(buf);
2270 tag = WMITLV_TAG_STRUC_wmi_pdev_set_stats_threshold_cmd_fixed_param;
2271 hdr_len = WMITLV_GET_STRUCT_TLVLEN(
2272 wmi_pdev_set_stats_threshold_cmd_fixed_param);
2273 WMA_LOGD(FL("Setting fixed parameters. tag=%d, len=%d"), tag, hdr_len);
2274 cmd = (wmi_pdev_set_stats_threshold_cmd_fixed_param *)buf_ptr;
2275 WMITLV_SET_HDR(&cmd->tlv_header, tag, hdr_len);
2276 cmd->enable_thresh = thresh->enable;
2277 cmd->use_thresh_bitmap = thresh->enable_bitmap;
2278 cmd->gbl_thresh = thresh->global_threshold;
2279 cmd->cca_thresh_enable_bitmap = thresh->cca_bitmap;
2280 cmd->signal_thresh_enable_bitmap = thresh->signal_bitmap;
2281 cmd->tx_thresh_enable_bitmap = thresh->tx_bitmap;
2282 cmd->rx_thresh_enable_bitmap = thresh->rx_bitmap;
2283 len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param);
2284
2285 tag = WMITLV_TAG_STRUC_wmi_chan_cca_stats_thresh,
2286 hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_chan_cca_stats_thresh);
2287 cca = (wmi_chan_cca_stats_thresh *)(buf_ptr + len);
2288 WMITLV_SET_HDR(&cca->tlv_header, tag, hdr_len);
2289 WMA_LOGD(FL("Setting cca parameters. tag=%d, len=%d"), tag, hdr_len);
2290 cca->idle_time = thresh->cca.idle_time;
2291 cca->tx_time = thresh->cca.tx_time;
2292 cca->rx_in_bss_time = thresh->cca.rx_in_bss_time;
2293 cca->rx_out_bss_time = thresh->cca.rx_out_bss_time;
2294 cca->rx_busy_time = thresh->cca.rx_busy_time;
2295 cca->rx_in_bad_cond_time = thresh->cca.rx_in_bad_cond_time;
2296 cca->tx_in_bad_cond_time = thresh->cca.tx_in_bad_cond_time;
2297 cca->wlan_not_avail_time = thresh->cca.wlan_not_avail_time;
2298 WMA_LOGD(FL("idle time=%d, tx_time=%d, in_bss=%d, out_bss=%d"),
2299 cca->idle_time, cca->tx_time,
2300 cca->rx_in_bss_time, cca->rx_out_bss_time);
2301 WMA_LOGD(FL("rx_busy=%d, rx_bad=%d, tx_bad=%d, not_avail=%d"),
2302 cca->rx_busy_time, cca->rx_in_bad_cond_time,
2303 cca->tx_in_bad_cond_time, cca->wlan_not_avail_time);
2304 len += sizeof(wmi_chan_cca_stats_thresh);
2305
2306 signal = (wmi_peer_signal_stats_thresh *)(buf_ptr + len);
2307 tag = WMITLV_TAG_STRUC_wmi_peer_signal_stats_thresh;
2308 hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_peer_signal_stats_thresh);
2309 WMA_LOGD(FL("Setting signal parameters. tag=%d, len=%d"), tag, hdr_len);
2310 WMITLV_SET_HDR(&signal->tlv_header, tag, hdr_len);
2311 signal->per_chain_snr = thresh->signal.snr;
2312 signal->per_chain_nf = thresh->signal.nf;
2313 WMA_LOGD(FL("snr=%d, nf=%d"), signal->per_chain_snr,
2314 signal->per_chain_nf);
2315 len += sizeof(wmi_peer_signal_stats_thresh);
2316
2317 tx = (wmi_tx_stats_thresh *)(buf_ptr + len);
2318 tag = WMITLV_TAG_STRUC_wmi_tx_stats_thresh;
2319 hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_tx_stats_thresh);
2320 WMA_LOGD(FL("Setting TX parameters. tag=%d, len=%d"), tag, len);
2321 WMITLV_SET_HDR(&tx->tlv_header, tag, hdr_len);
2322 tx->tx_msdu_cnt = thresh->tx.msdu;
2323 tx->tx_mpdu_cnt = thresh->tx.mpdu;
2324 tx->tx_ppdu_cnt = thresh->tx.ppdu;
2325 tx->tx_bytes = thresh->tx.bytes;
2326 tx->tx_msdu_drop_cnt = thresh->tx.msdu_drop;
2327 tx->tx_drop_bytes = thresh->tx.byte_drop;
2328 tx->tx_mpdu_retry_cnt = thresh->tx.mpdu_retry;
2329 tx->tx_mpdu_fail_cnt = thresh->tx.mpdu_fail;
2330 tx->tx_ppdu_fail_cnt = thresh->tx.ppdu_fail;
2331 tx->tx_mpdu_aggr = thresh->tx.aggregation;
2332 tx->tx_succ_mcs = thresh->tx.succ_mcs;
2333 tx->tx_fail_mcs = thresh->tx.fail_mcs;
2334 tx->tx_ppdu_delay = thresh->tx.delay;
2335 WMA_LOGD(FL("msdu=%d, mpdu=%d, ppdu=%d, bytes=%d, msdu_drop=%d"),
2336 tx->tx_msdu_cnt, tx->tx_mpdu_cnt, tx->tx_ppdu_cnt,
2337 tx->tx_bytes, tx->tx_msdu_drop_cnt);
2338 WMA_LOGD(FL("byte_drop=%d, mpdu_retry=%d, mpdu_fail=%d, ppdu_fail=%d"),
2339 tx->tx_drop_bytes, tx->tx_mpdu_retry_cnt,
2340 tx->tx_mpdu_fail_cnt, tx->tx_ppdu_fail_cnt);
2341 WMA_LOGD(FL("aggr=%d, succ_mcs=%d, fail_mcs=%d, delay=%d"),
2342 tx->tx_mpdu_aggr, tx->tx_succ_mcs, tx->tx_fail_mcs,
2343 tx->tx_ppdu_delay);
2344 len += sizeof(wmi_tx_stats_thresh);
2345
2346 rx = (wmi_rx_stats_thresh *)(buf_ptr + len);
2347 tag = WMITLV_TAG_STRUC_wmi_rx_stats_thresh,
2348 hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_rx_stats_thresh);
2349 WMITLV_SET_HDR(&rx->tlv_header, tag, hdr_len);
2350 WMA_LOGD(FL("Setting RX parameters. tag=%d, len=%d"), tag, hdr_len);
2351 rx->mac_rx_mpdu_cnt = thresh->rx.mpdu;
2352 rx->mac_rx_bytes = thresh->rx.bytes;
2353 rx->phy_rx_ppdu_cnt = thresh->rx.ppdu;
2354 rx->phy_rx_bytes = thresh->rx.ppdu_bytes;
2355 rx->rx_disorder_cnt = thresh->rx.disorder;
2356 rx->rx_mpdu_retry_cnt = thresh->rx.mpdu_retry;
2357 rx->rx_mpdu_dup_cnt = thresh->rx.mpdu_dup;
2358 rx->rx_mpdu_discard_cnt = thresh->rx.mpdu_discard;
2359 rx->rx_mpdu_aggr = thresh->rx.aggregation;
2360 rx->rx_mcs = thresh->rx.mcs;
2361 rx->sta_ps_inds = thresh->rx.ps_inds;
2362 rx->sta_ps_durs = thresh->rx.ps_durs;
2363 rx->rx_probe_reqs = thresh->rx.probe_reqs;
2364 rx->rx_oth_mgmts = thresh->rx.other_mgmt;
2365 WMA_LOGD(FL("rx_mpdu=%d, rx_bytes=%d, rx_ppdu=%d, rx_pbytes=%d"),
2366 rx->mac_rx_mpdu_cnt, rx->mac_rx_bytes,
2367 rx->phy_rx_ppdu_cnt, rx->phy_rx_bytes);
2368 WMA_LOGD(FL("disorder=%d, rx_dup=%d, rx_aggr=%d, rx_mcs=%d"),
2369 rx->rx_disorder_cnt, rx->rx_mpdu_dup_cnt,
2370 rx->rx_mpdu_aggr, rx->rx_mcs);
2371 WMA_LOGD(FL("rx_ind=%d, rx_dur=%d, rx_probe=%d, rx_mgmt=%d"),
2372 rx->sta_ps_inds, rx->sta_ps_durs,
2373 rx->rx_probe_reqs, rx->rx_oth_mgmts);
2374 len += sizeof(wmi_rx_stats_thresh);
2375
2376 WMA_LOGA("WMA --> WMI_PDEV_SET_STATS_THRESHOLD_CMDID(0x%x), length=%d",
2377 WMI_PDEV_SET_STATS_THRESHOLD_CMDID, len);
2378 if (EOK != wmi_unified_cmd_send(wma->wmi_handle,
2379 buf, len,
2380 WMI_PDEV_SET_STATS_THRESHOLD_CMDID)) {
2381 WMA_LOGE("Failed to send WMI_PDEV_SET_STATS_THRESHOLD_CMDID");
2382 wmi_buf_free(buf);
2383 }
2384}
2385
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002386#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
2387
2388/**
2389 * wma_update_pdev_stats() - update pdev stats
2390 * @wma: wma handle
2391 * @pdev_stats: pdev stats
2392 *
2393 * Return: none
2394 */
2395static void wma_update_pdev_stats(tp_wma_handle wma,
2396 wmi_pdev_stats *pdev_stats)
2397{
2398 tAniGetPEStatsRsp *stats_rsp_params;
2399 uint32_t temp_mask;
2400 uint8_t *stats_buf;
2401 tCsrGlobalClassAStatsInfo *classa_stats = NULL;
2402 struct wma_txrx_node *node;
2403 uint8_t i;
2404
2405 for (i = 0; i < wma->max_bssid; i++) {
2406 node = &wma->interfaces[i];
2407 stats_rsp_params = node->stats_rsp;
2408 if (stats_rsp_params) {
2409 node->fw_stats_set |= FW_PDEV_STATS_SET;
2410 WMA_LOGD("<---FW PDEV STATS received for vdevId:%d", i);
2411 stats_buf = (uint8_t *) (stats_rsp_params + 1);
2412 temp_mask = stats_rsp_params->statsMask;
2413 if (temp_mask & (1 << eCsrSummaryStats))
2414 stats_buf += sizeof(tCsrSummaryStatsInfo);
2415
2416 if (temp_mask & (1 << eCsrGlobalClassAStats)) {
2417 classa_stats =
2418 (tCsrGlobalClassAStatsInfo *) stats_buf;
2419 classa_stats->max_pwr = pdev_stats->chan_tx_pwr;
2420 }
2421 }
2422 }
2423}
2424
2425/**
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302426 * wma_vdev_stats_lost_link_helper() - helper function to extract
2427 * lost link information from vdev statistics event while deleting BSS.
2428 * @wma: WMA handle
2429 * @vdev_stats: statistics information from firmware
2430 *
2431 * This is for informing HDD to collect lost link information while
2432 * disconnection. Following conditions to check
2433 * 1. vdev is up
2434 * 2. bssid is zero. When handling DELETE_BSS request message, it sets bssid to
2435 * zero, hence add the check here to indicate the event comes during deleting
2436 * BSS
2437 * 3. DELETE_BSS is the request message queued. Put this condition check on the
2438 * last one as it consumes more resource searching entries in the list
2439 *
2440 * Return: none
2441 */
2442static void wma_vdev_stats_lost_link_helper(tp_wma_handle wma,
2443 wmi_vdev_stats *vdev_stats)
2444{
2445 struct wma_txrx_node *node;
2446 int32_t rssi;
2447 struct wma_target_req *req_msg;
2448 static const uint8_t zero_mac[QDF_MAC_ADDR_SIZE] = {0};
Naveen Rawatf440a132017-05-05 12:27:39 -07002449 int32_t bcn_snr, dat_snr;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302450
2451 node = &wma->interfaces[vdev_stats->vdev_id];
Mukul Sharmaf9047232017-03-02 16:58:56 +05302452 if (wma_is_vdev_up(vdev_stats->vdev_id) &&
Hanumanth Reddy Pothulaaef3c7f2017-05-18 12:19:23 +05302453 !qdf_mem_cmp(node->bssid, zero_mac, QDF_MAC_ADDR_SIZE)) {
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302454 req_msg = wma_peek_vdev_req(wma, vdev_stats->vdev_id,
2455 WMA_TARGET_REQ_TYPE_VDEV_STOP);
2456 if ((NULL == req_msg) ||
2457 (WMA_DELETE_BSS_REQ != req_msg->msg_type)) {
2458 WMA_LOGD(FL("cannot find DELETE_BSS request message"));
2459 return;
2460 }
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002461 bcn_snr = vdev_stats->vdev_snr.bcn_snr;
2462 dat_snr = vdev_stats->vdev_snr.dat_snr;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302463 WMA_LOGD(FL("get vdev id %d, beancon snr %d, data snr %d"),
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002464 vdev_stats->vdev_id, bcn_snr, dat_snr);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302465
2466 if (WMA_TGT_IS_VALID_SNR(bcn_snr))
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002467 rssi = bcn_snr;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302468 else if (WMA_TGT_IS_VALID_SNR(dat_snr))
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002469 rssi = dat_snr;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302470 else
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302471 rssi = WMA_TGT_INVALID_SNR;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302472
2473 /* Get the absolute rssi value from the current rssi value */
2474 rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
2475 wma_lost_link_info_handler(wma, vdev_stats->vdev_id, rssi);
2476 }
2477}
2478
2479/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002480 * wma_update_vdev_stats() - update vdev stats
2481 * @wma: wma handle
2482 * @vdev_stats: vdev stats
2483 *
2484 * Return: none
2485 */
2486static void wma_update_vdev_stats(tp_wma_handle wma,
2487 wmi_vdev_stats *vdev_stats)
2488{
2489 tAniGetPEStatsRsp *stats_rsp_params;
2490 tCsrSummaryStatsInfo *summary_stats = NULL;
2491 uint8_t *stats_buf;
2492 struct wma_txrx_node *node;
2493 uint8_t i;
Naveen Rawatf440a132017-05-05 12:27:39 -07002494 int32_t rssi = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302495 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002496 tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) wma->pGetRssiReq;
Rajeev Kumarb60abe42017-01-21 15:39:31 -08002497 struct scheduler_msg sme_msg = { 0 };
Naveen Rawatf440a132017-05-05 12:27:39 -07002498 int32_t bcn_snr, dat_snr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002499
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002500 bcn_snr = vdev_stats->vdev_snr.bcn_snr;
2501 dat_snr = vdev_stats->vdev_snr.dat_snr;
2502 WMA_LOGD("vdev id %d beancon snr %d data snr %d",
2503 vdev_stats->vdev_id, bcn_snr, dat_snr);
2504
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002505 node = &wma->interfaces[vdev_stats->vdev_id];
2506 stats_rsp_params = node->stats_rsp;
2507 if (stats_rsp_params) {
2508 stats_buf = (uint8_t *) (stats_rsp_params + 1);
2509 node->fw_stats_set |= FW_VDEV_STATS_SET;
2510 WMA_LOGD("<---FW VDEV STATS received for vdevId:%d",
2511 vdev_stats->vdev_id);
2512 if (stats_rsp_params->statsMask & (1 << eCsrSummaryStats)) {
2513 summary_stats = (tCsrSummaryStatsInfo *) stats_buf;
2514 for (i = 0; i < 4; i++) {
2515 summary_stats->tx_frm_cnt[i] =
2516 vdev_stats->tx_frm_cnt[i];
2517 summary_stats->fail_cnt[i] =
2518 vdev_stats->fail_cnt[i];
2519 summary_stats->multiple_retry_cnt[i] =
2520 vdev_stats->multiple_retry_cnt[i];
2521 }
2522
2523 summary_stats->rx_frm_cnt = vdev_stats->rx_frm_cnt;
2524 summary_stats->rx_error_cnt = vdev_stats->rx_err_cnt;
2525 summary_stats->rx_discard_cnt =
2526 vdev_stats->rx_discard_cnt;
2527 summary_stats->ack_fail_cnt = vdev_stats->ack_fail_cnt;
2528 summary_stats->rts_succ_cnt = vdev_stats->rts_succ_cnt;
2529 summary_stats->rts_fail_cnt = vdev_stats->rts_fail_cnt;
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002530 /* Update SNR and RSSI in SummaryStats */
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302531 if (WMA_TGT_IS_VALID_SNR(bcn_snr)) {
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002532 summary_stats->snr = bcn_snr;
2533 summary_stats->rssi =
2534 bcn_snr + WMA_TGT_NOISE_FLOOR_DBM;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302535 } else if (WMA_TGT_IS_VALID_SNR(dat_snr)) {
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002536 summary_stats->snr = dat_snr;
2537 summary_stats->rssi =
Naveen Rawatf440a132017-05-05 12:27:39 -07002538 dat_snr + WMA_TGT_NOISE_FLOOR_DBM;
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002539 } else {
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302540 summary_stats->snr = WMA_TGT_INVALID_SNR;
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002541 summary_stats->rssi = 0;
2542 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002543 }
2544 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002545
2546 if (pGetRssiReq && pGetRssiReq->sessionId == vdev_stats->vdev_id) {
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302547 if (WMA_TGT_IS_VALID_SNR(bcn_snr)) {
2548 rssi = bcn_snr;
2549 rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
2550 } else if (WMA_TGT_IS_VALID_SNR(dat_snr)) {
2551 rssi = dat_snr;
2552 rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
2553 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002554 /*
2555 * Firmware sends invalid snr till it sees
2556 * Beacon/Data after connection since after
2557 * vdev up fw resets the snr to invalid.
2558 * In this duartion Host will return the last know
2559 * rssi during connection.
2560 */
2561 WMA_LOGE("Invalid SNR from firmware");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002562 }
2563
2564 WMA_LOGD("Average Rssi = %d, vdev id= %d", rssi,
2565 pGetRssiReq->sessionId);
2566
2567 /* update the average rssi value to UMAC layer */
2568 if (NULL != pGetRssiReq->rssiCallback) {
2569 ((tCsrRssiCallback) (pGetRssiReq->rssiCallback))(rssi,
2570 pGetRssiReq->staId,
2571 pGetRssiReq->pDevContext);
2572 }
2573
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302574 qdf_mem_free(pGetRssiReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002575 wma->pGetRssiReq = NULL;
2576 }
2577
2578 if (node->psnr_req) {
2579 tAniGetSnrReq *p_snr_req = node->psnr_req;
2580
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302581 if (WMA_TGT_IS_VALID_SNR(bcn_snr))
Varun Reddy Yeturu83ccb9b2016-06-29 11:55:41 -07002582 p_snr_req->snr = bcn_snr;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302583 else if (WMA_TGT_IS_VALID_SNR(dat_snr))
Naveen Rawat2cb788d2016-10-11 17:44:44 -07002584 p_snr_req->snr = dat_snr;
Varun Reddy Yeturue5476a92017-02-18 12:16:43 -08002585 else
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302586 p_snr_req->snr = WMA_TGT_INVALID_SNR;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002587
2588 sme_msg.type = eWNI_SME_SNR_IND;
2589 sme_msg.bodyptr = p_snr_req;
2590 sme_msg.bodyval = 0;
2591
Rajeev Kumarb60abe42017-01-21 15:39:31 -08002592 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302593 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002594 WMA_LOGE("%s: Fail to post snr ind msg", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302595 qdf_mem_free(p_snr_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002596 }
2597
2598 node->psnr_req = NULL;
2599 }
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05302600 wma_vdev_stats_lost_link_helper(wma, vdev_stats);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002601}
2602
2603/**
2604 * wma_post_stats() - update stats to PE
2605 * @wma: wma handle
2606 * @node: txrx node
2607 *
2608 * Return: none
2609 */
2610static void wma_post_stats(tp_wma_handle wma, struct wma_txrx_node *node)
2611{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002612 /* send response to UMAC */
Naveen Rawat3c49d192017-03-02 18:43:16 -08002613 wma_send_msg(wma, WMA_GET_STATISTICS_RSP, node->stats_rsp, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002614 node->stats_rsp = NULL;
2615 node->fw_stats_set = 0;
2616}
2617
2618/**
2619 * wma_update_peer_stats() - update peer stats
2620 * @wma: wma handle
2621 * @peer_stats: peer stats
2622 *
2623 * Return: none
2624 */
2625static void wma_update_peer_stats(tp_wma_handle wma,
2626 wmi_peer_stats *peer_stats)
2627{
2628 tAniGetPEStatsRsp *stats_rsp_params;
2629 tCsrGlobalClassAStatsInfo *classa_stats = NULL;
2630 struct wma_txrx_node *node;
2631 uint8_t *stats_buf, vdev_id, macaddr[IEEE80211_ADDR_LEN], mcsRateFlags;
2632 uint32_t temp_mask;
2633
2634 WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, &macaddr[0]);
2635 if (!wma_find_vdev_by_bssid(wma, macaddr, &vdev_id))
2636 return;
2637
2638 node = &wma->interfaces[vdev_id];
Naveen Rawat3c49d192017-03-02 18:43:16 -08002639 stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp;
2640 if (stats_rsp_params) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002641 node->fw_stats_set |= FW_PEER_STATS_SET;
2642 WMA_LOGD("<-- FW PEER STATS received for vdevId:%d", vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002643 stats_buf = (uint8_t *) (stats_rsp_params + 1);
2644 temp_mask = stats_rsp_params->statsMask;
2645 if (temp_mask & (1 << eCsrSummaryStats))
2646 stats_buf += sizeof(tCsrSummaryStatsInfo);
2647
2648 if (temp_mask & (1 << eCsrGlobalClassAStats)) {
2649 classa_stats = (tCsrGlobalClassAStatsInfo *) stats_buf;
2650 WMA_LOGD("peer tx rate:%d", peer_stats->peer_tx_rate);
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002651 /* The linkspeed returned by fw is in kbps so convert
2652 * it in to units of 500kbps which is expected by UMAC
2653 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002654 if (peer_stats->peer_tx_rate) {
2655 classa_stats->tx_rate =
2656 peer_stats->peer_tx_rate / 500;
2657 }
2658
2659 classa_stats->tx_rate_flags = node->rate_flags;
2660 if (!(node->rate_flags & eHAL_TX_RATE_LEGACY)) {
2661 classa_stats->mcs_index =
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002662 wma_get_mcs_idx(
2663 (peer_stats->peer_tx_rate /
2664 100), node->rate_flags,
2665 node->nss, &mcsRateFlags);
Jeff Johnsonad0b2c62017-03-16 14:37:38 -07002666 classa_stats->nss = node->nss;
2667 classa_stats->mcs_rate_flags = mcsRateFlags;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002668 }
2669 /* FW returns tx power in intervals of 0.5 dBm
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002670 * Convert it back to intervals of 1 dBm
2671 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002672 classa_stats->max_pwr =
2673 roundup(classa_stats->max_pwr, 2) >> 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002674 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002675 }
2676}
2677
2678/**
2679 * wma_post_link_status() - post link status to SME
2680 * @pGetLinkStatus: SME Link status
2681 * @link_status: Link status
2682 *
2683 * Return: none
2684 */
2685void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus,
2686 uint8_t link_status)
2687{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302688 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Rajeev Kumarb60abe42017-01-21 15:39:31 -08002689 struct scheduler_msg sme_msg = { 0 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002690
2691 pGetLinkStatus->linkStatus = link_status;
2692 sme_msg.type = eWNI_SME_LINK_STATUS_IND;
2693 sme_msg.bodyptr = pGetLinkStatus;
2694 sme_msg.bodyval = 0;
2695
Rajeev Kumarb60abe42017-01-21 15:39:31 -08002696 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302697 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002698 WMA_LOGE("%s: Fail to post link status ind msg", __func__);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302699 qdf_mem_free(pGetLinkStatus);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002700 }
2701}
2702
2703/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302704 * wma_update_per_chain_rssi_stats() - to store per chain rssi stats
2705 * @wma: wma handle
2706 * @rssi_stats: rssi stats
2707 * @rssi_per_chain_stats: buffer where rssi stats to be stored
2708 *
2709 * This function stores per chain rssi stats received from fw for all vdevs for
2710 * which the stats were requested into a csr stats structure.
2711 *
2712 * Return: void
2713 */
2714static void wma_update_per_chain_rssi_stats(tp_wma_handle wma,
2715 wmi_rssi_stats *rssi_stats,
2716 struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats)
2717{
2718 int i;
Naveen Rawatf440a132017-05-05 12:27:39 -07002719 int32_t bcn_snr, dat_snr;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302720
2721 for (i = 0; i < NUM_CHAINS_MAX; i++) {
2722 bcn_snr = rssi_stats->rssi_avg_beacon[i];
2723 dat_snr = rssi_stats->rssi_avg_data[i];
2724 WMA_LOGD("chain %d beacon snr %d data snr %d",
2725 i, bcn_snr, dat_snr);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302726 if (WMA_TGT_IS_VALID_SNR(bcn_snr))
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302727 rssi_per_chain_stats->rssi[i] = bcn_snr;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302728 else if (WMA_TGT_IS_VALID_SNR(dat_snr))
2729 rssi_per_chain_stats->rssi[i] = dat_snr;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302730 else
2731 /*
2732 * Firmware sends invalid snr till it sees
2733 * Beacon/Data after connection since after
2734 * vdev up fw resets the snr to invalid.
2735 * In this duartion Host will return an invalid rssi
2736 * value.
2737 */
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05302738 rssi_per_chain_stats->rssi[i] = WMA_TGT_INVALID_SNR;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302739
2740 /*
2741 * Get the absolute rssi value from the current rssi value the
2742 * sinr value is hardcoded into 0 in the qcacld-new/CORE stack
2743 */
2744 rssi_per_chain_stats->rssi[i] += WMA_TGT_NOISE_FLOOR_DBM;
2745 WMI_MAC_ADDR_TO_CHAR_ARRAY(&(rssi_stats->peer_macaddr),
2746 rssi_per_chain_stats->peer_mac_addr);
2747 }
2748}
2749
2750/**
2751 * wma_update_rssi_stats() - to update rssi stats for all vdevs
2752 * for which the stats were requested.
2753 * @wma: wma handle
2754 * @rssi_stats: rssi stats
2755 *
2756 * This function updates the rssi stats for all vdevs for which
2757 * the stats were requested.
2758 *
2759 * Return: void
2760 */
2761static void wma_update_rssi_stats(tp_wma_handle wma,
2762 wmi_rssi_stats *rssi_stats)
2763{
2764 tAniGetPEStatsRsp *stats_rsp_params;
2765 struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats = NULL;
2766 struct wma_txrx_node *node;
2767 uint8_t *stats_buf;
2768 uint32_t temp_mask;
2769 uint8_t vdev_id;
2770
2771 vdev_id = rssi_stats->vdev_id;
2772 node = &wma->interfaces[vdev_id];
Naveen Rawat3c49d192017-03-02 18:43:16 -08002773 stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp;
2774 if (stats_rsp_params) {
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302775 node->fw_stats_set |= FW_RSSI_PER_CHAIN_STATS_SET;
2776 WMA_LOGD("<-- FW RSSI PER CHAIN STATS received for vdevId:%d",
2777 vdev_id);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302778 stats_buf = (uint8_t *) (stats_rsp_params + 1);
2779 temp_mask = stats_rsp_params->statsMask;
2780
2781 if (temp_mask & (1 << eCsrSummaryStats))
2782 stats_buf += sizeof(tCsrSummaryStatsInfo);
2783 if (temp_mask & (1 << eCsrGlobalClassAStats))
2784 stats_buf += sizeof(tCsrGlobalClassAStatsInfo);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302785 if (temp_mask & (1 << eCsrGlobalClassDStats))
2786 stats_buf += sizeof(tCsrGlobalClassDStatsInfo);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302787
2788 if (temp_mask & (1 << csr_per_chain_rssi_stats)) {
2789 rssi_per_chain_stats =
2790 (struct csr_per_chain_rssi_stats_info *)stats_buf;
2791 wma_update_per_chain_rssi_stats(wma, rssi_stats,
2792 rssi_per_chain_stats);
2793 }
2794 }
2795}
2796
2797
2798/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002799 * wma_link_status_event_handler() - link status event handler
2800 * @handle: wma handle
2801 * @cmd_param_info: data from event
2802 * @len: length
2803 *
2804 * Return: 0 for success or error code
2805 */
2806int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info,
2807 uint32_t len)
2808{
2809 tp_wma_handle wma = (tp_wma_handle) handle;
2810 WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf;
2811 wmi_vdev_rate_stats_event_fixed_param *event;
2812 wmi_vdev_rate_ht_info *ht_info;
2813 struct wma_txrx_node *intr = wma->interfaces;
2814 uint8_t link_status = LINK_STATUS_LEGACY;
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07002815 uint32_t i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002816
2817 param_buf =
2818 (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *) cmd_param_info;
2819 if (!param_buf) {
2820 WMA_LOGA("%s: Invalid stats event", __func__);
2821 return -EINVAL;
2822 }
2823
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002824 event = (wmi_vdev_rate_stats_event_fixed_param *)
2825 param_buf->fixed_param;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002826 ht_info = (wmi_vdev_rate_ht_info *) param_buf->ht_info;
2827
2828 WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats);
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07002829
2830 if (event->num_vdev_stats > ((WMI_SVC_MSG_MAX_SIZE -
2831 sizeof(*event)) / sizeof(*ht_info))) {
2832 WMA_LOGE("%s: excess vdev_stats buffers:%d", __func__,
2833 event->num_vdev_stats);
2834 QDF_ASSERT(0);
2835 return -EINVAL;
2836 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002837 for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) {
2838 WMA_LOGD("%s vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d",
2839 __func__, ht_info->vdevid, ht_info->tx_nss,
2840 ht_info->rx_nss, ht_info->tx_preamble,
2841 ht_info->rx_preamble);
2842 if (ht_info->vdevid < wma->max_bssid
2843 && intr[ht_info->vdevid].plink_status_req) {
2844 if (ht_info->tx_nss || ht_info->rx_nss)
2845 link_status = LINK_STATUS_MIMO;
2846
2847 if ((ht_info->tx_preamble == LINK_RATE_VHT) ||
2848 (ht_info->rx_preamble == LINK_RATE_VHT))
2849 link_status |= LINK_STATUS_VHT;
2850
2851 if (intr[ht_info->vdevid].nss == 2)
2852 link_status |= LINK_SUPPORT_MIMO;
2853
2854 if (intr[ht_info->vdevid].rate_flags &
2855 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
2856 eHAL_TX_RATE_VHT80))
2857 link_status |= LINK_SUPPORT_VHT;
2858
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07002859 wma_post_link_status(
2860 intr[ht_info->vdevid].plink_status_req,
2861 link_status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002862 intr[ht_info->vdevid].plink_status_req = NULL;
2863 link_status = LINK_STATUS_LEGACY;
2864 }
2865
2866 ht_info++;
2867 }
2868
2869 return 0;
2870}
2871
Sreelakshmi Konamki88a2a412017-04-14 15:11:55 +05302872int wma_rso_cmd_status_event_handler(wmi_roam_event_fixed_param *wmi_event)
2873{
2874 struct rso_cmd_status *rso_status;
Rajeev Kumarcf7bd802017-04-18 11:11:42 -07002875 struct scheduler_msg sme_msg = {0};
Sreelakshmi Konamki88a2a412017-04-14 15:11:55 +05302876 QDF_STATUS qdf_status;
2877
2878 rso_status = qdf_mem_malloc(sizeof(*rso_status));
2879 if (!rso_status) {
2880 WMA_LOGE("%s: malloc fails for rso cmd status", __func__);
2881 return -ENOMEM;
2882 }
2883
2884 rso_status->vdev_id = wmi_event->vdev_id;
2885 if (WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS == wmi_event->notif)
2886 rso_status->status = true;
2887 else if (WMI_ROAM_NOTIF_SCAN_MODE_FAIL == wmi_event->notif)
2888 rso_status->status = false;
2889 sme_msg.type = eWNI_SME_RSO_CMD_STATUS_IND;
2890 sme_msg.bodyptr = rso_status;
2891 sme_msg.bodyval = 0;
2892 WMA_LOGI("%s: Post RSO cmd status to SME", __func__);
2893
2894 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
2895 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
2896 WMA_LOGE("%s: fail to post RSO cmd status to SME", __func__);
2897 qdf_mem_free(rso_status);
2898 }
2899 return 0;
2900}
2901
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002902/**
Will Huanga9814592017-05-24 15:47:58 +08002903 * wma_handle_sta_peer_info() - handle peer information in
2904 * peer stats
2905 * @num_peer_stats: peer number
2906 * @peer_stats: peer stats received from firmware
2907 * @peer_macaddr: the specified mac address
2908 * @sapaddr: sap mac address
2909 *
2910 * This function will send eWNI_SME_GET_PEER_INFO_IND
2911 * to sme with stations' information
2912 *
2913 */
2914static void wma_handle_sta_peer_info(uint32_t num_peer_stats,
2915 wmi_peer_stats *peer_stats,
2916 struct qdf_mac_addr peer_macaddr,
2917 uint8_t *sapaddr)
2918{
2919 QDF_STATUS qdf_status;
2920 wmi_mac_addr temp_addr;
2921 struct sir_peer_info_resp *peer_info;
2922 struct scheduler_msg sme_msg = {0};
2923 uint32_t i;
2924 uint32_t j = 0;
2925
2926 if (!qdf_is_macaddr_broadcast(&peer_macaddr)) {
2927 WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_macaddr.bytes, &temp_addr);
2928 for (i = 0; i < num_peer_stats; i++) {
2929 if ((((temp_addr.mac_addr47to32) & 0x0000ffff) ==
2930 ((peer_stats->peer_macaddr.mac_addr47to32) &
2931 0x0000ffff))
2932 && (temp_addr.mac_addr31to0 ==
2933 peer_stats->peer_macaddr.mac_addr31to0)) {
2934
2935 break;
2936 }
2937 peer_stats = peer_stats + 1;
2938 }
2939 peer_info = qdf_mem_malloc(sizeof(*peer_info) +
2940 sizeof(peer_info->info[0]));
2941 if (NULL == peer_info) {
2942 WMA_LOGE("%s: Memory allocation failed.", __func__);
2943 return;
2944 }
2945 if (i < num_peer_stats) {
2946 peer_info->count = 1;
2947 WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
2948 peer_info->info[0].peer_macaddr.bytes);
2949 peer_info->info[0].rssi = peer_stats->peer_rssi;
2950 peer_info->info[0].tx_rate = peer_stats->peer_tx_rate;
2951 peer_info->info[0].rx_rate = peer_stats->peer_rx_rate;
2952 WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d",
2953 __func__,
2954 peer_info->info[0].peer_macaddr.bytes,
2955 peer_stats->peer_rssi,
2956 peer_stats->peer_tx_rate,
2957 peer_stats->peer_rx_rate);
2958 } else {
2959 WMA_LOGE("%s: no match mac address", __func__);
2960 peer_info->count = 0;
2961 }
2962 } else {
2963 peer_info = qdf_mem_malloc(sizeof(*peer_info) +
2964 num_peer_stats * sizeof(peer_info->info[0]));
2965 if (NULL == peer_info) {
2966 WMA_LOGE("%s: Memory allocation failed.", __func__);
2967 return;
2968 }
2969 peer_info->count = num_peer_stats;
2970
2971 for (i = 0; i < num_peer_stats; i++) {
2972 WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
2973 peer_info->info[j].peer_macaddr.bytes);
2974 peer_info->info[j].rssi = peer_stats->peer_rssi;
2975 peer_info->info[j].tx_rate = peer_stats->peer_tx_rate;
2976 peer_info->info[j].rx_rate = peer_stats->peer_rx_rate;
2977 WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d",
2978 __func__,
2979 peer_info->info[j].peer_macaddr.bytes,
2980 peer_stats->peer_rssi,
2981 peer_stats->peer_tx_rate,
2982 peer_stats->peer_rx_rate);
2983 if (!qdf_mem_cmp(peer_info->info[j].peer_macaddr.bytes,
2984 sapaddr, QDF_MAC_ADDR_SIZE)) {
2985 peer_info->count = peer_info->count - 1;
2986 } else {
2987 j++;
2988 }
2989 peer_stats = peer_stats + 1;
2990 }
2991 WMA_LOGD("WDA send peer num %d", peer_info->count);
2992 }
2993
2994 sme_msg.type = eWNI_SME_GET_PEER_INFO_IND;
2995 sme_msg.bodyptr = peer_info;
2996 sme_msg.bodyval = 0;
2997
2998 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
2999 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
3000 WMA_LOGE("%s: Fail to post get rssi msg", __func__);
3001 qdf_mem_free(peer_info);
3002 }
3003
3004 return;
3005}
3006
3007/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003008 * wma_stats_event_handler() - stats event handler
3009 * @handle: wma handle
3010 * @cmd_param_info: data from event
3011 * @len: length
3012 *
3013 * Return: 0 for success or error code
3014 */
3015int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info,
3016 uint32_t len)
3017{
3018 tp_wma_handle wma = (tp_wma_handle) handle;
3019 WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
3020 wmi_stats_event_fixed_param *event;
3021 wmi_pdev_stats *pdev_stats;
3022 wmi_vdev_stats *vdev_stats;
3023 wmi_peer_stats *peer_stats;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303024 wmi_rssi_stats *rssi_stats;
3025 wmi_per_chain_rssi_stats *rssi_event;
3026 struct wma_txrx_node *node;
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07003027 uint8_t *temp;
3028 uint32_t i;
3029 uint32_t buf_len = 0;
3030 bool excess_data = false;
Padma, Santhosh Kumar16dacfb2017-03-21 19:05:40 +05303031 wmi_congestion_stats *congestion_stats;
3032 tpAniSirGlobal mac;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003033
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003034 param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) cmd_param_info;
3035 if (!param_buf) {
3036 WMA_LOGA("%s: Invalid stats event", __func__);
3037 return -EINVAL;
3038 }
3039 event = param_buf->fixed_param;
3040 temp = (uint8_t *) param_buf->data;
3041
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07003042 do {
3043 if (event->num_pdev_stats > ((WMI_SVC_MSG_MAX_SIZE -
3044 sizeof(*event)) / sizeof(*pdev_stats))) {
3045 excess_data = true;
3046 break;
3047 } else {
3048 buf_len += event->num_pdev_stats * sizeof(*pdev_stats);
3049 }
3050
3051 if (event->num_vdev_stats > ((WMI_SVC_MSG_MAX_SIZE -
3052 sizeof(*event)) / sizeof(*vdev_stats))) {
3053 excess_data = true;
3054 break;
3055 } else {
3056 buf_len += event->num_vdev_stats * sizeof(*vdev_stats);
3057 }
3058
3059 if (event->num_peer_stats > ((WMI_SVC_MSG_MAX_SIZE -
3060 sizeof(*event)) / sizeof(*peer_stats))) {
3061 excess_data = true;
3062 break;
3063 } else {
3064 buf_len += event->num_peer_stats * sizeof(*peer_stats);
3065 }
3066
3067 rssi_event =
3068 (wmi_per_chain_rssi_stats *) param_buf->chain_stats;
bingsf9047652017-08-31 08:05:54 +08003069 if (rssi_event) {
3070 if (rssi_event->num_per_chain_rssi_stats >
3071 ((WMI_SVC_MSG_MAX_SIZE - sizeof(*event)) /
3072 sizeof(*rssi_event))) {
3073 excess_data = true;
3074 break;
3075 } else {
3076 buf_len += sizeof(*rssi_event) *
3077 rssi_event->num_per_chain_rssi_stats;
3078 }
Varun Reddy Yeturu46ba20c2017-08-17 15:03:27 -07003079 }
3080 } while (0);
3081
3082 if (excess_data ||
3083 (sizeof(*event) > WMI_SVC_MSG_MAX_SIZE - buf_len)) {
3084 WMA_LOGE("excess wmi buffer: stats pdev %d vdev %d peer %d",
3085 event->num_pdev_stats, event->num_vdev_stats,
3086 event->num_peer_stats);
3087 QDF_ASSERT(0);
3088 return -EINVAL;
3089 }
3090
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003091 if (event->num_pdev_stats > 0) {
3092 for (i = 0; i < event->num_pdev_stats; i++) {
3093 pdev_stats = (wmi_pdev_stats *) temp;
3094 wma_update_pdev_stats(wma, pdev_stats);
3095 temp += sizeof(wmi_pdev_stats);
3096 }
3097 }
3098
3099 if (event->num_vdev_stats > 0) {
3100 for (i = 0; i < event->num_vdev_stats; i++) {
3101 vdev_stats = (wmi_vdev_stats *) temp;
3102 wma_update_vdev_stats(wma, vdev_stats);
3103 temp += sizeof(wmi_vdev_stats);
3104 }
3105 }
3106
3107 if (event->num_peer_stats > 0) {
Will Huanga9814592017-05-24 15:47:58 +08003108 if (wma->get_sta_peer_info == true) {
3109 wma_handle_sta_peer_info(event->num_peer_stats,
3110 (wmi_peer_stats *)temp,
3111 wma->peer_macaddr,
3112 wma->myaddr);
3113 } else {
3114 for (i = 0; i < event->num_peer_stats; i++) {
3115 peer_stats = (wmi_peer_stats *) temp;
3116 wma_update_peer_stats(wma, peer_stats);
3117 temp += sizeof(wmi_peer_stats);
3118 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003119 }
3120 }
3121
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303122 rssi_event = (wmi_per_chain_rssi_stats *) param_buf->chain_stats;
3123 if (rssi_event) {
Himanshu Agarwalcd8a84a2016-07-21 14:59:50 +05303124 if (((rssi_event->tlv_header & 0xFFFF0000) >> 16 ==
3125 WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats) &&
3126 ((rssi_event->tlv_header & 0x0000FFFF) ==
3127 WMITLV_GET_STRUCT_TLVLEN(wmi_per_chain_rssi_stats))) {
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303128 if (rssi_event->num_per_chain_rssi_stats > 0) {
3129 temp = (uint8_t *) rssi_event;
3130 temp += sizeof(*rssi_event);
Dustin Brownc4a5ba22016-11-10 17:21:18 -08003131
3132 /* skip past struct array tlv header */
3133 temp += WMI_TLV_HDR_SIZE;
3134
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303135 for (i = 0;
3136 i < rssi_event->num_per_chain_rssi_stats;
3137 i++) {
3138 rssi_stats = (wmi_rssi_stats *)temp;
3139 wma_update_rssi_stats(wma, rssi_stats);
3140 temp += sizeof(wmi_rssi_stats);
3141 }
3142 }
3143 }
3144 }
3145
Padma, Santhosh Kumar16dacfb2017-03-21 19:05:40 +05303146 congestion_stats = (wmi_congestion_stats *) param_buf->congestion_stats;
3147 if (congestion_stats) {
3148 if (((congestion_stats->tlv_header & 0xFFFF0000) >> 16 ==
3149 WMITLV_TAG_STRUC_wmi_congestion_stats) &&
3150 ((congestion_stats->tlv_header & 0x0000FFFF) ==
3151 WMITLV_GET_STRUCT_TLVLEN(wmi_congestion_stats))) {
3152 mac = cds_get_context(QDF_MODULE_ID_PE);
3153 if (!mac) {
3154 WMA_LOGE("%s: Invalid mac", __func__);
3155 return -EINVAL;
3156 }
3157 if (!mac->sme.congestion_cb) {
3158 WMA_LOGE("%s: Callback not registered",
3159 __func__);
3160 return -EINVAL;
3161 }
3162 WMA_LOGI("%s: congestion %d", __func__,
3163 congestion_stats->congestion);
3164 mac->sme.congestion_cb(mac->hHdd,
3165 congestion_stats->congestion,
3166 congestion_stats->vdev_id);
3167 }
3168 }
3169
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303170 for (i = 0; i < wma->max_bssid; i++) {
3171 node = &wma->interfaces[i];
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003172 if (node->fw_stats_set & FW_PEER_STATS_SET)
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303173 wma_post_stats(wma, node);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303174 }
3175
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003176 return 0;
3177}
3178
3179/**
Will Huanga9814592017-05-24 15:47:58 +08003180 * wma_fill_peer_info() - fill SIR peer info from WMI peer info struct
3181 * @wma: wma interface
3182 * @stats_info: WMI peer info pointer
3183 * @peer_info: SIR peer info pointer
3184 *
3185 * This function will fill SIR peer info from WMI peer info struct
3186 *
3187 * Return: None
3188 */
3189static void wma_fill_peer_info(tp_wma_handle wma,
3190 wmi_peer_stats_info *stats_info,
3191 struct sir_peer_info_ext *peer_info)
3192{
3193 peer_info->tx_packets = stats_info->tx_packets.low_32;
3194 peer_info->tx_bytes = stats_info->tx_bytes.high_32;
3195 peer_info->tx_bytes <<= 32;
3196 peer_info->tx_bytes += stats_info->tx_bytes.low_32;
3197 peer_info->rx_packets = stats_info->rx_packets.low_32;
3198 peer_info->rx_bytes = stats_info->rx_bytes.high_32;
3199 peer_info->rx_bytes <<= 32;
3200 peer_info->rx_bytes += stats_info->rx_bytes.low_32;
3201 peer_info->tx_retries = stats_info->tx_retries;
3202 peer_info->tx_failed = stats_info->tx_failed;
3203 peer_info->rssi = stats_info->peer_rssi;
3204 peer_info->tx_rate = stats_info->last_tx_bitrate_kbps;
3205 peer_info->tx_rate_code = stats_info->last_tx_rate_code;
3206 peer_info->rx_rate = stats_info->last_rx_bitrate_kbps;
3207 peer_info->rx_rate_code = stats_info->last_rx_rate_code;
3208}
3209
3210/**
3211 * wma_peer_info_ext_rsp() - process peer ext info ext
3212 * @handle: wma interface
3213 * @buf: wmi event buf pointer
3214 *
3215 * This function will send eWNI_SME_GET_PEER_INFO_EXT_IND to SME
3216 *
3217 * Return: 0 on success, error code otherwise
3218 */
3219static QDF_STATUS wma_peer_info_ext_rsp(tp_wma_handle wma, u_int8_t *buf)
3220{
3221 wmi_peer_stats_info_event_fixed_param *event;
3222 wmi_peer_stats_info *stats_info;
3223 struct sir_peer_info_ext_resp *resp;
3224 struct sir_peer_info_ext *peer_info;
3225 struct scheduler_msg sme_msg = {0};
3226 int i, j = 0;
3227 QDF_STATUS qdf_status;
3228
3229 event = (wmi_peer_stats_info_event_fixed_param *)buf;
3230 stats_info = (wmi_peer_stats_info *)(buf +
3231 sizeof(wmi_peer_stats_info_event_fixed_param));
3232
3233 if (wma->get_one_peer_info) {
3234 resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
3235 sizeof(resp->info[0]));
3236 if (!resp) {
3237 WMA_LOGE(FL("resp allocation failed."));
3238 return QDF_STATUS_E_NOMEM;
3239 }
3240 resp->count = 0;
3241 peer_info = &resp->info[0];
3242 for (i = 0; i < event->num_peers; i++) {
3243 WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
3244 peer_info->peer_macaddr.bytes);
3245
3246 if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes,
3247 wma->peer_macaddr.bytes,
3248 QDF_MAC_ADDR_SIZE)) {
3249 wma_fill_peer_info(wma, stats_info, peer_info);
3250 resp->count++;
3251 break;
3252 }
3253
3254 stats_info = stats_info + 1;
3255 }
3256 } else {
3257 resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
3258 event->num_peers * sizeof(resp->info[0]));
3259 if (!resp) {
3260 WMA_LOGE(FL("resp allocation failed."));
3261 return QDF_STATUS_E_NOMEM;
3262 }
3263 resp->count = event->num_peers;
3264 for (i = 0; i < event->num_peers; i++) {
3265 peer_info = &resp->info[j];
3266 WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
3267 peer_info->peer_macaddr.bytes);
3268
3269 if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes,
3270 wma->myaddr, QDF_MAC_ADDR_SIZE)) {
3271 resp->count = resp->count - 1;
3272 } else {
3273 wma_fill_peer_info(wma, stats_info, peer_info);
3274 j++;
3275 }
3276 stats_info = stats_info + 1;
3277 }
3278 }
3279
3280 sme_msg.type = eWNI_SME_GET_PEER_INFO_EXT_IND;
3281 sme_msg.bodyptr = resp;
3282 sme_msg.bodyval = 0;
3283
3284 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg);
3285 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
3286 WMA_LOGE("%s: Fail to post get peer info msg", __func__);
3287 qdf_mem_free(resp);
3288 }
3289
3290 return qdf_status;
3291}
3292
3293/**
3294 * dump_peer_stats_info() - dump wmi peer info struct
3295 * @event: wmi peer info fixed param pointer
3296 * @peer_stats: wmi peer stats info pointer
3297 *
3298 * This function will dump wmi peer info struct
3299 *
3300 * Return: None
3301 */
3302static void dump_peer_stats_info(wmi_peer_stats_info_event_fixed_param *event,
3303 wmi_peer_stats_info *peer_stats)
3304{
3305 int i;
3306 wmi_peer_stats_info *stats = peer_stats;
3307 u_int8_t mac[6];
3308
3309 WMA_LOGI("%s vdev_id %d, num_peers %d more_data %d",
3310 __func__, event->vdev_id,
3311 event->num_peers, event->more_data);
3312
3313 for (i = 0; i < event->num_peers; i++) {
3314 WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats->peer_macaddr, mac);
3315 WMA_LOGI("%s mac %pM", __func__, mac);
3316 WMA_LOGI("%s tx_bytes %d %d tx_packets %d %d",
3317 __func__,
3318 stats->tx_bytes.low_32,
3319 stats->tx_bytes.high_32,
3320 stats->tx_packets.low_32,
3321 stats->tx_packets.high_32);
3322 WMA_LOGI("%s rx_bytes %d %d rx_packets %d %d",
3323 __func__,
3324 stats->rx_bytes.low_32,
3325 stats->rx_bytes.high_32,
3326 stats->rx_packets.low_32,
3327 stats->rx_packets.high_32);
3328 WMA_LOGI("%s tx_retries %d tx_failed %d",
3329 __func__, stats->tx_retries, stats->tx_failed);
3330 WMA_LOGI("%s tx_rate_code %x rx_rate_code %x",
3331 __func__,
3332 stats->last_tx_rate_code,
3333 stats->last_rx_rate_code);
3334 WMA_LOGI("%s tx_rate %x rx_rate %x",
3335 __func__,
3336 stats->last_tx_bitrate_kbps,
3337 stats->last_rx_bitrate_kbps);
3338 WMA_LOGI("%s peer_rssi %d", __func__, stats->peer_rssi);
3339 stats++;
3340 }
3341}
3342
3343int wma_peer_info_event_handler(void *handle, u_int8_t *cmd_param_info,
3344 u_int32_t len)
3345{
3346 tp_wma_handle wma = (tp_wma_handle) handle;
3347 WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf;
3348 wmi_peer_stats_info_event_fixed_param *event;
3349 u_int32_t buf_size;
3350 u_int8_t *buf;
3351
3352 param_buf =
3353 (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)cmd_param_info;
3354 if (!param_buf) {
3355 WMA_LOGA("%s: Invalid stats event", __func__);
3356 return -EINVAL;
3357 }
3358
3359 WMA_LOGI("%s Recv WMI_PEER_STATS_INFO_EVENTID", __func__);
3360 event = param_buf->fixed_param;
Varun Reddy Yeturue4e2f292017-09-26 15:51:07 -07003361 if (event->num_peers >
3362 ((WMI_SVC_MSG_MAX_SIZE -
3363 sizeof(wmi_peer_stats_info_event_fixed_param))/
3364 sizeof(wmi_peer_stats_info))) {
3365 WMA_LOGE("Excess num of peers from fw %d", event->num_peers);
3366 return -EINVAL;
3367 }
Will Huanga9814592017-05-24 15:47:58 +08003368 buf_size = sizeof(wmi_peer_stats_info_event_fixed_param) +
3369 sizeof(wmi_peer_stats_info) * event->num_peers;
3370 buf = qdf_mem_malloc(buf_size);
3371 if (!buf) {
3372 WMA_LOGE("%s: Failed alloc memory for buf", __func__);
3373 return -ENOMEM;
3374 }
3375
3376 qdf_mem_copy(buf, param_buf->fixed_param,
3377 sizeof(wmi_peer_stats_info_event_fixed_param));
3378 qdf_mem_copy((buf + sizeof(wmi_peer_stats_info_event_fixed_param)),
3379 param_buf->peer_stats_info,
3380 sizeof(wmi_peer_stats_info) * event->num_peers);
3381 WMA_LOGI("%s dump peer stats info", __func__);
3382 dump_peer_stats_info(event, param_buf->peer_stats_info);
3383
3384 wma_peer_info_ext_rsp(wma, buf);
3385 qdf_mem_free(buf);
3386
3387 return 0;
3388}
3389
3390/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003391 * wma_send_link_speed() - send link speed to SME
3392 * @link_speed: link speed
3393 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303394 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003395 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303396QDF_STATUS wma_send_link_speed(uint32_t link_speed)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003397{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303398 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Mukul Sharmac3886aa2017-05-04 17:53:22 +05303399 tpAniSirGlobal mac_ctx;
3400 tSirLinkSpeedInfo *ls_ind;
3401
3402 mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
3403 if (!mac_ctx) {
3404 WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
3405 return QDF_STATUS_E_INVAL;
3406 }
3407
3408 ls_ind = (tSirLinkSpeedInfo *)qdf_mem_malloc(sizeof(tSirLinkSpeedInfo));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003409 if (!ls_ind) {
3410 WMA_LOGE("%s: Memory allocation failed.", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303411 qdf_status = QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003412 } else {
3413 ls_ind->estLinkSpeed = link_speed;
Mukul Sharmac3886aa2017-05-04 17:53:22 +05303414 if (mac_ctx->sme.pLinkSpeedIndCb)
3415 mac_ctx->sme.pLinkSpeedIndCb(ls_ind,
3416 mac_ctx->sme.pLinkSpeedCbContext);
3417 else
3418 WMA_LOGD("%s: pLinkSpeedIndCb is null", __func__);
3419 qdf_mem_free(ls_ind);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003420
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303422 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003423}
3424
3425/**
3426 * wma_link_speed_event_handler() - link speed event handler
3427 * @handle: wma handle
3428 * @cmd_param_info: event data
3429 * @len: length
3430 *
3431 * Return: 0 for success or error code
3432 */
3433int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info,
3434 uint32_t len)
3435{
3436 WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *param_buf;
3437 wmi_peer_estimated_linkspeed_event_fixed_param *event;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303438 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003439
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003440 param_buf = (WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *)
3441 cmd_param_info;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003442 if (!param_buf) {
3443 WMA_LOGE("%s: Invalid linkspeed event", __func__);
3444 return -EINVAL;
3445 }
3446 event = param_buf->fixed_param;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303447 qdf_status = wma_send_link_speed(event->est_linkspeed_kbps);
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003448 if (!QDF_IS_STATUS_SUCCESS(qdf_status))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003449 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003450 return 0;
3451}
3452
3453/**
3454 * wma_wni_cfg_dnld() - cfg download request
3455 * @handle: wma handle
3456 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303457 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003458 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303459QDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003460{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303461 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Anurag Chouhan6d760662016-02-20 16:05:43 +05303462 void *mac = cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003463
3464 WMA_LOGD("%s: Enter", __func__);
3465
3466 if (NULL == mac) {
Srinivas Girigowdad1a07a52017-03-06 22:48:16 -08003467 WMA_LOGE("%s: Invalid context", __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303468 QDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303469 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003470 }
3471
3472 process_cfg_download_req(mac);
3473
3474 WMA_LOGD("%s: Exit", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303475 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003476}
3477
3478/**
3479 * wma_unified_debug_print_event_handler() - debug print event handler
3480 * @handle: wma handle
3481 * @datap: data pointer
3482 * @len: length
3483 *
3484 * Return: 0 for success or error code
3485 */
3486int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap,
3487 uint32_t len)
3488{
3489 WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf;
3490 uint8_t *data;
3491 uint32_t datalen;
3492
3493 param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap;
3494 if (!param_buf) {
3495 WMA_LOGE("Get NULL point message from FW");
3496 return -ENOMEM;
3497 }
3498 data = param_buf->data;
3499 datalen = param_buf->num_data;
3500
3501#ifdef BIG_ENDIAN_HOST
3502 {
3503 char dbgbuf[500] = { 0 };
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003504
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003505 memcpy(dbgbuf, data, datalen);
3506 SWAPME(dbgbuf, datalen);
3507 WMA_LOGD("FIRMWARE:%s", dbgbuf);
3508 return 0;
3509 }
3510#else
3511 WMA_LOGD("FIRMWARE:%s", data);
3512 return 0;
3513#endif /* BIG_ENDIAN_HOST */
3514}
3515
3516/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003517 * wma_is_sap_active() - check sap is active or not
3518 * @handle: wma handle
3519 *
3520 * Return: true/false
3521 */
3522bool wma_is_sap_active(tp_wma_handle wma_handle)
3523{
3524 int i;
3525
3526 for (i = 0; i < wma_handle->max_bssid; i++) {
Mukul Sharmaf9047232017-03-02 16:58:56 +05303527 if (!wma_is_vdev_up(i))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003528 continue;
3529 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
3530 wma_handle->interfaces[i].sub_type == 0)
3531 return true;
3532 }
3533 return false;
3534}
3535
3536/**
3537 * wma_is_p2p_go_active() - check p2p go is active or not
3538 * @handle: wma handle
3539 *
3540 * Return: true/false
3541 */
3542bool wma_is_p2p_go_active(tp_wma_handle wma_handle)
3543{
3544 int i;
3545
3546 for (i = 0; i < wma_handle->max_bssid; i++) {
Mukul Sharmaf9047232017-03-02 16:58:56 +05303547 if (!wma_is_vdev_up(i))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003548 continue;
3549 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
3550 wma_handle->interfaces[i].sub_type ==
3551 WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO)
3552 return true;
3553 }
3554 return false;
3555}
3556
3557/**
3558 * wma_is_p2p_cli_active() - check p2p cli is active or not
3559 * @handle: wma handle
3560 *
3561 * Return: true/false
3562 */
3563bool wma_is_p2p_cli_active(tp_wma_handle wma_handle)
3564{
3565 int i;
3566
3567 for (i = 0; i < wma_handle->max_bssid; i++) {
Mukul Sharmaf9047232017-03-02 16:58:56 +05303568 if (!wma_is_vdev_up(i))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003569 continue;
3570 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
3571 wma_handle->interfaces[i].sub_type ==
3572 WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT)
3573 return true;
3574 }
3575 return false;
3576}
3577
3578/**
3579 * wma_is_sta_active() - check sta is active or not
3580 * @handle: wma handle
3581 *
3582 * Return: true/false
3583 */
3584bool wma_is_sta_active(tp_wma_handle wma_handle)
3585{
3586 int i;
3587
3588 for (i = 0; i < wma_handle->max_bssid; i++) {
Mukul Sharmaf9047232017-03-02 16:58:56 +05303589 if (!wma_is_vdev_up(i))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003590 continue;
3591 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
3592 wma_handle->interfaces[i].sub_type == 0)
3593 return true;
3594 if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_IBSS)
3595 return true;
3596 }
3597 return false;
3598}
3599
3600/**
3601 * wma_peer_phymode() - get phymode
3602 * @nw_type: nw type
3603 * @sta_type: sta type
3604 * @is_ht: is ht supported
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003605 * @ch_width: supported channel width
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003606 * @is_vht: is vht supported
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003607 * @is_he: is HE supported
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003608 *
3609 * Return: WLAN_PHY_MODE
3610 */
3611WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type,
3612 uint8_t is_ht, uint8_t ch_width,
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003613 uint8_t is_vht, bool is_he)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003614{
3615 WLAN_PHY_MODE phymode = MODE_UNKNOWN;
3616
3617 switch (nw_type) {
3618 case eSIR_11B_NW_TYPE:
Kabilan Kannanedff06d2017-08-23 16:55:13 -07003619#ifdef FEATURE_WLAN_TDLS
3620 if (STA_ENTRY_TDLS_PEER == sta_type) {
3621 if (is_vht) {
3622 if (CH_WIDTH_80MHZ == ch_width)
3623 phymode = MODE_11AC_VHT80;
3624 else
3625 phymode = (CH_WIDTH_40MHZ == ch_width) ?
3626 MODE_11AC_VHT40 :
3627 MODE_11AC_VHT20;
3628 } else if (is_ht) {
3629 phymode = (CH_WIDTH_40MHZ == ch_width) ?
3630 MODE_11NG_HT40 : MODE_11NG_HT20;
3631 } else
3632 phymode = MODE_11B;
3633 } else
3634#endif /* FEATURE_WLAN_TDLS */
3635 {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003636 phymode = MODE_11B;
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003637 if (is_ht || is_vht || is_he)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003638 WMA_LOGE("HT/VHT is enabled with 11B NW type");
Kabilan Kannanedff06d2017-08-23 16:55:13 -07003639 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003640 break;
3641 case eSIR_11G_NW_TYPE:
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003642 if (!(is_ht || is_vht || is_he)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003643 phymode = MODE_11G;
3644 break;
3645 }
3646 if (CH_WIDTH_40MHZ < ch_width)
3647 WMA_LOGE("80/160 MHz BW sent in 11G, configured 40MHz");
3648 if (ch_width)
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003649 phymode = (is_he) ? MODE_11AX_HE40_2G : (is_vht) ?
3650 MODE_11AC_VHT40_2G : MODE_11NG_HT40;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003651 else
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003652 phymode = (is_he) ? MODE_11AX_HE20_2G : (is_vht) ?
3653 MODE_11AC_VHT20_2G : MODE_11NG_HT20;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003654 break;
3655 case eSIR_11A_NW_TYPE:
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003656 if (!(is_ht || is_vht || is_he)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003657 phymode = MODE_11A;
3658 break;
3659 }
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003660 if (is_he) {
3661 if (ch_width == CH_WIDTH_160MHZ)
3662 phymode = MODE_11AX_HE160;
3663 else if (ch_width == CH_WIDTH_80P80MHZ)
3664 phymode = MODE_11AX_HE80_80;
3665 else if (ch_width == CH_WIDTH_80MHZ)
3666 phymode = MODE_11AX_HE80;
3667 else
3668 phymode = (ch_width) ?
3669 MODE_11AX_HE40 : MODE_11AX_HE20;
3670 } else if (is_vht) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003671 if (ch_width == CH_WIDTH_160MHZ)
3672 phymode = MODE_11AC_VHT160;
3673 else if (ch_width == CH_WIDTH_80P80MHZ)
3674 phymode = MODE_11AC_VHT80_80;
Amar Singhal046eb8a2016-05-05 12:50:15 -07003675 else if (ch_width == CH_WIDTH_80MHZ)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003676 phymode = MODE_11AC_VHT80;
3677 else
3678 phymode = (ch_width) ?
3679 MODE_11AC_VHT40 : MODE_11AC_VHT20;
3680 } else
3681 phymode = (ch_width) ? MODE_11NA_HT40 : MODE_11NA_HT20;
3682 break;
3683 default:
Srinivas Girigowdad1a07a52017-03-06 22:48:16 -08003684 WMA_LOGE("%s: Invalid nw type %d", __func__, nw_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003685 break;
3686 }
Krishna Kumaar Natarajan0103ef82017-02-17 18:15:56 -08003687 WMA_LOGD(FL("nw_type %d is_ht %d ch_width %d is_vht %d is_he %d phymode %d"),
3688 nw_type, is_ht, ch_width, is_vht, is_he, phymode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003689
3690 return phymode;
3691}
3692
3693/**
3694 * wma_txrx_fw_stats_reset() - reset txrx fw statistics
3695 * @wma_handle: wma handle
3696 * @vdev_id: vdev id
3697 * @value: value
3698 *
3699 * Return: 0 for success or return error
3700 */
3701int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle,
3702 uint8_t vdev_id, uint32_t value)
3703{
3704 struct ol_txrx_stats_req req;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003705 struct cdp_vdev *vdev;
Nishank Aggarwala13b61d2016-12-01 12:53:58 +05303706 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3707
3708 if (!soc) {
3709 WMA_LOGE("%s:SOC context is NULL", __func__);
3710 return -EINVAL;
3711 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003712
3713 vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
3714 if (!vdev) {
3715 WMA_LOGE("%s:Invalid vdev handle", __func__);
3716 return -EINVAL;
3717 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303718 qdf_mem_zero(&req, sizeof(req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003719 req.stats_type_reset_mask = value;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003720 cdp_fw_stats_get(soc, vdev, &req, false, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003721
3722 return 0;
3723}
3724
3725#ifdef HELIUMPLUS
Jeff Johnson560dc562017-03-17 15:19:31 -07003726#define SET_UPLOAD_MASK(_mask, _rate_info) \
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003727 ((_mask) = 1 << (_rate_info ## _V2))
3728#else /* !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))
3731#endif
3732
Nirav Shah93e789e2016-04-14 19:47:43 +05303733#ifdef HELIUMPLUS
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07003734static bool wma_is_valid_fw_stats_cmd(uint32_t value)
Nirav Shah93e789e2016-04-14 19:47:43 +05303735{
3736 if (value > (HTT_DBG_NUM_STATS + 1) ||
3737 value == (HTT_DBG_STATS_RX_RATE_INFO + 1) ||
3738 value == (HTT_DBG_STATS_TX_RATE_INFO + 1) ||
3739 value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) {
3740 WMA_LOGE("%s: Not supported", __func__);
3741 return false;
3742 }
3743 return true;
3744}
3745#else
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07003746static bool wma_is_valid_fw_stats_cmd(uint32_t value)
Nirav Shah93e789e2016-04-14 19:47:43 +05303747{
3748 if (value > (HTT_DBG_NUM_STATS + 1) ||
3749 value == (HTT_DBG_STATS_RX_RATE_INFO_V2 + 1) ||
3750 value == (HTT_DBG_STATS_TX_RATE_INFO_V2 + 1) ||
3751 value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) {
3752 WMA_LOGE("%s: Not supported", __func__);
3753 return false;
3754 }
3755 return true;
3756}
3757#endif
3758
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003759/**
3760 * wma_set_txrx_fw_stats_level() - set txrx fw stats level
3761 * @wma_handle: wma handle
3762 * @vdev_id: vdev id
3763 * @value: value
3764 *
3765 * Return: 0 for success or return error
3766 */
3767int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle,
3768 uint8_t vdev_id, uint32_t value)
3769{
3770 struct ol_txrx_stats_req req;
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003771 struct cdp_vdev *vdev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003772 uint32_t l_up_mask;
Nishank Aggarwala13b61d2016-12-01 12:53:58 +05303773 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3774
3775 if (!soc) {
3776 WMA_LOGE("%s:SOC context is NULL", __func__);
3777 return -EINVAL;
3778 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003779
3780 vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
3781 if (!vdev) {
3782 WMA_LOGE("%s:Invalid vdev handle", __func__);
3783 return -EINVAL;
3784 }
Nirav Shah93e789e2016-04-14 19:47:43 +05303785
3786 if (wma_is_valid_fw_stats_cmd(value) == false)
3787 return -EINVAL;
3788
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303789 qdf_mem_zero(&req, sizeof(req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003790 req.print.verbose = 1;
3791
Nirav Shah93e789e2016-04-14 19:47:43 +05303792 /* TODO: Need to check how to avoid mem leak*/
3793 l_up_mask = 1 << (value - 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003794 req.stats_type_upload_mask = l_up_mask;
3795
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -08003796 cdp_fw_stats_get(soc, vdev, &req, false, true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003797
3798 return 0;
3799}
3800
3801/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003802 * wma_get_stats_rsp_buf() - fill get stats response buffer
3803 * @get_stats_param: get stats parameters
3804 *
3805 * Return: stats response buffer
3806 */
3807static tAniGetPEStatsRsp *wma_get_stats_rsp_buf
3808 (tAniGetPEStatsReq *get_stats_param)
3809{
3810 tAniGetPEStatsRsp *stats_rsp_params;
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003811 uint32_t len, temp_mask;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003812
3813 len = sizeof(tAniGetPEStatsRsp);
3814 temp_mask = get_stats_param->statsMask;
3815
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003816 if (temp_mask & (1 << eCsrSummaryStats))
3817 len += sizeof(tCsrSummaryStatsInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003818
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003819 if (temp_mask & (1 << eCsrGlobalClassAStats))
3820 len += sizeof(tCsrGlobalClassAStatsInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003821
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003822 if (temp_mask & (1 << eCsrGlobalClassDStats))
3823 len += sizeof(tCsrGlobalClassDStatsInfo);
3824
Jeff Johnsondfd360e2017-03-10 16:23:07 -08003825 if (temp_mask & (1 << csr_per_chain_rssi_stats))
3826 len += sizeof(struct csr_per_chain_rssi_stats_info);
3827
3828 stats_rsp_params = qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003829 if (!stats_rsp_params) {
3830 WMA_LOGE("memory allocation failed for tAniGetPEStatsRsp");
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303831 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003832 return NULL;
3833 }
3834
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003835 stats_rsp_params->staId = get_stats_param->staId;
3836 stats_rsp_params->statsMask = get_stats_param->statsMask;
3837 stats_rsp_params->msgType = WMA_GET_STATISTICS_RSP;
3838 stats_rsp_params->msgLen = len - sizeof(tAniGetPEStatsRsp);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303839 stats_rsp_params->rc = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003840 return stats_rsp_params;
3841}
3842
3843/**
3844 * wma_get_stats_req() - get stats request
3845 * @handle: wma handle
3846 * @get_stats_param: stats params
3847 *
3848 * Return: none
3849 */
3850void wma_get_stats_req(WMA_HANDLE handle,
3851 tAniGetPEStatsReq *get_stats_param)
3852{
3853 tp_wma_handle wma_handle = (tp_wma_handle) handle;
3854 struct wma_txrx_node *node;
Dustin Brown35619492017-10-03 15:16:12 -07003855 struct stats_request_params cmd = {0};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003856 tAniGetPEStatsRsp *pGetPEStatsRspParams;
Govind Singh4863da42016-03-08 11:45:00 +05303857
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003858
3859 WMA_LOGD("%s: Enter", __func__);
3860 node = &wma_handle->interfaces[get_stats_param->sessionId];
3861 if (node->stats_rsp) {
3862 pGetPEStatsRspParams = node->stats_rsp;
3863 if (pGetPEStatsRspParams->staId == get_stats_param->staId &&
3864 pGetPEStatsRspParams->statsMask ==
3865 get_stats_param->statsMask) {
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07003866 WMA_LOGD("Stats for staId %d with stats mask %d is pending.. ignore new request",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003867 get_stats_param->staId,
3868 get_stats_param->statsMask);
Ganesh Kondabattini5bcc3e72017-05-17 15:20:31 +05303869 pGetPEStatsRspParams =
3870 wma_get_stats_rsp_buf(get_stats_param);
3871 if (!pGetPEStatsRspParams) {
3872 WMA_LOGE("failed to allocate memory for stats response");
3873 goto end;
3874 }
3875 goto req_pending;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003876 } else {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303877 qdf_mem_free(node->stats_rsp);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003878 node->stats_rsp = NULL;
3879 node->fw_stats_set = 0;
3880 }
3881 }
3882
3883 pGetPEStatsRspParams = wma_get_stats_rsp_buf(get_stats_param);
3884 if (!pGetPEStatsRspParams)
3885 goto end;
3886
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003887 node->fw_stats_set = 0;
Naveen Rawat3c49d192017-03-02 18:43:16 -08003888 if (node->stats_rsp) {
Jeff Johnsonadba3962017-09-18 08:12:35 -07003889 WMA_LOGD(FL("stats_rsp is not null, prev_value: %pK"),
Naveen Rawat3c49d192017-03-02 18:43:16 -08003890 node->stats_rsp);
3891 qdf_mem_free(node->stats_rsp);
3892 node->stats_rsp = NULL;
3893 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003894 node->stats_rsp = pGetPEStatsRspParams;
Will Huanga9814592017-05-24 15:47:58 +08003895 wma_handle->get_sta_peer_info = false;
Jeff Johnsonadba3962017-09-18 08:12:35 -07003896 WMA_LOGD("stats_rsp allocated: %pK, sta_id: %d, mask: %d, vdev_id: %d",
Naveen Rawat3c49d192017-03-02 18:43:16 -08003897 node->stats_rsp, node->stats_rsp->staId,
3898 node->stats_rsp->statsMask, get_stats_param->sessionId);
Govind Singh4863da42016-03-08 11:45:00 +05303899
Dustin Brown35619492017-10-03 15:16:12 -07003900 cmd.vdev_id = get_stats_param->sessionId;
3901 cmd.stats_id = get_stats_param->statsMask;
3902 if (wmi_unified_stats_request_send(wma_handle->wmi_handle,
3903 node->bssid,
3904 &cmd)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003905 WMA_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID",
3906 __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003907 goto failed;
3908 }
3909
3910 goto end;
3911failed:
Ganesh Kondabattini5bcc3e72017-05-17 15:20:31 +05303912 node->stats_rsp = NULL;
3913req_pending:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05303914 pGetPEStatsRspParams->rc = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003915 /* send response to UMAC */
3916 wma_send_msg(wma_handle, WMA_GET_STATISTICS_RSP, pGetPEStatsRspParams,
3917 0);
3918end:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303919 qdf_mem_free(get_stats_param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003920 WMA_LOGD("%s: Exit", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003921}
3922
3923/**
Padma, Santhosh Kumar16dacfb2017-03-21 19:05:40 +05303924 * wma_get_cca_stats() - send request to fw to get CCA
3925 * @wma_handle: wma handle
3926 * @vdev_id: vdev id
3927 *
3928 * Return: QDF status
3929 */
3930QDF_STATUS wma_get_cca_stats(tp_wma_handle wma_handle,
3931 uint8_t vdev_id)
3932{
3933 if (wmi_unified_congestion_request_cmd(wma_handle->wmi_handle,
3934 vdev_id)) {
3935 WMA_LOGE("Failed to congestion request to fw");
3936 return QDF_STATUS_E_FAILURE;
3937 }
3938 return QDF_STATUS_SUCCESS;
3939}
3940
3941/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003942 * wma_get_beacon_buffer_by_vdev_id() - get the beacon buffer from vdev ID
3943 * @vdev_id: vdev id
3944 * @buffer_size: size of buffer
3945 *
3946 * Return: none
3947 */
3948void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size)
3949{
3950 tp_wma_handle wma;
3951 struct beacon_info *beacon;
3952 uint8_t *buf;
3953 uint32_t buf_size;
3954
Anurag Chouhan6d760662016-02-20 16:05:43 +05303955 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003956 if (!wma) {
3957 WMA_LOGE("%s: Invalid WMA handle", __func__);
3958 return NULL;
3959 }
3960
3961 if (vdev_id >= wma->max_bssid) {
3962 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
3963 return NULL;
3964 }
3965
3966 if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) {
3967 WMA_LOGE("%s: vdevid %d is not in AP mode", __func__, vdev_id);
3968 return NULL;
3969 }
3970
3971 beacon = wma->interfaces[vdev_id].beacon;
3972
3973 if (!beacon) {
3974 WMA_LOGE("%s: beacon invalid", __func__);
3975 return NULL;
3976 }
3977
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303978 qdf_spin_lock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003979
Nirav Shahcbc6d722016-03-01 16:24:53 +05303980 buf_size = qdf_nbuf_len(beacon->buf);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05303981 buf = qdf_mem_malloc(buf_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003982
3983 if (!buf) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303984 qdf_spin_unlock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003985 WMA_LOGE("%s: alloc failed for beacon buf", __func__);
3986 return NULL;
3987 }
3988
Nirav Shahcbc6d722016-03-01 16:24:53 +05303989 qdf_mem_copy(buf, qdf_nbuf_data(beacon->buf), buf_size);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003990
Anurag Chouhana37b5b72016-02-21 14:53:42 +05303991 qdf_spin_unlock_bh(&beacon->lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003992
3993 if (buffer_size)
3994 *buffer_size = buf_size;
3995
3996 return buf;
3997}
3998
3999/**
4000 * wma_get_vdev_address_by_vdev_id() - lookup MAC address from vdev ID
4001 * @vdev_id: vdev id
4002 *
4003 * Return: mac address
4004 */
4005uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id)
4006{
4007 tp_wma_handle wma;
4008
Anurag Chouhan6d760662016-02-20 16:05:43 +05304009 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004010 if (!wma) {
4011 WMA_LOGE("%s: Invalid WMA handle", __func__);
4012 return NULL;
4013 }
4014
4015 if (vdev_id >= wma->max_bssid) {
4016 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
4017 return NULL;
4018 }
4019
4020 return wma->interfaces[vdev_id].addr;
4021}
4022
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08004023QDF_STATUS wma_get_connection_info(uint8_t vdev_id,
4024 struct policy_mgr_vdev_entry_info *conn_table_entry)
4025{
4026 struct wma_txrx_node *wma_conn_table_entry;
4027
4028 wma_conn_table_entry = wma_get_interface_by_vdev_id(vdev_id);
4029 if (NULL == wma_conn_table_entry) {
4030 WMA_LOGE("%s: can't find vdev_id %d in WMA table", __func__, vdev_id);
4031 return QDF_STATUS_E_FAILURE;
4032 }
4033 conn_table_entry->chan_width = wma_conn_table_entry->chan_width;
4034 conn_table_entry->mac_id = wma_conn_table_entry->mac_id;
4035 conn_table_entry->mhz = wma_conn_table_entry->mhz;
4036 conn_table_entry->sub_type = wma_conn_table_entry->sub_type;
4037 conn_table_entry->type = wma_conn_table_entry->type;
4038
4039 return QDF_STATUS_SUCCESS;
4040}
4041
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004042/**
4043 * wma_get_interface_by_vdev_id() - lookup interface entry using vdev ID
4044 * @vdev_id: vdev id
4045 *
4046 * Return: entry from vdev table
4047 */
4048struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id)
4049{
4050 tp_wma_handle wma;
4051
Anurag Chouhan6d760662016-02-20 16:05:43 +05304052 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004053 if (!wma) {
4054 WMA_LOGE("%s: Invalid WMA handle", __func__);
4055 return NULL;
4056 }
4057
4058 if (vdev_id >= wma->max_bssid) {
4059 WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
4060 return NULL;
4061 }
4062
4063 return &wma->interfaces[vdev_id];
4064}
4065
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004066#if defined(QCA_WIFI_FTM)
4067/**
4068 * wma_utf_rsp() - utf response
4069 * @wma_handle: wma handle
4070 * @payload: payload
4071 * @len: length of payload
4072 *
4073 * Return: 0 for success or error code
4074 */
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07004075static int wma_utf_rsp(tp_wma_handle wma_handle, uint8_t **payload,
4076 uint32_t *len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004077{
4078 int ret = -1;
4079 uint32_t payload_len;
4080
4081 payload_len = wma_handle->utf_event_info.length;
4082 if (payload_len) {
4083 ret = 0;
4084
4085 /*
4086 * The first 4 bytes holds the payload size
4087 * and the actual payload sits next to it
4088 */
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304089 *payload = (uint8_t *) qdf_mem_malloc((uint32_t) payload_len
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004090 + sizeof(A_UINT32));
4091 *(A_UINT32 *) &(*payload[0]) =
4092 wma_handle->utf_event_info.length;
4093 memcpy(*payload + sizeof(A_UINT32),
4094 wma_handle->utf_event_info.data, payload_len);
4095 wma_handle->utf_event_info.length = 0;
4096 *len = payload_len;
4097 }
4098
4099 return ret;
4100}
4101
4102/**
4103 * wma_post_ftm_response() - post ftm response to upper layer
4104 * @wma_handle: wma handle
4105 *
4106 * Return: none
4107 */
4108static void wma_post_ftm_response(tp_wma_handle wma_handle)
4109{
4110 int ret;
4111 uint8_t *payload;
4112 uint32_t data_len;
Rajeev Kumarb60abe42017-01-21 15:39:31 -08004113 struct scheduler_msg msg = { 0 };
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304114 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004115
4116 ret = wma_utf_rsp(wma_handle, &payload, &data_len);
4117
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004118 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004119 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004120
4121 sys_build_message_header(SYS_MSG_ID_FTM_RSP, &msg);
4122 msg.bodyptr = payload;
4123 msg.bodyval = 0;
4124
Rajeev Kumarb60abe42017-01-21 15:39:31 -08004125 status = scheduler_post_msg(QDF_MODULE_ID_SYS, &msg);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004126
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304127 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004128 WMA_LOGE("failed to post ftm response to SYS");
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304129 qdf_mem_free(payload);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004130 }
4131}
4132
4133/**
4134 * wma_process_utf_event() - process utf event
4135 * @handle: wma handle
4136 * @datap: data buffer
4137 * @dataplen: data length
4138 *
4139 * Return: 0 for success or error code
4140 */
4141static int
4142wma_process_utf_event(WMA_HANDLE handle, uint8_t *datap, uint32_t dataplen)
4143{
4144 tp_wma_handle wma_handle = (tp_wma_handle) handle;
Govind Singhd76a5b02016-03-08 15:12:14 +05304145 struct seg_hdr_info segHdrInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004146 uint8_t totalNumOfSegments, currentSeq;
4147 WMI_PDEV_UTF_EVENTID_param_tlvs *param_buf;
4148 uint8_t *data;
4149 uint32_t datalen;
4150
4151 param_buf = (WMI_PDEV_UTF_EVENTID_param_tlvs *) datap;
4152 if (!param_buf) {
4153 WMA_LOGE("Get NULL point message from FW");
4154 return -EINVAL;
4155 }
4156 data = param_buf->data;
4157 datalen = param_buf->num_data;
4158
Amar Singhal4aaa6c42017-10-03 09:48:02 -07004159 if (datalen < sizeof(segHdrInfo)) {
4160 WMA_LOGE("message size %d is smaller than struct seg_hdr_info",
4161 datalen);
4162 return -EINVAL;
4163 }
4164
Govind Singhd76a5b02016-03-08 15:12:14 +05304165 segHdrInfo = *(struct seg_hdr_info *) &(data[0]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004166
4167 wma_handle->utf_event_info.currentSeq = (segHdrInfo.segmentInfo & 0xF);
4168
4169 currentSeq = (segHdrInfo.segmentInfo & 0xF);
4170 totalNumOfSegments = (segHdrInfo.segmentInfo >> 4) & 0xF;
4171
4172 datalen = datalen - sizeof(segHdrInfo);
4173
4174 if (currentSeq == 0) {
4175 wma_handle->utf_event_info.expectedSeq = 0;
4176 wma_handle->utf_event_info.offset = 0;
4177 } else {
4178 if (wma_handle->utf_event_info.expectedSeq != currentSeq)
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004179 WMA_LOGE("Mismatch in expecting seq expected Seq %d got seq %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004180 wma_handle->utf_event_info.expectedSeq,
4181 currentSeq);
4182 }
4183
Varun Reddy Yeturud4c523d2017-09-26 15:28:42 -07004184 if ((datalen > MAX_UTF_EVENT_LENGTH) ||
4185 (wma_handle->utf_event_info.offset >
4186 (MAX_UTF_EVENT_LENGTH - datalen))) {
4187 WMA_LOGE("Excess data from firmware, offset:%zu, len:%d",
4188 wma_handle->utf_event_info.offset, datalen);
4189 return -EINVAL;
4190 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004191 memcpy(&wma_handle->utf_event_info.
4192 data[wma_handle->utf_event_info.offset],
4193 &data[sizeof(segHdrInfo)], datalen);
4194 wma_handle->utf_event_info.offset =
4195 wma_handle->utf_event_info.offset + datalen;
4196 wma_handle->utf_event_info.expectedSeq++;
4197
4198 if (wma_handle->utf_event_info.expectedSeq == totalNumOfSegments) {
4199 if (wma_handle->utf_event_info.offset != segHdrInfo.len)
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004200 WMA_LOGE("All segs received total len mismatch.. len %zu total len %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004201 wma_handle->utf_event_info.offset,
4202 segHdrInfo.len);
4203
4204 wma_handle->utf_event_info.length =
4205 wma_handle->utf_event_info.offset;
4206 }
4207
4208 wma_post_ftm_response(wma_handle);
4209
4210 return 0;
4211}
4212
4213/**
4214 * wma_utf_detach() - utf detach
4215 * @wma_handle: wma handle
4216 *
4217 * Return: none
4218 */
4219void wma_utf_detach(tp_wma_handle wma_handle)
4220{
4221 if (wma_handle->utf_event_info.data) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304222 qdf_mem_free(wma_handle->utf_event_info.data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004223 wma_handle->utf_event_info.data = NULL;
4224 wma_handle->utf_event_info.length = 0;
4225 wmi_unified_unregister_event_handler(wma_handle->wmi_handle,
4226 WMI_PDEV_UTF_EVENTID);
4227 }
4228}
4229
4230/**
4231 * wma_utf_attach() - utf attach
4232 * @wma_handle: wma handle
4233 *
4234 * Return: none
4235 */
4236void wma_utf_attach(tp_wma_handle wma_handle)
4237{
4238 int ret;
4239
4240 wma_handle->utf_event_info.data = (unsigned char *)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304241 qdf_mem_malloc(MAX_UTF_EVENT_LENGTH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004242 wma_handle->utf_event_info.length = 0;
4243
4244 ret = wmi_unified_register_event_handler(wma_handle->wmi_handle,
4245 WMI_PDEV_UTF_EVENTID,
Govind Singhd76a5b02016-03-08 15:12:14 +05304246 wma_process_utf_event,
4247 WMA_RX_SERIALIZER_CTX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004248
4249 if (ret)
Srinivas Girigowdad1a07a52017-03-06 22:48:16 -08004250 WMA_LOGE("%s: Failed to register UTF event callback", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004251}
4252
4253/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 * wma_utf_cmd() - utf command
4255 * @wma_handle: wma handle
4256 * @data: data
4257 * @len: length
4258 *
Govind Singhd76a5b02016-03-08 15:12:14 +05304259 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004260 */
Jeff Johnsonc4b47a92016-10-07 12:34:41 -07004261static QDF_STATUS wma_utf_cmd(tp_wma_handle wma_handle, uint8_t *data,
4262 uint16_t len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004263{
Govind Singhd76a5b02016-03-08 15:12:14 +05304264 struct pdev_utf_params param = {0};
4265
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004266 wma_handle->utf_event_info.length = 0;
Govind Singhd76a5b02016-03-08 15:12:14 +05304267 param.utf_payload = data;
4268 param.len = len;
4269
4270 return wmi_unified_pdev_utf_cmd_send(wma_handle->wmi_handle, &param,
4271 WMA_WILDCARD_PDEV_ID);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004272}
4273
4274/**
4275 * wma_process_ftm_command() - process ftm command
4276 * @wma_handle: wma handle
4277 * @msg_buffer: message buffer
4278 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304279 * Return: QDF_STATUS_SUCCESS for success or error code
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304281QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004282wma_process_ftm_command(tp_wma_handle wma_handle,
4283 struct ar6k_testmode_cmd_data *msg_buffer)
4284{
4285 uint8_t *data = NULL;
4286 uint16_t len = 0;
4287 int ret;
4288
4289 if (!msg_buffer)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304290 return QDF_STATUS_E_INVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004291
Anurag Chouhan6d760662016-02-20 16:05:43 +05304292 if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004293 WMA_LOGE("FTM command issued in non-FTM mode");
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304294 qdf_mem_free(msg_buffer->data);
4295 qdf_mem_free(msg_buffer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304296 return QDF_STATUS_E_NOSUPPORT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004297 }
4298
4299 data = msg_buffer->data;
4300 len = msg_buffer->len;
4301
4302 ret = wma_utf_cmd(wma_handle, data, len);
4303
Anurag Chouhan600c3a02016-03-01 10:33:54 +05304304 qdf_mem_free(msg_buffer->data);
4305 qdf_mem_free(msg_buffer);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004306
4307 if (ret)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304308 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004309
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304310 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004311}
4312#endif /* QCA_WIFI_FTM */
4313
Jeff Johnsonabb74042017-08-31 11:44:55 -07004314QDF_STATUS wma_get_wcnss_software_version(uint8_t *version,
4315 uint32_t version_buffer_size)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004316{
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004317 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004318
4319 if (NULL == wma_handle) {
4320 WMA_LOGE("%s: Failed to get wma", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304321 return QDF_STATUS_E_FAULT;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004322 }
4323
Jeff Johnsonabb74042017-08-31 11:44:55 -07004324 snprintf(version, version_buffer_size, "%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004325 (unsigned int)wma_handle->target_fw_version);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05304326 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004327}
4328
Aravind Narasimhan5b7c2cd2016-12-08 21:04:26 -08004329/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004330 * wma_get_mac_id_of_vdev() - Get MAC id corresponding to a vdev
4331 * @vdev_id: VDEV whose MAC ID is required
4332 *
4333 * Get MAC id corresponding to a vdev id from the WMA structure
4334 *
4335 * Return: Negative value on failure and MAC id on success
4336 */
4337int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id)
4338{
4339 tp_wma_handle wma;
4340
Anurag Chouhan6d760662016-02-20 16:05:43 +05304341 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004342 if (!wma) {
4343 WMA_LOGE("%s: Invalid WMA handle", __func__);
4344 return -EINVAL;
4345 }
4346
4347 if (wma->interfaces)
4348 return wma->interfaces[vdev_id].mac_id;
4349
4350 return -EINVAL;
4351}
4352
4353/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004354 * wma_update_intf_hw_mode_params() - Update WMA params
4355 * @vdev_id: VDEV id whose params needs to be updated
4356 * @mac_id: MAC id to be updated
4357 * @cfgd_hw_mode_index: HW mode index from which Tx and Rx SS will be updated
4358 *
4359 * Updates the MAC id, tx spatial stream, rx spatial stream in WMA
4360 *
4361 * Return: None
4362 */
4363void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id,
4364 uint32_t cfgd_hw_mode_index)
4365{
4366 tp_wma_handle wma;
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08004367 uint32_t param;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004368
Anurag Chouhan6d760662016-02-20 16:05:43 +05304369 wma = cds_get_context(QDF_MODULE_ID_WMA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004370 if (!wma) {
4371 WMA_LOGE("%s: Invalid WMA handle", __func__);
4372 return;
4373 }
4374
4375 if (!wma->interfaces) {
4376 WMA_LOGE("%s: Interface is NULL", __func__);
4377 return;
4378 }
4379
Tushnim Bhattacharyya206bcac2015-11-10 15:20:06 -08004380 if (cfgd_hw_mode_index > wma->num_dbs_hw_modes) {
4381 WMA_LOGE("%s: Invalid index", __func__);
4382 return;
4383 }
4384
4385 param = wma->hw_mode.hw_mode_list[cfgd_hw_mode_index];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386 wma->interfaces[vdev_id].mac_id = mac_id;
4387 if (mac_id == 0) {
4388 wma->interfaces[vdev_id].tx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05304389 WMA_HW_MODE_MAC0_TX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004390 wma->interfaces[vdev_id].rx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05304391 WMA_HW_MODE_MAC0_RX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004392 } else {
4393 wma->interfaces[vdev_id].tx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05304394 WMA_HW_MODE_MAC1_TX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004395 wma->interfaces[vdev_id].rx_streams =
Nitesh Shah5b7bae02016-09-28 18:58:33 +05304396 WMA_HW_MODE_MAC1_RX_STREAMS_GET(param);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004397 }
4398}
4399
4400/**
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08004401 * wma_get_vht_ch_width - return vht channel width
4402 *
4403 * Return: return vht channel width
4404 */
4405uint32_t wma_get_vht_ch_width(void)
4406{
4407 uint32_t fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ;
Anurag Chouhan6d760662016-02-20 16:05:43 +05304408 tp_wma_handle wm_hdl = cds_get_context(QDF_MODULE_ID_WMA);
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08004409
4410 if (NULL == wm_hdl)
4411 return fw_ch_wd;
4412
Kiran Kumar Lokere02b9aa42016-05-26 14:54:49 -07004413 if (wm_hdl->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ)
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08004414 fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ;
Kiran Kumar Lokere02b9aa42016-05-26 14:54:49 -07004415 else if (wm_hdl->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_160MHZ)
4416 fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ;
Naveen Rawatc0c91cd2015-11-05 14:27:37 -08004417
4418 return fw_ch_wd;
4419}
Govind Singhd76a5b02016-03-08 15:12:14 +05304420
4421/**
Krunal Soniaa664da2016-06-15 23:46:40 -07004422 * wma_get_num_of_setbits_from_bitmask() - to get num of setbits from bitmask
4423 * @mask: given bitmask
4424 *
4425 * This helper function should return number of setbits from bitmask
4426 *
4427 * Return: number of setbits from bitmask
4428 */
4429uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask)
4430{
4431 uint32_t num_of_setbits = 0;
4432
4433 while (mask) {
4434 mask &= (mask - 1);
4435 num_of_setbits++;
4436 }
4437 return num_of_setbits;
4438}
4439
4440/**
Kiran Kumar Lokered0fad462017-06-13 18:23:48 -07004441 * wma_is_csa_offload_enabled - checks fw CSA offload capability
4442 *
4443 * Return: true or false
4444 */
4445
4446bool wma_is_csa_offload_enabled(void)
4447{
4448 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
4449
4450 if (!wma)
4451 return false;
4452
4453 return WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
4454 WMI_SERVICE_CSA_OFFLOAD);
4455}
4456/**
Govind Singhd76a5b02016-03-08 15:12:14 +05304457 * wma_config_debug_module_cmd - set debug log config
4458 * @wmi_handle: wmi layer handle
4459 * @param: debug log parameter
4460 * @val: debug log value
4461 * @module_id_bitmap: debug module id bitmap
4462 * @bitmap_len: debug module bitmap length
4463 *
4464 * Return: QDF_STATUS_SUCCESS for success or error code
4465 */
4466QDF_STATUS
4467wma_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param,
4468 A_UINT32 val, A_UINT32 *module_id_bitmap,
4469 A_UINT32 bitmap_len)
4470{
4471 struct dbglog_params dbg_param;
Manikandan Mohan1dd8b5d2017-04-18 15:54:09 -07004472
Govind Singhd76a5b02016-03-08 15:12:14 +05304473 dbg_param.param = param;
4474 dbg_param.val = val;
4475 dbg_param.module_id_bitmap = module_id_bitmap;
4476 dbg_param.bitmap_len = bitmap_len;
4477
4478 return wmi_unified_dbglog_cmd_send(wmi_handle, &dbg_param);
4479}
Peng Xu8fdaa492016-06-22 10:20:47 -07004480
4481/**
4482 * wma_is_p2p_lo_capable() - if driver is capable of p2p listen offload
4483 *
4484 * This function checks if driver is capable of p2p listen offload
4485 * true: capable of p2p offload
4486 * false: not capable
4487 *
4488 * Return: true - capable, false - not capable
4489 */
4490bool wma_is_p2p_lo_capable(void)
4491{
Dustin Brown8d8d9fe2017-07-18 16:01:25 -07004492 return wma_is_service_enabled(WMI_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT);
Peng Xu8fdaa492016-06-22 10:20:47 -07004493}
Aravind Narasimhan5b7c2cd2016-12-08 21:04:26 -08004494
Dustin Brown8d8d9fe2017-07-18 16:01:25 -07004495bool wma_capability_enhanced_mcast_filter(void)
4496{
4497 return wma_is_service_enabled(WMI_SERVICE_ENHANCED_MCAST_FILTER);
4498}
4499
4500
Mukul Sharmaf9047232017-03-02 16:58:56 +05304501bool wma_is_vdev_up(uint8_t vdev_id)
4502{
4503 struct wlan_objmgr_vdev *vdev;
4504 tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA);
4505 enum wlan_vdev_state state = WLAN_VDEV_S_INIT;
4506
4507 if (!wma) {
4508 WMA_LOGE("%s: WMA context is invald!", __func__);
4509 return false;
4510 }
4511
4512 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id,
4513 WLAN_LEGACY_WMA_ID);
4514 if (vdev) {
4515 wlan_vdev_obj_lock(vdev);
4516 state = wlan_vdev_mlme_get_state(vdev);
4517 wlan_vdev_obj_unlock(vdev);
4518 wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID);
4519 }
Mukul Sharmaf9047232017-03-02 16:58:56 +05304520 return (state == WLAN_VDEV_S_RUN) ? true : false;
4521}
4522
Dustin Brownec2c92e2017-07-26 11:13:49 -07004523void wma_acquire_wakelock(qdf_wake_lock_t *wl, uint32_t msec)
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004524{
Dustin Brownec2c92e2017-07-26 11:13:49 -07004525 t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA);
4526
4527 cds_host_diag_log_work(wl, msec, WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
4528 qdf_wake_lock_timeout_acquire(wl, msec);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -08004529 qdf_runtime_pm_prevent_suspend(&wma->wmi_cmd_rsp_runtime_lock);
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004530}
4531
Dustin Brownec2c92e2017-07-26 11:13:49 -07004532void wma_release_wakelock(qdf_wake_lock_t *wl)
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004533{
Dustin Brownec2c92e2017-07-26 11:13:49 -07004534 t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA);
4535
4536 qdf_wake_lock_release(wl, WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -08004537 qdf_runtime_pm_allow_suspend(&wma->wmi_cmd_rsp_runtime_lock);
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004538}
4539
Dustin Brownd5f12942017-03-10 11:06:25 -08004540QDF_STATUS
4541wma_send_vdev_start_to_fw(t_wma_handle *wma, struct vdev_start_params *params)
4542{
4543 QDF_STATUS status;
Dustin Brownec2c92e2017-07-26 11:13:49 -07004544 struct wma_txrx_node *vdev = &wma->interfaces[params->vdev_id];
Dustin Brownd5f12942017-03-10 11:06:25 -08004545
Dustin Brownec2c92e2017-07-26 11:13:49 -07004546 wma_acquire_wakelock(&vdev->vdev_start_wakelock,
4547 WMA_VDEV_START_REQUEST_TIMEOUT);
Dustin Brownd5f12942017-03-10 11:06:25 -08004548 status = wmi_unified_vdev_start_send(wma->wmi_handle, params);
4549 if (QDF_IS_STATUS_ERROR(status))
Dustin Brownec2c92e2017-07-26 11:13:49 -07004550 wma_release_wakelock(&vdev->vdev_start_wakelock);
Dustin Brownd5f12942017-03-10 11:06:25 -08004551
4552 return status;
4553}
4554
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004555QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id)
4556{
4557 QDF_STATUS status;
Dustin Brownec2c92e2017-07-26 11:13:49 -07004558 struct wma_txrx_node *vdev = &wma->interfaces[vdev_id];
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004559
Dustin Brownec2c92e2017-07-26 11:13:49 -07004560 wma_acquire_wakelock(&vdev->vdev_stop_wakelock,
4561 WMA_VDEV_STOP_REQUEST_TIMEOUT);
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004562 status = wmi_unified_vdev_stop_send(wma->wmi_handle, vdev_id);
4563 if (QDF_IS_STATUS_ERROR(status))
Dustin Brownec2c92e2017-07-26 11:13:49 -07004564 wma_release_wakelock(&vdev->vdev_stop_wakelock);
Dustin Brownbf6d16b2017-03-03 11:41:05 -08004565
4566 return status;
4567}
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -08004568
4569bool wma_is_service_enabled(WMI_SERVICE service_type)
4570{
4571 tp_wma_handle wma;
4572 wma = cds_get_context(QDF_MODULE_ID_WMA);
4573 if (!wma) {
4574 WMA_LOGE("%s: Invalid WMA handle", __func__);
4575 return false;
4576 }
4577
4578 return WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, service_type);
4579}
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08004580
Dustin Brownec2c92e2017-07-26 11:13:49 -07004581QDF_STATUS wma_send_vdev_up_to_fw(t_wma_handle *wma,
4582 struct vdev_up_params *params,
4583 uint8_t bssid[IEEE80211_ADDR_LEN])
4584{
4585 QDF_STATUS status;
4586 struct wma_txrx_node *vdev = &wma->interfaces[params->vdev_id];
4587
4588 status = wmi_unified_vdev_up_send(wma->wmi_handle, bssid, params);
4589 wma_release_wakelock(&vdev->vdev_start_wakelock);
4590
4591 return status;
4592}
4593
4594QDF_STATUS wma_send_vdev_down_to_fw(t_wma_handle *wma, uint8_t vdev_id)
4595{
4596 QDF_STATUS status;
4597 struct wma_txrx_node *vdev = &wma->interfaces[vdev_id];
4598
4599 status = wmi_unified_vdev_down_send(wma->wmi_handle, vdev_id);
4600 wma_release_wakelock(&vdev->vdev_start_wakelock);
4601
4602 return status;
4603}
4604
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08004605tSirWifiPeerType wmi_to_sir_peer_type(enum wmi_peer_type type)
4606{
4607 switch (type) {
4608 case WMI_PEER_TYPE_DEFAULT:
4609 return WIFI_PEER_STA;
4610 case WMI_PEER_TYPE_BSS:
4611 return WIFI_PEER_AP;
4612 case WMI_PEER_TYPE_TDLS:
4613 return WIFI_PEER_TDLS;
4614 case WMI_PEER_TYPE_NAN_DATA:
4615 return WIFI_PEER_NAN;
4616 default:
4617 WMA_LOGE("Cannot map wmi_peer_type %d to HAL peer type", type);
4618 return WIFI_PEER_INVALID;
4619 }
4620}
Ravi Kumar Bokka05c14e52017-03-27 14:48:23 +05304621
4622int wma_chip_power_save_failure_detected_handler(void *handle,
4623 uint8_t *cmd_param_info,
4624 uint32_t len)
4625{
4626 tp_wma_handle wma = (tp_wma_handle)handle;
4627 WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *param_buf;
4628 wmi_chip_power_save_failure_detected_fixed_param *event;
4629 struct chip_pwr_save_fail_detected_params pwr_save_fail_params;
4630 tpAniSirGlobal mac = (tpAniSirGlobal)cds_get_context(
4631 QDF_MODULE_ID_PE);
4632 if (wma == NULL) {
4633 WMA_LOGE("%s: wma_handle is NULL", __func__);
4634 return -EINVAL;
4635 }
4636 if (!mac) {
4637 WMA_LOGE("%s: Invalid mac context", __func__);
4638 return -EINVAL;
4639 }
4640 if (!mac->sme.chip_power_save_fail_cb) {
4641 WMA_LOGE("%s: Callback not registered", __func__);
4642 return -EINVAL;
4643 }
4644
4645 param_buf =
4646 (WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *)
4647 cmd_param_info;
4648 if (!param_buf) {
4649 WMA_LOGE("%s: Invalid pwr_save_fail_params breached event",
4650 __func__);
4651 return -EINVAL;
4652 }
4653 event = param_buf->fixed_param;
4654 pwr_save_fail_params.failure_reason_code =
4655 event->power_save_failure_reason_code;
4656 pwr_save_fail_params.wake_lock_bitmap[0] =
4657 event->protocol_wake_lock_bitmap[0];
4658 pwr_save_fail_params.wake_lock_bitmap[1] =
4659 event->protocol_wake_lock_bitmap[1];
4660 pwr_save_fail_params.wake_lock_bitmap[2] =
4661 event->protocol_wake_lock_bitmap[2];
4662 pwr_save_fail_params.wake_lock_bitmap[3] =
4663 event->protocol_wake_lock_bitmap[3];
4664 mac->sme.chip_power_save_fail_cb(mac->hHdd,
4665 &pwr_save_fail_params);
4666
4667 WMA_LOGD("%s: Invoke HDD pwr_save_fail callback", __func__);
4668 return 0;
4669}