blob: 70db6bd7b4539e1358709b7d4c8b70176710c2d7 [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>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080036
37#ifdef WLAN_FEATURE_LINK_LAYER_STATS
38
39/**
40 * struct hdd_ll_stats_context - hdd link layer stats context
41 *
42 * @request_id: userspace-assigned link layer stats request id
43 * @request_bitmap: userspace-assigned link layer stats request bitmap
44 * @response_event: LL stats request wait event
45 */
46struct hdd_ll_stats_context {
47 uint32_t request_id;
48 uint32_t request_bitmap;
49 struct completion response_event;
50 spinlock_t context_lock;
51};
52
53static struct hdd_ll_stats_context ll_stats_context;
54
55#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */
56
57/* 11B, 11G Rate table include Basic rate and Extended rate
58 * The IDX field is the rate index
59 * The HI field is the rate when RSSI is strong or being ignored
60 * (in this case we report actual rate)
61 * The MID field is the rate when RSSI is moderate
62 * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
63 * The LO field is the rate when RSSI is low
64 * (in this case we don't report rates, actual current rate used)
65 */
66static const struct {
67 uint8_t beacon_rate_index;
68 uint16_t supported_rate[4];
69} supported_data_rate[] = {
70/* IDX HI HM LM LO (RSSI-based index */
71 {
72 2, {
73 10, 10, 10, 0
74 }
75 }, {
76 4, {
77 20, 20, 10, 0
78 }
79 }, {
80 11, {
81 55, 20, 10, 0
82 }
83 }, {
84 12, {
85 60, 55, 20, 0
86 }
87 }, {
88 18, {
89 90, 55, 20, 0
90 }
91 }, {
92 22, {
93 110, 55, 20, 0
94 }
95 }, {
96 24, {
97 120, 90, 60, 0
98 }
99 }, {
100 36, {
101 180, 120, 60, 0
102 }
103 }, {
104 44, {
105 220, 180, 60, 0
106 }
107 }, {
108 48, {
109 240, 180, 90, 0
110 }
111 }, {
112 66, {
113 330, 180, 90, 0
114 }
115 }, {
116 72, {
117 360, 240, 90, 0
118 }
119 }, {
120 96, {
121 480, 240, 120, 0
122 }
123 }, {
124 108, {
125 540, 240, 120, 0
126 }
127 }
128};
129/* MCS Based rate table HT MCS parameters with Nss = 1 */
130static struct index_data_rate_type supported_mcs_rate_nss1[] = {
131/* MCS L20 L40 S20 S40 */
132 {0, {65, 135, 72, 150} },
133 {1, {130, 270, 144, 300} },
134 {2, {195, 405, 217, 450} },
135 {3, {260, 540, 289, 600} },
136 {4, {390, 810, 433, 900} },
137 {5, {520, 1080, 578, 1200} },
138 {6, {585, 1215, 650, 1350} },
139 {7, {650, 1350, 722, 1500} }
140};
141
142/* HT MCS parameters with Nss = 2 */
143static struct index_data_rate_type supported_mcs_rate_nss2[] = {
144/* MCS L20 L40 S20 S40 */
145 {0, {130, 270, 144, 300} },
146 {1, {260, 540, 289, 600} },
147 {2, {390, 810, 433, 900} },
148 {3, {520, 1080, 578, 1200} },
149 {4, {780, 1620, 867, 1800} },
150 {5, {1040, 2160, 1156, 2400} },
151 {6, {1170, 2430, 1300, 2700} },
152 {7, {1300, 2700, 1444, 3000} }
153};
154
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800155/* MCS Based VHT rate table MCS parameters with Nss = 1*/
156static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
157/* MCS L80 S80 L40 S40 L20 S40*/
158 {0, {293, 325}, {135, 150}, {65, 72} },
159 {1, {585, 650}, {270, 300}, {130, 144} },
160 {2, {878, 975}, {405, 450}, {195, 217} },
161 {3, {1170, 1300}, {540, 600}, {260, 289} },
162 {4, {1755, 1950}, {810, 900}, {390, 433} },
163 {5, {2340, 2600}, {1080, 1200}, {520, 578} },
164 {6, {2633, 2925}, {1215, 1350}, {585, 650} },
165 {7, {2925, 3250}, {1350, 1500}, {650, 722} },
166 {8, {3510, 3900}, {1620, 1800}, {780, 867} },
167 {9, {3900, 4333}, {1800, 2000}, {780, 867} }
168};
169
170/*MCS parameters with Nss = 2*/
171static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
172/* MCS L80 S80 L40 S40 L20 S40*/
173 {0, {585, 650}, {270, 300}, {130, 144} },
174 {1, {1170, 1300}, {540, 600}, {260, 289} },
175 {2, {1755, 1950}, {810, 900}, {390, 433} },
176 {3, {2340, 2600}, {1080, 1200}, {520, 578} },
177 {4, {3510, 3900}, {1620, 1800}, {780, 867} },
178 {5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
179 {6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
180 {7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
181 {8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
182 {9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
183};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184
185/*array index ponints to MCS and array value points respective rssi*/
186static int rssi_mcs_tbl[][10] = {
187/*MCS 0 1 2 3 4 5 6 7 8 9*/
188 {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */
189 {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */
190 {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */
191};
192
193
194#ifdef WLAN_FEATURE_LINK_LAYER_STATS
195
196/**
197 * put_wifi_rate_stat() - put wifi rate stats
198 * @stats: Pointer to stats context
199 * @vendor_event: Pointer to vendor event
200 *
201 * Return: bool
202 */
203static bool put_wifi_rate_stat(tpSirWifiRateStat stats,
204 struct sk_buff *vendor_event)
205{
206 if (nla_put_u8(vendor_event,
207 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
208 stats->rate.preamble) ||
209 nla_put_u8(vendor_event,
210 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
211 stats->rate.nss) ||
212 nla_put_u8(vendor_event,
213 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
214 stats->rate.bw) ||
215 nla_put_u8(vendor_event,
216 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
217 stats->rate.rateMcsIdx) ||
218 nla_put_u32(vendor_event,
219 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
220 stats->rate.bitrate) ||
221 nla_put_u32(vendor_event,
222 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
223 stats->txMpdu) ||
224 nla_put_u32(vendor_event,
225 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
226 stats->rxMpdu) ||
227 nla_put_u32(vendor_event,
228 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
229 stats->mpduLost) ||
230 nla_put_u32(vendor_event,
231 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
232 stats->retries) ||
233 nla_put_u32(vendor_event,
234 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
235 stats->retriesShort) ||
236 nla_put_u32(vendor_event,
237 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
238 stats->retriesLong)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700239 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800240 return false;
241 }
242
243 return true;
244}
245
Dustin Brown877a5a92016-11-17 13:56:52 -0800246static tSirWifiPeerType wmi_to_sir_peer_type(enum wmi_peer_type type)
247{
248 switch (type) {
249 case WMI_PEER_TYPE_DEFAULT:
250 return WIFI_PEER_STA;
251 case WMI_PEER_TYPE_BSS:
252 return WIFI_PEER_AP;
253 case WMI_PEER_TYPE_TDLS:
254 return WIFI_PEER_TDLS;
255 case WMI_PEER_TYPE_NAN_DATA:
Dustin Brown59184702016-11-21 14:23:40 -0800256 return WIFI_PEER_NAN;
Dustin Brown877a5a92016-11-17 13:56:52 -0800257 default:
258 hdd_err("Cannot map wmi_peer_type %d to HAL peer type", type);
259 return WIFI_PEER_INVALID;
260 }
261}
262
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800263/**
264 * put_wifi_peer_info() - put wifi peer info
265 * @stats: Pointer to stats context
266 * @vendor_event: Pointer to vendor event
267 *
268 * Return: bool
269 */
270static bool put_wifi_peer_info(tpSirWifiPeerInfo stats,
271 struct sk_buff *vendor_event)
272{
273 u32 i = 0;
274 tpSirWifiRateStat pRateStats;
275
276 if (nla_put_u32
277 (vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
Dustin Brown877a5a92016-11-17 13:56:52 -0800278 wmi_to_sir_peer_type(stats->type)) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800279 nla_put(vendor_event,
280 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530281 QDF_MAC_ADDR_SIZE, &stats->peerMacAddress.bytes[0]) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800282 nla_put_u32(vendor_event,
283 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
284 stats->capabilities) ||
285 nla_put_u32(vendor_event,
286 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
287 stats->numRate)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700288 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800289 goto error;
290 }
291
292 if (stats->numRate) {
293 struct nlattr *rateInfo;
294 struct nlattr *rates;
295
296 rateInfo = nla_nest_start(vendor_event,
297 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO);
298 if (rateInfo == NULL)
299 goto error;
300
301 for (i = 0; i < stats->numRate; i++) {
302 pRateStats = (tpSirWifiRateStat) ((uint8_t *)
303 stats->rateStats +
304 (i *
305 sizeof
306 (tSirWifiRateStat)));
307 rates = nla_nest_start(vendor_event, i);
308 if (rates == NULL)
309 goto error;
310
311 if (false ==
312 put_wifi_rate_stat(pRateStats, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700313 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800314 return false;
315 }
316 nla_nest_end(vendor_event, rates);
317 }
318 nla_nest_end(vendor_event, rateInfo);
319 }
320
321 return true;
322error:
323 return false;
324}
325
326/**
327 * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
328 * @stats: Pointer to stats context
329 * @vendor_event: Pointer to vendor event
330 *
331 * Return: bool
332 */
333static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats,
334 struct sk_buff *vendor_event)
335{
336 if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
337 stats->ac) ||
338 nla_put_u32(vendor_event,
339 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
340 stats->txMpdu) ||
341 nla_put_u32(vendor_event,
342 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
343 stats->rxMpdu) ||
344 nla_put_u32(vendor_event,
345 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
346 stats->txMcast) ||
347 nla_put_u32(vendor_event,
348 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
349 stats->rxMcast) ||
350 nla_put_u32(vendor_event,
351 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
352 stats->rxAmpdu) ||
353 nla_put_u32(vendor_event,
354 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
355 stats->txAmpdu) ||
356 nla_put_u32(vendor_event,
357 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
358 stats->mpduLost) ||
359 nla_put_u32(vendor_event,
360 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
361 stats->retries) ||
362 nla_put_u32(vendor_event,
363 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
364 stats->retriesShort) ||
365 nla_put_u32(vendor_event,
366 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
367 stats->retriesLong) ||
368 nla_put_u32(vendor_event,
369 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
370 stats->contentionTimeMin) ||
371 nla_put_u32(vendor_event,
372 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
373 stats->contentionTimeMax) ||
374 nla_put_u32(vendor_event,
375 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
376 stats->contentionTimeAvg) ||
377 nla_put_u32(vendor_event,
378 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
379 stats->contentionNumSamples)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700380 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800381 return false;
382 }
383
384 return true;
385}
386
387/**
388 * put_wifi_interface_info() - put wifi interface info
389 * @stats: Pointer to stats context
390 * @vendor_event: Pointer to vendor event
391 *
392 * Return: bool
393 */
394static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats,
395 struct sk_buff *vendor_event)
396{
397 if (nla_put_u32(vendor_event,
398 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
399 stats->mode) ||
400 nla_put(vendor_event,
401 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530402 QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800403 nla_put_u32(vendor_event,
404 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
405 stats->state) ||
406 nla_put_u32(vendor_event,
407 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
408 stats->roaming) ||
409 nla_put_u32(vendor_event,
410 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
411 stats->capabilities) ||
412 nla_put(vendor_event,
413 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
414 strlen(stats->ssid), stats->ssid) ||
415 nla_put(vendor_event,
416 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530417 QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800418 nla_put(vendor_event,
419 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
420 WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) ||
421 nla_put(vendor_event,
422 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
423 WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700424 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800425 return false;
426 }
427
428 return true;
429}
430
431/**
432 * put_wifi_iface_stats() - put wifi interface stats
433 * @pWifiIfaceStat: Pointer to interface stats context
434 * @num_peer: Number of peers
435 * @vendor_event: Pointer to vendor event
436 *
437 * Return: bool
438 */
439static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
440 u32 num_peers, struct sk_buff *vendor_event)
441{
442 int i = 0;
443 struct nlattr *wmmInfo;
444 struct nlattr *wmmStats;
445 u64 average_tsf_offset;
446
447 if (false == put_wifi_interface_info(&pWifiIfaceStat->info,
448 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700449 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800450 return false;
451
452 }
453
454 average_tsf_offset = pWifiIfaceStat->avg_bcn_spread_offset_high;
455 average_tsf_offset = (average_tsf_offset << 32) |
456 pWifiIfaceStat->avg_bcn_spread_offset_low ;
457
458 if (nla_put_u32(vendor_event,
459 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
460 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) ||
461 nla_put_u32(vendor_event,
462 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
463 num_peers) ||
464 nla_put_u32(vendor_event,
465 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
466 pWifiIfaceStat->beaconRx) ||
467 nla_put_u32(vendor_event,
468 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
469 pWifiIfaceStat->mgmtRx) ||
470 nla_put_u32(vendor_event,
471 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
472 pWifiIfaceStat->mgmtActionRx) ||
473 nla_put_u32(vendor_event,
474 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
475 pWifiIfaceStat->mgmtActionTx) ||
476 nla_put_u32(vendor_event,
477 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
478 pWifiIfaceStat->rssiMgmt) ||
479 nla_put_u32(vendor_event,
480 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
481 pWifiIfaceStat->rssiData) ||
482 nla_put_u32(vendor_event,
483 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
484 pWifiIfaceStat->rssiAck) ||
485 nla_put_u32(vendor_event,
486 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
487 pWifiIfaceStat->is_leaky_ap) ||
488 nla_put_u32(vendor_event,
489 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
490 pWifiIfaceStat->avg_rx_frms_leaked) ||
491 nla_put_u32(vendor_event,
492 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
493 pWifiIfaceStat->rx_leak_window) ||
Dustin Brownbb7e2f52016-10-17 12:16:35 -0700494 hdd_wlan_nla_put_u64(vendor_event,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800495 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
496 average_tsf_offset)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700497 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800498 return false;
499 }
500
501 wmmInfo = nla_nest_start(vendor_event,
502 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
503 if (wmmInfo == NULL)
504 return false;
505
506 for (i = 0; i < WIFI_AC_MAX; i++) {
507 wmmStats = nla_nest_start(vendor_event, i);
508 if (wmmStats == NULL)
509 return false;
510
511 if (false ==
512 put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i],
513 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700514 hdd_err("put_wifi_wmm_ac_stat Fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800515 return false;
516 }
517
518 nla_nest_end(vendor_event, wmmStats);
519 }
520 nla_nest_end(vendor_event, wmmInfo);
521 return true;
522}
523
524/**
525 * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
526 * @deviceMode: Device mode
527 *
528 * Return: interface mode
529 */
530static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode)
531{
532 switch (deviceMode) {
Krunal Sonif07bb382016-03-10 13:02:11 -0800533 case QDF_STA_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800534 return WIFI_INTERFACE_STA;
Krunal Sonif07bb382016-03-10 13:02:11 -0800535 case QDF_SAP_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800536 return WIFI_INTERFACE_SOFTAP;
Krunal Sonif07bb382016-03-10 13:02:11 -0800537 case QDF_P2P_CLIENT_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800538 return WIFI_INTERFACE_P2P_CLIENT;
Krunal Sonif07bb382016-03-10 13:02:11 -0800539 case QDF_P2P_GO_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800540 return WIFI_INTERFACE_P2P_GO;
Krunal Sonif07bb382016-03-10 13:02:11 -0800541 case QDF_IBSS_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800542 return WIFI_INTERFACE_IBSS;
543 default:
544 /* Return Interface Mode as STA for all the unsupported modes */
545 return WIFI_INTERFACE_STA;
546 }
547}
548
549/**
550 * hdd_get_interface_info() - get interface info
551 * @pAdapter: Pointer to device adapter
552 * @pInfo: Pointer to interface info
553 *
554 * Return: bool
555 */
556static bool hdd_get_interface_info(hdd_adapter_t *pAdapter,
557 tpSirWifiInterfaceInfo pInfo)
558{
559 uint8_t *staMac = NULL;
560 hdd_station_ctx_t *pHddStaCtx;
561 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
562 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
563
564 pInfo->mode = hdd_map_device_to_ll_iface_mode(pAdapter->device_mode);
565
Anurag Chouhanc5548422016-02-24 18:33:27 +0530566 qdf_copy_macaddr(&pInfo->macAddr, &pAdapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800567
Krunal Sonif07bb382016-03-10 13:02:11 -0800568 if (((QDF_STA_MODE == pAdapter->device_mode) ||
569 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
570 (QDF_P2P_DEVICE_MODE == pAdapter->device_mode))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800571 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
572 if (eConnectionState_NotConnected ==
573 pHddStaCtx->conn_info.connState) {
574 pInfo->state = WIFI_DISCONNECTED;
575 }
576 if (eConnectionState_Connecting ==
577 pHddStaCtx->conn_info.connState) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700578 hdd_err("Session ID %d, Connection is in progress",
579 pAdapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800580 pInfo->state = WIFI_ASSOCIATING;
581 }
582 if ((eConnectionState_Associated ==
583 pHddStaCtx->conn_info.connState)
584 && (false == pHddStaCtx->conn_info.uIsAuthenticated)) {
585 staMac =
586 (uint8_t *) &(pAdapter->macAddressCurrent.
587 bytes[0]);
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700588 hdd_err("client " MAC_ADDRESS_STR
589 " is in the middle of WPS/EAPOL exchange.",
590 MAC_ADDR_ARRAY(staMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800591 pInfo->state = WIFI_AUTHENTICATING;
592 }
593 if (eConnectionState_Associated ==
594 pHddStaCtx->conn_info.connState) {
595 pInfo->state = WIFI_ASSOCIATED;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530596 qdf_copy_macaddr(&pInfo->bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800597 &pHddStaCtx->conn_info.bssId);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530598 qdf_mem_copy(pInfo->ssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800599 pHddStaCtx->conn_info.SSID.SSID.ssId,
600 pHddStaCtx->conn_info.SSID.SSID.length);
601 /*
602 * NULL Terminate the string
603 */
604 pInfo->ssid[pHddStaCtx->conn_info.SSID.SSID.length] = 0;
605 }
606 }
607
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530608 qdf_mem_copy(pInfo->countryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800609 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
610
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530611 qdf_mem_copy(pInfo->apCountryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800612 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
613
614 return true;
615}
616
617/**
618 * hdd_link_layer_process_peer_stats() - This function is called after
619 * @pAdapter: Pointer to device adapter
620 * @more_data: More data
621 * @pData: Pointer to stats data
622 *
623 * Receiving Link Layer Peer statistics from FW.This function converts
624 * the firmware data to the NL data and sends the same to the kernel/upper
625 * layers.
626 *
627 * Return: None
628 */
629static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter,
630 u32 more_data,
631 tpSirWifiPeerStat pData)
632{
633 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800634 tpSirWifiPeerStat pWifiPeerStat;
635 tpSirWifiPeerInfo pWifiPeerInfo;
636 struct sk_buff *vendor_event;
Sushant Kaushik7a535882015-11-02 13:31:21 +0530637 int status, i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800638 struct nlattr *peers;
639 int numRate;
640
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530641 ENTER();
642
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800643 pWifiPeerStat = pData;
644
645 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530646 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800647 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800648
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700649 hdd_notice("LL_STATS_PEER_ALL : numPeers %u, more data = %u",
650 pWifiPeerStat->numPeers, more_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800651
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800652 /*
653 * Allocate a size of 4096 for the peer stats comprising
654 * each of size = sizeof (tSirWifiPeerInfo) + numRate *
655 * sizeof (tSirWifiRateStat).Each field is put with an
656 * NL attribute.The size of 4096 is considered assuming
657 * that number of rates shall not exceed beyond 50 with
658 * the sizeof (tSirWifiRateStat) being 32.
659 */
660 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
661 LL_STATS_EVENT_BUF_SIZE);
662
663 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700664 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800665 return;
666 }
667
668 if (nla_put_u32(vendor_event,
669 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
670 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
671 nla_put_u32(vendor_event,
672 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
673 more_data) ||
674 nla_put_u32(vendor_event,
675 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
676 pWifiPeerStat->numPeers)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700677 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800678
679 kfree_skb(vendor_event);
680 return;
681 }
682
683 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
684 pWifiPeerStat->peerInfo);
685
686 if (pWifiPeerStat->numPeers) {
687 struct nlattr *peerInfo;
688 peerInfo = nla_nest_start(vendor_event,
689 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO);
690 if (peerInfo == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700691 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800692 kfree_skb(vendor_event);
693 return;
694 }
695
696 for (i = 1; i <= pWifiPeerStat->numPeers; i++) {
697 peers = nla_nest_start(vendor_event, i);
698 if (peers == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700699 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800700 kfree_skb(vendor_event);
701 return;
702 }
703
704 numRate = pWifiPeerInfo->numRate;
705
706 if (false ==
707 put_wifi_peer_info(pWifiPeerInfo, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700708 hdd_err("put_wifi_peer_info fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800709 kfree_skb(vendor_event);
710 return;
711 }
712
713 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
714 pWifiPeerStat->
715 peerInfo +
716 (i *
717 sizeof
718 (tSirWifiPeerInfo))
719 +
720 (numRate *
721 sizeof
722 (tSirWifiRateStat)));
723 nla_nest_end(vendor_event, peers);
724 }
725 nla_nest_end(vendor_event, peerInfo);
726 }
727 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530728 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800729 return;
730}
731
732/**
733 * hdd_link_layer_process_iface_stats() - This function is called after
734 * @pAdapter: Pointer to device adapter
735 * @pData: Pointer to stats data
736 * @num_peers: Number of peers
737 *
738 * Receiving Link Layer Interface statistics from FW.This function converts
739 * the firmware data to the NL data and sends the same to the kernel/upper
740 * layers.
741 *
742 * Return: None
743 */
744static void hdd_link_layer_process_iface_stats(hdd_adapter_t *pAdapter,
745 tpSirWifiIfaceStat pData,
746 u32 num_peers)
747{
748 tpSirWifiIfaceStat pWifiIfaceStat;
749 struct sk_buff *vendor_event;
750 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
751 int status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800752
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530753 ENTER();
754
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800755 pWifiIfaceStat = pData;
756
757 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530758 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800759 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800760
761 /*
762 * Allocate a size of 4096 for the interface stats comprising
763 * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered
764 * assuming that all these fit with in the limit.Please take
765 * a call on the limit based on the data requirements on
766 * interface statistics.
767 */
768 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
769 LL_STATS_EVENT_BUF_SIZE);
770
771 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700772 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800773 return;
774 }
775
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700776 hdd_notice("WMI_LINK_STATS_IFACE Data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800777
778 if (false == hdd_get_interface_info(pAdapter, &pWifiIfaceStat->info)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700779 hdd_err("hdd_get_interface_info get fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800780 kfree_skb(vendor_event);
781 return;
782 }
783
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800784 if (false ==
785 put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700786 hdd_err("put_wifi_iface_stats fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787 kfree_skb(vendor_event);
788 return;
789 }
790
791 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530792 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 return;
794}
795
796/**
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700797 * hdd_llstats_radio_fill_channels() - radio stats fill channels
798 * @adapter: Pointer to device adapter
799 * @radiostat: Pointer to stats data
800 * @vendor_event: vendor event
801 *
802 * Return: 0 on success; errno on failure
803 */
804static int hdd_llstats_radio_fill_channels(hdd_adapter_t *adapter,
805 tSirWifiRadioStat *radiostat,
806 struct sk_buff *vendor_event)
807{
808 tSirWifiChannelStats *channel_stats;
809 struct nlattr *chlist;
810 struct nlattr *chinfo;
811 int i;
812
813 chlist = nla_nest_start(vendor_event,
814 QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
815 if (chlist == NULL) {
816 hdd_err("nla_nest_start failed");
817 return -EINVAL;
818 }
819
820 for (i = 0; i < radiostat->numChannels; i++) {
821 channel_stats = (tSirWifiChannelStats *) ((uint8_t *)
822 radiostat->channels +
823 (i * sizeof(tSirWifiChannelStats)));
824
825 chinfo = nla_nest_start(vendor_event, i);
826 if (chinfo == NULL) {
827 hdd_err("nla_nest_start failed");
828 return -EINVAL;
829 }
830
831 if (nla_put_u32(vendor_event,
832 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
833 channel_stats->channel.width) ||
834 nla_put_u32(vendor_event,
835 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
836 channel_stats->channel.centerFreq) ||
837 nla_put_u32(vendor_event,
838 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
839 channel_stats->channel.centerFreq0) ||
840 nla_put_u32(vendor_event,
841 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
842 channel_stats->channel.centerFreq1) ||
843 nla_put_u32(vendor_event,
844 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
845 channel_stats->onTime) ||
846 nla_put_u32(vendor_event,
847 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
848 channel_stats->ccaBusyTime)) {
849 hdd_err("nla_put failed");
850 return -EINVAL;
851 }
852 nla_nest_end(vendor_event, chinfo);
853 }
854 nla_nest_end(vendor_event, chlist);
855
856 return 0;
857}
858
859/**
860 * hdd_llstats_post_radio_stats() - post radio stats
861 * @adapter: Pointer to device adapter
862 * @more_data: More data
863 * @radiostat: Pointer to stats data
864 * @num_radio: Number of radios
865 *
866 * Return: 0 on success; errno on failure
867 */
868static int hdd_llstats_post_radio_stats(hdd_adapter_t *adapter,
869 u32 more_data,
870 tSirWifiRadioStat *radiostat,
871 u32 num_radio)
872{
873 struct sk_buff *vendor_event;
874 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
875 int ret;
876
877 /*
878 * Allocate a size of 4096 for the Radio stats comprising
879 * sizeof (tSirWifiRadioStat) + numChannels * sizeof
880 * (tSirWifiChannelStats).Each channel data is put with an
881 * NL attribute.The size of 4096 is considered assuming that
882 * number of channels shall not exceed beyond 60 with the
883 * sizeof (tSirWifiChannelStats) being 24 bytes.
884 */
885
886 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(
887 hdd_ctx->wiphy,
888 LL_STATS_EVENT_BUF_SIZE);
889
890 if (!vendor_event) {
891 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
892 return -ENOMEM;
893 }
894
895 if (nla_put_u32(vendor_event,
896 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
897 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
898 nla_put_u32(vendor_event,
899 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
900 more_data) ||
901 nla_put_u32(vendor_event,
902 QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
903 num_radio) ||
904 nla_put_u32(vendor_event,
905 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
906 radiostat->radio) ||
907 nla_put_u32(vendor_event,
908 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
909 radiostat->onTime) ||
910 nla_put_u32(vendor_event,
911 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
912 radiostat->txTime) ||
913 nla_put_u32(vendor_event,
914 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
915 radiostat->rxTime) ||
916 nla_put_u32(vendor_event,
917 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
918 radiostat->onTimeScan) ||
919 nla_put_u32(vendor_event,
920 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
921 radiostat->onTimeNbd) ||
922 nla_put_u32(vendor_event,
923 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
924 radiostat->onTimeGscan) ||
925 nla_put_u32(vendor_event,
926 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
927 radiostat->onTimeRoamScan) ||
928 nla_put_u32(vendor_event,
929 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
930 radiostat->onTimePnoScan) ||
931 nla_put_u32(vendor_event,
932 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
933 radiostat->onTimeHs20) ||
934 nla_put_u32(vendor_event,
935 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
936 radiostat->total_num_tx_power_levels) ||
937 nla_put_u32(vendor_event,
938 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
939 radiostat->numChannels)) {
940 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
941 goto failure;
942 }
943
944 if (radiostat->total_num_tx_power_levels) {
945 if (nla_put(vendor_event,
946 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
947 sizeof(u32) *
948 radiostat->total_num_tx_power_levels,
949 radiostat->tx_time_per_power_level)) {
950 hdd_err("nla_put fail");
951 goto failure;
952 }
953 }
954
955 if (radiostat->numChannels) {
956 ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
957 vendor_event);
958 if (ret)
959 goto failure;
960 }
961
962 cfg80211_vendor_cmd_reply(vendor_event);
963 return 0;
964
965failure:
966 kfree_skb(vendor_event);
967 return -EINVAL;
968}
969
970/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800971 * hdd_link_layer_process_radio_stats() - This function is called after
972 * @pAdapter: Pointer to device adapter
973 * @more_data: More data
974 * @pData: Pointer to stats data
975 * @num_radios: Number of radios
976 *
977 * Receiving Link Layer Radio statistics from FW.This function converts
978 * the firmware data to the NL data and sends the same to the kernel/upper
979 * layers.
980 *
981 * Return: None
982 */
983static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter,
984 u32 more_data,
985 tpSirWifiRadioStat pData,
986 u32 num_radio)
987{
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700988 int status, i, nr, ret;
989 tSirWifiRadioStat *pWifiRadioStat = pData;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
991
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530992 ENTER();
993
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530995 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800996 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800997
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700998 hdd_notice("LL_STATS_RADIO: number of radios: %u", num_radio);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800999
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001000 for (i = 0; i < num_radio; i++) {
1001 hdd_notice("LL_STATS_RADIO"
1002 " radio: %u onTime: %u txTime: %u rxTime: %u"
1003 " onTimeScan: %u onTimeNbd: %u"
1004 " onTimeGscan: %u onTimeRoamScan: %u"
1005 " onTimePnoScan: %u onTimeHs20: %u"
1006 " numChannels: %u total_num_tx_pwr_levels: %u",
1007 pWifiRadioStat->radio, pWifiRadioStat->onTime,
1008 pWifiRadioStat->txTime, pWifiRadioStat->rxTime,
1009 pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd,
1010 pWifiRadioStat->onTimeGscan,
1011 pWifiRadioStat->onTimeRoamScan,
1012 pWifiRadioStat->onTimePnoScan,
1013 pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels,
1014 pWifiRadioStat->total_num_tx_power_levels);
1015 pWifiRadioStat++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001016 }
1017
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001018 pWifiRadioStat = pData;
1019 for (nr = 0; nr < num_radio; nr++) {
1020 ret = hdd_llstats_post_radio_stats(pAdapter, more_data,
1021 pWifiRadioStat, num_radio);
1022 if (ret)
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001023 return;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001024
1025 pWifiRadioStat++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001026 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301027 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 return;
1029}
1030
1031/**
1032 * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called
1033 * @ctx: Pointer to hdd context
1034 * @indType: Indication type
1035 * @pRsp: Pointer to response
1036 *
1037 * After receiving Link Layer indications from FW.This callback converts the
1038 * firmware data to the NL data and send the same to the kernel/upper layers.
1039 *
1040 * Return: None
1041 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301042void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043 int indType, void *pRsp)
1044{
1045 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
1046 struct hdd_ll_stats_context *context;
1047 hdd_adapter_t *pAdapter = NULL;
1048 tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp;
1049 int status;
1050
1051 status = wlan_hdd_validate_context(pHddCtx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301052 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001053 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001054
1055 pAdapter = hdd_get_adapter_by_vdev(pHddCtx,
1056 linkLayerStatsResults->ifaceId);
1057
1058 if (NULL == pAdapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001059 hdd_err("vdev_id %d does not exist with host",
1060 linkLayerStatsResults->ifaceId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001061 return;
1062 }
1063
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001064 hdd_notice("Link Layer Indication indType: %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065
1066 switch (indType) {
1067 case SIR_HAL_LL_STATS_RESULTS_RSP:
1068 {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001069 hdd_notice("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %p",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301070 linkLayerStatsResults->paramId,
1071 linkLayerStatsResults->ifaceId,
1072 linkLayerStatsResults->rspId,
1073 linkLayerStatsResults->moreResultToFollow,
1074 linkLayerStatsResults->num_radio,
1075 linkLayerStatsResults->results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076
1077 context = &ll_stats_context;
1078 spin_lock(&context->context_lock);
1079 /* validate response received from target */
1080 if ((context->request_id != linkLayerStatsResults->rspId) ||
1081 !(context->request_bitmap & linkLayerStatsResults->paramId)) {
1082 spin_unlock(&context->context_lock);
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001083 hdd_err("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 context->request_id, linkLayerStatsResults->rspId,
1085 context->request_bitmap, linkLayerStatsResults->paramId);
1086 return;
1087 }
1088 spin_unlock(&context->context_lock);
1089
1090 if (linkLayerStatsResults->
1091 paramId & WMI_LINK_STATS_RADIO) {
1092 hdd_link_layer_process_radio_stats(pAdapter,
1093 linkLayerStatsResults->moreResultToFollow,
1094 (tpSirWifiRadioStat)linkLayerStatsResults->results,
1095 linkLayerStatsResults->num_radio);
1096
1097 spin_lock(&context->context_lock);
1098 if (!linkLayerStatsResults->moreResultToFollow)
1099 context->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
1100 spin_unlock(&context->context_lock);
1101
1102 } else if (linkLayerStatsResults->
1103 paramId & WMI_LINK_STATS_IFACE) {
1104 hdd_link_layer_process_iface_stats(pAdapter,
1105 (tpSirWifiIfaceStat)linkLayerStatsResults->results,
1106 linkLayerStatsResults->num_peers);
1107
1108 spin_lock(&context->context_lock);
Srinivas Dasari6946a792015-09-28 15:01:49 +05301109 /* Firmware doesn't send peerstats event if no peers are
1110 * connected. HDD should not wait for any peerstats in
1111 * this case and return the status to middleware after
1112 * receiving iface stats
1113 */
1114 if (!linkLayerStatsResults->num_peers)
1115 context->request_bitmap &=
1116 ~(WMI_LINK_STATS_ALL_PEER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
1118 spin_unlock(&context->context_lock);
1119
1120 } else if (linkLayerStatsResults->
1121 paramId & WMI_LINK_STATS_ALL_PEER) {
1122 hdd_link_layer_process_peer_stats(pAdapter,
1123 linkLayerStatsResults->moreResultToFollow,
1124 (tpSirWifiPeerStat)linkLayerStatsResults->results);
1125
1126 spin_lock(&context->context_lock);
1127 if (!linkLayerStatsResults->moreResultToFollow)
1128 context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
1129 spin_unlock(&context->context_lock);
1130
1131 } else {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001132 hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133 }
1134
1135 spin_lock(&context->context_lock);
1136 /* complete response event if all requests are completed */
1137 if (0 == context->request_bitmap)
1138 complete(&context->response_event);
1139 spin_unlock(&context->context_lock);
1140
1141 break;
1142 }
1143 default:
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001144 hdd_err("invalid event type %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145 break;
1146 }
1147
1148 return;
1149}
1150
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301151void hdd_lost_link_info_cb(void *context,
1152 struct sir_lost_link_info *lost_link_info)
1153{
1154 hdd_context_t *hdd_ctx = (hdd_context_t *)context;
1155 int status;
1156 hdd_adapter_t *adapter;
1157
1158 status = wlan_hdd_validate_context(hdd_ctx);
1159 if (0 != status)
1160 return;
1161
1162 if (NULL == lost_link_info) {
1163 hdd_err("lost_link_info is NULL");
1164 return;
1165 }
1166
1167 adapter = hdd_get_adapter_by_vdev(hdd_ctx, lost_link_info->vdev_id);
1168 if (NULL == adapter) {
1169 hdd_err("invalid adapter");
1170 return;
1171 }
1172
1173 adapter->rssi_on_disconnect = lost_link_info->rssi;
1174 hdd_info("rssi on disconnect %d", adapter->rssi_on_disconnect);
1175}
1176
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001177const struct
1178nla_policy
1179 qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1180 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1181 .type = NLA_U32},
1182 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1183 .type = NLA_U32},
1184};
1185
1186/**
1187 * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1188 * @wiphy: Pointer to wiphy
1189 * @wdev: Pointer to wdev
1190 * @data: Pointer to data
1191 * @data_len: Data length
1192 *
1193 * Return: int
1194 */
1195static int
1196__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1197 struct wireless_dev *wdev,
1198 const void *data,
1199 int data_len)
1200{
1201 int status;
1202 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
1203 tSirLLStatsSetReq LinkLayerStatsSetReq;
1204 struct net_device *dev = wdev->netdev;
1205 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1206 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1207
Jeff Johnson1f61b612016-02-12 16:28:33 -08001208 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301209
Anurag Chouhan6d760662016-02-20 16:05:43 +05301210 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001211 hdd_err("Command not allowed in FTM mode");
1212 return -EPERM;
1213 }
1214
1215 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301216 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001218
1219 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1220 (struct nlattr *)data,
1221 data_len, qca_wlan_vendor_ll_set_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001222 hdd_err("maximum attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001223 return -EINVAL;
1224 }
1225
1226 if (!tb_vendor
1227 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001228 hdd_err("MPDU size Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 return -EINVAL;
1230 }
1231
1232 if (!tb_vendor
1233 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001234 hdd_err("Stats Gathering Not Present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001235 return -EINVAL;
1236 }
1237
1238 /* Shall take the request Id if the Upper layers pass. 1 For now. */
1239 LinkLayerStatsSetReq.reqId = 1;
1240
1241 LinkLayerStatsSetReq.mpduSizeThreshold =
1242 nla_get_u32(tb_vendor
1243 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1244
1245 LinkLayerStatsSetReq.aggressiveStatisticsGathering =
1246 nla_get_u32(tb_vendor
1247 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1248
1249 LinkLayerStatsSetReq.staId = pAdapter->sessionId;
1250
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001251 hdd_notice("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301252 LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId,
1253 LinkLayerStatsSetReq.mpduSizeThreshold,
1254 LinkLayerStatsSetReq.aggressiveStatisticsGathering);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001255
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301256 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(pHddCtx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257 &LinkLayerStatsSetReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001258 hdd_err("sme_ll_stats_set_req Failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001259 return -EINVAL;
1260 }
1261
1262 pAdapter->isLinkLayerStatsSet = 1;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301263 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001264 return 0;
1265}
1266
1267/**
1268 * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1269 * @wiphy: Pointer to wiphy
1270 * @wdev: Pointer to wdev
1271 * @data: Pointer to data
1272 * @data_len: Data length
1273 *
1274 * Return: 0 if success, non-zero for failure
1275 */
1276int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1277 struct wireless_dev *wdev,
1278 const void *data,
1279 int data_len)
1280{
1281 int ret = 0;
1282
1283 cds_ssr_protect(__func__);
1284 ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
1285 cds_ssr_unprotect(__func__);
1286
1287 return ret;
1288}
1289
1290const struct
1291nla_policy
1292 qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1293 /* Unsigned 32bit value provided by the caller issuing the GET stats
1294 * command. When reporting
1295 * the stats results, the driver uses the same value to indicate
1296 * which GET request the results
1297 * correspond to.
1298 */
1299 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1300
1301 /* Unsigned 32bit value . bit mask to identify what statistics are
Jeff Johnson8bb78c32017-01-12 08:42:50 -08001302 * requested for retrieval
1303 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001304 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1305};
1306
1307/**
1308 * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1309 * @wiphy: Pointer to wiphy
1310 * @wdev: Pointer to wdev
1311 * @data: Pointer to data
1312 * @data_len: Data length
1313 *
1314 * Return: int
1315 */
1316static int
1317__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1318 struct wireless_dev *wdev,
1319 const void *data,
1320 int data_len)
1321{
1322 unsigned long rc;
1323 struct hdd_ll_stats_context *context;
1324 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1325 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1326 tSirLLStatsGetReq LinkLayerStatsGetReq;
1327 struct net_device *dev = wdev->netdev;
1328 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Anurag Chouhan22520002016-09-03 16:20:32 +05301329 hdd_station_ctx_t *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001330 int status;
1331
Kapil Guptabf4943c2016-10-13 12:15:39 +05301332 /* ENTER() intentionally not used in a frequently invoked API */
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301333
Anurag Chouhan6d760662016-02-20 16:05:43 +05301334 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001335 hdd_err("Command not allowed in FTM mode");
1336 return -EPERM;
1337 }
1338
1339 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301340 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001341 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001342
1343 if (!pAdapter->isLinkLayerStatsSet) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001344 hdd_warn("isLinkLayerStatsSet: %d",
1345 pAdapter->isLinkLayerStatsSet);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001346 return -EINVAL;
1347 }
1348
Anurag Chouhan22520002016-09-03 16:20:32 +05301349 if (hddstactx->hdd_ReassocScenario) {
1350 hdd_err("Roaming in progress, so unable to proceed this request");
1351 return -EBUSY;
1352 }
1353
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1355 (struct nlattr *)data,
1356 data_len, qca_wlan_vendor_ll_get_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001357 hdd_err("max attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001358 return -EINVAL;
1359 }
1360
1361 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001362 hdd_err("Request Id Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001363 return -EINVAL;
1364 }
1365
1366 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001367 hdd_err("Req Mask Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001368 return -EINVAL;
1369 }
1370
1371 LinkLayerStatsGetReq.reqId =
1372 nla_get_u32(tb_vendor
1373 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1374 LinkLayerStatsGetReq.paramIdMask =
1375 nla_get_u32(tb_vendor
1376 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1377
1378 LinkLayerStatsGetReq.staId = pAdapter->sessionId;
1379
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001380 context = &ll_stats_context;
1381 spin_lock(&context->context_lock);
1382 context->request_id = LinkLayerStatsGetReq.reqId;
1383 context->request_bitmap = LinkLayerStatsGetReq.paramIdMask;
1384 INIT_COMPLETION(context->response_event);
1385 spin_unlock(&context->context_lock);
1386
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301387 if (QDF_STATUS_SUCCESS != sme_ll_stats_get_req(pHddCtx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001388 &LinkLayerStatsGetReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001389 hdd_err("sme_ll_stats_get_req Failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001390 return -EINVAL;
1391 }
1392
1393 rc = wait_for_completion_timeout(&context->response_event,
1394 msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
1395 if (!rc) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001396 hdd_err("Target response timed out request id %d request bitmap 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001397 context->request_id, context->request_bitmap);
1398 return -ETIMEDOUT;
1399 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301400 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401 return 0;
1402}
1403
1404/**
1405 * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1406 * @wiphy: Pointer to wiphy
1407 * @wdev: Pointer to wdev
1408 * @data: Pointer to data
1409 * @data_len: Data length
1410 *
1411 * Return: 0 if success, non-zero for failure
1412 */
1413int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1414 struct wireless_dev *wdev,
1415 const void *data,
1416 int data_len)
1417{
1418 int ret = 0;
1419
1420 cds_ssr_protect(__func__);
1421 ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1422 cds_ssr_unprotect(__func__);
1423
1424 return ret;
1425}
1426
1427const struct
1428nla_policy
1429 qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1430 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1431 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1432 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1433 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1434};
1435
1436/**
1437 * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1438 * @wiphy: Pointer to wiphy
1439 * @wdev: Pointer to wdev
1440 * @data: Pointer to data
1441 * @data_len: Data length
1442 *
1443 * Return: int
1444 */
1445static int
1446__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1447 struct wireless_dev *wdev,
1448 const void *data,
1449 int data_len)
1450{
1451 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1452 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1453 tSirLLStatsClearReq LinkLayerStatsClearReq;
1454 struct net_device *dev = wdev->netdev;
1455 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1456 u32 statsClearReqMask;
1457 u8 stopReq;
1458 int status;
1459 struct sk_buff *temp_skbuff;
1460
Jeff Johnson1f61b612016-02-12 16:28:33 -08001461 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301462
Anurag Chouhan6d760662016-02-20 16:05:43 +05301463 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 hdd_err("Command not allowed in FTM mode");
1465 return -EPERM;
1466 }
1467
1468 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301469 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001470 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001471
1472 if (!pAdapter->isLinkLayerStatsSet) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001473 hdd_alert("isLinkLayerStatsSet : %d",
1474 pAdapter->isLinkLayerStatsSet);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001475 return -EINVAL;
1476 }
1477
1478 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1479 (struct nlattr *)data,
1480 data_len, qca_wlan_vendor_ll_clr_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001481 hdd_err("STATS_CLR_MAX is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001482 return -EINVAL;
1483 }
1484
1485 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1486 !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001487 hdd_err("Error in LL_STATS CLR CONFIG PARA");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001488 return -EINVAL;
1489 }
1490
1491 statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1492 nla_get_u32(tb_vendor
1493 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1494
1495 stopReq = LinkLayerStatsClearReq.stopReq =
1496 nla_get_u8(tb_vendor
1497 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1498
1499 /*
1500 * Shall take the request Id if the Upper layers pass. 1 For now.
1501 */
1502 LinkLayerStatsClearReq.reqId = 1;
1503
1504 LinkLayerStatsClearReq.staId = pAdapter->sessionId;
1505
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001506 hdd_notice("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301507 LinkLayerStatsClearReq.reqId,
1508 LinkLayerStatsClearReq.staId,
1509 LinkLayerStatsClearReq.statsClearReqMask,
1510 LinkLayerStatsClearReq.stopReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001511
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301512 if (QDF_STATUS_SUCCESS == sme_ll_stats_clear_req(pHddCtx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513 &LinkLayerStatsClearReq)) {
1514 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1515 2 *
1516 sizeof(u32) +
1517 2 *
1518 NLMSG_HDRLEN);
1519 if (temp_skbuff != NULL) {
1520 if (nla_put_u32(temp_skbuff,
1521 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1522 statsClearReqMask) ||
1523 nla_put_u32(temp_skbuff,
1524 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1525 stopReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001526 hdd_err("LL_STATS_CLR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001527 kfree_skb(temp_skbuff);
1528 return -EINVAL;
1529 }
1530
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001531 /* If the ask is to stop the stats collection
1532 * as part of clear (stopReq = 1), ensure
1533 * that no further requests of get go to the
1534 * firmware by having isLinkLayerStatsSet set
1535 * to 0. However it the stopReq as part of
1536 * the clear request is 0, the request to get
1537 * the statistics are honoured as in this case
1538 * the firmware is just asked to clear the
1539 * statistics.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001540 */
1541 if (stopReq == 1)
1542 pAdapter->isLinkLayerStatsSet = 0;
1543
1544 return cfg80211_vendor_cmd_reply(temp_skbuff);
1545 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301546 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001547 return -ENOMEM;
1548 }
1549
1550 return -EINVAL;
1551}
1552
1553/**
1554 * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1555 * @wiphy: Pointer to wiphy
1556 * @wdev: Pointer to wdev
1557 * @data: Pointer to data
1558 * @data_len: Data length
1559 *
1560 * Return: 0 if success, non-zero for failure
1561 */
1562int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1563 struct wireless_dev *wdev,
1564 const void *data,
1565 int data_len)
1566{
1567 int ret = 0;
1568
1569 cds_ssr_protect(__func__);
1570 ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
1571 cds_ssr_unprotect(__func__);
1572
1573 return ret;
1574}
1575
1576#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
1577
1578#ifdef WLAN_FEATURE_STATS_EXT
1579/**
1580 * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
1581 * @wiphy: Pointer to wiphy
1582 * @wdev: Pointer to wdev
1583 * @data: Pointer to data
1584 * @data_len: Data length
1585 *
1586 * Return: int
1587 */
1588static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
1589 struct wireless_dev *wdev,
1590 const void *data,
1591 int data_len)
1592{
1593 tStatsExtRequestReq stats_ext_req;
1594 struct net_device *dev = wdev->netdev;
1595 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1596 int ret_val;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301597 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001598 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1599
Jeff Johnson1f61b612016-02-12 16:28:33 -08001600 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001601
1602 ret_val = wlan_hdd_validate_context(hdd_ctx);
1603 if (ret_val)
1604 return ret_val;
1605
Anurag Chouhan6d760662016-02-20 16:05:43 +05301606 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001607 hdd_err("Command not allowed in FTM mode");
1608 return -EPERM;
1609 }
1610
1611 stats_ext_req.request_data_len = data_len;
1612 stats_ext_req.request_data = (void *)data;
1613
1614 status = sme_stats_ext_request(pAdapter->sessionId, &stats_ext_req);
1615
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301616 if (QDF_STATUS_SUCCESS != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001617 ret_val = -EINVAL;
1618
1619 return ret_val;
1620}
1621
1622/**
1623 * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
1624 * @wiphy: Pointer to wiphy
1625 * @wdev: Pointer to wdev
1626 * @data: Pointer to data
1627 * @data_len: Data length
1628 *
1629 * Return: int
1630 */
1631int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
1632 struct wireless_dev *wdev,
1633 const void *data,
1634 int data_len)
1635{
1636 int ret;
1637
1638 cds_ssr_protect(__func__);
1639 ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
1640 data, data_len);
1641 cds_ssr_unprotect(__func__);
1642
1643 return ret;
1644}
1645
1646/**
1647 * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback
1648 * @ctx: Pointer to HDD context
1649 * @msg: Message received
1650 *
1651 * Return: nothing
1652 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301653void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654 tStatsExtEvent *msg)
1655{
1656
1657 hdd_context_t *pHddCtx = (hdd_context_t *) ctx;
1658 struct sk_buff *vendor_event;
1659 int status;
1660 int ret_val;
1661 tStatsExtEvent *data = msg;
1662 hdd_adapter_t *pAdapter = NULL;
1663
1664 status = wlan_hdd_validate_context(pHddCtx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301665 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001666 return;
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301667
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001668 pAdapter = hdd_get_adapter_by_vdev(pHddCtx, data->vdev_id);
1669
1670 if (NULL == pAdapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001671 hdd_err("vdev_id %d does not exist with host", data->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672 return;
1673 }
1674
1675 vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
1676 NULL,
1677 data->event_data_len +
1678 sizeof(uint32_t) +
1679 NLMSG_HDRLEN + NLMSG_HDRLEN,
1680 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
1681 GFP_KERNEL);
1682
1683 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001684 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685 return;
1686 }
1687
1688 ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
1689 pAdapter->dev->ifindex);
1690 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001691 hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692 kfree_skb(vendor_event);
1693
1694 return;
1695 }
1696
1697 ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
1698 data->event_data_len, data->event_data);
1699
1700 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001701 hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702 kfree_skb(vendor_event);
1703
1704 return;
1705 }
1706
1707 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
1708
1709}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001710#endif /* End of WLAN_FEATURE_STATS_EXT */
1711
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05301712#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
1713static inline void wlan_hdd_fill_station_info_signal(struct station_info
1714 *sinfo)
1715{
1716 sinfo->filled |= STATION_INFO_SIGNAL;
1717}
1718#else
1719static inline void wlan_hdd_fill_station_info_signal(struct station_info
1720 *sinfo)
1721{
1722 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
1723}
1724#endif
1725
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001726/**
1727 * __wlan_hdd_cfg80211_get_station() - get station statistics
1728 * @wiphy: Pointer to wiphy
1729 * @dev: Pointer to network device
1730 * @mac: Pointer to mac
1731 * @sinfo: Pointer to station info
1732 *
1733 * Return: 0 for success, non-zero for failure
1734 */
1735static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
1736 struct net_device *dev,
1737 const uint8_t *mac,
1738 struct station_info *sinfo)
1739{
1740 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1741 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
1742 int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length;
1743 uint8_t rate_flags;
Dustin Brown905cdc72016-11-16 16:51:10 -08001744 uint8_t mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001745
1746 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
1747 struct hdd_config *pCfg = pHddCtx->config;
1748
1749 uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
1750 uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX;
1751 uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
1752 uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
1753 uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET];
1754 uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET;
1755 uint16_t maxRate = 0;
Anurag Chouhan5de8d172016-07-13 14:44:28 +05301756 int8_t snr = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001757 uint16_t myRate;
1758 uint16_t currentRate = 0;
1759 uint8_t maxSpeedMCS = 0;
1760 uint8_t maxMCSIdx = 0;
1761 uint8_t rateFlag = 1;
1762 uint8_t i, j, rssidx;
1763 uint8_t nss = 1;
1764 int status, mode = 0, maxHtIdx;
1765 struct index_vht_data_rate_type *supported_vht_mcs_rate;
1766 struct index_data_rate_type *supported_mcs_rate;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05301767#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1768 bool rssi_stats_valid = false;
1769#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001771 uint32_t vht_mcs_map;
1772 enum eDataRate11ACMaxMcs vhtMaxMcs;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001773
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001774 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775
Anurag Chouhan6d760662016-02-20 16:05:43 +05301776 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001777 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001778 return -EINVAL;
1779 }
1780
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301781 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1782 hdd_err("invalid session id: %d", pAdapter->sessionId);
1783 return -EINVAL;
1784 }
1785
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001786 if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) ||
1787 (0 == ssidlen)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001788 hdd_notice("Not associated or Invalid ssidlen, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789 ssidlen);
1790 /*To keep GUI happy */
1791 return 0;
1792 }
1793
1794 if (true == pHddStaCtx->hdd_ReassocScenario) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001795 hdd_notice("Roaming is in progress, cannot continue with this request");
Sachin Ahujafeedeba2016-09-13 21:54:16 +05301796 /*
1797 * supplicant reports very low rssi to upper layer
1798 * and handover happens to cellular.
1799 * send the cached rssi when get_station
1800 */
1801 sinfo->signal = pAdapter->rssi;
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05301802 wlan_hdd_fill_station_info_signal(sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001803 return 0;
1804 }
1805
1806 status = wlan_hdd_validate_context(pHddCtx);
1807
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301808 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001809 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001810
Naveen Rawat2cb788d2016-10-11 17:44:44 -07001811 wlan_hdd_get_station_stats(pAdapter);
1812 sinfo->signal = pAdapter->hdd_stats.summary_stat.rssi;
1813 snr = pAdapter->hdd_stats.summary_stat.snr;
1814 hdd_info("snr: %d, rssi: %d",
1815 pAdapter->hdd_stats.summary_stat.snr,
1816 pAdapter->hdd_stats.summary_stat.rssi);
Anurag Chouhan5de8d172016-07-13 14:44:28 +05301817 pHddStaCtx->conn_info.signal = sinfo->signal;
1818 pHddStaCtx->conn_info.noise =
1819 pHddStaCtx->conn_info.signal - snr;
1820
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05301821 wlan_hdd_fill_station_info_signal(sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001822
Jeff Johnson71396692016-09-23 15:41:52 -07001823 /*
1824 * we notify connect to lpass here instead of during actual
1825 * connect processing because rssi info is not accurate during
1826 * actual connection. lpass will ensure the notification is
1827 * only processed once per association.
1828 */
1829 hdd_lpass_notify_connect(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001831 rate_flags = pAdapter->hdd_stats.ClassA_stat.tx_rate_flags;
Dustin Brown905cdc72016-11-16 16:51:10 -08001832 mcs_index = pAdapter->hdd_stats.ClassA_stat.mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001833
1834 /* convert to the UI units of 100kbps */
1835 myRate = pAdapter->hdd_stats.ClassA_stat.tx_rate * 5;
1836 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
1837 nss = pAdapter->hdd_stats.ClassA_stat.rx_frag_cnt;
1838
1839 if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) {
1840 /* Get current rate flags if report actual */
1841 rate_flags =
1842 pAdapter->hdd_stats.ClassA_stat.
1843 promiscuous_rx_frag_cnt;
1844 }
1845
Dustin Brown905cdc72016-11-16 16:51:10 -08001846 if (mcs_index == INVALID_MCS_IDX)
1847 mcs_index = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001848 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08001849
1850 hdd_info("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d",
1851 sinfo->signal, pCfg->reportMaxLinkSpeed, myRate,
1852 (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid,
Dustin Brown905cdc72016-11-16 16:51:10 -08001853 (int)pCfg->linkSpeedRssiLow, (int)rate_flags, (int)mcs_index);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07001855#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
1856 /* assume basic BW. anything else will override this later */
1857 sinfo->txrate.bw = RATE_INFO_BW_20;
1858#endif
1859
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860 if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) {
1861 /* we do not want to necessarily report the current speed */
1862 if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) {
1863 /* report the max possible speed */
1864 rssidx = 0;
1865 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
1866 pCfg->reportMaxLinkSpeed) {
1867 /* report the max possible speed with RSSI scaling */
1868 if (sinfo->signal >= pCfg->linkSpeedRssiHigh) {
1869 /* report the max possible speed */
1870 rssidx = 0;
1871 } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) {
1872 /* report middle speed */
1873 rssidx = 1;
1874 } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) {
1875 /* report middle speed */
1876 rssidx = 2;
1877 } else {
1878 /* report actual speed */
1879 rssidx = 3;
1880 }
1881 } else {
1882 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001883 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001884 pCfg->reportMaxLinkSpeed);
1885 rssidx = 0;
1886 }
1887
1888 maxRate = 0;
1889
1890 /* Get Basic Rate Set */
1891 if (0 !=
1892 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
1893 WNI_CFG_OPERATIONAL_RATE_SET,
1894 OperationalRates,
1895 &ORLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001896 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001897 /*To keep GUI happy */
1898 return 0;
1899 }
1900
1901 for (i = 0; i < ORLeng; i++) {
1902 for (j = 0;
1903 j < ARRAY_SIZE(supported_data_rate); j++) {
1904 /* Validate Rate Set */
1905 if (supported_data_rate[j].beacon_rate_index ==
1906 (OperationalRates[i] & 0x7F)) {
1907 currentRate =
1908 supported_data_rate[j].
1909 supported_rate[rssidx];
1910 break;
1911 }
1912 }
1913 /* Update MAX rate */
1914 maxRate =
1915 (currentRate > maxRate) ? currentRate : maxRate;
1916 }
1917
1918 /* Get Extended Rate Set */
1919 if (0 !=
1920 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
1921 WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
1922 ExtendedRates, &ERLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001923 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001924 /*To keep GUI happy */
1925 return 0;
1926 }
1927
1928 for (i = 0; i < ERLeng; i++) {
1929 for (j = 0;
1930 j < ARRAY_SIZE(supported_data_rate); j++) {
1931 if (supported_data_rate[j].beacon_rate_index ==
1932 (ExtendedRates[i] & 0x7F)) {
1933 currentRate =
1934 supported_data_rate[j].
1935 supported_rate[rssidx];
1936 break;
1937 }
1938 }
1939 /* Update MAX rate */
1940 maxRate =
1941 (currentRate > maxRate) ? currentRate : maxRate;
1942 }
Jeff Johnson8bb78c32017-01-12 08:42:50 -08001943 /*
1944 * Get MCS Rate Set --
1945 * Only if we are connected in non legacy mode and not
1946 * reporting actual speed
1947 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001948 if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) {
1949 if (0 !=
1950 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
1951 WNI_CFG_CURRENT_MCS_SET, MCSRates,
1952 &MCSLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001953 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001954 /*To keep GUI happy */
1955 return 0;
1956 }
1957 rateFlag = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958 supported_vht_mcs_rate =
1959 (struct index_vht_data_rate_type *)
1960 ((nss ==
1961 1) ? &supported_vht_mcs_rate_nss1 :
1962 &supported_vht_mcs_rate_nss2);
1963
1964 if (rate_flags & eHAL_TX_RATE_VHT80)
1965 mode = 2;
1966 else if ((rate_flags & eHAL_TX_RATE_VHT40) ||
1967 (rate_flags & eHAL_TX_RATE_HT40))
1968 mode = 1;
1969 else
1970 mode = 0;
1971
1972 /* VHT80 rate has seperate rate table */
1973 if (rate_flags &
1974 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
1975 eHAL_TX_RATE_VHT80)) {
1976 sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter),
1977 WNI_CFG_VHT_TX_MCS_MAP,
1978 &vht_mcs_map);
1979 vhtMaxMcs = (enum eDataRate11ACMaxMcs)
1980 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
1981 if (rate_flags & eHAL_TX_RATE_SGI)
1982 rateFlag |= 1;
1983 if (DATA_RATE_11AC_MAX_MCS_7 == vhtMaxMcs)
1984 maxMCSIdx = 7;
1985 else if (DATA_RATE_11AC_MAX_MCS_8 ==
1986 vhtMaxMcs)
1987 maxMCSIdx = 8;
1988 else if (DATA_RATE_11AC_MAX_MCS_9 ==
1989 vhtMaxMcs) {
Hu Wang1f2b8a82016-08-25 15:15:54 +08001990 /*
1991 * IEEE_P802.11ac_2013.pdf page 325, 326
1992 * - MCS9 is valid for VHT20 when
1993 * Nss = 3 or Nss = 6
1994 * - MCS9 is not valid for VHT20 when
1995 * Nss = 1,2,4,5,7,8
1996 */
1997 if ((rate_flags & eHAL_TX_RATE_VHT20) &&
1998 (nss != 3 && nss != 6))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999 maxMCSIdx = 8;
2000 else
2001 maxMCSIdx = 9;
2002 }
2003
2004 if (rssidx != 0) {
2005 for (i = 0; i <= maxMCSIdx; i++) {
2006 if (sinfo->signal <=
2007 rssi_mcs_tbl[mode][i]) {
2008 maxMCSIdx = i;
2009 break;
2010 }
2011 }
2012 }
2013
2014 if (rate_flags & eHAL_TX_RATE_VHT80) {
2015 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08002016 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017 supported_VHT80_rate[rateFlag];
2018 maxRate =
2019 supported_vht_mcs_rate[maxMCSIdx].
2020 supported_VHT80_rate[rateFlag];
2021 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2022 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08002023 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002024 supported_VHT40_rate[rateFlag];
2025 maxRate =
2026 supported_vht_mcs_rate[maxMCSIdx].
2027 supported_VHT40_rate[rateFlag];
2028 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
2029 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08002030 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002031 supported_VHT20_rate[rateFlag];
2032 maxRate =
2033 supported_vht_mcs_rate[maxMCSIdx].
2034 supported_VHT20_rate[rateFlag];
2035 }
2036
2037 maxSpeedMCS = 1;
2038 if (currentRate > maxRate)
2039 maxRate = currentRate;
2040
Kiran Kumar Lokere9a733a72016-02-17 19:01:15 -08002041 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042 if (rate_flags & eHAL_TX_RATE_HT40)
2043 rateFlag |= 1;
2044 if (rate_flags & eHAL_TX_RATE_SGI)
2045 rateFlag |= 2;
2046
2047 supported_mcs_rate =
2048 (struct index_data_rate_type *)
2049 ((nss ==
2050 1) ? &supported_mcs_rate_nss1 :
2051 &supported_mcs_rate_nss2);
2052
2053 maxHtIdx = MAX_HT_MCS_IDX;
2054 if (rssidx != 0) {
2055 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
2056 if (sinfo->signal <=
2057 rssi_mcs_tbl[mode][i]) {
2058 maxHtIdx = i + 1;
2059 break;
2060 }
2061 }
2062 }
2063
2064 for (i = 0; i < MCSLeng; i++) {
2065 for (j = 0; j < maxHtIdx; j++) {
2066 if (supported_mcs_rate[j].
2067 beacon_rate_index ==
2068 MCSRates[i]) {
2069 currentRate =
2070 supported_mcs_rate[j].
2071 supported_rate
2072 [rateFlag];
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05302073 maxMCSIdx =
2074 supported_mcs_rate[j].
2075 beacon_rate_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002076 break;
2077 }
2078 }
2079
2080 if ((j < MAX_HT_MCS_IDX)
2081 && (currentRate > maxRate)) {
2082 maxRate = currentRate;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083 }
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05302084 maxSpeedMCS = 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085 }
2086 }
2087 }
2088
2089 else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
2090 maxRate = myRate;
2091 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08002092 maxMCSIdx = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002093 }
2094 /* report a value at least as big as current rate */
2095 if ((maxRate < myRate) || (0 == maxRate)) {
2096 maxRate = myRate;
2097 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2098 maxSpeedMCS = 0;
2099 } else {
2100 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08002101 maxMCSIdx = mcs_index;
Hu Wang1f2b8a82016-08-25 15:15:54 +08002102 /*
2103 * IEEE_P802.11ac_2013.pdf page 325, 326
2104 * - MCS9 is valid for VHT20 when
2105 * Nss = 3 or Nss = 6
2106 * - MCS9 is not valid for VHT20 when
2107 * Nss = 1,2,4,5,7,8
2108 */
2109 if ((rate_flags & eHAL_TX_RATE_VHT20) &&
2110 (maxMCSIdx > 8) &&
2111 (nss != 3 && nss != 6)) {
2112 maxMCSIdx = 8;
2113 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002114 }
2115 }
2116
2117 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2118 sinfo->txrate.legacy = maxRate;
2119#ifdef LINKSPEED_DEBUG_ENABLED
2120 pr_info("Reporting legacy rate %d\n",
2121 sinfo->txrate.legacy);
2122#endif /* LINKSPEED_DEBUG_ENABLED */
2123 } else {
2124 sinfo->txrate.mcs = maxMCSIdx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002125 sinfo->txrate.nss = nss;
2126 if (rate_flags & eHAL_TX_RATE_VHT80) {
2127 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002128#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
2129 sinfo->txrate.bw = RATE_INFO_BW_80;
2130#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002131 sinfo->txrate.flags |=
2132 RATE_INFO_FLAGS_80_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002133#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002134 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
2135 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002136#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
2137 sinfo->txrate.bw = RATE_INFO_BW_40;
2138#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002139 sinfo->txrate.flags |=
2140 RATE_INFO_FLAGS_40_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002141#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002142 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
2143 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2144 } else
2145 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002146 if (rate_flags &
2147 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
2148 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2149 if (rate_flags & eHAL_TX_RATE_HT40) {
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002150#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
2151 sinfo->txrate.bw = RATE_INFO_BW_40;
2152#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002153 sinfo->txrate.flags |=
2154 RATE_INFO_FLAGS_40_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002155#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002156 }
2157 }
2158 if (rate_flags & eHAL_TX_RATE_SGI) {
2159 if (!
2160 (sinfo->txrate.
2161 flags & RATE_INFO_FLAGS_VHT_MCS))
2162 sinfo->txrate.flags |=
2163 RATE_INFO_FLAGS_MCS;
2164 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2165 }
2166#ifdef LINKSPEED_DEBUG_ENABLED
2167 pr_info("Reporting MCS rate %d flags %x\n",
2168 sinfo->txrate.mcs, sinfo->txrate.flags);
2169#endif /* LINKSPEED_DEBUG_ENABLED */
2170 }
2171 } else {
2172 /* report current rate instead of max rate */
2173
2174 if (rate_flags & eHAL_TX_RATE_LEGACY) {
2175 /* provide to the UI in units of 100kbps */
2176 sinfo->txrate.legacy = myRate;
2177#ifdef LINKSPEED_DEBUG_ENABLED
2178 pr_info("Reporting actual legacy rate %d\n",
2179 sinfo->txrate.legacy);
2180#endif /* LINKSPEED_DEBUG_ENABLED */
2181 } else {
2182 /* must be MCS */
Dustin Brown905cdc72016-11-16 16:51:10 -08002183 sinfo->txrate.mcs = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002184 sinfo->txrate.nss = nss;
2185 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
2186 if (rate_flags & eHAL_TX_RATE_VHT80) {
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002187#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
2188 sinfo->txrate.bw = RATE_INFO_BW_80;
2189#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002190 sinfo->txrate.flags |=
2191 RATE_INFO_FLAGS_80_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002192#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002193 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002194#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
2195 sinfo->txrate.bw = RATE_INFO_BW_40;
2196#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002197 sinfo->txrate.flags |=
2198 RATE_INFO_FLAGS_40_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002199#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002200 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002201 if (rate_flags &
2202 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
2203 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2204 if (rate_flags & eHAL_TX_RATE_HT40) {
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002205#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS)
2206 sinfo->txrate.bw = RATE_INFO_BW_40;
2207#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002208 sinfo->txrate.flags |=
2209 RATE_INFO_FLAGS_40_MHZ_WIDTH;
Ryan Hsu3a0f5232016-01-21 14:40:11 -08002210#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211 }
2212 }
2213 if (rate_flags & eHAL_TX_RATE_SGI) {
2214 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
2215 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2216 }
2217#ifdef LINKSPEED_DEBUG_ENABLED
2218 pr_info("Reporting actual MCS rate %d flags %x\n",
2219 sinfo->txrate.mcs, sinfo->txrate.flags);
2220#endif /* LINKSPEED_DEBUG_ENABLED */
2221 }
2222 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08002223
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002224 sinfo->tx_bytes = pAdapter->stats.tx_bytes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002225
2226 sinfo->tx_packets =
2227 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[0] +
2228 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[1] +
2229 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[2] +
2230 pAdapter->hdd_stats.summary_stat.tx_frm_cnt[3];
2231
2232 sinfo->tx_retries =
gbian4c2f9d92016-09-29 17:27:04 +08002233 pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[0] +
2234 pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[1] +
2235 pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[2] +
2236 pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[3];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002237
2238 sinfo->tx_failed =
2239 pAdapter->hdd_stats.summary_stat.fail_cnt[0] +
2240 pAdapter->hdd_stats.summary_stat.fail_cnt[1] +
2241 pAdapter->hdd_stats.summary_stat.fail_cnt[2] +
2242 pAdapter->hdd_stats.summary_stat.fail_cnt[3];
2243
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002244 sinfo->rx_bytes = pAdapter->stats.rx_bytes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002245 sinfo->rx_packets = pAdapter->stats.rx_packets;
Ryan Hsue7bc3a72016-01-18 12:08:22 -08002246
Anurag Chouhan5de8d172016-07-13 14:44:28 +05302247 qdf_mem_copy(&pHddStaCtx->conn_info.txrate,
2248 &sinfo->txrate, sizeof(sinfo->txrate));
2249
Ryan Hsue7bc3a72016-01-18 12:08:22 -08002250#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
2251 sinfo->filled |= STATION_INFO_TX_BITRATE |
2252 STATION_INFO_TX_BYTES |
2253 STATION_INFO_TX_PACKETS |
2254 STATION_INFO_TX_RETRIES |
2255 STATION_INFO_TX_FAILED |
2256 STATION_INFO_RX_BYTES |
2257 STATION_INFO_RX_PACKETS;
2258#else
2259 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) |
2260 BIT(NL80211_STA_INFO_TX_BITRATE) |
2261 BIT(NL80211_STA_INFO_TX_PACKETS) |
2262 BIT(NL80211_STA_INFO_TX_RETRIES) |
2263 BIT(NL80211_STA_INFO_TX_FAILED) |
2264 BIT(NL80211_STA_INFO_RX_BYTES) |
2265 BIT(NL80211_STA_INFO_RX_PACKETS);
2266#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002267
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05302268 if (rate_flags & eHAL_TX_RATE_LEGACY)
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002269 hdd_notice("Reporting legacy rate %d pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05302270 sinfo->txrate.legacy, sinfo->tx_packets,
2271 sinfo->rx_packets);
2272 else
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002273 hdd_notice("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05302274 sinfo->txrate.mcs, sinfo->txrate.flags,
2275 sinfo->tx_packets, sinfo->rx_packets);
2276
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302277#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
2278 sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
2279 for (i = 0; i < NUM_CHAINS_MAX; i++) {
2280 sinfo->chain_signal_avg[i] =
2281 pAdapter->hdd_stats.per_chain_rssi_stats.rssi[i];
2282 sinfo->chains |= 1 << i;
2283 if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
2284 sinfo->chain_signal_avg[i] != 0)
2285 sinfo->signal_avg = sinfo->chain_signal_avg[i];
2286
2287 hdd_info("RSSI for chain %d, vdev_id %d is %d",
2288 i, pAdapter->sessionId, sinfo->chain_signal_avg[i]);
2289
2290 if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
2291 rssi_stats_valid = true;
2292 }
2293
2294 if (rssi_stats_valid) {
2295#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
2296 sinfo->filled |= STATION_INFO_CHAIN_SIGNAL_AVG;
2297 sinfo->filled |= STATION_INFO_SIGNAL_AVG;
2298#else
2299 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
2300 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
2301#endif
2302 }
2303#endif
2304
2305
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302306 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002307 TRACE_CODE_HDD_CFG80211_GET_STA,
2308 pAdapter->sessionId, maxRate));
2309 EXIT();
2310 return 0;
2311}
2312
2313/**
2314 * wlan_hdd_cfg80211_get_station() - get station statistics
2315 * @wiphy: Pointer to wiphy
2316 * @dev: Pointer to network device
2317 * @mac: Pointer to mac
2318 * @sinfo: Pointer to station info
2319 *
2320 * Return: 0 for success, non-zero for failure
2321 */
2322#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
2323int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
2324 struct net_device *dev, const uint8_t *mac,
2325 struct station_info *sinfo)
2326#else
2327int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
2328 struct net_device *dev, uint8_t *mac,
2329 struct station_info *sinfo)
2330#endif
2331{
2332 int ret;
2333
2334 cds_ssr_protect(__func__);
2335 ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
2336 cds_ssr_unprotect(__func__);
2337
2338 return ret;
2339}
2340
2341/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05302342 * __wlan_hdd_cfg80211_dump_station() - dump station statistics
2343 * @wiphy: Pointer to wiphy
2344 * @dev: Pointer to network device
2345 * @idx: variable to determine whether to get stats or not
2346 * @mac: Pointer to mac
2347 * @sinfo: Pointer to station info
2348 *
2349 * Return: 0 for success, non-zero for failure
2350 */
2351static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
2352 struct net_device *dev,
2353 int idx, u8 *mac,
2354 struct station_info *sinfo)
2355{
2356 hdd_context_t *hdd_ctx = (hdd_context_t *) wiphy_priv(wiphy);
2357
2358 hdd_debug("%s: idx %d", __func__, idx);
2359 if (idx != 0)
2360 return -ENOENT;
2361 qdf_mem_copy(mac, hdd_ctx->config->intfMacAddr[0].bytes,
2362 QDF_MAC_ADDR_SIZE);
2363 return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
2364}
2365
2366/**
2367 * wlan_hdd_cfg80211_dump_station() - dump station statistics
2368 * @wiphy: Pointer to wiphy
2369 * @dev: Pointer to network device
2370 * @idx: variable to determine whether to get stats or not
2371 * @mac: Pointer to mac
2372 * @sinfo: Pointer to station info
2373 *
2374 * Return: 0 for success, non-zero for failure
2375 */
2376int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
2377 struct net_device *dev,
2378 int idx, u8 *mac,
2379 struct station_info *sinfo)
2380{
2381 int ret;
2382
2383 cds_ssr_protect(__func__);
2384 ret = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
2385 cds_ssr_unprotect(__func__);
2386 return ret;
2387}
2388
2389/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002390 * hdd_get_stats() - Function to retrieve interface statistics
2391 * @dev: pointer to network device
2392 *
2393 * This function is the ndo_get_stats method for all netdevs
2394 * registered with the kernel
2395 *
2396 * Return: pointer to net_device_stats structure
2397 */
2398struct net_device_stats *hdd_get_stats(struct net_device *dev)
2399{
2400 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2401
Jeff Johnson3c3994a2016-02-11 08:12:30 -08002402 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002403 return &adapter->stats;
2404}
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05302405
2406
2407/*
2408 * time = cycle_count * cycle
2409 * cycle = 1 / clock_freq
2410 * Since the unit of clock_freq reported from
2411 * FW is MHZ, and we want to calculate time in
2412 * ms level, the result is
2413 * time = cycle / (clock_freq * 1000)
2414 */
2415#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
2416static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
2417 struct scan_chan_info *chan_info,
2418 struct ieee80211_channel *channels)
2419{
2420 uint64_t clock_freq = chan_info->clock_freq * 1000;
2421
2422 if (channels->center_freq != (uint16_t)chan_info->freq)
2423 return false;
2424
2425 survey->channel = channels;
2426 survey->noise = chan_info->noise_floor;
2427 survey->filled = SURVEY_INFO_NOISE_DBM;
2428
2429 if (opfreq == chan_info->freq)
2430 survey->filled |= SURVEY_INFO_IN_USE;
2431
2432 if (clock_freq == 0)
2433 return true;
2434
2435 survey->time = chan_info->cycle_count / clock_freq;
2436 survey->time_busy = chan_info->rx_clear_count / clock_freq;
2437 survey->time_tx = chan_info->tx_frame_count / clock_freq;
2438
2439 survey->filled |= SURVEY_INFO_TIME |
2440 SURVEY_INFO_TIME_BUSY |
2441 SURVEY_INFO_TIME_TX;
2442 return true;
2443}
2444#else
2445static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
2446 struct scan_chan_info *chan_info,
2447 struct ieee80211_channel *channels)
2448{
2449 uint64_t clock_freq = chan_info->clock_freq * 1000;
2450
2451 if (channels->center_freq != (uint16_t)chan_info->freq)
2452 return false;
2453
2454 survey->channel = channels;
2455 survey->noise = chan_info->noise_floor;
2456 survey->filled = SURVEY_INFO_NOISE_DBM;
2457
2458 if (opfreq == chan_info->freq)
2459 survey->filled |= SURVEY_INFO_IN_USE;
2460
2461 if (clock_freq == 0)
2462 return true;
2463
2464 survey->channel_time = chan_info->cycle_count / clock_freq;
2465 survey->channel_time_busy = chan_info->rx_clear_count / clock_freq;
2466 survey->channel_time_tx = chan_info->tx_frame_count / clock_freq;
2467
2468 survey->filled |= SURVEY_INFO_CHANNEL_TIME |
2469 SURVEY_INFO_CHANNEL_TIME_BUSY |
2470 SURVEY_INFO_CHANNEL_TIME_TX;
2471 return true;
2472}
2473#endif
2474
2475static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
2476 hdd_adapter_t *pAdapter, struct survey_info *survey, int idx)
2477{
2478 bool filled = false;
2479 int i, j = 0;
2480 uint32_t channel = 0, opfreq; /* Initialization Required */
2481 hdd_context_t *pHddCtx;
2482
2483 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2484 sme_get_operation_channel(pHddCtx->hHal, &channel, pAdapter->sessionId);
2485 hdd_wlan_get_freq(channel, &opfreq);
2486
2487 mutex_lock(&pHddCtx->chan_info_lock);
2488
2489 for (i = 0; i < IEEE80211_NUM_BANDS && !filled; i++) {
2490 if (wiphy->bands[i] == NULL)
2491 continue;
2492
2493 for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
2494 struct ieee80211_supported_band *band = wiphy->bands[i];
2495 filled = wlan_fill_survey_result(survey, opfreq,
2496 &pHddCtx->chan_info[idx],
2497 &band->channels[j]);
2498 }
2499 }
2500 mutex_unlock(&pHddCtx->chan_info_lock);
2501
2502 return filled;
2503}
2504
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002505/**
2506 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
2507 * @wiphy: Pointer to wiphy
2508 * @dev: Pointer to network device
2509 * @idx: Index
2510 * @survey: Pointer to survey info
2511 *
2512 * Return: 0 for success, non-zero for failure
2513 */
2514static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
2515 struct net_device *dev,
2516 int idx, struct survey_info *survey)
2517{
2518 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2519 hdd_context_t *pHddCtx;
2520 hdd_station_ctx_t *pHddStaCtx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05302521 int status;
2522 bool filled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002523
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002524 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002525
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05302526 hdd_info("dump survey index:%d", idx);
2527 if (idx > QDF_MAX_NUM_CHAN - 1)
2528 return -EINVAL;
2529
2530 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2531 status = wlan_hdd_validate_context(pHddCtx);
2532 if (0 != status)
2533 return status;
2534
2535 if (pHddCtx->chan_info == NULL) {
2536 hdd_err("chan_info is NULL");
2537 return -EINVAL;
2538 }
2539
2540 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002541 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002542 return -EINVAL;
2543 }
2544
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002545 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
2546
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05302547 if (pHddCtx->config->fEnableSNRMonitoring == 0)
2548 return -ENONET;
2549
2550
2551 if (pHddStaCtx->hdd_ReassocScenario) {
2552 hdd_info("Roaming in progress, hence return");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002553 return -ENONET;
2554 }
2555
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05302556 filled = wlan_hdd_update_survey_info(wiphy, pAdapter, survey, idx);
2557
2558 if (!filled)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002559 return -ENONET;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302560 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002561 return 0;
2562}
2563
2564/**
2565 * wlan_hdd_cfg80211_dump_survey() - get survey related info
2566 * @wiphy: Pointer to wiphy
2567 * @dev: Pointer to network device
2568 * @idx: Index
2569 * @survey: Pointer to survey info
2570 *
2571 * Return: 0 for success, non-zero for failure
2572 */
2573int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
2574 struct net_device *dev,
2575 int idx, struct survey_info *survey)
2576{
2577 int ret;
2578
2579 cds_ssr_protect(__func__);
2580 ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
2581 cds_ssr_unprotect(__func__);
2582
2583 return ret;
2584}
2585/**
2586 * hdd_init_ll_stats_ctx() - initialize link layer stats context
2587 *
2588 * Return: none
2589 */
2590inline void hdd_init_ll_stats_ctx(void)
2591{
2592 spin_lock_init(&ll_stats_context.context_lock);
2593 init_completion(&ll_stats_context.response_event);
2594 ll_stats_context.request_bitmap = 0;
2595
2596 return;
2597}
Nirav Shahbf1b0332016-05-25 14:27:39 +05302598
2599/**
2600 * hdd_display_hif_stats() - display hif stats
2601 *
2602 * Return: none
2603 *
2604 */
2605void hdd_display_hif_stats(void)
2606{
2607 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2608
2609 if (!hif_ctx)
2610 return;
2611 hif_display_stats(hif_ctx);
2612}
2613
2614/**
2615 * hdd_clear_hif_stats() - clear hif stats
2616 *
2617 * Return: none
2618 */
2619void hdd_clear_hif_stats(void)
2620{
2621 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
2622
2623 if (!hif_ctx)
2624 return;
2625 hif_clear_stats(hif_ctx);
2626}