blob: 871fdb5bfa878c9101702783c84e6f4479bfa7a5 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jeff Johnson8bb78c32017-01-12 08:42:50 -08002 * Copyright (c) 2012-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 * DOC : wlan_hdd_stats.c
24 *
25 * WLAN Host Device Driver statistics related implementation
26 *
27 */
28
29#include "wlan_hdd_stats.h"
30#include "sme_api.h"
31#include "cds_sched.h"
32#include "wlan_hdd_trace.h"
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070033#include "wlan_hdd_lpass.h"
Nirav Shahbf1b0332016-05-25 14:27:39 +053034#include "hif.h"
Sandeep Puligillafdd201e2017-02-02 18:43:46 -080035#include <qca_vendor.h>
Zhang Qian4ead8f02017-03-27 14:21:47 +080036#include "wma_api.h"
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -080037#include "wlan_hdd_debugfs_llstat.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080038
39/* 11B, 11G Rate table include Basic rate and Extended rate
40 * The IDX field is the rate index
41 * The HI field is the rate when RSSI is strong or being ignored
42 * (in this case we report actual rate)
43 * The MID field is the rate when RSSI is moderate
44 * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
45 * The LO field is the rate when RSSI is low
46 * (in this case we don't report rates, actual current rate used)
47 */
48static const struct {
49 uint8_t beacon_rate_index;
50 uint16_t supported_rate[4];
51} supported_data_rate[] = {
52/* IDX HI HM LM LO (RSSI-based index */
53 {
54 2, {
55 10, 10, 10, 0
56 }
57 }, {
58 4, {
59 20, 20, 10, 0
60 }
61 }, {
62 11, {
63 55, 20, 10, 0
64 }
65 }, {
66 12, {
67 60, 55, 20, 0
68 }
69 }, {
70 18, {
71 90, 55, 20, 0
72 }
73 }, {
74 22, {
75 110, 55, 20, 0
76 }
77 }, {
78 24, {
79 120, 90, 60, 0
80 }
81 }, {
82 36, {
83 180, 120, 60, 0
84 }
85 }, {
86 44, {
87 220, 180, 60, 0
88 }
89 }, {
90 48, {
91 240, 180, 90, 0
92 }
93 }, {
94 66, {
95 330, 180, 90, 0
96 }
97 }, {
98 72, {
99 360, 240, 90, 0
100 }
101 }, {
102 96, {
103 480, 240, 120, 0
104 }
105 }, {
106 108, {
107 540, 240, 120, 0
108 }
109 }
110};
111/* MCS Based rate table HT MCS parameters with Nss = 1 */
112static struct index_data_rate_type supported_mcs_rate_nss1[] = {
113/* MCS L20 L40 S20 S40 */
114 {0, {65, 135, 72, 150} },
115 {1, {130, 270, 144, 300} },
116 {2, {195, 405, 217, 450} },
117 {3, {260, 540, 289, 600} },
118 {4, {390, 810, 433, 900} },
119 {5, {520, 1080, 578, 1200} },
120 {6, {585, 1215, 650, 1350} },
121 {7, {650, 1350, 722, 1500} }
122};
123
124/* HT MCS parameters with Nss = 2 */
125static struct index_data_rate_type supported_mcs_rate_nss2[] = {
126/* MCS L20 L40 S20 S40 */
127 {0, {130, 270, 144, 300} },
128 {1, {260, 540, 289, 600} },
129 {2, {390, 810, 433, 900} },
130 {3, {520, 1080, 578, 1200} },
131 {4, {780, 1620, 867, 1800} },
132 {5, {1040, 2160, 1156, 2400} },
133 {6, {1170, 2430, 1300, 2700} },
134 {7, {1300, 2700, 1444, 3000} }
135};
136
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800137/* MCS Based VHT rate table MCS parameters with Nss = 1*/
138static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
139/* MCS L80 S80 L40 S40 L20 S40*/
140 {0, {293, 325}, {135, 150}, {65, 72} },
141 {1, {585, 650}, {270, 300}, {130, 144} },
142 {2, {878, 975}, {405, 450}, {195, 217} },
143 {3, {1170, 1300}, {540, 600}, {260, 289} },
144 {4, {1755, 1950}, {810, 900}, {390, 433} },
145 {5, {2340, 2600}, {1080, 1200}, {520, 578} },
146 {6, {2633, 2925}, {1215, 1350}, {585, 650} },
147 {7, {2925, 3250}, {1350, 1500}, {650, 722} },
148 {8, {3510, 3900}, {1620, 1800}, {780, 867} },
149 {9, {3900, 4333}, {1800, 2000}, {780, 867} }
150};
151
152/*MCS parameters with Nss = 2*/
153static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
154/* MCS L80 S80 L40 S40 L20 S40*/
155 {0, {585, 650}, {270, 300}, {130, 144} },
156 {1, {1170, 1300}, {540, 600}, {260, 289} },
157 {2, {1755, 1950}, {810, 900}, {390, 433} },
158 {3, {2340, 2600}, {1080, 1200}, {520, 578} },
159 {4, {3510, 3900}, {1620, 1800}, {780, 867} },
160 {5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
161 {6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
162 {7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
163 {8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
164 {9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
165};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800166
167/*array index ponints to MCS and array value points respective rssi*/
168static int rssi_mcs_tbl[][10] = {
169/*MCS 0 1 2 3 4 5 6 7 8 9*/
170 {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */
171 {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */
172 {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */
173};
174
175
176#ifdef WLAN_FEATURE_LINK_LAYER_STATS
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800177static struct hdd_ll_stats_context ll_stats_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800178
179/**
180 * put_wifi_rate_stat() - put wifi rate stats
181 * @stats: Pointer to stats context
182 * @vendor_event: Pointer to vendor event
183 *
184 * Return: bool
185 */
186static bool put_wifi_rate_stat(tpSirWifiRateStat stats,
187 struct sk_buff *vendor_event)
188{
189 if (nla_put_u8(vendor_event,
190 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
191 stats->rate.preamble) ||
192 nla_put_u8(vendor_event,
193 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
194 stats->rate.nss) ||
195 nla_put_u8(vendor_event,
196 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
197 stats->rate.bw) ||
198 nla_put_u8(vendor_event,
199 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
200 stats->rate.rateMcsIdx) ||
201 nla_put_u32(vendor_event,
202 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
203 stats->rate.bitrate) ||
204 nla_put_u32(vendor_event,
205 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
206 stats->txMpdu) ||
207 nla_put_u32(vendor_event,
208 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
209 stats->rxMpdu) ||
210 nla_put_u32(vendor_event,
211 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
212 stats->mpduLost) ||
213 nla_put_u32(vendor_event,
214 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
215 stats->retries) ||
216 nla_put_u32(vendor_event,
217 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
218 stats->retriesShort) ||
219 nla_put_u32(vendor_event,
220 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
221 stats->retriesLong)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700222 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 return false;
224 }
225
226 return true;
227}
228
229/**
230 * put_wifi_peer_info() - put wifi peer info
231 * @stats: Pointer to stats context
232 * @vendor_event: Pointer to vendor event
233 *
234 * Return: bool
235 */
236static bool put_wifi_peer_info(tpSirWifiPeerInfo stats,
237 struct sk_buff *vendor_event)
238{
239 u32 i = 0;
240 tpSirWifiRateStat pRateStats;
241
242 if (nla_put_u32
243 (vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
Dustin Brown877a5a92016-11-17 13:56:52 -0800244 wmi_to_sir_peer_type(stats->type)) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800245 nla_put(vendor_event,
246 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530247 QDF_MAC_ADDR_SIZE, &stats->peerMacAddress.bytes[0]) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800248 nla_put_u32(vendor_event,
249 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
250 stats->capabilities) ||
251 nla_put_u32(vendor_event,
252 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
253 stats->numRate)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700254 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800255 goto error;
256 }
257
258 if (stats->numRate) {
259 struct nlattr *rateInfo;
260 struct nlattr *rates;
261
262 rateInfo = nla_nest_start(vendor_event,
263 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO);
264 if (rateInfo == NULL)
265 goto error;
266
267 for (i = 0; i < stats->numRate; i++) {
268 pRateStats = (tpSirWifiRateStat) ((uint8_t *)
269 stats->rateStats +
270 (i *
271 sizeof
272 (tSirWifiRateStat)));
273 rates = nla_nest_start(vendor_event, i);
274 if (rates == NULL)
275 goto error;
276
277 if (false ==
278 put_wifi_rate_stat(pRateStats, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700279 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800280 return false;
281 }
282 nla_nest_end(vendor_event, rates);
283 }
284 nla_nest_end(vendor_event, rateInfo);
285 }
286
287 return true;
288error:
289 return false;
290}
291
292/**
293 * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
294 * @stats: Pointer to stats context
295 * @vendor_event: Pointer to vendor event
296 *
297 * Return: bool
298 */
299static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats,
300 struct sk_buff *vendor_event)
301{
302 if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
303 stats->ac) ||
304 nla_put_u32(vendor_event,
305 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
306 stats->txMpdu) ||
307 nla_put_u32(vendor_event,
308 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
309 stats->rxMpdu) ||
310 nla_put_u32(vendor_event,
311 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
312 stats->txMcast) ||
313 nla_put_u32(vendor_event,
314 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
315 stats->rxMcast) ||
316 nla_put_u32(vendor_event,
317 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
318 stats->rxAmpdu) ||
319 nla_put_u32(vendor_event,
320 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
321 stats->txAmpdu) ||
322 nla_put_u32(vendor_event,
323 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
324 stats->mpduLost) ||
325 nla_put_u32(vendor_event,
326 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
327 stats->retries) ||
328 nla_put_u32(vendor_event,
329 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
330 stats->retriesShort) ||
331 nla_put_u32(vendor_event,
332 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
333 stats->retriesLong) ||
334 nla_put_u32(vendor_event,
335 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
336 stats->contentionTimeMin) ||
337 nla_put_u32(vendor_event,
338 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
339 stats->contentionTimeMax) ||
340 nla_put_u32(vendor_event,
341 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
342 stats->contentionTimeAvg) ||
343 nla_put_u32(vendor_event,
344 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
345 stats->contentionNumSamples)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700346 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800347 return false;
348 }
349
350 return true;
351}
352
353/**
354 * put_wifi_interface_info() - put wifi interface info
355 * @stats: Pointer to stats context
356 * @vendor_event: Pointer to vendor event
357 *
358 * Return: bool
359 */
360static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats,
361 struct sk_buff *vendor_event)
362{
363 if (nla_put_u32(vendor_event,
364 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
365 stats->mode) ||
366 nla_put(vendor_event,
367 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530368 QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800369 nla_put_u32(vendor_event,
370 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
371 stats->state) ||
372 nla_put_u32(vendor_event,
373 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
374 stats->roaming) ||
375 nla_put_u32(vendor_event,
376 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
377 stats->capabilities) ||
378 nla_put(vendor_event,
379 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
380 strlen(stats->ssid), stats->ssid) ||
381 nla_put(vendor_event,
382 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530383 QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800384 nla_put(vendor_event,
385 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
386 WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) ||
387 nla_put(vendor_event,
388 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
389 WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700390 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800391 return false;
392 }
393
394 return true;
395}
396
397/**
398 * put_wifi_iface_stats() - put wifi interface stats
399 * @pWifiIfaceStat: Pointer to interface stats context
400 * @num_peer: Number of peers
401 * @vendor_event: Pointer to vendor event
402 *
403 * Return: bool
404 */
405static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
406 u32 num_peers, struct sk_buff *vendor_event)
407{
408 int i = 0;
409 struct nlattr *wmmInfo;
410 struct nlattr *wmmStats;
411 u64 average_tsf_offset;
412
413 if (false == put_wifi_interface_info(&pWifiIfaceStat->info,
414 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700415 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800416 return false;
417
418 }
419
420 average_tsf_offset = pWifiIfaceStat->avg_bcn_spread_offset_high;
421 average_tsf_offset = (average_tsf_offset << 32) |
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700422 pWifiIfaceStat->avg_bcn_spread_offset_low;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423
424 if (nla_put_u32(vendor_event,
425 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
426 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) ||
427 nla_put_u32(vendor_event,
428 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
429 num_peers) ||
430 nla_put_u32(vendor_event,
431 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
432 pWifiIfaceStat->beaconRx) ||
433 nla_put_u32(vendor_event,
434 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
435 pWifiIfaceStat->mgmtRx) ||
436 nla_put_u32(vendor_event,
437 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
438 pWifiIfaceStat->mgmtActionRx) ||
439 nla_put_u32(vendor_event,
440 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
441 pWifiIfaceStat->mgmtActionTx) ||
442 nla_put_u32(vendor_event,
443 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
444 pWifiIfaceStat->rssiMgmt) ||
445 nla_put_u32(vendor_event,
446 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
447 pWifiIfaceStat->rssiData) ||
448 nla_put_u32(vendor_event,
449 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
450 pWifiIfaceStat->rssiAck) ||
451 nla_put_u32(vendor_event,
452 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
453 pWifiIfaceStat->is_leaky_ap) ||
454 nla_put_u32(vendor_event,
455 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
456 pWifiIfaceStat->avg_rx_frms_leaked) ||
457 nla_put_u32(vendor_event,
458 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
459 pWifiIfaceStat->rx_leak_window) ||
Dustin Brownbb7e2f52016-10-17 12:16:35 -0700460 hdd_wlan_nla_put_u64(vendor_event,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800461 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
gaolezb432ed92017-03-16 18:40:04 +0800462 average_tsf_offset) ||
463 nla_put_u32(vendor_event,
464 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT,
465 pWifiIfaceStat->rts_succ_cnt) ||
466 nla_put_u32(vendor_event,
467 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT,
468 pWifiIfaceStat->rts_fail_cnt) ||
469 nla_put_u32(vendor_event,
470 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT,
471 pWifiIfaceStat->ppdu_succ_cnt) ||
472 nla_put_u32(vendor_event,
473 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT,
474 pWifiIfaceStat->ppdu_fail_cnt)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700475 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 return false;
477 }
478
479 wmmInfo = nla_nest_start(vendor_event,
480 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
481 if (wmmInfo == NULL)
482 return false;
483
484 for (i = 0; i < WIFI_AC_MAX; i++) {
485 wmmStats = nla_nest_start(vendor_event, i);
486 if (wmmStats == NULL)
487 return false;
488
489 if (false ==
490 put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i],
491 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700492 hdd_err("put_wifi_wmm_ac_stat Fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800493 return false;
494 }
495
496 nla_nest_end(vendor_event, wmmStats);
497 }
498 nla_nest_end(vendor_event, wmmInfo);
499 return true;
500}
501
502/**
503 * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
504 * @deviceMode: Device mode
505 *
506 * Return: interface mode
507 */
508static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode)
509{
510 switch (deviceMode) {
Krunal Sonif07bb382016-03-10 13:02:11 -0800511 case QDF_STA_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800512 return WIFI_INTERFACE_STA;
Krunal Sonif07bb382016-03-10 13:02:11 -0800513 case QDF_SAP_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800514 return WIFI_INTERFACE_SOFTAP;
Krunal Sonif07bb382016-03-10 13:02:11 -0800515 case QDF_P2P_CLIENT_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800516 return WIFI_INTERFACE_P2P_CLIENT;
Krunal Sonif07bb382016-03-10 13:02:11 -0800517 case QDF_P2P_GO_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800518 return WIFI_INTERFACE_P2P_GO;
Krunal Sonif07bb382016-03-10 13:02:11 -0800519 case QDF_IBSS_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800520 return WIFI_INTERFACE_IBSS;
521 default:
522 /* Return Interface Mode as STA for all the unsupported modes */
523 return WIFI_INTERFACE_STA;
524 }
525}
526
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800527bool hdd_get_interface_info(hdd_adapter_t *pAdapter,
528 tpSirWifiInterfaceInfo pInfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800529{
530 uint8_t *staMac = NULL;
531 hdd_station_ctx_t *pHddStaCtx;
532 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
533 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
534
535 pInfo->mode = hdd_map_device_to_ll_iface_mode(pAdapter->device_mode);
536
Anurag Chouhanc5548422016-02-24 18:33:27 +0530537 qdf_copy_macaddr(&pInfo->macAddr, &pAdapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800538
Krunal Sonif07bb382016-03-10 13:02:11 -0800539 if (((QDF_STA_MODE == pAdapter->device_mode) ||
540 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
541 (QDF_P2P_DEVICE_MODE == pAdapter->device_mode))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800542 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
543 if (eConnectionState_NotConnected ==
544 pHddStaCtx->conn_info.connState) {
545 pInfo->state = WIFI_DISCONNECTED;
546 }
547 if (eConnectionState_Connecting ==
548 pHddStaCtx->conn_info.connState) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700549 hdd_err("Session ID %d, Connection is in progress",
550 pAdapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800551 pInfo->state = WIFI_ASSOCIATING;
552 }
553 if ((eConnectionState_Associated ==
554 pHddStaCtx->conn_info.connState)
555 && (false == pHddStaCtx->conn_info.uIsAuthenticated)) {
556 staMac =
557 (uint8_t *) &(pAdapter->macAddressCurrent.
558 bytes[0]);
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700559 hdd_err("client " MAC_ADDRESS_STR
560 " is in the middle of WPS/EAPOL exchange.",
561 MAC_ADDR_ARRAY(staMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800562 pInfo->state = WIFI_AUTHENTICATING;
563 }
564 if (eConnectionState_Associated ==
565 pHddStaCtx->conn_info.connState) {
566 pInfo->state = WIFI_ASSOCIATED;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530567 qdf_copy_macaddr(&pInfo->bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800568 &pHddStaCtx->conn_info.bssId);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530569 qdf_mem_copy(pInfo->ssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800570 pHddStaCtx->conn_info.SSID.SSID.ssId,
571 pHddStaCtx->conn_info.SSID.SSID.length);
572 /*
573 * NULL Terminate the string
574 */
575 pInfo->ssid[pHddStaCtx->conn_info.SSID.SSID.length] = 0;
576 }
577 }
578
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530579 qdf_mem_copy(pInfo->countryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800580 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
581
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530582 qdf_mem_copy(pInfo->apCountryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800583 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
584
585 return true;
586}
587
588/**
589 * hdd_link_layer_process_peer_stats() - This function is called after
590 * @pAdapter: Pointer to device adapter
591 * @more_data: More data
592 * @pData: Pointer to stats data
593 *
594 * Receiving Link Layer Peer statistics from FW.This function converts
595 * the firmware data to the NL data and sends the same to the kernel/upper
596 * layers.
597 *
598 * Return: None
599 */
600static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter,
601 u32 more_data,
602 tpSirWifiPeerStat pData)
603{
604 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800605 tpSirWifiPeerStat pWifiPeerStat;
606 tpSirWifiPeerInfo pWifiPeerInfo;
607 struct sk_buff *vendor_event;
Sushant Kaushik7a535882015-11-02 13:31:21 +0530608 int status, i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800609 struct nlattr *peers;
610 int numRate;
611
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530612 ENTER();
613
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800614 pWifiPeerStat = pData;
615
616 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530617 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800618 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800619
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800620 hdd_debug("LL_STATS_PEER_ALL : numPeers %u, more data = %u",
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700621 pWifiPeerStat->numPeers, more_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800622
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800623 /*
624 * Allocate a size of 4096 for the peer stats comprising
625 * each of size = sizeof (tSirWifiPeerInfo) + numRate *
626 * sizeof (tSirWifiRateStat).Each field is put with an
627 * NL attribute.The size of 4096 is considered assuming
628 * that number of rates shall not exceed beyond 50 with
629 * the sizeof (tSirWifiRateStat) being 32.
630 */
631 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
632 LL_STATS_EVENT_BUF_SIZE);
633
634 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700635 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800636 return;
637 }
638
639 if (nla_put_u32(vendor_event,
640 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
641 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
642 nla_put_u32(vendor_event,
643 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
644 more_data) ||
645 nla_put_u32(vendor_event,
646 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
647 pWifiPeerStat->numPeers)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700648 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800649
650 kfree_skb(vendor_event);
651 return;
652 }
653
654 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
655 pWifiPeerStat->peerInfo);
656
657 if (pWifiPeerStat->numPeers) {
658 struct nlattr *peerInfo;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700659
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800660 peerInfo = nla_nest_start(vendor_event,
661 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO);
662 if (peerInfo == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700663 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800664 kfree_skb(vendor_event);
665 return;
666 }
667
668 for (i = 1; i <= pWifiPeerStat->numPeers; i++) {
669 peers = nla_nest_start(vendor_event, i);
670 if (peers == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700671 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800672 kfree_skb(vendor_event);
673 return;
674 }
675
676 numRate = pWifiPeerInfo->numRate;
677
678 if (false ==
679 put_wifi_peer_info(pWifiPeerInfo, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700680 hdd_err("put_wifi_peer_info fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800681 kfree_skb(vendor_event);
682 return;
683 }
684
685 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
686 pWifiPeerStat->
687 peerInfo +
688 (i *
689 sizeof
690 (tSirWifiPeerInfo))
691 +
692 (numRate *
693 sizeof
694 (tSirWifiRateStat)));
695 nla_nest_end(vendor_event, peers);
696 }
697 nla_nest_end(vendor_event, peerInfo);
698 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700699
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800700 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530701 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800702}
703
704/**
705 * hdd_link_layer_process_iface_stats() - This function is called after
706 * @pAdapter: Pointer to device adapter
707 * @pData: Pointer to stats data
708 * @num_peers: Number of peers
709 *
710 * Receiving Link Layer Interface statistics from FW.This function converts
711 * the firmware data to the NL data and sends the same to the kernel/upper
712 * layers.
713 *
714 * Return: None
715 */
716static void hdd_link_layer_process_iface_stats(hdd_adapter_t *pAdapter,
717 tpSirWifiIfaceStat pData,
718 u32 num_peers)
719{
720 tpSirWifiIfaceStat pWifiIfaceStat;
721 struct sk_buff *vendor_event;
722 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
723 int status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800724
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530725 ENTER();
726
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800727 pWifiIfaceStat = pData;
728
729 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530730 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800731 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732
733 /*
734 * Allocate a size of 4096 for the interface stats comprising
735 * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered
736 * assuming that all these fit with in the limit.Please take
737 * a call on the limit based on the data requirements on
738 * interface statistics.
739 */
740 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
741 LL_STATS_EVENT_BUF_SIZE);
742
743 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700744 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745 return;
746 }
747
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800748 hdd_debug("WMI_LINK_STATS_IFACE Data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800749
750 if (false == hdd_get_interface_info(pAdapter, &pWifiIfaceStat->info)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700751 hdd_err("hdd_get_interface_info get fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800752 kfree_skb(vendor_event);
753 return;
754 }
755
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800756 if (false ==
757 put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700758 hdd_err("put_wifi_iface_stats fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800759 kfree_skb(vendor_event);
760 return;
761 }
762
763 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530764 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800765}
766
767/**
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700768 * hdd_llstats_radio_fill_channels() - radio stats fill channels
769 * @adapter: Pointer to device adapter
770 * @radiostat: Pointer to stats data
771 * @vendor_event: vendor event
772 *
773 * Return: 0 on success; errno on failure
774 */
775static int hdd_llstats_radio_fill_channels(hdd_adapter_t *adapter,
776 tSirWifiRadioStat *radiostat,
777 struct sk_buff *vendor_event)
778{
779 tSirWifiChannelStats *channel_stats;
780 struct nlattr *chlist;
781 struct nlattr *chinfo;
782 int i;
783
784 chlist = nla_nest_start(vendor_event,
785 QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
786 if (chlist == NULL) {
787 hdd_err("nla_nest_start failed");
788 return -EINVAL;
789 }
790
791 for (i = 0; i < radiostat->numChannels; i++) {
792 channel_stats = (tSirWifiChannelStats *) ((uint8_t *)
793 radiostat->channels +
794 (i * sizeof(tSirWifiChannelStats)));
795
796 chinfo = nla_nest_start(vendor_event, i);
797 if (chinfo == NULL) {
798 hdd_err("nla_nest_start failed");
799 return -EINVAL;
800 }
801
802 if (nla_put_u32(vendor_event,
803 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
804 channel_stats->channel.width) ||
805 nla_put_u32(vendor_event,
806 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
807 channel_stats->channel.centerFreq) ||
808 nla_put_u32(vendor_event,
809 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
810 channel_stats->channel.centerFreq0) ||
811 nla_put_u32(vendor_event,
812 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
813 channel_stats->channel.centerFreq1) ||
814 nla_put_u32(vendor_event,
815 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
816 channel_stats->onTime) ||
817 nla_put_u32(vendor_event,
818 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
819 channel_stats->ccaBusyTime)) {
820 hdd_err("nla_put failed");
821 return -EINVAL;
822 }
823 nla_nest_end(vendor_event, chinfo);
824 }
825 nla_nest_end(vendor_event, chlist);
826
827 return 0;
828}
829
830/**
831 * hdd_llstats_post_radio_stats() - post radio stats
832 * @adapter: Pointer to device adapter
833 * @more_data: More data
834 * @radiostat: Pointer to stats data
835 * @num_radio: Number of radios
836 *
837 * Return: 0 on success; errno on failure
838 */
839static int hdd_llstats_post_radio_stats(hdd_adapter_t *adapter,
840 u32 more_data,
841 tSirWifiRadioStat *radiostat,
842 u32 num_radio)
843{
844 struct sk_buff *vendor_event;
845 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
846 int ret;
847
848 /*
849 * Allocate a size of 4096 for the Radio stats comprising
850 * sizeof (tSirWifiRadioStat) + numChannels * sizeof
851 * (tSirWifiChannelStats).Each channel data is put with an
852 * NL attribute.The size of 4096 is considered assuming that
853 * number of channels shall not exceed beyond 60 with the
854 * sizeof (tSirWifiChannelStats) being 24 bytes.
855 */
856
857 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(
858 hdd_ctx->wiphy,
859 LL_STATS_EVENT_BUF_SIZE);
860
861 if (!vendor_event) {
862 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
863 return -ENOMEM;
864 }
865
866 if (nla_put_u32(vendor_event,
867 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
868 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
869 nla_put_u32(vendor_event,
870 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
871 more_data) ||
872 nla_put_u32(vendor_event,
873 QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
874 num_radio) ||
875 nla_put_u32(vendor_event,
876 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
877 radiostat->radio) ||
878 nla_put_u32(vendor_event,
879 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
880 radiostat->onTime) ||
881 nla_put_u32(vendor_event,
882 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
883 radiostat->txTime) ||
884 nla_put_u32(vendor_event,
885 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
886 radiostat->rxTime) ||
887 nla_put_u32(vendor_event,
888 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
889 radiostat->onTimeScan) ||
890 nla_put_u32(vendor_event,
891 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
892 radiostat->onTimeNbd) ||
893 nla_put_u32(vendor_event,
894 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
895 radiostat->onTimeGscan) ||
896 nla_put_u32(vendor_event,
897 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
898 radiostat->onTimeRoamScan) ||
899 nla_put_u32(vendor_event,
900 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
901 radiostat->onTimePnoScan) ||
902 nla_put_u32(vendor_event,
903 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
904 radiostat->onTimeHs20) ||
905 nla_put_u32(vendor_event,
906 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
907 radiostat->total_num_tx_power_levels) ||
908 nla_put_u32(vendor_event,
909 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
910 radiostat->numChannels)) {
911 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
912 goto failure;
913 }
914
915 if (radiostat->total_num_tx_power_levels) {
916 if (nla_put(vendor_event,
917 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
918 sizeof(u32) *
919 radiostat->total_num_tx_power_levels,
920 radiostat->tx_time_per_power_level)) {
921 hdd_err("nla_put fail");
922 goto failure;
923 }
924 }
925
926 if (radiostat->numChannels) {
927 ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
928 vendor_event);
929 if (ret)
930 goto failure;
931 }
932
933 cfg80211_vendor_cmd_reply(vendor_event);
934 return 0;
935
936failure:
937 kfree_skb(vendor_event);
938 return -EINVAL;
939}
940
941/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800942 * hdd_link_layer_process_radio_stats() - This function is called after
943 * @pAdapter: Pointer to device adapter
944 * @more_data: More data
945 * @pData: Pointer to stats data
946 * @num_radios: Number of radios
947 *
948 * Receiving Link Layer Radio statistics from FW.This function converts
949 * the firmware data to the NL data and sends the same to the kernel/upper
950 * layers.
951 *
952 * Return: None
953 */
954static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter,
955 u32 more_data,
956 tpSirWifiRadioStat pData,
957 u32 num_radio)
958{
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700959 int status, i, nr, ret;
960 tSirWifiRadioStat *pWifiRadioStat = pData;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800961 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
962
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530963 ENTER();
964
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800965 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530966 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800967 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800968
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800969 hdd_debug("LL_STATS_RADIO: number of radios: %u", num_radio);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800970
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700971 for (i = 0; i < num_radio; i++) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800972 hdd_debug("LL_STATS_RADIO"
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700973 " radio: %u onTime: %u txTime: %u rxTime: %u"
974 " onTimeScan: %u onTimeNbd: %u"
975 " onTimeGscan: %u onTimeRoamScan: %u"
976 " onTimePnoScan: %u onTimeHs20: %u"
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -0800977 " numChannels: %u total_num_tx_pwr_levels: %u"
978 " on_time_host_scan: %u, on_time_lpi_scan: %u",
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700979 pWifiRadioStat->radio, pWifiRadioStat->onTime,
980 pWifiRadioStat->txTime, pWifiRadioStat->rxTime,
981 pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd,
982 pWifiRadioStat->onTimeGscan,
983 pWifiRadioStat->onTimeRoamScan,
984 pWifiRadioStat->onTimePnoScan,
985 pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels,
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -0800986 pWifiRadioStat->total_num_tx_power_levels,
987 pWifiRadioStat->on_time_host_scan,
988 pWifiRadioStat->on_time_lpi_scan);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700989 pWifiRadioStat++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990 }
991
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700992 pWifiRadioStat = pData;
993 for (nr = 0; nr < num_radio; nr++) {
994 ret = hdd_llstats_post_radio_stats(pAdapter, more_data,
995 pWifiRadioStat, num_radio);
996 if (ret)
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700997 return;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700998
999 pWifiRadioStat++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001000 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -07001001
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301002 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001003}
1004
1005/**
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001006 * hdd_ll_process_radio_stats() - Wrapper function for cfg80211/debugfs
1007 * @adapter: Pointer to device adapter
1008 * @more_data: More data
1009 * @data: Pointer to stats data
1010 * @num_radios: Number of radios
1011 * @resp_id: Response ID from FW
1012 *
1013 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1014 * function which calls cfg80211/debugfs functions based on the response ID.
1015 *
1016 * Return: None
1017 */
1018static void hdd_ll_process_radio_stats(hdd_adapter_t *adapter,
1019 uint32_t more_data, void *data, uint32_t num_radio,
1020 uint32_t resp_id)
1021{
1022 if (DEBUGFS_LLSTATS_REQID == resp_id)
1023 hdd_debugfs_process_radio_stats(adapter, more_data,
1024 (tpSirWifiRadioStat)data, num_radio);
1025 else
1026 hdd_link_layer_process_radio_stats(adapter, more_data,
1027 (tpSirWifiRadioStat)data, num_radio);
1028}
1029
1030/**
1031 * hdd_ll_process_iface_stats() - Wrapper function for cfg80211/debugfs
1032 * @adapter: Pointer to device adapter
1033 * @data: Pointer to stats data
1034 * @num_peers: Number of peers
1035 * @resp_id: Response ID from FW
1036 *
1037 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1038 * function which calls cfg80211/debugfs functions based on the response ID.
1039 *
1040 * Return: None
1041 */
1042static void hdd_ll_process_iface_stats(hdd_adapter_t *adapter,
1043 void *data, uint32_t num_peers, uint32_t resp_id)
1044{
1045 if (DEBUGFS_LLSTATS_REQID == resp_id)
1046 hdd_debugfs_process_iface_stats(adapter,
1047 (tpSirWifiIfaceStat) data, num_peers);
1048 else
1049 hdd_link_layer_process_iface_stats(adapter,
1050 (tpSirWifiIfaceStat) data, num_peers);
1051}
1052
1053/**
1054 * hdd_ll_process_peer_stats() - Wrapper function for cfg80211/debugfs
1055 * @adapter: Pointer to device adapter
1056 * @more_data: More data
1057 * @data: Pointer to stats data
1058 * @resp_id: Response ID from FW
1059 *
1060 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1061 * function which calls cfg80211/debugfs functions based on the response ID.
1062 *
1063 * Return: None
1064 */
1065static void hdd_ll_process_peer_stats(hdd_adapter_t *adapter,
1066 uint32_t more_data, void *data, uint32_t resp_id)
1067{
1068 if (DEBUGFS_LLSTATS_REQID == resp_id)
1069 hdd_debugfs_process_peer_stats(adapter, data);
1070 else
1071 hdd_link_layer_process_peer_stats(adapter, more_data,
1072 (tpSirWifiPeerStat) data);
1073}
1074
1075/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076 * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called
1077 * @ctx: Pointer to hdd context
1078 * @indType: Indication type
1079 * @pRsp: Pointer to response
1080 *
1081 * After receiving Link Layer indications from FW.This callback converts the
1082 * firmware data to the NL data and send the same to the kernel/upper layers.
1083 *
1084 * Return: None
1085 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301086void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001087 int indType, void *pRsp)
1088{
1089 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
1090 struct hdd_ll_stats_context *context;
1091 hdd_adapter_t *pAdapter = NULL;
1092 tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp;
1093 int status;
1094
1095 status = wlan_hdd_validate_context(pHddCtx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301096 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001097 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098
1099 pAdapter = hdd_get_adapter_by_vdev(pHddCtx,
1100 linkLayerStatsResults->ifaceId);
1101
1102 if (NULL == pAdapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001103 hdd_err("vdev_id %d does not exist with host",
1104 linkLayerStatsResults->ifaceId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105 return;
1106 }
1107
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001108 hdd_debug("Link Layer Indication indType: %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109
1110 switch (indType) {
1111 case SIR_HAL_LL_STATS_RESULTS_RSP:
1112 {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001113 hdd_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %p",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301114 linkLayerStatsResults->paramId,
1115 linkLayerStatsResults->ifaceId,
1116 linkLayerStatsResults->rspId,
1117 linkLayerStatsResults->moreResultToFollow,
1118 linkLayerStatsResults->num_radio,
1119 linkLayerStatsResults->results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001120
1121 context = &ll_stats_context;
1122 spin_lock(&context->context_lock);
1123 /* validate response received from target */
1124 if ((context->request_id != linkLayerStatsResults->rspId) ||
1125 !(context->request_bitmap & linkLayerStatsResults->paramId)) {
1126 spin_unlock(&context->context_lock);
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001127 hdd_err("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 context->request_id, linkLayerStatsResults->rspId,
1129 context->request_bitmap, linkLayerStatsResults->paramId);
1130 return;
1131 }
1132 spin_unlock(&context->context_lock);
1133
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001134 if (linkLayerStatsResults->paramId & WMI_LINK_STATS_RADIO) {
1135 hdd_ll_process_radio_stats(pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001136 linkLayerStatsResults->moreResultToFollow,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001137 linkLayerStatsResults->results,
1138 linkLayerStatsResults->num_radio,
1139 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140
1141 spin_lock(&context->context_lock);
1142 if (!linkLayerStatsResults->moreResultToFollow)
1143 context->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
1144 spin_unlock(&context->context_lock);
1145
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001146 } else if (linkLayerStatsResults->paramId &
1147 WMI_LINK_STATS_IFACE) {
1148 hdd_ll_process_iface_stats(pAdapter,
1149 linkLayerStatsResults->results,
1150 linkLayerStatsResults->num_peers,
1151 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001152
1153 spin_lock(&context->context_lock);
Srinivas Dasari6946a792015-09-28 15:01:49 +05301154 /* Firmware doesn't send peerstats event if no peers are
1155 * connected. HDD should not wait for any peerstats in
1156 * this case and return the status to middleware after
1157 * receiving iface stats
1158 */
1159 if (!linkLayerStatsResults->num_peers)
1160 context->request_bitmap &=
1161 ~(WMI_LINK_STATS_ALL_PEER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001162 context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
1163 spin_unlock(&context->context_lock);
1164
1165 } else if (linkLayerStatsResults->
1166 paramId & WMI_LINK_STATS_ALL_PEER) {
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001167 hdd_ll_process_peer_stats(pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001168 linkLayerStatsResults->moreResultToFollow,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001169 linkLayerStatsResults->results,
1170 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001171
1172 spin_lock(&context->context_lock);
1173 if (!linkLayerStatsResults->moreResultToFollow)
1174 context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
1175 spin_unlock(&context->context_lock);
1176
1177 } else {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001178 hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001179 }
1180
1181 spin_lock(&context->context_lock);
1182 /* complete response event if all requests are completed */
1183 if (0 == context->request_bitmap)
1184 complete(&context->response_event);
1185 spin_unlock(&context->context_lock);
1186
1187 break;
1188 }
1189 default:
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001190 hdd_warn("invalid event type %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001191 break;
1192 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001193}
1194
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301195void hdd_lost_link_info_cb(void *context,
1196 struct sir_lost_link_info *lost_link_info)
1197{
1198 hdd_context_t *hdd_ctx = (hdd_context_t *)context;
1199 int status;
1200 hdd_adapter_t *adapter;
1201
1202 status = wlan_hdd_validate_context(hdd_ctx);
1203 if (0 != status)
1204 return;
1205
1206 if (NULL == lost_link_info) {
1207 hdd_err("lost_link_info is NULL");
1208 return;
1209 }
1210
1211 adapter = hdd_get_adapter_by_vdev(hdd_ctx, lost_link_info->vdev_id);
1212 if (NULL == adapter) {
1213 hdd_err("invalid adapter");
1214 return;
1215 }
1216
1217 adapter->rssi_on_disconnect = lost_link_info->rssi;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001218 hdd_debug("rssi on disconnect %d", adapter->rssi_on_disconnect);
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301219}
1220
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001221const struct
1222nla_policy
1223 qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1224 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1225 .type = NLA_U32},
1226 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1227 .type = NLA_U32},
1228};
1229
1230/**
1231 * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1232 * @wiphy: Pointer to wiphy
1233 * @wdev: Pointer to wdev
1234 * @data: Pointer to data
1235 * @data_len: Data length
1236 *
1237 * Return: int
1238 */
1239static int
1240__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1241 struct wireless_dev *wdev,
1242 const void *data,
1243 int data_len)
1244{
1245 int status;
1246 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
1247 tSirLLStatsSetReq LinkLayerStatsSetReq;
1248 struct net_device *dev = wdev->netdev;
1249 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1250 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1251
Jeff Johnson1f61b612016-02-12 16:28:33 -08001252 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301253
Anurag Chouhan6d760662016-02-20 16:05:43 +05301254 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001255 hdd_err("Command not allowed in FTM mode");
1256 return -EPERM;
1257 }
1258
1259 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301260 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001261 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001262
1263 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1264 (struct nlattr *)data,
1265 data_len, qca_wlan_vendor_ll_set_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001266 hdd_err("maximum attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001267 return -EINVAL;
1268 }
1269
1270 if (!tb_vendor
1271 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001272 hdd_err("MPDU size Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001273 return -EINVAL;
1274 }
1275
1276 if (!tb_vendor
1277 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001278 hdd_err("Stats Gathering Not Present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 return -EINVAL;
1280 }
1281
1282 /* Shall take the request Id if the Upper layers pass. 1 For now. */
1283 LinkLayerStatsSetReq.reqId = 1;
1284
1285 LinkLayerStatsSetReq.mpduSizeThreshold =
1286 nla_get_u32(tb_vendor
1287 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1288
1289 LinkLayerStatsSetReq.aggressiveStatisticsGathering =
1290 nla_get_u32(tb_vendor
1291 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1292
1293 LinkLayerStatsSetReq.staId = pAdapter->sessionId;
1294
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001295 hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301296 LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId,
1297 LinkLayerStatsSetReq.mpduSizeThreshold,
1298 LinkLayerStatsSetReq.aggressiveStatisticsGathering);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001299
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301300 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(pHddCtx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001301 &LinkLayerStatsSetReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001302 hdd_err("sme_ll_stats_set_req Failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001303 return -EINVAL;
1304 }
1305
1306 pAdapter->isLinkLayerStatsSet = 1;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301307 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001308 return 0;
1309}
1310
1311/**
1312 * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1313 * @wiphy: Pointer to wiphy
1314 * @wdev: Pointer to wdev
1315 * @data: Pointer to data
1316 * @data_len: Data length
1317 *
1318 * Return: 0 if success, non-zero for failure
1319 */
1320int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1321 struct wireless_dev *wdev,
1322 const void *data,
1323 int data_len)
1324{
1325 int ret = 0;
1326
1327 cds_ssr_protect(__func__);
1328 ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
1329 cds_ssr_unprotect(__func__);
1330
1331 return ret;
1332}
1333
1334const struct
1335nla_policy
1336 qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1337 /* Unsigned 32bit value provided by the caller issuing the GET stats
1338 * command. When reporting
1339 * the stats results, the driver uses the same value to indicate
1340 * which GET request the results
1341 * correspond to.
1342 */
1343 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1344
1345 /* Unsigned 32bit value . bit mask to identify what statistics are
Jeff Johnson8bb78c32017-01-12 08:42:50 -08001346 * requested for retrieval
1347 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001348 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1349};
1350
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001351static int wlan_hdd_send_ll_stats_req(hdd_context_t *hdd_ctx,
1352 tSirLLStatsGetReq *req)
1353{
1354 unsigned long rc;
1355 struct hdd_ll_stats_context *context;
1356
1357 context = &ll_stats_context;
1358 spin_lock(&context->context_lock);
1359 context->request_id = req->reqId;
1360 context->request_bitmap = req->paramIdMask;
1361 INIT_COMPLETION(context->response_event);
1362 spin_unlock(&context->context_lock);
1363
1364 if (QDF_STATUS_SUCCESS !=
1365 sme_ll_stats_get_req(hdd_ctx->hHal, req)) {
1366 hdd_err("sme_ll_stats_get_req Failed");
1367 return -EINVAL;
1368 }
1369
1370 rc = wait_for_completion_timeout(&context->response_event,
1371 msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
1372 if (!rc) {
1373 hdd_err("Target response timed out request id %d request bitmap 0x%x",
1374 context->request_id, context->request_bitmap);
1375 return -ETIMEDOUT;
1376 }
1377
1378 return 0;
1379}
1380
1381int wlan_hdd_ll_stats_get(hdd_adapter_t *adapter, uint32_t req_id,
1382 uint32_t req_mask)
1383{
1384 unsigned long rc;
1385 tSirLLStatsGetReq get_req;
1386 hdd_station_ctx_t *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1387 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1388 int status;
1389
1390 ENTER();
1391
1392 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1393 hdd_warn("Command not allowed in FTM mode");
1394 return -EPERM;
1395 }
1396
1397 status = wlan_hdd_validate_context(hdd_ctx);
1398 if (0 != status)
1399 return -EINVAL;
1400
1401 if (hddstactx->hdd_ReassocScenario) {
1402 hdd_err("Roaming in progress, so unable to proceed this request");
1403 return -EBUSY;
1404 }
1405
1406 if (!adapter->isLinkLayerStatsSet)
1407 hdd_info("isLinkLayerStatsSet: %d; STATs will be all zero",
1408 adapter->isLinkLayerStatsSet);
1409
1410 get_req.reqId = req_id;
1411 get_req.paramIdMask = req_mask;
1412 get_req.staId = adapter->sessionId;
1413
1414 rtnl_lock();
1415 rc = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req);
1416 if (0 != rc) {
1417 hdd_err("Failed to send LL stats request (id:%u)", req_id);
1418 goto err_rtnl_unlock;
1419 }
1420
1421 rtnl_unlock();
1422
1423 EXIT();
1424 return rc;
1425
1426err_rtnl_unlock:
1427 rtnl_unlock();
1428 return rc;
1429}
1430
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001431/**
1432 * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1433 * @wiphy: Pointer to wiphy
1434 * @wdev: Pointer to wdev
1435 * @data: Pointer to data
1436 * @data_len: Data length
1437 *
1438 * Return: int
1439 */
1440static int
1441__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1442 struct wireless_dev *wdev,
1443 const void *data,
1444 int data_len)
1445{
1446 unsigned long rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001447 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1448 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1449 tSirLLStatsGetReq LinkLayerStatsGetReq;
1450 struct net_device *dev = wdev->netdev;
1451 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Anurag Chouhan22520002016-09-03 16:20:32 +05301452 hdd_station_ctx_t *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 int status;
1454
Kapil Guptabf4943c2016-10-13 12:15:39 +05301455 /* ENTER() intentionally not used in a frequently invoked API */
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301456
Anurag Chouhan6d760662016-02-20 16:05:43 +05301457 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001458 hdd_err("Command not allowed in FTM mode");
1459 return -EPERM;
1460 }
1461
1462 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301463 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001465
1466 if (!pAdapter->isLinkLayerStatsSet) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001467 hdd_warn("isLinkLayerStatsSet: %d",
1468 pAdapter->isLinkLayerStatsSet);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001469 return -EINVAL;
1470 }
1471
Anurag Chouhan22520002016-09-03 16:20:32 +05301472 if (hddstactx->hdd_ReassocScenario) {
1473 hdd_err("Roaming in progress, so unable to proceed this request");
1474 return -EBUSY;
1475 }
1476
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001477 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1478 (struct nlattr *)data,
1479 data_len, qca_wlan_vendor_ll_get_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001480 hdd_err("max attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001481 return -EINVAL;
1482 }
1483
1484 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001485 hdd_err("Request Id Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001486 return -EINVAL;
1487 }
1488
1489 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001490 hdd_err("Req Mask Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001491 return -EINVAL;
1492 }
1493
1494 LinkLayerStatsGetReq.reqId =
1495 nla_get_u32(tb_vendor
1496 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1497 LinkLayerStatsGetReq.paramIdMask =
1498 nla_get_u32(tb_vendor
1499 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1500
1501 LinkLayerStatsGetReq.staId = pAdapter->sessionId;
1502
yeshwanth sriram guntuka08e995b2017-04-26 12:32:12 +05301503 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1504 hdd_err("invalid session id: %d", pAdapter->sessionId);
1505 return -EINVAL;
1506 }
1507
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001508 rc = wlan_hdd_send_ll_stats_req(pHddCtx, &LinkLayerStatsGetReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001509 if (!rc) {
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001510 hdd_err("Failed to send LL stats request (id:%u)",
1511 LinkLayerStatsGetReq.reqId);
1512 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513 }
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001514
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301515 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001516 return 0;
1517}
1518
1519/**
1520 * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1521 * @wiphy: Pointer to wiphy
1522 * @wdev: Pointer to wdev
1523 * @data: Pointer to data
1524 * @data_len: Data length
1525 *
1526 * Return: 0 if success, non-zero for failure
1527 */
1528int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1529 struct wireless_dev *wdev,
1530 const void *data,
1531 int data_len)
1532{
1533 int ret = 0;
1534
1535 cds_ssr_protect(__func__);
1536 ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1537 cds_ssr_unprotect(__func__);
1538
1539 return ret;
1540}
1541
1542const struct
1543nla_policy
1544 qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1545 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1546 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1547 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1548 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1549};
1550
1551/**
1552 * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1553 * @wiphy: Pointer to wiphy
1554 * @wdev: Pointer to wdev
1555 * @data: Pointer to data
1556 * @data_len: Data length
1557 *
1558 * Return: int
1559 */
1560static int
1561__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1562 struct wireless_dev *wdev,
1563 const void *data,
1564 int data_len)
1565{
1566 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1567 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1568 tSirLLStatsClearReq LinkLayerStatsClearReq;
1569 struct net_device *dev = wdev->netdev;
1570 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1571 u32 statsClearReqMask;
1572 u8 stopReq;
1573 int status;
1574 struct sk_buff *temp_skbuff;
1575
Jeff Johnson1f61b612016-02-12 16:28:33 -08001576 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301577
Anurag Chouhan6d760662016-02-20 16:05:43 +05301578 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001579 hdd_err("Command not allowed in FTM mode");
1580 return -EPERM;
1581 }
1582
1583 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301584 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001585 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586
1587 if (!pAdapter->isLinkLayerStatsSet) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001588 hdd_warn("isLinkLayerStatsSet : %d",
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001589 pAdapter->isLinkLayerStatsSet);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001590 return -EINVAL;
1591 }
1592
1593 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1594 (struct nlattr *)data,
1595 data_len, qca_wlan_vendor_ll_clr_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001596 hdd_err("STATS_CLR_MAX is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001597 return -EINVAL;
1598 }
1599
1600 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1601 !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001602 hdd_err("Error in LL_STATS CLR CONFIG PARA");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001603 return -EINVAL;
1604 }
1605
1606 statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1607 nla_get_u32(tb_vendor
1608 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1609
1610 stopReq = LinkLayerStatsClearReq.stopReq =
1611 nla_get_u8(tb_vendor
1612 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1613
1614 /*
1615 * Shall take the request Id if the Upper layers pass. 1 For now.
1616 */
1617 LinkLayerStatsClearReq.reqId = 1;
1618
1619 LinkLayerStatsClearReq.staId = pAdapter->sessionId;
1620
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001621 hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301622 LinkLayerStatsClearReq.reqId,
1623 LinkLayerStatsClearReq.staId,
1624 LinkLayerStatsClearReq.statsClearReqMask,
1625 LinkLayerStatsClearReq.stopReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301627 if (QDF_STATUS_SUCCESS == sme_ll_stats_clear_req(pHddCtx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001628 &LinkLayerStatsClearReq)) {
1629 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1630 2 *
1631 sizeof(u32) +
1632 2 *
1633 NLMSG_HDRLEN);
1634 if (temp_skbuff != NULL) {
1635 if (nla_put_u32(temp_skbuff,
1636 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1637 statsClearReqMask) ||
1638 nla_put_u32(temp_skbuff,
1639 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1640 stopReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001641 hdd_err("LL_STATS_CLR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001642 kfree_skb(temp_skbuff);
1643 return -EINVAL;
1644 }
1645
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001646 /* If the ask is to stop the stats collection
1647 * as part of clear (stopReq = 1), ensure
1648 * that no further requests of get go to the
1649 * firmware by having isLinkLayerStatsSet set
1650 * to 0. However it the stopReq as part of
1651 * the clear request is 0, the request to get
1652 * the statistics are honoured as in this case
1653 * the firmware is just asked to clear the
1654 * statistics.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001655 */
1656 if (stopReq == 1)
1657 pAdapter->isLinkLayerStatsSet = 0;
1658
1659 return cfg80211_vendor_cmd_reply(temp_skbuff);
1660 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301661 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001662 return -ENOMEM;
1663 }
1664
1665 return -EINVAL;
1666}
1667
1668/**
1669 * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1670 * @wiphy: Pointer to wiphy
1671 * @wdev: Pointer to wdev
1672 * @data: Pointer to data
1673 * @data_len: Data length
1674 *
1675 * Return: 0 if success, non-zero for failure
1676 */
1677int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1678 struct wireless_dev *wdev,
1679 const void *data,
1680 int data_len)
1681{
1682 int ret = 0;
1683
1684 cds_ssr_protect(__func__);
1685 ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
1686 cds_ssr_unprotect(__func__);
1687
1688 return ret;
1689}
1690
Zhang Qianca38fb12016-12-23 11:10:48 +08001691/**
1692 * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
1693 * @wifi_peer_info: peer information
1694 * @vendor_event: buffer for vendor event
1695 *
1696 * Return: 0 success
1697 */
1698static inline int
1699hdd_populate_per_peer_ps_info(tSirWifiPeerInfo *wifi_peer_info,
1700 struct sk_buff *vendor_event)
1701{
1702 if (!wifi_peer_info) {
1703 hdd_err("Invalid pointer to peer info.");
1704 return -EINVAL;
1705 }
1706
1707 if (nla_put_u32(vendor_event,
1708 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
1709 wifi_peer_info->power_saving) ||
1710 nla_put(vendor_event,
1711 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
1712 QDF_MAC_ADDR_SIZE, &wifi_peer_info->peerMacAddress)) {
1713 hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
1714 return -EINVAL;
1715 }
1716 return 0;
1717}
1718
1719/**
1720 * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
1721 * @data: stats for peer STA
1722 * @vendor_event: buffer for vendor event
1723 *
1724 * Return: 0 success
1725 */
1726static int hdd_populate_wifi_peer_ps_info(tSirWifiPeerStat *data,
1727 struct sk_buff *vendor_event)
1728{
1729 uint32_t peer_num, i;
1730 tSirWifiPeerInfo *wifi_peer_info;
1731 struct nlattr *peer_info, *peers;
1732
1733 if (!data) {
1734 hdd_err("Invalid pointer to Wifi peer stat.");
1735 return -EINVAL;
1736 }
1737
1738 peer_num = data->numPeers;
1739 if (peer_num == 0) {
1740 hdd_err("Peer number is zero.");
1741 return -EINVAL;
1742 }
1743
1744 if (nla_put_u32(vendor_event,
1745 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
1746 peer_num)) {
1747 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1748 return -EINVAL;
1749 }
1750
1751 peer_info = nla_nest_start(vendor_event,
1752 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
1753 if (peer_info == NULL) {
1754 hdd_err("nla_nest_start failed");
1755 return -EINVAL;
1756 }
1757
1758 for (i = 0; i < peer_num; i++) {
1759 wifi_peer_info = &data->peerInfo[i];
1760 peers = nla_nest_start(vendor_event, i);
1761
1762 if (peers == NULL) {
1763 hdd_err("nla_nest_start failed");
1764 return -EINVAL;
1765 }
1766
1767 if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
1768 return -EINVAL;
1769
1770 nla_nest_end(vendor_event, peers);
1771 }
1772 nla_nest_end(vendor_event, peer_info);
1773
1774 return 0;
1775}
1776
1777/**
1778 * hdd_populate_tx_failure_info() - populate TX failure info
1779 * @tx_fail: TX failure info
1780 * @skb: buffer for vendor event
1781 *
1782 * Return: 0 Success
1783 */
1784static inline int
1785hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
1786 struct sk_buff *skb)
1787{
1788 int status = 0;
1789
1790 if (tx_fail == NULL || skb == NULL)
1791 return -EINVAL;
1792
1793 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
1794 tx_fail->tid) ||
1795 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
1796 tx_fail->msdu_num) ||
1797 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
1798 tx_fail->status)) {
1799 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1800 status = -EINVAL;
1801 }
1802
1803 return status;
1804}
1805
1806/**
Zhang Qian4ead8f02017-03-27 14:21:47 +08001807 * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event
1808 * @info: cca info array for all channels
1809 * @vendor_event: vendor event buffer
1810 *
1811 * Return: 0 Success, EINVAL failure
1812 */
1813static int
1814hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca,
1815 struct sk_buff *vendor_event)
1816{
1817 /* There might be no CCA info for a channel */
1818 if (!cca)
1819 return 0;
1820
1821 if (nla_put_u32(vendor_event,
1822 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
1823 cca->idle_time) ||
1824 nla_put_u32(vendor_event,
1825 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
1826 cca->tx_time) ||
1827 nla_put_u32(vendor_event,
1828 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
1829 cca->rx_in_bss_time) ||
1830 nla_put_u32(vendor_event,
1831 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
1832 cca->rx_out_bss_time) ||
1833 nla_put_u32(vendor_event,
1834 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
1835 cca->rx_busy_time) ||
1836 nla_put_u32(vendor_event,
1837 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
1838 cca->rx_in_bad_cond_time) ||
1839 nla_put_u32(vendor_event,
1840 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
1841 cca->tx_in_bad_cond_time) ||
1842 nla_put_u32(vendor_event,
1843 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
1844 cca->wlan_not_avail_time) ||
1845 nla_put_u32(vendor_event,
1846 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
1847 cca->vdev_id)) {
1848 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1849 return -EINVAL;
1850 }
1851 return 0;
1852}
1853
1854/**
1855 * hdd_populate_wifi_signal_info - put chain signal info
1856 * @info: RF chain signal info
1857 * @skb: vendor event buffer
1858 *
1859 * Return: 0 Success, EINVAL failure
1860 */
1861static int
1862hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal,
1863 struct sk_buff *skb)
1864{
1865 uint32_t i;
1866 struct nlattr *chains, *att;
1867
1868 /* There might be no signal info for a peer */
1869 if (!peer_signal)
1870 return 0;
1871
1872 if (nla_put_u32(skb,
1873 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
1874 WIFI_MAX_CHAINS)) {
1875 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1876 return -EINVAL;
1877 }
1878
1879 att = nla_nest_start(skb,
1880 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL);
1881 if (!att) {
1882 hdd_err("nla_nest_start failed");
1883 return -EINVAL;
1884 }
1885
1886 for (i = 0; i < WIFI_MAX_CHAINS; i++) {
1887 chains = nla_nest_start(skb, i);
1888
1889 if (!chains) {
1890 hdd_err("nla_nest_start failed");
1891 return -EINVAL;
1892 }
1893
1894 if (nla_put_u32(skb,
1895 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
1896 peer_signal->per_ant_snr[i]) ||
1897 nla_put_u32(skb,
1898 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
1899 peer_signal->nf[i])) {
1900 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1901 return -EINVAL;
1902 }
1903 nla_nest_end(skb, chains);
1904 }
1905 nla_nest_end(skb, att);
1906
1907 return 0;
1908}
1909
1910/**
1911 * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info
1912 * @info: tx info
1913 * @skb: vendor event buffer
1914 *
1915 * Return: 0 Success, EINVAL failure
1916 */
1917static int
1918hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats,
1919 struct sk_buff *skb)
1920{
1921 uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay;
1922
1923 /* There might be no TX info for a peer */
1924 if (!tx_stats)
1925 return 0;
1926
1927 agg_size = tx_stats->mpdu_aggr_size;
1928 succ_mcs = tx_stats->success_mcs;
1929 fail_mcs = tx_stats->fail_mcs;
1930 delay = tx_stats->delay;
1931
1932 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
1933 tx_stats->msdus) ||
1934 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1935 tx_stats->mpdus) ||
1936 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
1937 tx_stats->ppdus) ||
1938 nla_put_u32(skb,
1939 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
1940 tx_stats->bytes) ||
1941 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
1942 tx_stats->drops) ||
1943 nla_put_u32(skb,
1944 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
1945 tx_stats->drop_bytes) ||
1946 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
1947 tx_stats->retries) ||
1948 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
1949 tx_stats->failed) ||
1950 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
1951 tx_stats->aggr_len) ||
1952 nla_put_u32(skb,
1953 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
1954 tx_stats->success_mcs_len) ||
1955 nla_put_u32(skb,
1956 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
1957 tx_stats->fail_mcs_len) ||
1958 nla_put_u32(skb,
1959 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
1960 tx_stats->delay_len))
1961 goto put_attr_fail;
1962
1963 if (agg_size) {
1964 if (nla_put(skb,
1965 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
1966 tx_stats->aggr_len, agg_size))
1967 goto put_attr_fail;
1968 }
1969
1970 if (succ_mcs) {
1971 if (nla_put(skb,
1972 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
1973 tx_stats->success_mcs_len, succ_mcs))
1974 goto put_attr_fail;
1975 }
1976
1977 if (fail_mcs) {
1978 if (nla_put(skb,
1979 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
1980 tx_stats->fail_mcs_len, fail_mcs))
1981 goto put_attr_fail;
1982 }
1983
1984 if (delay) {
1985 if (nla_put(skb,
1986 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
1987 tx_stats->delay_len, delay))
1988 goto put_attr_fail;
1989 }
1990 return 0;
1991
1992put_attr_fail:
1993 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1994 return -EINVAL;
1995}
1996
1997/**
1998 * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info
1999 * @info: rx info
2000 * @skb: vendor event buffer
2001 *
2002 * Return: 0 Success, EINVAL failure
2003 */
2004static int
2005hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats,
2006 struct sk_buff *skb)
2007{
2008 uint32_t *mcs, *aggr;
2009
2010 /* There might be no RX info for a peer */
2011 if (!rx_stats)
2012 return 0;
2013
2014 aggr = rx_stats->mpdu_aggr;
2015 mcs = rx_stats->mcs;
2016
2017 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
2018 rx_stats->mpdus) ||
2019 nla_put_u32(skb,
2020 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
2021 rx_stats->bytes) ||
2022 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
2023 rx_stats->ppdus) ||
2024 nla_put_u32(skb,
2025 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
2026 rx_stats->ppdu_bytes) ||
2027 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
2028 rx_stats->mpdu_lost) ||
2029 nla_put_u32(skb,
2030 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
2031 rx_stats->mpdu_retry) ||
2032 nla_put_u32(skb,
2033 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
2034 rx_stats->mpdu_dup) ||
2035 nla_put_u32(skb,
2036 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
2037 rx_stats->mpdu_discard) ||
2038 nla_put_u32(skb,
2039 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
2040 rx_stats->aggr_len) ||
2041 nla_put_u32(skb,
2042 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
2043 rx_stats->mcs_len))
2044 goto put_attr_fail;
2045
2046 if (aggr) {
2047 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
2048 rx_stats->aggr_len, aggr))
2049 goto put_attr_fail;
2050 }
2051
2052 if (mcs) {
2053 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
2054 rx_stats->mcs_len, mcs))
2055 goto put_attr_fail;
2056 }
2057
2058 return 0;
2059
2060put_attr_fail:
2061 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2062 return -EINVAL;
2063}
2064
2065/**
2066 * hdd_populate_wifi_wmm_ac_info() - put WMM AC info
2067 * @info: per AC stats
2068 * @skb: vendor event buffer
2069 *
2070 * Return: 0 Success, EINVAL failure
2071 */
2072static int
2073hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats,
2074 struct sk_buff *skb)
2075{
2076 struct nlattr *wmm;
2077
2078 wmm = nla_nest_start(skb, ac_stats->type);
2079 if (!wmm)
2080 goto nest_start_fail;
2081
2082 if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) ||
2083 hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb))
2084 goto put_attr_fail;
2085
2086 nla_nest_end(skb, wmm);
2087 return 0;
2088
2089nest_start_fail:
2090 hdd_err("nla_nest_start failed");
2091 return -EINVAL;
2092
2093put_attr_fail:
2094 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2095 return -EINVAL;
2096}
2097
2098/**
2099 * hdd_populate_wifi_ll_ext_peer_info() - put per peer info
2100 * @info: peer stats
2101 * @skb: vendor event buffer
2102 *
2103 * Return: 0 Success, EINVAL failure
2104 */
2105static int
2106hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers,
2107 struct sk_buff *skb)
2108{
2109 uint32_t i;
2110 struct nlattr *wmm_ac;
2111
2112 if (nla_put_u32(skb,
2113 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
2114 peers->peer_id) ||
2115 nla_put_u32(skb,
2116 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
2117 peers->vdev_id) ||
2118 nla_put_u32(skb,
2119 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
2120 peers->sta_ps_inds) ||
2121 nla_put_u32(skb,
2122 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
2123 peers->sta_ps_durs) ||
2124 nla_put_u32(skb,
2125 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
2126 peers->rx_probe_reqs) ||
2127 nla_put_u32(skb,
2128 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
2129 peers->rx_oth_mgmts) ||
2130 nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
2131 QDF_MAC_ADDR_SIZE, peers->mac_address) ||
2132 hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) {
2133 hdd_err("put peer signal attr failed");
2134 return -EINVAL;
2135 }
2136
2137 wmm_ac = nla_nest_start(skb,
2138 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS);
2139 if (!wmm_ac) {
2140 hdd_err("nla_nest_start failed");
2141 return -EINVAL;
2142 }
2143
2144 for (i = 0; i < WLAN_MAX_AC; i++) {
2145 if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) {
2146 hdd_err("put WMM AC attr failed");
2147 return -EINVAL;
2148 }
2149 }
2150
2151 nla_nest_end(skb, wmm_ac);
2152 return 0;
2153}
2154
2155/**
2156 * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats
2157 * @info: link layer stats
2158 * @skb: vendor event buffer
2159 *
2160 * Return: 0 Success, EINVAL failure
2161 */
2162static int
2163hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats,
2164 struct sk_buff *skb)
2165{
2166 uint32_t i;
2167 struct nlattr *peer, *peer_info, *channels, *channel_info;
2168
2169 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
2170 stats->trigger_cond_id) ||
2171 nla_put_u32(skb,
2172 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
2173 stats->cca_chgd_bitmap) ||
2174 nla_put_u32(skb,
2175 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
2176 stats->sig_chgd_bitmap) ||
2177 nla_put_u32(skb,
2178 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
2179 stats->tx_chgd_bitmap) ||
2180 nla_put_u32(skb,
2181 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
2182 stats->rx_chgd_bitmap) ||
2183 nla_put_u32(skb,
2184 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
2185 stats->channel_num) ||
2186 nla_put_u32(skb,
2187 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
2188 stats->peer_num)) {
2189 goto put_attr_fail;
2190 }
2191
2192 channels = nla_nest_start(skb,
2193 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS);
2194 if (!channels) {
2195 hdd_err("nla_nest_start failed");
2196 return -EINVAL;
2197 }
2198
2199 for (i = 0; i < stats->channel_num; i++) {
2200 channel_info = nla_nest_start(skb, i);
2201 if (!channel_info) {
2202 hdd_err("nla_nest_start failed");
2203 return -EINVAL;
2204 }
2205
2206 if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb))
2207 goto put_attr_fail;
2208 nla_nest_end(skb, channel_info);
2209 }
2210 nla_nest_end(skb, channels);
2211
2212 peer_info = nla_nest_start(skb,
2213 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER);
2214 if (!peer_info) {
2215 hdd_err("nla_nest_start failed");
2216 return -EINVAL;
2217 }
2218
2219 for (i = 0; i < stats->peer_num; i++) {
2220 peer = nla_nest_start(skb, i);
2221 if (!peer) {
2222 hdd_err("nla_nest_start failed");
2223 return -EINVAL;
2224 }
2225
2226 if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i],
2227 skb))
2228 goto put_attr_fail;
2229 nla_nest_end(skb, peer);
2230 }
2231
2232 nla_nest_end(skb, peer_info);
2233 return 0;
2234
2235put_attr_fail:
2236 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2237 return -EINVAL;
2238}
2239
2240/**
Zhang Qianca38fb12016-12-23 11:10:48 +08002241 * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
2242 * @ctx: HDD context
2243 * @rsp: msg from FW
2244 *
2245 * This function is an extension of
2246 * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
2247 * monitoring parameters offloaded to NL data and send the same to the
2248 * kernel/upper layers.
2249 *
2250 * Return: None
2251 */
2252void wlan_hdd_cfg80211_link_layer_stats_ext_callback(tHddHandle ctx,
2253 tSirLLStatsResults *rsp)
2254{
2255 hdd_context_t *hdd_ctx;
2256 struct sk_buff *skb = NULL;
2257 uint32_t param_id, index;
2258 hdd_adapter_t *adapter = NULL;
2259 tSirLLStatsResults *linkLayer_stats_results;
2260 tSirWifiPeerStat *peer_stats;
2261 uint8_t *results;
2262 int status;
2263
2264 ENTER();
2265
2266 if (!ctx) {
2267 hdd_err("Invalid HDD context.");
2268 return;
2269 }
2270
2271 if (!rsp) {
2272 hdd_err("Invalid result.");
2273 return;
2274 }
2275
2276 hdd_ctx = (hdd_context_t *)ctx;
2277 linkLayer_stats_results = rsp;
2278
2279 status = wlan_hdd_validate_context(hdd_ctx);
2280 if (0 != status)
2281 return;
2282
2283 adapter = hdd_get_adapter_by_vdev(hdd_ctx,
2284 linkLayer_stats_results->ifaceId);
2285
Zhang Qian4ead8f02017-03-27 14:21:47 +08002286 if (!adapter) {
Zhang Qianca38fb12016-12-23 11:10:48 +08002287 hdd_err("vdev_id %d does not exist with host.",
2288 linkLayer_stats_results->ifaceId);
2289 return;
2290 }
2291
2292 index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
2293 skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2294 NULL, LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
2295 index, GFP_KERNEL);
2296 if (!skb) {
2297 hdd_err("cfg80211_vendor_event_alloc failed.");
2298 return;
2299 }
2300
2301 results = linkLayer_stats_results->results;
2302 param_id = linkLayer_stats_results->paramId;
2303 hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %p",
2304 linkLayer_stats_results->paramId,
2305 linkLayer_stats_results->ifaceId,
2306 linkLayer_stats_results->results);
2307 if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
2308 peer_stats = (tSirWifiPeerStat *)results;
2309 status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
2310 } else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
2311 struct sir_wifi_iface_tx_fail *tx_fail;
2312
2313 tx_fail = (struct sir_wifi_iface_tx_fail *)results;
2314 status = hdd_populate_tx_failure_info(tx_fail, skb);
2315 } else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
2316 hdd_info("MAC counters stats");
Zhang Qian4ead8f02017-03-27 14:21:47 +08002317 status = hdd_populate_wifi_ll_ext_stats(
2318 (struct sir_wifi_ll_ext_stats *)
2319 rsp->results, skb);
Zhang Qianca38fb12016-12-23 11:10:48 +08002320 } else {
2321 hdd_info("Unknown link layer stats");
2322 status = -EINVAL;
2323 }
2324
2325 if (status == 0)
2326 cfg80211_vendor_event(skb, GFP_KERNEL);
2327 else
2328 kfree_skb(skb);
2329 EXIT();
2330}
2331
Zhang Qian4ead8f02017-03-27 14:21:47 +08002332static const struct nla_policy
2333qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = {
2334 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = {
2335 .type = NLA_U32
2336 },
2337 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = {
2338 .type = NLA_U32
2339 },
2340 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = {
2341 .type = NLA_U32
2342 },
2343 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = {
2344 .type = NLA_U32
2345 },
2346 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = {
2347 .type = NLA_U32
2348 },
2349 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = {
2350 .type = NLA_U32
2351 },
2352 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = {
2353 .type = NLA_U32
2354 },
2355 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = {
2356 .type = NLA_U32
2357 },
2358 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = {
2359 .type = NLA_U32
2360 },
2361 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = {
2362 .type = NLA_U32
2363 },
2364 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = {
2365 .type = NLA_U32
2366 },
2367 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = {
2368 .type = NLA_U32
2369 },
2370 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = {
2371 .type = NLA_U32
2372 },
2373 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = {
2374 .type = NLA_U32
2375 },
2376 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = {
2377 .type = NLA_U32
2378 },
2379 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = {
2380 .type = NLA_U32
2381 },
2382 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = {
2383 .type = NLA_U32
2384 },
2385 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = {
2386 .type = NLA_U32
2387 },
2388 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = {
2389 .type = NLA_U32
2390 },
2391 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = {
2392 .type = NLA_U32
2393 },
2394 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = {
2395 .type = NLA_U32
2396 },
2397 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = {
2398 .type = NLA_U32
2399 },
2400 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = {
2401 .type = NLA_U32
2402 },
2403 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = {
2404 .type = NLA_U32
2405 },
2406 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = {
2407 .type = NLA_U32
2408 },
2409 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = {
2410 .type = NLA_U32
2411 },
2412 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = {
2413 .type = NLA_U32
2414 },
2415 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = {
2416 .type = NLA_U32
2417 },
2418 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = {
2419 .type = NLA_U32
2420 },
2421 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = {
2422 .type = NLA_U32
2423 },
2424 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = {
2425 .type = NLA_U32
2426 },
2427 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = {
2428 .type = NLA_U32
2429 },
2430 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = {
2431 .type = NLA_U32
2432 },
2433 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = {
2434 .type = NLA_U32
2435 },
2436 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = {
2437 .type = NLA_U32
2438 },
2439 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = {
2440 .type = NLA_U32
2441 },
2442 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = {
2443 .type = NLA_U32
2444 },
2445 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = {
2446 .type = NLA_U32
2447 },
2448 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = {
2449 .type = NLA_U32
2450 },
2451 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = {
2452 .type = NLA_U32
2453 },
2454 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = {
2455 .type = NLA_U32
2456 },
2457 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = {
2458 .type = NLA_U32
2459 },
2460 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = {
2461 .type = NLA_U32
2462 },
2463 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = {
2464 .type = NLA_U32
2465 },
2466};
2467
2468/**
2469 * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2470 * @wiphy: wiphy handle
2471 * @wdev: wdev handle
2472 * @data: user layer input
2473 * @data_len: length of user layer input
2474 *
2475 * this function is called in ssr protected environment.
2476 *
2477 * return: 0 success, none zero for failure
2478 */
2479static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2480 struct wireless_dev *wdev,
2481 const void *data,
2482 int data_len)
2483{
2484 int status;
2485 uint32_t period;
2486 struct net_device *dev = wdev->netdev;
2487 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2488 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
2489 struct sir_ll_ext_stats_threshold thresh = {0,};
2490 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1];
2491
2492 ENTER_DEV(dev);
2493
2494 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2495 hdd_warn("command not allowed in ftm mode");
2496 return -EPERM;
2497 }
2498
2499 status = wlan_hdd_validate_context(hdd_ctx);
2500 if (0 != status)
2501 return -EPERM;
2502
2503 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX,
2504 (struct nlattr *)data, data_len,
2505 qca_wlan_vendor_ll_ext_policy)) {
2506 hdd_err("maximum attribute not present");
2507 return -EPERM;
2508 }
2509
2510 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) {
2511 period = nla_get_u32(tb[
2512 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]);
2513
2514 if (period != 0 && period < LL_STATS_MIN_PERIOD)
2515 period = LL_STATS_MIN_PERIOD;
2516
2517 /*
2518 * Only enable/disbale counters.
2519 * Keep the last threshold settings.
2520 */
2521 goto set_period;
2522 }
2523
2524 /* global thresh is not enabled */
2525 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) {
2526 thresh.global = false;
2527 hdd_warn("global thresh is not set");
2528 } else {
2529 thresh.global_threshold = nla_get_u32(tb[
2530 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]);
2531 thresh.global = true;
2532 hdd_debug("globle thresh is %d", thresh.global_threshold);
2533 }
2534
2535 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) {
2536 thresh.global = false;
2537 hdd_warn("global thresh is not enabled");
2538 } else {
2539 thresh.global = nla_get_u32(tb[
2540 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]);
2541 hdd_debug("global is %d", thresh.global);
2542 }
2543
2544 thresh.enable_bitmap = false;
2545 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) {
2546 thresh.tx_bitmap = nla_get_u32(tb[
2547 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]);
2548 thresh.enable_bitmap = true;
2549 }
2550
2551 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) {
2552 thresh.rx_bitmap = nla_get_u32(tb[
2553 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]);
2554 thresh.enable_bitmap = true;
2555 }
2556
2557 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) {
2558 thresh.cca_bitmap = nla_get_u32(tb[
2559 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]);
2560 thresh.enable_bitmap = true;
2561 }
2562
2563 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) {
2564 thresh.signal_bitmap = nla_get_u32(tb[
2565 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]);
2566 thresh.enable_bitmap = true;
2567 }
2568
2569 if (!thresh.global && !thresh.enable_bitmap) {
2570 hdd_warn("threshold will be disabled.");
2571 thresh.enable = false;
2572
2573 /* Just disable threshold */
2574 goto set_thresh;
2575 } else {
2576 thresh.enable = true;
2577 }
2578
2579 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) {
2580 thresh.tx.msdu = nla_get_u32(tb[
2581 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]);
2582 }
2583
2584 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) {
2585 thresh.tx.mpdu = nla_get_u32(tb[
2586 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]);
2587 }
2588
2589 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) {
2590 thresh.tx.ppdu = nla_get_u32(tb[
2591 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]);
2592 }
2593
2594 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) {
2595 thresh.tx.bytes = nla_get_u32(tb[
2596 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]);
2597 }
2598
2599 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) {
2600 thresh.tx.msdu_drop = nla_get_u32(
2601 tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]);
2602 }
2603
2604 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) {
2605 thresh.tx.byte_drop = nla_get_u32(tb[
2606 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]);
2607 }
2608
2609 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) {
2610 thresh.tx.mpdu_retry = nla_get_u32(tb[
2611 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]);
2612 }
2613
2614 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) {
2615 thresh.tx.mpdu_fail = nla_get_u32(tb[
2616 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]);
2617 }
2618
2619 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) {
2620 thresh.tx.ppdu_fail = nla_get_u32(tb[
2621 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]);
2622 }
2623
2624 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) {
2625 thresh.tx.aggregation = nla_get_u32(tb[
2626 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]);
2627 }
2628
2629 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) {
2630 thresh.tx.succ_mcs = nla_get_u32(tb[
2631 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]);
2632 }
2633
2634 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) {
2635 thresh.tx.fail_mcs = nla_get_u32(tb[
2636 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]);
2637 }
2638
2639 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) {
2640 thresh.tx.delay = nla_get_u32(tb[
2641 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]);
2642 }
2643
2644 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) {
2645 thresh.rx.mpdu = nla_get_u32(tb[
2646 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]);
2647 }
2648
2649 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) {
2650 thresh.rx.bytes = nla_get_u32(tb[
2651 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]);
2652 }
2653
2654 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) {
2655 thresh.rx.ppdu = nla_get_u32(tb[
2656 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]);
2657 }
2658
2659 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) {
2660 thresh.rx.ppdu_bytes = nla_get_u32(tb[
2661 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]);
2662 }
2663
2664 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) {
2665 thresh.rx.mpdu_lost = nla_get_u32(tb[
2666 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]);
2667 }
2668
2669 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) {
2670 thresh.rx.mpdu_retry = nla_get_u32(tb[
2671 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]);
2672 }
2673
2674 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) {
2675 thresh.rx.mpdu_dup = nla_get_u32(tb[
2676 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]);
2677 }
2678
2679 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) {
2680 thresh.rx.mpdu_discard = nla_get_u32(tb[
2681 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]);
2682 }
2683
2684 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) {
2685 thresh.rx.aggregation = nla_get_u32(tb[
2686 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]);
2687 }
2688
2689 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) {
2690 thresh.rx.mcs = nla_get_u32(tb[
2691 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]);
2692 }
2693
2694 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) {
2695 thresh.rx.ps_inds = nla_get_u32(tb[
2696 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]);
2697 }
2698
2699 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) {
2700 thresh.rx.ps_durs = nla_get_u32(tb[
2701 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]);
2702 }
2703
2704 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) {
2705 thresh.rx.probe_reqs = nla_get_u32(tb[
2706 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]);
2707 }
2708
2709 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) {
2710 thresh.rx.other_mgmt = nla_get_u32(tb[
2711 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]);
2712 }
2713
2714 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) {
2715 thresh.cca.idle_time = nla_get_u32(tb[
2716 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]);
2717 }
2718
2719 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) {
2720 thresh.cca.tx_time = nla_get_u32(tb[
2721 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]);
2722 }
2723
2724 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) {
2725 thresh.cca.rx_in_bss_time = nla_get_u32(tb[
2726 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]);
2727 }
2728
2729 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) {
2730 thresh.cca.rx_out_bss_time = nla_get_u32(tb[
2731 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]);
2732 }
2733
2734 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) {
2735 thresh.cca.rx_busy_time = nla_get_u32(tb[
2736 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]);
2737 }
2738
2739 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) {
2740 thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[
2741 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]);
2742 }
2743
2744 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) {
2745 thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[
2746 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]);
2747 }
2748
2749 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) {
2750 thresh.cca.wlan_not_avail_time = nla_get_u32(tb[
2751 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]);
2752 }
2753
2754 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) {
2755 thresh.signal.snr = nla_get_u32(tb[
2756 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]);
2757 }
2758
2759 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) {
2760 thresh.signal.nf = nla_get_u32(tb[
2761 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]);
2762 }
2763
2764set_thresh:
2765 hdd_info("send thresh settings to target");
2766 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_thresh(hdd_ctx->hHal,
2767 &thresh)) {
2768 hdd_err("sme_ll_stats_set_thresh failed.");
2769 return -EINVAL;
2770 }
2771 return 0;
2772
2773set_period:
2774 hdd_info("send period to target");
2775 status = wma_cli_set_command(adapter->sessionId,
2776 WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD,
2777 period, PDEV_CMD);
2778 if (status) {
2779 hdd_err("wma_cli_set_command set_period failed.");
2780 return -EINVAL;
2781 }
2782 return 0;
2783}
2784
2785/**
2786 * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2787 * @wiphy: wiphy handle
2788 * @wdev: wdev handle
2789 * @data: user layer input
2790 * @data_len: length of user layer input
2791 *
2792 * return: 0 success, einval failure
2793 */
2794int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2795 struct wireless_dev *wdev,
2796 const void *data,
2797 int data_len)
2798{
2799 int ret;
2800
2801 cds_ssr_protect(__func__);
2802 ret = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev,
2803 data, data_len);
2804 cds_ssr_unprotect(__func__);
2805
2806 return ret;
2807}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002808#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
2809
2810#ifdef WLAN_FEATURE_STATS_EXT
2811/**
2812 * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2813 * @wiphy: Pointer to wiphy
2814 * @wdev: Pointer to wdev
2815 * @data: Pointer to data
2816 * @data_len: Data length
2817 *
2818 * Return: int
2819 */
2820static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2821 struct wireless_dev *wdev,
2822 const void *data,
2823 int data_len)
2824{
2825 tStatsExtRequestReq stats_ext_req;
2826 struct net_device *dev = wdev->netdev;
2827 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2828 int ret_val;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302829 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002830 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
2831
Jeff Johnson1f61b612016-02-12 16:28:33 -08002832 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002833
2834 ret_val = wlan_hdd_validate_context(hdd_ctx);
2835 if (ret_val)
2836 return ret_val;
2837
Anurag Chouhan6d760662016-02-20 16:05:43 +05302838 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002839 hdd_err("Command not allowed in FTM mode");
2840 return -EPERM;
2841 }
2842
2843 stats_ext_req.request_data_len = data_len;
2844 stats_ext_req.request_data = (void *)data;
2845
2846 status = sme_stats_ext_request(pAdapter->sessionId, &stats_ext_req);
2847
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302848 if (QDF_STATUS_SUCCESS != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002849 ret_val = -EINVAL;
2850
2851 return ret_val;
2852}
2853
2854/**
2855 * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2856 * @wiphy: Pointer to wiphy
2857 * @wdev: Pointer to wdev
2858 * @data: Pointer to data
2859 * @data_len: Data length
2860 *
2861 * Return: int
2862 */
2863int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2864 struct wireless_dev *wdev,
2865 const void *data,
2866 int data_len)
2867{
2868 int ret;
2869
2870 cds_ssr_protect(__func__);
2871 ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
2872 data, data_len);
2873 cds_ssr_unprotect(__func__);
2874
2875 return ret;
2876}
2877
2878/**
2879 * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback
2880 * @ctx: Pointer to HDD context
2881 * @msg: Message received
2882 *
2883 * Return: nothing
2884 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05302885void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002886 tStatsExtEvent *msg)
2887{
2888
2889 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
2890 struct sk_buff *vendor_event;
2891 int status;
2892 int ret_val;
2893 tStatsExtEvent *data = msg;
2894 hdd_adapter_t *pAdapter = NULL;
2895
2896 status = wlan_hdd_validate_context(pHddCtx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302897 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002898 return;
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302899
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002900 pAdapter = hdd_get_adapter_by_vdev(pHddCtx, data->vdev_id);
2901
2902 if (NULL == pAdapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002903 hdd_err("vdev_id %d does not exist with host", data->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002904 return;
2905 }
2906
2907 vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
2908 NULL,
2909 data->event_data_len +
2910 sizeof(uint32_t) +
2911 NLMSG_HDRLEN + NLMSG_HDRLEN,
2912 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2913 GFP_KERNEL);
2914
2915 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002916 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002917 return;
2918 }
2919
2920 ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
2921 pAdapter->dev->ifindex);
2922 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002923 hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002924 kfree_skb(vendor_event);
2925
2926 return;
2927 }
2928
2929 ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
2930 data->event_data_len, data->event_data);
2931
2932 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002933 hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002934 kfree_skb(vendor_event);
2935
2936 return;
2937 }
2938
2939 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2940
2941}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002942#endif /* End of WLAN_FEATURE_STATS_EXT */
2943
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05302944#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
2945static inline void wlan_hdd_fill_station_info_signal(struct station_info
2946 *sinfo)
2947{
2948 sinfo->filled |= STATION_INFO_SIGNAL;
2949}
2950#else
2951static inline void wlan_hdd_fill_station_info_signal(struct station_info
2952 *sinfo)
2953{
2954 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2955}
2956#endif
2957
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002958/**
2959 * __wlan_hdd_cfg80211_get_station() - get station statistics
2960 * @wiphy: Pointer to wiphy
2961 * @dev: Pointer to network device
2962 * @mac: Pointer to mac
2963 * @sinfo: Pointer to station info
2964 *
2965 * Return: 0 for success, non-zero for failure
2966 */
2967static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
2968 struct net_device *dev,
2969 const uint8_t *mac,
2970 struct station_info *sinfo)
2971{
2972 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2973 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
2974 int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length;
2975 uint8_t rate_flags;
Dustin Brown905cdc72016-11-16 16:51:10 -08002976 uint8_t mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002977
2978 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
2979 struct hdd_config *pCfg = pHddCtx->config;
2980
2981 uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
2982 uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX;
2983 uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
2984 uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
2985 uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET];
2986 uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET;
2987 uint16_t maxRate = 0;
Anurag Chouhan5de8d172016-07-13 14:44:28 +05302988 int8_t snr = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002989 uint16_t myRate;
2990 uint16_t currentRate = 0;
2991 uint8_t maxSpeedMCS = 0;
2992 uint8_t maxMCSIdx = 0;
2993 uint8_t rateFlag = 1;
2994 uint8_t i, j, rssidx;
2995 uint8_t nss = 1;
2996 int status, mode = 0, maxHtIdx;
2997 struct index_vht_data_rate_type *supported_vht_mcs_rate;
2998 struct index_data_rate_type *supported_mcs_rate;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302999#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
3000 bool rssi_stats_valid = false;
3001#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003002
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003003 uint32_t vht_mcs_map;
3004 enum eDataRate11ACMaxMcs vhtMaxMcs;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003005
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003006 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003007
Anurag Chouhan6d760662016-02-20 16:05:43 +05303008 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003009 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003010 return -EINVAL;
3011 }
3012
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05303013 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
3014 hdd_err("invalid session id: %d", pAdapter->sessionId);
3015 return -EINVAL;
3016 }
3017
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003018 if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) ||
3019 (0 == ssidlen)) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003020 hdd_debug("Not associated or Invalid ssidlen, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003021 ssidlen);
3022 /*To keep GUI happy */
3023 return 0;
3024 }
3025
3026 if (true == pHddStaCtx->hdd_ReassocScenario) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003027 hdd_debug("Roaming is in progress, cannot continue with this request");
Sachin Ahujafeedeba2016-09-13 21:54:16 +05303028 /*
3029 * supplicant reports very low rssi to upper layer
3030 * and handover happens to cellular.
3031 * send the cached rssi when get_station
3032 */
3033 sinfo->signal = pAdapter->rssi;
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05303034 wlan_hdd_fill_station_info_signal(sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003035 return 0;
3036 }
3037
3038 status = wlan_hdd_validate_context(pHddCtx);
3039
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303040 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003041 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003042
Naveen Rawat2cb788d2016-10-11 17:44:44 -07003043 wlan_hdd_get_station_stats(pAdapter);
3044 sinfo->signal = pAdapter->hdd_stats.summary_stat.rssi;
3045 snr = pAdapter->hdd_stats.summary_stat.snr;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003046 hdd_debug("snr: %d, rssi: %d",
Naveen Rawat2cb788d2016-10-11 17:44:44 -07003047 pAdapter->hdd_stats.summary_stat.snr,
3048 pAdapter->hdd_stats.summary_stat.rssi);
Anurag Chouhan5de8d172016-07-13 14:44:28 +05303049 pHddStaCtx->conn_info.signal = sinfo->signal;
3050 pHddStaCtx->conn_info.noise =
3051 pHddStaCtx->conn_info.signal - snr;
3052
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05303053 wlan_hdd_fill_station_info_signal(sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003054
Jeff Johnson71396692016-09-23 15:41:52 -07003055 /*
3056 * we notify connect to lpass here instead of during actual
3057 * connect processing because rssi info is not accurate during
3058 * actual connection. lpass will ensure the notification is
3059 * only processed once per association.
3060 */
3061 hdd_lpass_notify_connect(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003062
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003063 rate_flags = pAdapter->hdd_stats.ClassA_stat.tx_rate_flags;
Dustin Brown905cdc72016-11-16 16:51:10 -08003064 mcs_index = pAdapter->hdd_stats.ClassA_stat.mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003065
3066 /* convert to the UI units of 100kbps */
3067 myRate = pAdapter->hdd_stats.ClassA_stat.tx_rate * 5;
3068 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
Jeff Johnsonad0b2c62017-03-16 14:37:38 -07003069 nss = pAdapter->hdd_stats.ClassA_stat.nss;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003070
3071 if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) {
3072 /* Get current rate flags if report actual */
3073 rate_flags =
Jeff Johnsonad0b2c62017-03-16 14:37:38 -07003074 pAdapter->hdd_stats.ClassA_stat.mcs_rate_flags;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003075 }
3076
Dustin Brown905cdc72016-11-16 16:51:10 -08003077 if (mcs_index == INVALID_MCS_IDX)
3078 mcs_index = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003079 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08003080
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003081 hdd_debug("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d",
Ryan Hsu6139d2d2015-11-04 17:29:00 -08003082 sinfo->signal, pCfg->reportMaxLinkSpeed, myRate,
3083 (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid,
Dustin Brown905cdc72016-11-16 16:51:10 -08003084 (int)pCfg->linkSpeedRssiLow, (int)rate_flags, (int)mcs_index);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003085
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07003086#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
3087 /* assume basic BW. anything else will override this later */
3088 sinfo->txrate.bw = RATE_INFO_BW_20;
3089#endif
3090
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003091 if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) {
3092 /* we do not want to necessarily report the current speed */
3093 if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) {
3094 /* report the max possible speed */
3095 rssidx = 0;
3096 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
3097 pCfg->reportMaxLinkSpeed) {
3098 /* report the max possible speed with RSSI scaling */
3099 if (sinfo->signal >= pCfg->linkSpeedRssiHigh) {
3100 /* report the max possible speed */
3101 rssidx = 0;
3102 } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) {
3103 /* report middle speed */
3104 rssidx = 1;
3105 } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) {
3106 /* report middle speed */
3107 rssidx = 2;
3108 } else {
3109 /* report actual speed */
3110 rssidx = 3;
3111 }
3112 } else {
3113 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003114 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003115 pCfg->reportMaxLinkSpeed);
3116 rssidx = 0;
3117 }
3118
3119 maxRate = 0;
3120
3121 /* Get Basic Rate Set */
3122 if (0 !=
3123 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
3124 WNI_CFG_OPERATIONAL_RATE_SET,
3125 OperationalRates,
3126 &ORLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003127 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003128 /*To keep GUI happy */
3129 return 0;
3130 }
3131
3132 for (i = 0; i < ORLeng; i++) {
3133 for (j = 0;
3134 j < ARRAY_SIZE(supported_data_rate); j++) {
3135 /* Validate Rate Set */
3136 if (supported_data_rate[j].beacon_rate_index ==
3137 (OperationalRates[i] & 0x7F)) {
3138 currentRate =
3139 supported_data_rate[j].
3140 supported_rate[rssidx];
3141 break;
3142 }
3143 }
3144 /* Update MAX rate */
3145 maxRate =
3146 (currentRate > maxRate) ? currentRate : maxRate;
3147 }
3148
3149 /* Get Extended Rate Set */
3150 if (0 !=
3151 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
3152 WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
3153 ExtendedRates, &ERLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003154 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003155 /*To keep GUI happy */
3156 return 0;
3157 }
3158
3159 for (i = 0; i < ERLeng; i++) {
3160 for (j = 0;
3161 j < ARRAY_SIZE(supported_data_rate); j++) {
3162 if (supported_data_rate[j].beacon_rate_index ==
3163 (ExtendedRates[i] & 0x7F)) {
3164 currentRate =
3165 supported_data_rate[j].
3166 supported_rate[rssidx];
3167 break;
3168 }
3169 }
3170 /* Update MAX rate */
3171 maxRate =
3172 (currentRate > maxRate) ? currentRate : maxRate;
3173 }
Jeff Johnson8bb78c32017-01-12 08:42:50 -08003174 /*
3175 * Get MCS Rate Set --
3176 * Only if we are connected in non legacy mode and not
3177 * reporting actual speed
3178 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003179 if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) {
3180 if (0 !=
3181 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
3182 WNI_CFG_CURRENT_MCS_SET, MCSRates,
3183 &MCSLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003184 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003185 /*To keep GUI happy */
3186 return 0;
3187 }
3188 rateFlag = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003189 supported_vht_mcs_rate =
3190 (struct index_vht_data_rate_type *)
3191 ((nss ==
3192 1) ? &supported_vht_mcs_rate_nss1 :
3193 &supported_vht_mcs_rate_nss2);
3194
3195 if (rate_flags & eHAL_TX_RATE_VHT80)
3196 mode = 2;
3197 else if ((rate_flags & eHAL_TX_RATE_VHT40) ||
3198 (rate_flags & eHAL_TX_RATE_HT40))
3199 mode = 1;
3200 else
3201 mode = 0;
3202
3203 /* VHT80 rate has seperate rate table */
3204 if (rate_flags &
3205 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
3206 eHAL_TX_RATE_VHT80)) {
3207 sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter),
3208 WNI_CFG_VHT_TX_MCS_MAP,
3209 &vht_mcs_map);
3210 vhtMaxMcs = (enum eDataRate11ACMaxMcs)
3211 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
3212 if (rate_flags & eHAL_TX_RATE_SGI)
3213 rateFlag |= 1;
3214 if (DATA_RATE_11AC_MAX_MCS_7 == vhtMaxMcs)
3215 maxMCSIdx = 7;
3216 else if (DATA_RATE_11AC_MAX_MCS_8 ==
3217 vhtMaxMcs)
3218 maxMCSIdx = 8;
3219 else if (DATA_RATE_11AC_MAX_MCS_9 ==
3220 vhtMaxMcs) {
Hu Wang1f2b8a82016-08-25 15:15:54 +08003221 /*
3222 * IEEE_P802.11ac_2013.pdf page 325, 326
3223 * - MCS9 is valid for VHT20 when
3224 * Nss = 3 or Nss = 6
3225 * - MCS9 is not valid for VHT20 when
3226 * Nss = 1,2,4,5,7,8
3227 */
3228 if ((rate_flags & eHAL_TX_RATE_VHT20) &&
3229 (nss != 3 && nss != 6))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003230 maxMCSIdx = 8;
3231 else
3232 maxMCSIdx = 9;
3233 }
3234
3235 if (rssidx != 0) {
3236 for (i = 0; i <= maxMCSIdx; i++) {
3237 if (sinfo->signal <=
3238 rssi_mcs_tbl[mode][i]) {
3239 maxMCSIdx = i;
3240 break;
3241 }
3242 }
3243 }
3244
3245 if (rate_flags & eHAL_TX_RATE_VHT80) {
3246 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08003247 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003248 supported_VHT80_rate[rateFlag];
3249 maxRate =
3250 supported_vht_mcs_rate[maxMCSIdx].
3251 supported_VHT80_rate[rateFlag];
3252 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
3253 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08003254 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003255 supported_VHT40_rate[rateFlag];
3256 maxRate =
3257 supported_vht_mcs_rate[maxMCSIdx].
3258 supported_VHT40_rate[rateFlag];
3259 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
3260 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08003261 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003262 supported_VHT20_rate[rateFlag];
3263 maxRate =
3264 supported_vht_mcs_rate[maxMCSIdx].
3265 supported_VHT20_rate[rateFlag];
3266 }
3267
3268 maxSpeedMCS = 1;
3269 if (currentRate > maxRate)
3270 maxRate = currentRate;
3271
Kiran Kumar Lokere9a733a72016-02-17 19:01:15 -08003272 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003273 if (rate_flags & eHAL_TX_RATE_HT40)
3274 rateFlag |= 1;
3275 if (rate_flags & eHAL_TX_RATE_SGI)
3276 rateFlag |= 2;
3277
3278 supported_mcs_rate =
3279 (struct index_data_rate_type *)
3280 ((nss ==
3281 1) ? &supported_mcs_rate_nss1 :
3282 &supported_mcs_rate_nss2);
3283
3284 maxHtIdx = MAX_HT_MCS_IDX;
3285 if (rssidx != 0) {
3286 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
3287 if (sinfo->signal <=
3288 rssi_mcs_tbl[mode][i]) {
3289 maxHtIdx = i + 1;
3290 break;
3291 }
3292 }
3293 }
3294
3295 for (i = 0; i < MCSLeng; i++) {
3296 for (j = 0; j < maxHtIdx; j++) {
3297 if (supported_mcs_rate[j].
3298 beacon_rate_index ==
3299 MCSRates[i]) {
3300 currentRate =
3301 supported_mcs_rate[j].
3302 supported_rate
3303 [rateFlag];
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05303304 maxMCSIdx =
3305 supported_mcs_rate[j].
3306 beacon_rate_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003307 break;
3308 }
3309 }
3310
3311 if ((j < MAX_HT_MCS_IDX)
3312 && (currentRate > maxRate)) {
3313 maxRate = currentRate;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003314 }
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05303315 maxSpeedMCS = 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003316 }
3317 }
3318 }
3319
3320 else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3321 maxRate = myRate;
3322 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08003323 maxMCSIdx = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003324 }
3325 /* report a value at least as big as current rate */
3326 if ((maxRate < myRate) || (0 == maxRate)) {
3327 maxRate = myRate;
3328 if (rate_flags & eHAL_TX_RATE_LEGACY) {
3329 maxSpeedMCS = 0;
3330 } else {
3331 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08003332 maxMCSIdx = mcs_index;
Hu Wang1f2b8a82016-08-25 15:15:54 +08003333 /*
3334 * IEEE_P802.11ac_2013.pdf page 325, 326
3335 * - MCS9 is valid for VHT20 when
3336 * Nss = 3 or Nss = 6
3337 * - MCS9 is not valid for VHT20 when
3338 * Nss = 1,2,4,5,7,8
3339 */
3340 if ((rate_flags & eHAL_TX_RATE_VHT20) &&
3341 (maxMCSIdx > 8) &&
3342 (nss != 3 && nss != 6)) {
3343 maxMCSIdx = 8;
3344 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003345 }
3346 }
3347
3348 if (rate_flags & eHAL_TX_RATE_LEGACY) {
3349 sinfo->txrate.legacy = maxRate;
3350#ifdef LINKSPEED_DEBUG_ENABLED
3351 pr_info("Reporting legacy rate %d\n",
3352 sinfo->txrate.legacy);
3353#endif /* LINKSPEED_DEBUG_ENABLED */
3354 } else {
3355 sinfo->txrate.mcs = maxMCSIdx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003356 sinfo->txrate.nss = nss;
3357 if (rate_flags & eHAL_TX_RATE_VHT80) {
3358 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003359#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
3360 sinfo->txrate.bw = RATE_INFO_BW_80;
3361#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003362 sinfo->txrate.flags |=
3363 RATE_INFO_FLAGS_80_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003364#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003365 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
3366 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003367#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
3368 sinfo->txrate.bw = RATE_INFO_BW_40;
3369#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003370 sinfo->txrate.flags |=
3371 RATE_INFO_FLAGS_40_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003372#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003373 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
3374 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3375 } else
3376 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003377 if (rate_flags &
3378 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
3379 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3380 if (rate_flags & eHAL_TX_RATE_HT40) {
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003381#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
3382 sinfo->txrate.bw = RATE_INFO_BW_40;
3383#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003384 sinfo->txrate.flags |=
3385 RATE_INFO_FLAGS_40_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003386#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003387 }
3388 }
3389 if (rate_flags & eHAL_TX_RATE_SGI) {
3390 if (!
3391 (sinfo->txrate.
3392 flags & RATE_INFO_FLAGS_VHT_MCS))
3393 sinfo->txrate.flags |=
3394 RATE_INFO_FLAGS_MCS;
3395 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3396 }
3397#ifdef LINKSPEED_DEBUG_ENABLED
3398 pr_info("Reporting MCS rate %d flags %x\n",
3399 sinfo->txrate.mcs, sinfo->txrate.flags);
3400#endif /* LINKSPEED_DEBUG_ENABLED */
3401 }
3402 } else {
3403 /* report current rate instead of max rate */
3404
3405 if (rate_flags & eHAL_TX_RATE_LEGACY) {
3406 /* provide to the UI in units of 100kbps */
3407 sinfo->txrate.legacy = myRate;
3408#ifdef LINKSPEED_DEBUG_ENABLED
3409 pr_info("Reporting actual legacy rate %d\n",
3410 sinfo->txrate.legacy);
3411#endif /* LINKSPEED_DEBUG_ENABLED */
3412 } else {
3413 /* must be MCS */
Dustin Brown905cdc72016-11-16 16:51:10 -08003414 sinfo->txrate.mcs = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003415 sinfo->txrate.nss = nss;
3416 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3417 if (rate_flags & eHAL_TX_RATE_VHT80) {
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003418#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
3419 sinfo->txrate.bw = RATE_INFO_BW_80;
3420#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003421 sinfo->txrate.flags |=
3422 RATE_INFO_FLAGS_80_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003423#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003424 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003425#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
3426 sinfo->txrate.bw = RATE_INFO_BW_40;
3427#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003428 sinfo->txrate.flags |=
3429 RATE_INFO_FLAGS_40_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003430#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003431 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003432 if (rate_flags &
3433 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
3434 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3435 if (rate_flags & eHAL_TX_RATE_HT40) {
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003436#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
3437 sinfo->txrate.bw = RATE_INFO_BW_40;
3438#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003439 sinfo->txrate.flags |=
3440 RATE_INFO_FLAGS_40_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08003441#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003442 }
3443 }
3444 if (rate_flags & eHAL_TX_RATE_SGI) {
3445 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3446 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3447 }
3448#ifdef LINKSPEED_DEBUG_ENABLED
3449 pr_info("Reporting actual MCS rate %d flags %x\n",
3450 sinfo->txrate.mcs, sinfo->txrate.flags);
3451#endif /* LINKSPEED_DEBUG_ENABLED */
3452 }
3453 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08003454
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003455 sinfo->tx_bytes = pAdapter->stats.tx_bytes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003456
3457 sinfo->tx_packets =
3458 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[0] +
3459 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[1] +
3460 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[2] +
3461 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[3];
3462
3463 sinfo->tx_retries =
gbian4c2f9d92016-09-29 17:27:04 +08003464 pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[0] +
3465 pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[1] +
3466 pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[2] +
3467 pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[3];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003468
3469 sinfo->tx_failed =
3470 pAdapter->hdd_stats.summary_stat.fail_cnt[0] +
3471 pAdapter->hdd_stats.summary_stat.fail_cnt[1] +
3472 pAdapter->hdd_stats.summary_stat.fail_cnt[2] +
3473 pAdapter->hdd_stats.summary_stat.fail_cnt[3];
3474
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003475 sinfo->rx_bytes = pAdapter->stats.rx_bytes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003476 sinfo->rx_packets = pAdapter->stats.rx_packets;
Ryan Hsue7bc3a72016-01-18 12:08:22 -08003477
Anurag Chouhan5de8d172016-07-13 14:44:28 +05303478 qdf_mem_copy(&pHddStaCtx->conn_info.txrate,
3479 &sinfo->txrate, sizeof(sinfo->txrate));
3480
Ryan Hsue7bc3a72016-01-18 12:08:22 -08003481#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
3482 sinfo->filled |= STATION_INFO_TX_BITRATE |
3483 STATION_INFO_TX_BYTES |
3484 STATION_INFO_TX_PACKETS |
3485 STATION_INFO_TX_RETRIES |
3486 STATION_INFO_TX_FAILED |
3487 STATION_INFO_RX_BYTES |
3488 STATION_INFO_RX_PACKETS;
3489#else
3490 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) |
3491 BIT(NL80211_STA_INFO_TX_BITRATE) |
3492 BIT(NL80211_STA_INFO_TX_PACKETS) |
3493 BIT(NL80211_STA_INFO_TX_RETRIES) |
3494 BIT(NL80211_STA_INFO_TX_FAILED) |
3495 BIT(NL80211_STA_INFO_RX_BYTES) |
3496 BIT(NL80211_STA_INFO_RX_PACKETS);
3497#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003498
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05303499 if (rate_flags & eHAL_TX_RATE_LEGACY)
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003500 hdd_debug("Reporting legacy rate %d pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05303501 sinfo->txrate.legacy, sinfo->tx_packets,
3502 sinfo->rx_packets);
3503 else
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003504 hdd_debug("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05303505 sinfo->txrate.mcs, sinfo->txrate.flags,
3506 sinfo->tx_packets, sinfo->rx_packets);
3507
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303508#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
3509 sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
3510 for (i = 0; i < NUM_CHAINS_MAX; i++) {
3511 sinfo->chain_signal_avg[i] =
3512 pAdapter->hdd_stats.per_chain_rssi_stats.rssi[i];
3513 sinfo->chains |= 1 << i;
3514 if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
3515 sinfo->chain_signal_avg[i] != 0)
3516 sinfo->signal_avg = sinfo->chain_signal_avg[i];
3517
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003518 hdd_debug("RSSI for chain %d, vdev_id %d is %d",
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303519 i, pAdapter->sessionId, sinfo->chain_signal_avg[i]);
3520
3521 if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
3522 rssi_stats_valid = true;
3523 }
3524
3525 if (rssi_stats_valid) {
3526#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
3527 sinfo->filled |= STATION_INFO_CHAIN_SIGNAL_AVG;
3528 sinfo->filled |= STATION_INFO_SIGNAL_AVG;
3529#else
3530 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
3531 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
3532#endif
3533 }
3534#endif
3535
3536
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05303537 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003538 TRACE_CODE_HDD_CFG80211_GET_STA,
3539 pAdapter->sessionId, maxRate));
3540 EXIT();
3541 return 0;
3542}
3543
3544/**
3545 * wlan_hdd_cfg80211_get_station() - get station statistics
3546 * @wiphy: Pointer to wiphy
3547 * @dev: Pointer to network device
3548 * @mac: Pointer to mac
3549 * @sinfo: Pointer to station info
3550 *
3551 * Return: 0 for success, non-zero for failure
3552 */
3553#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
3554int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
3555 struct net_device *dev, const uint8_t *mac,
3556 struct station_info *sinfo)
3557#else
3558int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
3559 struct net_device *dev, uint8_t *mac,
3560 struct station_info *sinfo)
3561#endif
3562{
3563 int ret;
3564
3565 cds_ssr_protect(__func__);
3566 ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
3567 cds_ssr_unprotect(__func__);
3568
3569 return ret;
3570}
3571
3572/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303573 * __wlan_hdd_cfg80211_dump_station() - dump station statistics
3574 * @wiphy: Pointer to wiphy
3575 * @dev: Pointer to network device
3576 * @idx: variable to determine whether to get stats or not
3577 * @mac: Pointer to mac
3578 * @sinfo: Pointer to station info
3579 *
3580 * Return: 0 for success, non-zero for failure
3581 */
3582static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
3583 struct net_device *dev,
3584 int idx, u8 *mac,
3585 struct station_info *sinfo)
3586{
3587 hdd_context_t *hdd_ctx = (hdd_context_t *) wiphy_priv(wiphy);
3588
3589 hdd_debug("%s: idx %d", __func__, idx);
3590 if (idx != 0)
3591 return -ENOENT;
3592 qdf_mem_copy(mac, hdd_ctx->config->intfMacAddr[0].bytes,
3593 QDF_MAC_ADDR_SIZE);
3594 return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
3595}
3596
3597/**
3598 * wlan_hdd_cfg80211_dump_station() - dump station statistics
3599 * @wiphy: Pointer to wiphy
3600 * @dev: Pointer to network device
3601 * @idx: variable to determine whether to get stats or not
3602 * @mac: Pointer to mac
3603 * @sinfo: Pointer to station info
3604 *
3605 * Return: 0 for success, non-zero for failure
3606 */
3607int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
3608 struct net_device *dev,
3609 int idx, u8 *mac,
3610 struct station_info *sinfo)
3611{
3612 int ret;
3613
3614 cds_ssr_protect(__func__);
3615 ret = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
3616 cds_ssr_unprotect(__func__);
3617 return ret;
3618}
3619
3620/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003621 * hdd_get_stats() - Function to retrieve interface statistics
3622 * @dev: pointer to network device
3623 *
3624 * This function is the ndo_get_stats method for all netdevs
3625 * registered with the kernel
3626 *
3627 * Return: pointer to net_device_stats structure
3628 */
3629struct net_device_stats *hdd_get_stats(struct net_device *dev)
3630{
3631 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3632
Jeff Johnson3c3994a2016-02-11 08:12:30 -08003633 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003634 return &adapter->stats;
3635}
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05303636
3637
3638/*
3639 * time = cycle_count * cycle
3640 * cycle = 1 / clock_freq
3641 * Since the unit of clock_freq reported from
3642 * FW is MHZ, and we want to calculate time in
3643 * ms level, the result is
3644 * time = cycle / (clock_freq * 1000)
3645 */
3646#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
3647static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
3648 struct scan_chan_info *chan_info,
3649 struct ieee80211_channel *channels)
3650{
3651 uint64_t clock_freq = chan_info->clock_freq * 1000;
3652
3653 if (channels->center_freq != (uint16_t)chan_info->freq)
3654 return false;
3655
3656 survey->channel = channels;
3657 survey->noise = chan_info->noise_floor;
3658 survey->filled = SURVEY_INFO_NOISE_DBM;
3659
3660 if (opfreq == chan_info->freq)
3661 survey->filled |= SURVEY_INFO_IN_USE;
3662
3663 if (clock_freq == 0)
3664 return true;
3665
3666 survey->time = chan_info->cycle_count / clock_freq;
3667 survey->time_busy = chan_info->rx_clear_count / clock_freq;
3668 survey->time_tx = chan_info->tx_frame_count / clock_freq;
3669
3670 survey->filled |= SURVEY_INFO_TIME |
3671 SURVEY_INFO_TIME_BUSY |
3672 SURVEY_INFO_TIME_TX;
3673 return true;
3674}
3675#else
3676static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
3677 struct scan_chan_info *chan_info,
3678 struct ieee80211_channel *channels)
3679{
3680 uint64_t clock_freq = chan_info->clock_freq * 1000;
3681
3682 if (channels->center_freq != (uint16_t)chan_info->freq)
3683 return false;
3684
3685 survey->channel = channels;
3686 survey->noise = chan_info->noise_floor;
3687 survey->filled = SURVEY_INFO_NOISE_DBM;
3688
3689 if (opfreq == chan_info->freq)
3690 survey->filled |= SURVEY_INFO_IN_USE;
3691
3692 if (clock_freq == 0)
3693 return true;
3694
3695 survey->channel_time = chan_info->cycle_count / clock_freq;
3696 survey->channel_time_busy = chan_info->rx_clear_count / clock_freq;
3697 survey->channel_time_tx = chan_info->tx_frame_count / clock_freq;
3698
3699 survey->filled |= SURVEY_INFO_CHANNEL_TIME |
3700 SURVEY_INFO_CHANNEL_TIME_BUSY |
3701 SURVEY_INFO_CHANNEL_TIME_TX;
3702 return true;
3703}
3704#endif
3705
3706static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
3707 hdd_adapter_t *pAdapter, struct survey_info *survey, int idx)
3708{
3709 bool filled = false;
3710 int i, j = 0;
3711 uint32_t channel = 0, opfreq; /* Initialization Required */
3712 hdd_context_t *pHddCtx;
3713
3714 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
3715 sme_get_operation_channel(pHddCtx->hHal, &channel, pAdapter->sessionId);
3716 hdd_wlan_get_freq(channel, &opfreq);
3717
3718 mutex_lock(&pHddCtx->chan_info_lock);
3719
Kapil Guptaacb3dbd2017-04-04 11:06:51 +05303720 for (i = 0; i < NUM_NL80211_BANDS && !filled; i++) {
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05303721 if (wiphy->bands[i] == NULL)
3722 continue;
3723
3724 for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
3725 struct ieee80211_supported_band *band = wiphy->bands[i];
3726 filled = wlan_fill_survey_result(survey, opfreq,
3727 &pHddCtx->chan_info[idx],
3728 &band->channels[j]);
3729 }
3730 }
3731 mutex_unlock(&pHddCtx->chan_info_lock);
3732
3733 return filled;
3734}
3735
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003736/**
3737 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
3738 * @wiphy: Pointer to wiphy
3739 * @dev: Pointer to network device
3740 * @idx: Index
3741 * @survey: Pointer to survey info
3742 *
3743 * Return: 0 for success, non-zero for failure
3744 */
3745static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
3746 struct net_device *dev,
3747 int idx, struct survey_info *survey)
3748{
3749 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
3750 hdd_context_t *pHddCtx;
3751 hdd_station_ctx_t *pHddStaCtx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05303752 int status;
3753 bool filled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003754
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003755 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003756
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05303757 hdd_info("dump survey index:%d", idx);
3758 if (idx > QDF_MAX_NUM_CHAN - 1)
3759 return -EINVAL;
3760
3761 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
3762 status = wlan_hdd_validate_context(pHddCtx);
3763 if (0 != status)
3764 return status;
3765
3766 if (pHddCtx->chan_info == NULL) {
3767 hdd_err("chan_info is NULL");
3768 return -EINVAL;
3769 }
3770
3771 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003772 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003773 return -EINVAL;
3774 }
3775
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003776 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
3777
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05303778 if (pHddCtx->config->fEnableSNRMonitoring == 0)
3779 return -ENONET;
3780
3781
3782 if (pHddStaCtx->hdd_ReassocScenario) {
3783 hdd_info("Roaming in progress, hence return");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003784 return -ENONET;
3785 }
3786
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05303787 filled = wlan_hdd_update_survey_info(wiphy, pAdapter, survey, idx);
3788
3789 if (!filled)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003790 return -ENONET;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303791 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003792 return 0;
3793}
3794
3795/**
3796 * wlan_hdd_cfg80211_dump_survey() - get survey related info
3797 * @wiphy: Pointer to wiphy
3798 * @dev: Pointer to network device
3799 * @idx: Index
3800 * @survey: Pointer to survey info
3801 *
3802 * Return: 0 for success, non-zero for failure
3803 */
3804int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
3805 struct net_device *dev,
3806 int idx, struct survey_info *survey)
3807{
3808 int ret;
3809
3810 cds_ssr_protect(__func__);
3811 ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
3812 cds_ssr_unprotect(__func__);
3813
3814 return ret;
3815}
3816/**
3817 * hdd_init_ll_stats_ctx() - initialize link layer stats context
3818 *
3819 * Return: none
3820 */
3821inline void hdd_init_ll_stats_ctx(void)
3822{
3823 spin_lock_init(&ll_stats_context.context_lock);
3824 init_completion(&ll_stats_context.response_event);
3825 ll_stats_context.request_bitmap = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003826}
Nirav Shahbf1b0332016-05-25 14:27:39 +05303827
3828/**
3829 * hdd_display_hif_stats() - display hif stats
3830 *
3831 * Return: none
3832 *
3833 */
3834void hdd_display_hif_stats(void)
3835{
3836 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
3837
3838 if (!hif_ctx)
3839 return;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -07003840
Nirav Shahbf1b0332016-05-25 14:27:39 +05303841 hif_display_stats(hif_ctx);
3842}
3843
3844/**
3845 * hdd_clear_hif_stats() - clear hif stats
3846 *
3847 * Return: none
3848 */
3849void hdd_clear_hif_stats(void)
3850{
3851 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
3852
3853 if (!hif_ctx)
3854 return;
3855 hif_clear_stats(hif_ctx);
3856}