blob: e3ba119f79024089cc9ccd20e425309cebaa0338 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jeff Johnson8bb78c32017-01-12 08:42:50 -08002 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/**
23 * DOC : wlan_hdd_stats.c
24 *
25 * WLAN Host Device Driver statistics related implementation
26 *
27 */
28
29#include "wlan_hdd_stats.h"
30#include "sme_api.h"
31#include "cds_sched.h"
32#include "wlan_hdd_trace.h"
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070033#include "wlan_hdd_lpass.h"
Nirav Shahbf1b0332016-05-25 14:27:39 +053034#include "hif.h"
Sandeep Puligillafdd201e2017-02-02 18:43:46 -080035#include <qca_vendor.h>
Zhang Qian4ead8f02017-03-27 14:21:47 +080036#include "wma_api.h"
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -080037#include "wlan_hdd_debugfs_llstat.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080038
39/* 11B, 11G Rate table include Basic rate and Extended rate
40 * The IDX field is the rate index
41 * The HI field is the rate when RSSI is strong or being ignored
42 * (in this case we report actual rate)
43 * The MID field is the rate when RSSI is moderate
44 * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
45 * The LO field is the rate when RSSI is low
46 * (in this case we don't report rates, actual current rate used)
47 */
Will Huang496b36c2017-07-11 16:38:50 +080048static const struct index_data_rate_type supported_data_rate[] = {
49 /* IDX HI HM LM LO (RSSI-based index */
50 {2, { 10, 10, 10, 0} },
51 {4, { 20, 20, 10, 0} },
52 {11, { 55, 20, 10, 0} },
53 {12, { 60, 55, 20, 0} },
54 {18, { 90, 55, 20, 0} },
55 {22, {110, 55, 20, 0} },
56 {24, {120, 90, 60, 0} },
57 {36, {180, 120, 60, 0} },
58 {44, {220, 180, 60, 0} },
59 {48, {240, 180, 90, 0} },
60 {66, {330, 180, 90, 0} },
61 {72, {360, 240, 90, 0} },
62 {96, {480, 240, 120, 0} },
63 {108, {540, 240, 120, 0} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080064};
65/* MCS Based rate table HT MCS parameters with Nss = 1 */
66static struct index_data_rate_type supported_mcs_rate_nss1[] = {
67/* MCS L20 L40 S20 S40 */
68 {0, {65, 135, 72, 150} },
69 {1, {130, 270, 144, 300} },
70 {2, {195, 405, 217, 450} },
71 {3, {260, 540, 289, 600} },
72 {4, {390, 810, 433, 900} },
73 {5, {520, 1080, 578, 1200} },
74 {6, {585, 1215, 650, 1350} },
75 {7, {650, 1350, 722, 1500} }
76};
77
78/* HT MCS parameters with Nss = 2 */
79static struct index_data_rate_type supported_mcs_rate_nss2[] = {
80/* MCS L20 L40 S20 S40 */
81 {0, {130, 270, 144, 300} },
82 {1, {260, 540, 289, 600} },
83 {2, {390, 810, 433, 900} },
84 {3, {520, 1080, 578, 1200} },
85 {4, {780, 1620, 867, 1800} },
86 {5, {1040, 2160, 1156, 2400} },
87 {6, {1170, 2430, 1300, 2700} },
88 {7, {1300, 2700, 1444, 3000} }
89};
90
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080091/* MCS Based VHT rate table MCS parameters with Nss = 1*/
92static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
93/* MCS L80 S80 L40 S40 L20 S40*/
94 {0, {293, 325}, {135, 150}, {65, 72} },
95 {1, {585, 650}, {270, 300}, {130, 144} },
96 {2, {878, 975}, {405, 450}, {195, 217} },
97 {3, {1170, 1300}, {540, 600}, {260, 289} },
98 {4, {1755, 1950}, {810, 900}, {390, 433} },
99 {5, {2340, 2600}, {1080, 1200}, {520, 578} },
100 {6, {2633, 2925}, {1215, 1350}, {585, 650} },
101 {7, {2925, 3250}, {1350, 1500}, {650, 722} },
102 {8, {3510, 3900}, {1620, 1800}, {780, 867} },
103 {9, {3900, 4333}, {1800, 2000}, {780, 867} }
104};
105
106/*MCS parameters with Nss = 2*/
107static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
108/* MCS L80 S80 L40 S40 L20 S40*/
109 {0, {585, 650}, {270, 300}, {130, 144} },
110 {1, {1170, 1300}, {540, 600}, {260, 289} },
111 {2, {1755, 1950}, {810, 900}, {390, 433} },
112 {3, {2340, 2600}, {1080, 1200}, {520, 578} },
113 {4, {3510, 3900}, {1620, 1800}, {780, 867} },
114 {5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
115 {6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
116 {7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
117 {8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
118 {9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
119};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800120
121/*array index ponints to MCS and array value points respective rssi*/
122static int rssi_mcs_tbl[][10] = {
123/*MCS 0 1 2 3 4 5 6 7 8 9*/
124 {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */
125 {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */
126 {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */
127};
128
129
130#ifdef WLAN_FEATURE_LINK_LAYER_STATS
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800131static struct hdd_ll_stats_context ll_stats_context;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800132
133/**
134 * put_wifi_rate_stat() - put wifi rate stats
135 * @stats: Pointer to stats context
136 * @vendor_event: Pointer to vendor event
137 *
138 * Return: bool
139 */
140static bool put_wifi_rate_stat(tpSirWifiRateStat stats,
141 struct sk_buff *vendor_event)
142{
143 if (nla_put_u8(vendor_event,
144 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
145 stats->rate.preamble) ||
146 nla_put_u8(vendor_event,
147 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
148 stats->rate.nss) ||
149 nla_put_u8(vendor_event,
150 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
151 stats->rate.bw) ||
152 nla_put_u8(vendor_event,
153 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
154 stats->rate.rateMcsIdx) ||
155 nla_put_u32(vendor_event,
156 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
157 stats->rate.bitrate) ||
158 nla_put_u32(vendor_event,
159 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
160 stats->txMpdu) ||
161 nla_put_u32(vendor_event,
162 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
163 stats->rxMpdu) ||
164 nla_put_u32(vendor_event,
165 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
166 stats->mpduLost) ||
167 nla_put_u32(vendor_event,
168 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
169 stats->retries) ||
170 nla_put_u32(vendor_event,
171 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
172 stats->retriesShort) ||
173 nla_put_u32(vendor_event,
174 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
175 stats->retriesLong)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700176 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800177 return false;
178 }
179
180 return true;
181}
182
183/**
184 * put_wifi_peer_info() - put wifi peer info
185 * @stats: Pointer to stats context
186 * @vendor_event: Pointer to vendor event
187 *
188 * Return: bool
189 */
190static bool put_wifi_peer_info(tpSirWifiPeerInfo stats,
191 struct sk_buff *vendor_event)
192{
193 u32 i = 0;
194 tpSirWifiRateStat pRateStats;
195
196 if (nla_put_u32
197 (vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
Dustin Brown877a5a92016-11-17 13:56:52 -0800198 wmi_to_sir_peer_type(stats->type)) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800199 nla_put(vendor_event,
200 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530201 QDF_MAC_ADDR_SIZE, &stats->peerMacAddress.bytes[0]) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800202 nla_put_u32(vendor_event,
203 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
204 stats->capabilities) ||
205 nla_put_u32(vendor_event,
206 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
207 stats->numRate)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700208 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800209 goto error;
210 }
211
212 if (stats->numRate) {
213 struct nlattr *rateInfo;
214 struct nlattr *rates;
215
216 rateInfo = nla_nest_start(vendor_event,
217 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO);
218 if (rateInfo == NULL)
219 goto error;
220
221 for (i = 0; i < stats->numRate; i++) {
222 pRateStats = (tpSirWifiRateStat) ((uint8_t *)
223 stats->rateStats +
224 (i *
225 sizeof
226 (tSirWifiRateStat)));
227 rates = nla_nest_start(vendor_event, i);
228 if (rates == NULL)
229 goto error;
230
231 if (false ==
232 put_wifi_rate_stat(pRateStats, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700233 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800234 return false;
235 }
236 nla_nest_end(vendor_event, rates);
237 }
238 nla_nest_end(vendor_event, rateInfo);
239 }
240
241 return true;
242error:
243 return false;
244}
245
246/**
247 * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
248 * @stats: Pointer to stats context
249 * @vendor_event: Pointer to vendor event
250 *
251 * Return: bool
252 */
253static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats,
254 struct sk_buff *vendor_event)
255{
256 if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
257 stats->ac) ||
258 nla_put_u32(vendor_event,
259 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
260 stats->txMpdu) ||
261 nla_put_u32(vendor_event,
262 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
263 stats->rxMpdu) ||
264 nla_put_u32(vendor_event,
265 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
266 stats->txMcast) ||
267 nla_put_u32(vendor_event,
268 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
269 stats->rxMcast) ||
270 nla_put_u32(vendor_event,
271 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
272 stats->rxAmpdu) ||
273 nla_put_u32(vendor_event,
274 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
275 stats->txAmpdu) ||
276 nla_put_u32(vendor_event,
277 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
278 stats->mpduLost) ||
279 nla_put_u32(vendor_event,
280 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
281 stats->retries) ||
282 nla_put_u32(vendor_event,
283 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
284 stats->retriesShort) ||
285 nla_put_u32(vendor_event,
286 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
287 stats->retriesLong) ||
288 nla_put_u32(vendor_event,
289 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
290 stats->contentionTimeMin) ||
291 nla_put_u32(vendor_event,
292 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
293 stats->contentionTimeMax) ||
294 nla_put_u32(vendor_event,
295 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
296 stats->contentionTimeAvg) ||
297 nla_put_u32(vendor_event,
298 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
299 stats->contentionNumSamples)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700300 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800301 return false;
302 }
303
304 return true;
305}
306
307/**
308 * put_wifi_interface_info() - put wifi interface info
309 * @stats: Pointer to stats context
310 * @vendor_event: Pointer to vendor event
311 *
312 * Return: bool
313 */
314static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats,
315 struct sk_buff *vendor_event)
316{
317 if (nla_put_u32(vendor_event,
318 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
319 stats->mode) ||
320 nla_put(vendor_event,
321 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530322 QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800323 nla_put_u32(vendor_event,
324 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
325 stats->state) ||
326 nla_put_u32(vendor_event,
327 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
328 stats->roaming) ||
329 nla_put_u32(vendor_event,
330 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
331 stats->capabilities) ||
332 nla_put(vendor_event,
333 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
334 strlen(stats->ssid), stats->ssid) ||
335 nla_put(vendor_event,
336 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530337 QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800338 nla_put(vendor_event,
339 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
340 WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) ||
341 nla_put(vendor_event,
342 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
343 WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700344 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800345 return false;
346 }
347
348 return true;
349}
350
351/**
352 * put_wifi_iface_stats() - put wifi interface stats
353 * @pWifiIfaceStat: Pointer to interface stats context
354 * @num_peer: Number of peers
355 * @vendor_event: Pointer to vendor event
356 *
357 * Return: bool
358 */
359static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
360 u32 num_peers, struct sk_buff *vendor_event)
361{
362 int i = 0;
363 struct nlattr *wmmInfo;
364 struct nlattr *wmmStats;
365 u64 average_tsf_offset;
366
367 if (false == put_wifi_interface_info(&pWifiIfaceStat->info,
368 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700369 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370 return false;
371
372 }
373
374 average_tsf_offset = pWifiIfaceStat->avg_bcn_spread_offset_high;
375 average_tsf_offset = (average_tsf_offset << 32) |
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700376 pWifiIfaceStat->avg_bcn_spread_offset_low;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800377
378 if (nla_put_u32(vendor_event,
379 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
380 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) ||
381 nla_put_u32(vendor_event,
382 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
383 num_peers) ||
384 nla_put_u32(vendor_event,
385 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
386 pWifiIfaceStat->beaconRx) ||
387 nla_put_u32(vendor_event,
388 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
389 pWifiIfaceStat->mgmtRx) ||
390 nla_put_u32(vendor_event,
391 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
392 pWifiIfaceStat->mgmtActionRx) ||
393 nla_put_u32(vendor_event,
394 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
395 pWifiIfaceStat->mgmtActionTx) ||
396 nla_put_u32(vendor_event,
397 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
398 pWifiIfaceStat->rssiMgmt) ||
399 nla_put_u32(vendor_event,
400 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
401 pWifiIfaceStat->rssiData) ||
402 nla_put_u32(vendor_event,
403 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
404 pWifiIfaceStat->rssiAck) ||
405 nla_put_u32(vendor_event,
406 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
407 pWifiIfaceStat->is_leaky_ap) ||
408 nla_put_u32(vendor_event,
409 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
410 pWifiIfaceStat->avg_rx_frms_leaked) ||
411 nla_put_u32(vendor_event,
412 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
413 pWifiIfaceStat->rx_leak_window) ||
Dustin Brownbb7e2f52016-10-17 12:16:35 -0700414 hdd_wlan_nla_put_u64(vendor_event,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800415 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
gaolezb432ed92017-03-16 18:40:04 +0800416 average_tsf_offset) ||
417 nla_put_u32(vendor_event,
418 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT,
419 pWifiIfaceStat->rts_succ_cnt) ||
420 nla_put_u32(vendor_event,
421 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT,
422 pWifiIfaceStat->rts_fail_cnt) ||
423 nla_put_u32(vendor_event,
424 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT,
425 pWifiIfaceStat->ppdu_succ_cnt) ||
426 nla_put_u32(vendor_event,
427 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT,
428 pWifiIfaceStat->ppdu_fail_cnt)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700429 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800430 return false;
431 }
432
433 wmmInfo = nla_nest_start(vendor_event,
434 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
435 if (wmmInfo == NULL)
436 return false;
437
438 for (i = 0; i < WIFI_AC_MAX; i++) {
439 wmmStats = nla_nest_start(vendor_event, i);
440 if (wmmStats == NULL)
441 return false;
442
443 if (false ==
444 put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i],
445 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700446 hdd_err("put_wifi_wmm_ac_stat Fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800447 return false;
448 }
449
450 nla_nest_end(vendor_event, wmmStats);
451 }
452 nla_nest_end(vendor_event, wmmInfo);
453 return true;
454}
455
456/**
457 * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
458 * @deviceMode: Device mode
459 *
460 * Return: interface mode
461 */
462static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode)
463{
464 switch (deviceMode) {
Krunal Sonif07bb382016-03-10 13:02:11 -0800465 case QDF_STA_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800466 return WIFI_INTERFACE_STA;
Krunal Sonif07bb382016-03-10 13:02:11 -0800467 case QDF_SAP_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800468 return WIFI_INTERFACE_SOFTAP;
Krunal Sonif07bb382016-03-10 13:02:11 -0800469 case QDF_P2P_CLIENT_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800470 return WIFI_INTERFACE_P2P_CLIENT;
Krunal Sonif07bb382016-03-10 13:02:11 -0800471 case QDF_P2P_GO_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800472 return WIFI_INTERFACE_P2P_GO;
Krunal Sonif07bb382016-03-10 13:02:11 -0800473 case QDF_IBSS_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474 return WIFI_INTERFACE_IBSS;
475 default:
476 /* Return Interface Mode as STA for all the unsupported modes */
477 return WIFI_INTERFACE_STA;
478 }
479}
480
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700481bool hdd_get_interface_info(struct hdd_adapter *pAdapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800482 tpSirWifiInterfaceInfo pInfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800483{
484 uint8_t *staMac = NULL;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700485 struct hdd_station_ctx *pHddStaCtx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800486 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
487 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
488
489 pInfo->mode = hdd_map_device_to_ll_iface_mode(pAdapter->device_mode);
490
Anurag Chouhanc5548422016-02-24 18:33:27 +0530491 qdf_copy_macaddr(&pInfo->macAddr, &pAdapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800492
Krunal Sonif07bb382016-03-10 13:02:11 -0800493 if (((QDF_STA_MODE == pAdapter->device_mode) ||
494 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
495 (QDF_P2P_DEVICE_MODE == pAdapter->device_mode))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800496 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
497 if (eConnectionState_NotConnected ==
498 pHddStaCtx->conn_info.connState) {
499 pInfo->state = WIFI_DISCONNECTED;
500 }
501 if (eConnectionState_Connecting ==
502 pHddStaCtx->conn_info.connState) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700503 hdd_err("Session ID %d, Connection is in progress",
504 pAdapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800505 pInfo->state = WIFI_ASSOCIATING;
506 }
507 if ((eConnectionState_Associated ==
508 pHddStaCtx->conn_info.connState)
509 && (false == pHddStaCtx->conn_info.uIsAuthenticated)) {
510 staMac =
511 (uint8_t *) &(pAdapter->macAddressCurrent.
512 bytes[0]);
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700513 hdd_err("client " MAC_ADDRESS_STR
514 " is in the middle of WPS/EAPOL exchange.",
515 MAC_ADDR_ARRAY(staMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800516 pInfo->state = WIFI_AUTHENTICATING;
517 }
518 if (eConnectionState_Associated ==
519 pHddStaCtx->conn_info.connState) {
520 pInfo->state = WIFI_ASSOCIATED;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530521 qdf_copy_macaddr(&pInfo->bssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800522 &pHddStaCtx->conn_info.bssId);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530523 qdf_mem_copy(pInfo->ssid,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800524 pHddStaCtx->conn_info.SSID.SSID.ssId,
525 pHddStaCtx->conn_info.SSID.SSID.length);
526 /*
527 * NULL Terminate the string
528 */
529 pInfo->ssid[pHddStaCtx->conn_info.SSID.SSID.length] = 0;
530 }
531 }
532
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530533 qdf_mem_copy(pInfo->countryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800534 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
535
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530536 qdf_mem_copy(pInfo->apCountryStr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800537 pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
538
539 return true;
540}
541
542/**
543 * hdd_link_layer_process_peer_stats() - This function is called after
544 * @pAdapter: Pointer to device adapter
545 * @more_data: More data
546 * @pData: Pointer to stats data
547 *
548 * Receiving Link Layer Peer statistics from FW.This function converts
549 * the firmware data to the NL data and sends the same to the kernel/upper
550 * layers.
551 *
552 * Return: None
553 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700554static void hdd_link_layer_process_peer_stats(struct hdd_adapter *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800555 u32 more_data,
556 tpSirWifiPeerStat pData)
557{
Jeff Johnson5eb1e682017-08-28 11:42:15 -0700558 struct hdd_context *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800559 tpSirWifiPeerStat pWifiPeerStat;
560 tpSirWifiPeerInfo pWifiPeerInfo;
561 struct sk_buff *vendor_event;
Sushant Kaushik7a535882015-11-02 13:31:21 +0530562 int status, i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800563 struct nlattr *peers;
564 int numRate;
565
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530566 ENTER();
567
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800568 pWifiPeerStat = pData;
569
570 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530571 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800572 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800573
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800574 hdd_debug("LL_STATS_PEER_ALL : numPeers %u, more data = %u",
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700575 pWifiPeerStat->numPeers, more_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800576
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800577 /*
578 * Allocate a size of 4096 for the peer stats comprising
579 * each of size = sizeof (tSirWifiPeerInfo) + numRate *
580 * sizeof (tSirWifiRateStat).Each field is put with an
581 * NL attribute.The size of 4096 is considered assuming
582 * that number of rates shall not exceed beyond 50 with
583 * the sizeof (tSirWifiRateStat) being 32.
584 */
585 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
586 LL_STATS_EVENT_BUF_SIZE);
587
588 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700589 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800590 return;
591 }
592
593 if (nla_put_u32(vendor_event,
594 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
595 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
596 nla_put_u32(vendor_event,
597 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
598 more_data) ||
599 nla_put_u32(vendor_event,
600 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
601 pWifiPeerStat->numPeers)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700602 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800603
604 kfree_skb(vendor_event);
605 return;
606 }
607
608 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
609 pWifiPeerStat->peerInfo);
610
611 if (pWifiPeerStat->numPeers) {
612 struct nlattr *peerInfo;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700613
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800614 peerInfo = nla_nest_start(vendor_event,
615 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO);
616 if (peerInfo == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700617 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800618 kfree_skb(vendor_event);
619 return;
620 }
621
622 for (i = 1; i <= pWifiPeerStat->numPeers; i++) {
623 peers = nla_nest_start(vendor_event, i);
624 if (peers == NULL) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700625 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800626 kfree_skb(vendor_event);
627 return;
628 }
629
630 numRate = pWifiPeerInfo->numRate;
631
632 if (false ==
633 put_wifi_peer_info(pWifiPeerInfo, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700634 hdd_err("put_wifi_peer_info fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800635 kfree_skb(vendor_event);
636 return;
637 }
638
639 pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *)
640 pWifiPeerStat->
641 peerInfo +
642 (i *
643 sizeof
644 (tSirWifiPeerInfo))
645 +
646 (numRate *
647 sizeof
648 (tSirWifiRateStat)));
649 nla_nest_end(vendor_event, peers);
650 }
651 nla_nest_end(vendor_event, peerInfo);
652 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700653
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800654 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530655 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800656}
657
658/**
659 * hdd_link_layer_process_iface_stats() - This function is called after
660 * @pAdapter: Pointer to device adapter
661 * @pData: Pointer to stats data
662 * @num_peers: Number of peers
663 *
664 * Receiving Link Layer Interface statistics from FW.This function converts
665 * the firmware data to the NL data and sends the same to the kernel/upper
666 * layers.
667 *
668 * Return: None
669 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700670static void hdd_link_layer_process_iface_stats(struct hdd_adapter *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800671 tpSirWifiIfaceStat pData,
672 u32 num_peers)
673{
674 tpSirWifiIfaceStat pWifiIfaceStat;
675 struct sk_buff *vendor_event;
Jeff Johnson5eb1e682017-08-28 11:42:15 -0700676 struct hdd_context *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800677 int status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800678
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530679 ENTER();
680
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800681 pWifiIfaceStat = pData;
682
683 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530684 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800685 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800686
687 /*
688 * Allocate a size of 4096 for the interface stats comprising
689 * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered
690 * assuming that all these fit with in the limit.Please take
691 * a call on the limit based on the data requirements on
692 * interface statistics.
693 */
694 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
695 LL_STATS_EVENT_BUF_SIZE);
696
697 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700698 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800699 return;
700 }
701
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800702 hdd_debug("WMI_LINK_STATS_IFACE Data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800703
704 if (false == hdd_get_interface_info(pAdapter, &pWifiIfaceStat->info)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700705 hdd_err("hdd_get_interface_info get fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800706 kfree_skb(vendor_event);
707 return;
708 }
709
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800710 if (false ==
711 put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700712 hdd_err("put_wifi_iface_stats fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800713 kfree_skb(vendor_event);
714 return;
715 }
716
717 cfg80211_vendor_cmd_reply(vendor_event);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530718 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800719}
720
721/**
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700722 * hdd_llstats_radio_fill_channels() - radio stats fill channels
723 * @adapter: Pointer to device adapter
724 * @radiostat: Pointer to stats data
725 * @vendor_event: vendor event
726 *
727 * Return: 0 on success; errno on failure
728 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700729static int hdd_llstats_radio_fill_channels(struct hdd_adapter *adapter,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700730 tSirWifiRadioStat *radiostat,
731 struct sk_buff *vendor_event)
732{
733 tSirWifiChannelStats *channel_stats;
734 struct nlattr *chlist;
735 struct nlattr *chinfo;
736 int i;
737
738 chlist = nla_nest_start(vendor_event,
739 QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
740 if (chlist == NULL) {
741 hdd_err("nla_nest_start failed");
742 return -EINVAL;
743 }
744
745 for (i = 0; i < radiostat->numChannels; i++) {
746 channel_stats = (tSirWifiChannelStats *) ((uint8_t *)
747 radiostat->channels +
748 (i * sizeof(tSirWifiChannelStats)));
749
750 chinfo = nla_nest_start(vendor_event, i);
751 if (chinfo == NULL) {
752 hdd_err("nla_nest_start failed");
753 return -EINVAL;
754 }
755
756 if (nla_put_u32(vendor_event,
757 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
758 channel_stats->channel.width) ||
759 nla_put_u32(vendor_event,
760 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
761 channel_stats->channel.centerFreq) ||
762 nla_put_u32(vendor_event,
763 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
764 channel_stats->channel.centerFreq0) ||
765 nla_put_u32(vendor_event,
766 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
767 channel_stats->channel.centerFreq1) ||
768 nla_put_u32(vendor_event,
769 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
770 channel_stats->onTime) ||
771 nla_put_u32(vendor_event,
772 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
773 channel_stats->ccaBusyTime)) {
774 hdd_err("nla_put failed");
775 return -EINVAL;
776 }
777 nla_nest_end(vendor_event, chinfo);
778 }
779 nla_nest_end(vendor_event, chlist);
780
781 return 0;
782}
783
784/**
785 * hdd_llstats_post_radio_stats() - post radio stats
786 * @adapter: Pointer to device adapter
787 * @more_data: More data
788 * @radiostat: Pointer to stats data
789 * @num_radio: Number of radios
790 *
791 * Return: 0 on success; errno on failure
792 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700793static int hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700794 u32 more_data,
795 tSirWifiRadioStat *radiostat,
796 u32 num_radio)
797{
798 struct sk_buff *vendor_event;
Jeff Johnson5eb1e682017-08-28 11:42:15 -0700799 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700800 int ret;
801
802 /*
803 * Allocate a size of 4096 for the Radio stats comprising
804 * sizeof (tSirWifiRadioStat) + numChannels * sizeof
805 * (tSirWifiChannelStats).Each channel data is put with an
806 * NL attribute.The size of 4096 is considered assuming that
807 * number of channels shall not exceed beyond 60 with the
808 * sizeof (tSirWifiChannelStats) being 24 bytes.
809 */
810
811 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(
812 hdd_ctx->wiphy,
813 LL_STATS_EVENT_BUF_SIZE);
814
815 if (!vendor_event) {
816 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
817 return -ENOMEM;
818 }
819
820 if (nla_put_u32(vendor_event,
821 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
822 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
823 nla_put_u32(vendor_event,
824 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
825 more_data) ||
826 nla_put_u32(vendor_event,
827 QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
828 num_radio) ||
829 nla_put_u32(vendor_event,
830 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
831 radiostat->radio) ||
832 nla_put_u32(vendor_event,
833 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
834 radiostat->onTime) ||
835 nla_put_u32(vendor_event,
836 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
837 radiostat->txTime) ||
838 nla_put_u32(vendor_event,
839 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
840 radiostat->rxTime) ||
841 nla_put_u32(vendor_event,
842 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
843 radiostat->onTimeScan) ||
844 nla_put_u32(vendor_event,
845 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
846 radiostat->onTimeNbd) ||
847 nla_put_u32(vendor_event,
848 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
849 radiostat->onTimeGscan) ||
850 nla_put_u32(vendor_event,
851 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
852 radiostat->onTimeRoamScan) ||
853 nla_put_u32(vendor_event,
854 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
855 radiostat->onTimePnoScan) ||
856 nla_put_u32(vendor_event,
857 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
858 radiostat->onTimeHs20) ||
859 nla_put_u32(vendor_event,
860 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
861 radiostat->total_num_tx_power_levels) ||
862 nla_put_u32(vendor_event,
863 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
864 radiostat->numChannels)) {
865 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
866 goto failure;
867 }
868
869 if (radiostat->total_num_tx_power_levels) {
870 if (nla_put(vendor_event,
871 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
872 sizeof(u32) *
873 radiostat->total_num_tx_power_levels,
874 radiostat->tx_time_per_power_level)) {
875 hdd_err("nla_put fail");
876 goto failure;
877 }
878 }
879
880 if (radiostat->numChannels) {
881 ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
882 vendor_event);
883 if (ret)
884 goto failure;
885 }
886
887 cfg80211_vendor_cmd_reply(vendor_event);
888 return 0;
889
890failure:
891 kfree_skb(vendor_event);
892 return -EINVAL;
893}
894
895/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896 * hdd_link_layer_process_radio_stats() - This function is called after
897 * @pAdapter: Pointer to device adapter
898 * @more_data: More data
899 * @pData: Pointer to stats data
900 * @num_radios: Number of radios
901 *
902 * Receiving Link Layer Radio statistics from FW.This function converts
903 * the firmware data to the NL data and sends the same to the kernel/upper
904 * layers.
905 *
906 * Return: None
907 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700908static void hdd_link_layer_process_radio_stats(struct hdd_adapter *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800909 u32 more_data,
910 tpSirWifiRadioStat pData,
911 u32 num_radio)
912{
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700913 int status, i, nr, ret;
914 tSirWifiRadioStat *pWifiRadioStat = pData;
Jeff Johnson5eb1e682017-08-28 11:42:15 -0700915 struct hdd_context *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530917 ENTER();
918
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800919 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530920 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800921 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800922
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800923 hdd_debug("LL_STATS_RADIO: number of radios: %u", num_radio);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700925 for (i = 0; i < num_radio; i++) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800926 hdd_debug("LL_STATS_RADIO"
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700927 " radio: %u onTime: %u txTime: %u rxTime: %u"
928 " onTimeScan: %u onTimeNbd: %u"
929 " onTimeGscan: %u onTimeRoamScan: %u"
930 " onTimePnoScan: %u onTimeHs20: %u"
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -0800931 " numChannels: %u total_num_tx_pwr_levels: %u"
932 " on_time_host_scan: %u, on_time_lpi_scan: %u",
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700933 pWifiRadioStat->radio, pWifiRadioStat->onTime,
934 pWifiRadioStat->txTime, pWifiRadioStat->rxTime,
935 pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd,
936 pWifiRadioStat->onTimeGscan,
937 pWifiRadioStat->onTimeRoamScan,
938 pWifiRadioStat->onTimePnoScan,
939 pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels,
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -0800940 pWifiRadioStat->total_num_tx_power_levels,
941 pWifiRadioStat->on_time_host_scan,
942 pWifiRadioStat->on_time_lpi_scan);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700943 pWifiRadioStat++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 }
945
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700946 pWifiRadioStat = pData;
947 for (nr = 0; nr < num_radio; nr++) {
948 ret = hdd_llstats_post_radio_stats(pAdapter, more_data,
949 pWifiRadioStat, num_radio);
950 if (ret)
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700951 return;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700952
953 pWifiRadioStat++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -0700954 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700955
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530956 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800957}
958
959/**
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800960 * hdd_ll_process_radio_stats() - Wrapper function for cfg80211/debugfs
961 * @adapter: Pointer to device adapter
962 * @more_data: More data
963 * @data: Pointer to stats data
964 * @num_radios: Number of radios
965 * @resp_id: Response ID from FW
966 *
967 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
968 * function which calls cfg80211/debugfs functions based on the response ID.
969 *
970 * Return: None
971 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700972static void hdd_ll_process_radio_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800973 uint32_t more_data, void *data, uint32_t num_radio,
974 uint32_t resp_id)
975{
976 if (DEBUGFS_LLSTATS_REQID == resp_id)
977 hdd_debugfs_process_radio_stats(adapter, more_data,
978 (tpSirWifiRadioStat)data, num_radio);
979 else
980 hdd_link_layer_process_radio_stats(adapter, more_data,
981 (tpSirWifiRadioStat)data, num_radio);
982}
983
984/**
985 * hdd_ll_process_iface_stats() - Wrapper function for cfg80211/debugfs
986 * @adapter: Pointer to device adapter
987 * @data: Pointer to stats data
988 * @num_peers: Number of peers
989 * @resp_id: Response ID from FW
990 *
991 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
992 * function which calls cfg80211/debugfs functions based on the response ID.
993 *
994 * Return: None
995 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700996static void hdd_ll_process_iface_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800997 void *data, uint32_t num_peers, uint32_t resp_id)
998{
999 if (DEBUGFS_LLSTATS_REQID == resp_id)
1000 hdd_debugfs_process_iface_stats(adapter,
1001 (tpSirWifiIfaceStat) data, num_peers);
1002 else
1003 hdd_link_layer_process_iface_stats(adapter,
1004 (tpSirWifiIfaceStat) data, num_peers);
1005}
1006
1007/**
1008 * hdd_ll_process_peer_stats() - Wrapper function for cfg80211/debugfs
1009 * @adapter: Pointer to device adapter
1010 * @more_data: More data
1011 * @data: Pointer to stats data
1012 * @resp_id: Response ID from FW
1013 *
1014 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1015 * function which calls cfg80211/debugfs functions based on the response ID.
1016 *
1017 * Return: None
1018 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001019static void hdd_ll_process_peer_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001020 uint32_t more_data, void *data, uint32_t resp_id)
1021{
1022 if (DEBUGFS_LLSTATS_REQID == resp_id)
1023 hdd_debugfs_process_peer_stats(adapter, data);
1024 else
1025 hdd_link_layer_process_peer_stats(adapter, more_data,
1026 (tpSirWifiPeerStat) data);
1027}
1028
1029/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001030 * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called
1031 * @ctx: Pointer to hdd context
1032 * @indType: Indication type
1033 * @pRsp: Pointer to response
1034 *
1035 * After receiving Link Layer indications from FW.This callback converts the
1036 * firmware data to the NL data and send the same to the kernel/upper layers.
1037 *
1038 * Return: None
1039 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05301040void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001041 int indType, void *pRsp)
1042{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001043 struct hdd_context *pHddCtx = (struct hdd_context *) ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001044 struct hdd_ll_stats_context *context;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001045 struct hdd_adapter *pAdapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046 tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp;
1047 int status;
1048
1049 status = wlan_hdd_validate_context(pHddCtx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301050 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001051 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052
1053 pAdapter = hdd_get_adapter_by_vdev(pHddCtx,
1054 linkLayerStatsResults->ifaceId);
1055
1056 if (NULL == pAdapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001057 hdd_err("vdev_id %d does not exist with host",
1058 linkLayerStatsResults->ifaceId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001059 return;
1060 }
1061
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001062 hdd_debug("Link Layer Indication indType: %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001063
1064 switch (indType) {
1065 case SIR_HAL_LL_STATS_RESULTS_RSP:
1066 {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001067 hdd_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %p",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301068 linkLayerStatsResults->paramId,
1069 linkLayerStatsResults->ifaceId,
1070 linkLayerStatsResults->rspId,
1071 linkLayerStatsResults->moreResultToFollow,
1072 linkLayerStatsResults->num_radio,
1073 linkLayerStatsResults->results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001074
1075 context = &ll_stats_context;
1076 spin_lock(&context->context_lock);
1077 /* validate response received from target */
1078 if ((context->request_id != linkLayerStatsResults->rspId) ||
1079 !(context->request_bitmap & linkLayerStatsResults->paramId)) {
1080 spin_unlock(&context->context_lock);
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001081 hdd_err("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001082 context->request_id, linkLayerStatsResults->rspId,
1083 context->request_bitmap, linkLayerStatsResults->paramId);
1084 return;
1085 }
1086 spin_unlock(&context->context_lock);
1087
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001088 if (linkLayerStatsResults->paramId & WMI_LINK_STATS_RADIO) {
1089 hdd_ll_process_radio_stats(pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001090 linkLayerStatsResults->moreResultToFollow,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001091 linkLayerStatsResults->results,
1092 linkLayerStatsResults->num_radio,
1093 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001094
1095 spin_lock(&context->context_lock);
1096 if (!linkLayerStatsResults->moreResultToFollow)
1097 context->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
1098 spin_unlock(&context->context_lock);
1099
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001100 } else if (linkLayerStatsResults->paramId &
1101 WMI_LINK_STATS_IFACE) {
1102 hdd_ll_process_iface_stats(pAdapter,
1103 linkLayerStatsResults->results,
1104 linkLayerStatsResults->num_peers,
1105 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106
1107 spin_lock(&context->context_lock);
Srinivas Dasari6946a792015-09-28 15:01:49 +05301108 /* Firmware doesn't send peerstats event if no peers are
1109 * connected. HDD should not wait for any peerstats in
1110 * this case and return the status to middleware after
1111 * receiving iface stats
1112 */
1113 if (!linkLayerStatsResults->num_peers)
1114 context->request_bitmap &=
1115 ~(WMI_LINK_STATS_ALL_PEER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001116 context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
1117 spin_unlock(&context->context_lock);
1118
1119 } else if (linkLayerStatsResults->
1120 paramId & WMI_LINK_STATS_ALL_PEER) {
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001121 hdd_ll_process_peer_stats(pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001122 linkLayerStatsResults->moreResultToFollow,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001123 linkLayerStatsResults->results,
1124 linkLayerStatsResults->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001125
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:
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001144 hdd_warn("invalid event type %d", indType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145 break;
1146 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001147}
1148
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301149void hdd_lost_link_info_cb(void *context,
1150 struct sir_lost_link_info *lost_link_info)
1151{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001152 struct hdd_context *hdd_ctx = (struct hdd_context *)context;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301153 int status;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001154 struct hdd_adapter *adapter;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301155
1156 status = wlan_hdd_validate_context(hdd_ctx);
1157 if (0 != status)
1158 return;
1159
1160 if (NULL == lost_link_info) {
1161 hdd_err("lost_link_info is NULL");
1162 return;
1163 }
1164
1165 adapter = hdd_get_adapter_by_vdev(hdd_ctx, lost_link_info->vdev_id);
1166 if (NULL == adapter) {
1167 hdd_err("invalid adapter");
1168 return;
1169 }
1170
1171 adapter->rssi_on_disconnect = lost_link_info->rssi;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001172 hdd_debug("rssi on disconnect %d", adapter->rssi_on_disconnect);
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301173}
1174
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001175const struct
1176nla_policy
1177 qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1178 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1179 .type = NLA_U32},
1180 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1181 .type = NLA_U32},
1182};
1183
1184/**
1185 * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1186 * @wiphy: Pointer to wiphy
1187 * @wdev: Pointer to wdev
1188 * @data: Pointer to data
1189 * @data_len: Data length
1190 *
1191 * Return: int
1192 */
1193static int
1194__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1195 struct wireless_dev *wdev,
1196 const void *data,
1197 int data_len)
1198{
1199 int status;
1200 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
1201 tSirLLStatsSetReq LinkLayerStatsSetReq;
1202 struct net_device *dev = wdev->netdev;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001203 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001204 struct hdd_context *pHddCtx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001205
Jeff Johnson1f61b612016-02-12 16:28:33 -08001206 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301207
Anurag Chouhan6d760662016-02-20 16:05:43 +05301208 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001209 hdd_err("Command not allowed in FTM mode");
1210 return -EPERM;
1211 }
1212
1213 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301214 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001215 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001216
Dustin Brown3fb15042017-08-15 15:54:49 -07001217 if (hdd_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1218 (struct nlattr *)data, data_len,
1219 qca_wlan_vendor_ll_set_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001220 hdd_err("maximum attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001221 return -EINVAL;
1222 }
1223
1224 if (!tb_vendor
1225 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001226 hdd_err("MPDU size Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001227 return -EINVAL;
1228 }
1229
1230 if (!tb_vendor
1231 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001232 hdd_err("Stats Gathering Not Present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001233 return -EINVAL;
1234 }
1235
1236 /* Shall take the request Id if the Upper layers pass. 1 For now. */
1237 LinkLayerStatsSetReq.reqId = 1;
1238
1239 LinkLayerStatsSetReq.mpduSizeThreshold =
1240 nla_get_u32(tb_vendor
1241 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1242
1243 LinkLayerStatsSetReq.aggressiveStatisticsGathering =
1244 nla_get_u32(tb_vendor
1245 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1246
1247 LinkLayerStatsSetReq.staId = pAdapter->sessionId;
1248
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001249 hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301250 LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId,
1251 LinkLayerStatsSetReq.mpduSizeThreshold,
1252 LinkLayerStatsSetReq.aggressiveStatisticsGathering);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301254 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(pHddCtx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001255 &LinkLayerStatsSetReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001256 hdd_err("sme_ll_stats_set_req Failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257 return -EINVAL;
1258 }
1259
1260 pAdapter->isLinkLayerStatsSet = 1;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301261 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001262 return 0;
1263}
1264
1265/**
1266 * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1267 * @wiphy: Pointer to wiphy
1268 * @wdev: Pointer to wdev
1269 * @data: Pointer to data
1270 * @data_len: Data length
1271 *
1272 * Return: 0 if success, non-zero for failure
1273 */
1274int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1275 struct wireless_dev *wdev,
1276 const void *data,
1277 int data_len)
1278{
1279 int ret = 0;
1280
1281 cds_ssr_protect(__func__);
1282 ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
1283 cds_ssr_unprotect(__func__);
1284
1285 return ret;
1286}
1287
1288const struct
1289nla_policy
1290 qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1291 /* Unsigned 32bit value provided by the caller issuing the GET stats
1292 * command. When reporting
1293 * the stats results, the driver uses the same value to indicate
1294 * which GET request the results
1295 * correspond to.
1296 */
1297 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1298
1299 /* Unsigned 32bit value . bit mask to identify what statistics are
Jeff Johnson8bb78c32017-01-12 08:42:50 -08001300 * requested for retrieval
1301 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001302 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1303};
1304
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001305static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001306 tSirLLStatsGetReq *req)
1307{
1308 unsigned long rc;
1309 struct hdd_ll_stats_context *context;
1310
1311 context = &ll_stats_context;
1312 spin_lock(&context->context_lock);
1313 context->request_id = req->reqId;
1314 context->request_bitmap = req->paramIdMask;
1315 INIT_COMPLETION(context->response_event);
1316 spin_unlock(&context->context_lock);
1317
1318 if (QDF_STATUS_SUCCESS !=
1319 sme_ll_stats_get_req(hdd_ctx->hHal, req)) {
1320 hdd_err("sme_ll_stats_get_req Failed");
1321 return -EINVAL;
1322 }
1323
1324 rc = wait_for_completion_timeout(&context->response_event,
1325 msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
1326 if (!rc) {
1327 hdd_err("Target response timed out request id %d request bitmap 0x%x",
1328 context->request_id, context->request_bitmap);
1329 return -ETIMEDOUT;
1330 }
1331
1332 return 0;
1333}
1334
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001335int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001336 uint32_t req_mask)
1337{
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001338 int ret;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001339 tSirLLStatsGetReq get_req;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001340 struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001341 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001342
1343 ENTER();
1344
1345 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1346 hdd_warn("Command not allowed in FTM mode");
1347 return -EPERM;
1348 }
1349
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001350 ret = wlan_hdd_validate_context(hdd_ctx);
1351 if (0 != ret)
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001352 return -EINVAL;
1353
1354 if (hddstactx->hdd_ReassocScenario) {
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001355 hdd_err("Roaming in progress, cannot process the request");
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001356 return -EBUSY;
1357 }
1358
1359 if (!adapter->isLinkLayerStatsSet)
1360 hdd_info("isLinkLayerStatsSet: %d; STATs will be all zero",
1361 adapter->isLinkLayerStatsSet);
1362
1363 get_req.reqId = req_id;
1364 get_req.paramIdMask = req_mask;
1365 get_req.staId = adapter->sessionId;
1366
1367 rtnl_lock();
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001368 ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001369 rtnl_unlock();
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001370 if (0 != ret)
1371 hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
1372 req_id, req_mask, adapter->sessionId);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001373
1374 EXIT();
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001375 return ret;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001376
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001377}
1378
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001379/**
1380 * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1381 * @wiphy: Pointer to wiphy
1382 * @wdev: Pointer to wdev
1383 * @data: Pointer to data
1384 * @data_len: Data length
1385 *
1386 * Return: int
1387 */
1388static int
1389__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1390 struct wireless_dev *wdev,
1391 const void *data,
1392 int data_len)
1393{
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001394 int ret;
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001395 struct hdd_context *pHddCtx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001396 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1397 tSirLLStatsGetReq LinkLayerStatsGetReq;
1398 struct net_device *dev = wdev->netdev;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001399 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001400 struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401
Kapil Guptabf4943c2016-10-13 12:15:39 +05301402 /* ENTER() intentionally not used in a frequently invoked API */
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301403
Anurag Chouhan6d760662016-02-20 16:05:43 +05301404 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405 hdd_err("Command not allowed in FTM mode");
1406 return -EPERM;
1407 }
1408
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001409 ret = wlan_hdd_validate_context(pHddCtx);
1410 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001412
1413 if (!pAdapter->isLinkLayerStatsSet) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001414 hdd_warn("isLinkLayerStatsSet: %d",
1415 pAdapter->isLinkLayerStatsSet);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001416 return -EINVAL;
1417 }
1418
Anurag Chouhan22520002016-09-03 16:20:32 +05301419 if (hddstactx->hdd_ReassocScenario) {
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001420 hdd_err("Roaming in progress, cannot process the request");
Anurag Chouhan22520002016-09-03 16:20:32 +05301421 return -EBUSY;
1422 }
1423
Dustin Brown3fb15042017-08-15 15:54:49 -07001424 if (hdd_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1425 (struct nlattr *)data, data_len,
1426 qca_wlan_vendor_ll_get_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001427 hdd_err("max attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001428 return -EINVAL;
1429 }
1430
1431 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001432 hdd_err("Request Id Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001433 return -EINVAL;
1434 }
1435
1436 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001437 hdd_err("Req Mask Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438 return -EINVAL;
1439 }
1440
1441 LinkLayerStatsGetReq.reqId =
1442 nla_get_u32(tb_vendor
1443 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1444 LinkLayerStatsGetReq.paramIdMask =
1445 nla_get_u32(tb_vendor
1446 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1447
1448 LinkLayerStatsGetReq.staId = pAdapter->sessionId;
1449
yeshwanth sriram guntuka08e995b2017-04-26 12:32:12 +05301450 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1451 hdd_err("invalid session id: %d", pAdapter->sessionId);
1452 return -EINVAL;
1453 }
1454
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001455 ret = wlan_hdd_send_ll_stats_req(pHddCtx, &LinkLayerStatsGetReq);
1456 if (0 != ret) {
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001457 hdd_err("Failed to send LL stats request (id:%u)",
1458 LinkLayerStatsGetReq.reqId);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001459 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001460 }
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001461
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301462 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001463 return 0;
1464}
1465
1466/**
1467 * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1468 * @wiphy: Pointer to wiphy
1469 * @wdev: Pointer to wdev
1470 * @data: Pointer to data
1471 * @data_len: Data length
1472 *
1473 * Return: 0 if success, non-zero for failure
1474 */
1475int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1476 struct wireless_dev *wdev,
1477 const void *data,
1478 int data_len)
1479{
1480 int ret = 0;
1481
1482 cds_ssr_protect(__func__);
1483 ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1484 cds_ssr_unprotect(__func__);
1485
1486 return ret;
1487}
1488
1489const struct
1490nla_policy
1491 qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1492 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1493 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1494 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1495 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1496};
1497
1498/**
1499 * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1500 * @wiphy: Pointer to wiphy
1501 * @wdev: Pointer to wdev
1502 * @data: Pointer to data
1503 * @data_len: Data length
1504 *
1505 * Return: int
1506 */
1507static int
1508__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1509 struct wireless_dev *wdev,
1510 const void *data,
1511 int data_len)
1512{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001513 struct hdd_context *pHddCtx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001514 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1515 tSirLLStatsClearReq LinkLayerStatsClearReq;
1516 struct net_device *dev = wdev->netdev;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001517 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001518 u32 statsClearReqMask;
1519 u8 stopReq;
1520 int status;
1521 struct sk_buff *temp_skbuff;
1522
Jeff Johnson1f61b612016-02-12 16:28:33 -08001523 ENTER_DEV(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301524
Anurag Chouhan6d760662016-02-20 16:05:43 +05301525 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001526 hdd_err("Command not allowed in FTM mode");
1527 return -EPERM;
1528 }
1529
1530 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301531 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001532 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001533
1534 if (!pAdapter->isLinkLayerStatsSet) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001535 hdd_warn("isLinkLayerStatsSet : %d",
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001536 pAdapter->isLinkLayerStatsSet);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001537 return -EINVAL;
1538 }
1539
Dustin Brown3fb15042017-08-15 15:54:49 -07001540 if (hdd_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1541 (struct nlattr *)data, data_len,
1542 qca_wlan_vendor_ll_clr_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001543 hdd_err("STATS_CLR_MAX is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001544 return -EINVAL;
1545 }
1546
1547 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1548 !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001549 hdd_err("Error in LL_STATS CLR CONFIG PARA");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001550 return -EINVAL;
1551 }
1552
1553 statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1554 nla_get_u32(tb_vendor
1555 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1556
1557 stopReq = LinkLayerStatsClearReq.stopReq =
1558 nla_get_u8(tb_vendor
1559 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1560
1561 /*
1562 * Shall take the request Id if the Upper layers pass. 1 For now.
1563 */
1564 LinkLayerStatsClearReq.reqId = 1;
1565
1566 LinkLayerStatsClearReq.staId = pAdapter->sessionId;
1567
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001568 hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301569 LinkLayerStatsClearReq.reqId,
1570 LinkLayerStatsClearReq.staId,
1571 LinkLayerStatsClearReq.statsClearReqMask,
1572 LinkLayerStatsClearReq.stopReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001573
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301574 if (QDF_STATUS_SUCCESS == sme_ll_stats_clear_req(pHddCtx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001575 &LinkLayerStatsClearReq)) {
1576 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1577 2 *
1578 sizeof(u32) +
1579 2 *
1580 NLMSG_HDRLEN);
1581 if (temp_skbuff != NULL) {
1582 if (nla_put_u32(temp_skbuff,
1583 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1584 statsClearReqMask) ||
1585 nla_put_u32(temp_skbuff,
1586 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1587 stopReq)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001588 hdd_err("LL_STATS_CLR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001589 kfree_skb(temp_skbuff);
1590 return -EINVAL;
1591 }
1592
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001593 /* If the ask is to stop the stats collection
1594 * as part of clear (stopReq = 1), ensure
1595 * that no further requests of get go to the
1596 * firmware by having isLinkLayerStatsSet set
1597 * to 0. However it the stopReq as part of
1598 * the clear request is 0, the request to get
1599 * the statistics are honoured as in this case
1600 * the firmware is just asked to clear the
1601 * statistics.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001602 */
1603 if (stopReq == 1)
1604 pAdapter->isLinkLayerStatsSet = 0;
1605
1606 return cfg80211_vendor_cmd_reply(temp_skbuff);
1607 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301608 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001609 return -ENOMEM;
1610 }
1611
1612 return -EINVAL;
1613}
1614
1615/**
1616 * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1617 * @wiphy: Pointer to wiphy
1618 * @wdev: Pointer to wdev
1619 * @data: Pointer to data
1620 * @data_len: Data length
1621 *
1622 * Return: 0 if success, non-zero for failure
1623 */
1624int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1625 struct wireless_dev *wdev,
1626 const void *data,
1627 int data_len)
1628{
1629 int ret = 0;
1630
1631 cds_ssr_protect(__func__);
1632 ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
1633 cds_ssr_unprotect(__func__);
1634
1635 return ret;
1636}
1637
Zhang Qianca38fb12016-12-23 11:10:48 +08001638/**
1639 * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
1640 * @wifi_peer_info: peer information
1641 * @vendor_event: buffer for vendor event
1642 *
1643 * Return: 0 success
1644 */
1645static inline int
1646hdd_populate_per_peer_ps_info(tSirWifiPeerInfo *wifi_peer_info,
1647 struct sk_buff *vendor_event)
1648{
1649 if (!wifi_peer_info) {
1650 hdd_err("Invalid pointer to peer info.");
1651 return -EINVAL;
1652 }
1653
1654 if (nla_put_u32(vendor_event,
1655 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
1656 wifi_peer_info->power_saving) ||
1657 nla_put(vendor_event,
1658 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
1659 QDF_MAC_ADDR_SIZE, &wifi_peer_info->peerMacAddress)) {
1660 hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
1661 return -EINVAL;
1662 }
1663 return 0;
1664}
1665
1666/**
1667 * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
1668 * @data: stats for peer STA
1669 * @vendor_event: buffer for vendor event
1670 *
1671 * Return: 0 success
1672 */
1673static int hdd_populate_wifi_peer_ps_info(tSirWifiPeerStat *data,
1674 struct sk_buff *vendor_event)
1675{
1676 uint32_t peer_num, i;
1677 tSirWifiPeerInfo *wifi_peer_info;
1678 struct nlattr *peer_info, *peers;
1679
1680 if (!data) {
1681 hdd_err("Invalid pointer to Wifi peer stat.");
1682 return -EINVAL;
1683 }
1684
1685 peer_num = data->numPeers;
1686 if (peer_num == 0) {
1687 hdd_err("Peer number is zero.");
1688 return -EINVAL;
1689 }
1690
1691 if (nla_put_u32(vendor_event,
1692 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
1693 peer_num)) {
1694 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1695 return -EINVAL;
1696 }
1697
1698 peer_info = nla_nest_start(vendor_event,
1699 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
1700 if (peer_info == NULL) {
1701 hdd_err("nla_nest_start failed");
1702 return -EINVAL;
1703 }
1704
1705 for (i = 0; i < peer_num; i++) {
1706 wifi_peer_info = &data->peerInfo[i];
1707 peers = nla_nest_start(vendor_event, i);
1708
1709 if (peers == NULL) {
1710 hdd_err("nla_nest_start failed");
1711 return -EINVAL;
1712 }
1713
1714 if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
1715 return -EINVAL;
1716
1717 nla_nest_end(vendor_event, peers);
1718 }
1719 nla_nest_end(vendor_event, peer_info);
1720
1721 return 0;
1722}
1723
1724/**
1725 * hdd_populate_tx_failure_info() - populate TX failure info
1726 * @tx_fail: TX failure info
1727 * @skb: buffer for vendor event
1728 *
1729 * Return: 0 Success
1730 */
1731static inline int
1732hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
1733 struct sk_buff *skb)
1734{
1735 int status = 0;
1736
1737 if (tx_fail == NULL || skb == NULL)
1738 return -EINVAL;
1739
1740 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
1741 tx_fail->tid) ||
1742 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
1743 tx_fail->msdu_num) ||
1744 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
1745 tx_fail->status)) {
1746 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1747 status = -EINVAL;
1748 }
1749
1750 return status;
1751}
1752
1753/**
Zhang Qian4ead8f02017-03-27 14:21:47 +08001754 * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event
1755 * @info: cca info array for all channels
1756 * @vendor_event: vendor event buffer
1757 *
1758 * Return: 0 Success, EINVAL failure
1759 */
1760static int
1761hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca,
1762 struct sk_buff *vendor_event)
1763{
1764 /* There might be no CCA info for a channel */
1765 if (!cca)
1766 return 0;
1767
1768 if (nla_put_u32(vendor_event,
1769 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
1770 cca->idle_time) ||
1771 nla_put_u32(vendor_event,
1772 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
1773 cca->tx_time) ||
1774 nla_put_u32(vendor_event,
1775 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
1776 cca->rx_in_bss_time) ||
1777 nla_put_u32(vendor_event,
1778 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
1779 cca->rx_out_bss_time) ||
1780 nla_put_u32(vendor_event,
1781 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
1782 cca->rx_busy_time) ||
1783 nla_put_u32(vendor_event,
1784 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
1785 cca->rx_in_bad_cond_time) ||
1786 nla_put_u32(vendor_event,
1787 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
1788 cca->tx_in_bad_cond_time) ||
1789 nla_put_u32(vendor_event,
1790 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
1791 cca->wlan_not_avail_time) ||
1792 nla_put_u32(vendor_event,
1793 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
1794 cca->vdev_id)) {
1795 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1796 return -EINVAL;
1797 }
1798 return 0;
1799}
1800
1801/**
1802 * hdd_populate_wifi_signal_info - put chain signal info
1803 * @info: RF chain signal info
1804 * @skb: vendor event buffer
1805 *
1806 * Return: 0 Success, EINVAL failure
1807 */
1808static int
1809hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal,
1810 struct sk_buff *skb)
1811{
Zhang Qian303ebe92017-05-18 13:59:07 +08001812 uint32_t i, chain_count;
Zhang Qian4ead8f02017-03-27 14:21:47 +08001813 struct nlattr *chains, *att;
1814
1815 /* There might be no signal info for a peer */
1816 if (!peer_signal)
1817 return 0;
1818
Zhang Qian303ebe92017-05-18 13:59:07 +08001819 chain_count = peer_signal->num_chain < WIFI_MAX_CHAINS ?
1820 peer_signal->num_chain : WIFI_MAX_CHAINS;
Zhang Qian4ead8f02017-03-27 14:21:47 +08001821 if (nla_put_u32(skb,
1822 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
Zhang Qian303ebe92017-05-18 13:59:07 +08001823 chain_count)) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001824 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1825 return -EINVAL;
1826 }
1827
1828 att = nla_nest_start(skb,
1829 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL);
1830 if (!att) {
1831 hdd_err("nla_nest_start failed");
1832 return -EINVAL;
1833 }
1834
Zhang Qian303ebe92017-05-18 13:59:07 +08001835 for (i = 0; i < chain_count; i++) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001836 chains = nla_nest_start(skb, i);
1837
1838 if (!chains) {
1839 hdd_err("nla_nest_start failed");
1840 return -EINVAL;
1841 }
1842
Zhang Qian303ebe92017-05-18 13:59:07 +08001843 hdd_debug("SNR=%d, NF=%d, Rx=%d, Tx=%d",
1844 peer_signal->per_ant_snr[i],
1845 peer_signal->nf[i],
1846 peer_signal->per_ant_rx_mpdus[i],
1847 peer_signal->per_ant_tx_mpdus[i]);
Zhang Qian4ead8f02017-03-27 14:21:47 +08001848 if (nla_put_u32(skb,
1849 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
1850 peer_signal->per_ant_snr[i]) ||
1851 nla_put_u32(skb,
1852 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
Zhang Qian303ebe92017-05-18 13:59:07 +08001853 peer_signal->nf[i]) ||
1854 nla_put_u32(skb,
1855 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
1856 peer_signal->per_ant_rx_mpdus[i]) ||
1857 nla_put_u32(skb,
1858 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1859 peer_signal->per_ant_tx_mpdus[i])) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001860 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1861 return -EINVAL;
1862 }
1863 nla_nest_end(skb, chains);
1864 }
1865 nla_nest_end(skb, att);
1866
1867 return 0;
1868}
1869
1870/**
1871 * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info
1872 * @info: tx info
1873 * @skb: vendor event buffer
1874 *
1875 * Return: 0 Success, EINVAL failure
1876 */
1877static int
1878hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats,
1879 struct sk_buff *skb)
1880{
1881 uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay;
1882
1883 /* There might be no TX info for a peer */
1884 if (!tx_stats)
1885 return 0;
1886
1887 agg_size = tx_stats->mpdu_aggr_size;
1888 succ_mcs = tx_stats->success_mcs;
1889 fail_mcs = tx_stats->fail_mcs;
1890 delay = tx_stats->delay;
1891
1892 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
1893 tx_stats->msdus) ||
1894 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1895 tx_stats->mpdus) ||
1896 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
1897 tx_stats->ppdus) ||
1898 nla_put_u32(skb,
1899 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
1900 tx_stats->bytes) ||
1901 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
1902 tx_stats->drops) ||
1903 nla_put_u32(skb,
1904 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
1905 tx_stats->drop_bytes) ||
1906 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
1907 tx_stats->retries) ||
1908 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
1909 tx_stats->failed) ||
1910 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
1911 tx_stats->aggr_len) ||
1912 nla_put_u32(skb,
1913 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
1914 tx_stats->success_mcs_len) ||
1915 nla_put_u32(skb,
1916 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
1917 tx_stats->fail_mcs_len) ||
1918 nla_put_u32(skb,
1919 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
1920 tx_stats->delay_len))
1921 goto put_attr_fail;
1922
1923 if (agg_size) {
1924 if (nla_put(skb,
1925 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
1926 tx_stats->aggr_len, agg_size))
1927 goto put_attr_fail;
1928 }
1929
1930 if (succ_mcs) {
1931 if (nla_put(skb,
1932 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
1933 tx_stats->success_mcs_len, succ_mcs))
1934 goto put_attr_fail;
1935 }
1936
1937 if (fail_mcs) {
1938 if (nla_put(skb,
1939 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
1940 tx_stats->fail_mcs_len, fail_mcs))
1941 goto put_attr_fail;
1942 }
1943
1944 if (delay) {
1945 if (nla_put(skb,
1946 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
1947 tx_stats->delay_len, delay))
1948 goto put_attr_fail;
1949 }
1950 return 0;
1951
1952put_attr_fail:
1953 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1954 return -EINVAL;
1955}
1956
1957/**
1958 * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info
1959 * @info: rx info
1960 * @skb: vendor event buffer
1961 *
1962 * Return: 0 Success, EINVAL failure
1963 */
1964static int
1965hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats,
1966 struct sk_buff *skb)
1967{
1968 uint32_t *mcs, *aggr;
1969
1970 /* There might be no RX info for a peer */
1971 if (!rx_stats)
1972 return 0;
1973
1974 aggr = rx_stats->mpdu_aggr;
1975 mcs = rx_stats->mcs;
1976
1977 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
1978 rx_stats->mpdus) ||
1979 nla_put_u32(skb,
1980 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
1981 rx_stats->bytes) ||
1982 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
1983 rx_stats->ppdus) ||
1984 nla_put_u32(skb,
1985 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
1986 rx_stats->ppdu_bytes) ||
1987 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
1988 rx_stats->mpdu_lost) ||
1989 nla_put_u32(skb,
1990 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
1991 rx_stats->mpdu_retry) ||
1992 nla_put_u32(skb,
1993 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
1994 rx_stats->mpdu_dup) ||
1995 nla_put_u32(skb,
1996 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
1997 rx_stats->mpdu_discard) ||
1998 nla_put_u32(skb,
1999 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
2000 rx_stats->aggr_len) ||
2001 nla_put_u32(skb,
2002 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
2003 rx_stats->mcs_len))
2004 goto put_attr_fail;
2005
2006 if (aggr) {
2007 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
2008 rx_stats->aggr_len, aggr))
2009 goto put_attr_fail;
2010 }
2011
2012 if (mcs) {
2013 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
2014 rx_stats->mcs_len, mcs))
2015 goto put_attr_fail;
2016 }
2017
2018 return 0;
2019
2020put_attr_fail:
2021 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2022 return -EINVAL;
2023}
2024
2025/**
2026 * hdd_populate_wifi_wmm_ac_info() - put WMM AC info
2027 * @info: per AC stats
2028 * @skb: vendor event buffer
2029 *
2030 * Return: 0 Success, EINVAL failure
2031 */
2032static int
2033hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats,
2034 struct sk_buff *skb)
2035{
2036 struct nlattr *wmm;
2037
2038 wmm = nla_nest_start(skb, ac_stats->type);
2039 if (!wmm)
2040 goto nest_start_fail;
2041
2042 if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) ||
2043 hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb))
2044 goto put_attr_fail;
2045
2046 nla_nest_end(skb, wmm);
2047 return 0;
2048
2049nest_start_fail:
2050 hdd_err("nla_nest_start failed");
2051 return -EINVAL;
2052
2053put_attr_fail:
2054 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2055 return -EINVAL;
2056}
2057
2058/**
2059 * hdd_populate_wifi_ll_ext_peer_info() - put per peer info
2060 * @info: peer stats
2061 * @skb: vendor event buffer
2062 *
2063 * Return: 0 Success, EINVAL failure
2064 */
2065static int
2066hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers,
2067 struct sk_buff *skb)
2068{
2069 uint32_t i;
2070 struct nlattr *wmm_ac;
2071
2072 if (nla_put_u32(skb,
2073 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
2074 peers->peer_id) ||
2075 nla_put_u32(skb,
2076 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
2077 peers->vdev_id) ||
2078 nla_put_u32(skb,
2079 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
2080 peers->sta_ps_inds) ||
2081 nla_put_u32(skb,
2082 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
2083 peers->sta_ps_durs) ||
2084 nla_put_u32(skb,
2085 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
2086 peers->rx_probe_reqs) ||
2087 nla_put_u32(skb,
2088 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
2089 peers->rx_oth_mgmts) ||
2090 nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
2091 QDF_MAC_ADDR_SIZE, peers->mac_address) ||
2092 hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) {
2093 hdd_err("put peer signal attr failed");
2094 return -EINVAL;
2095 }
2096
2097 wmm_ac = nla_nest_start(skb,
2098 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS);
2099 if (!wmm_ac) {
2100 hdd_err("nla_nest_start failed");
2101 return -EINVAL;
2102 }
2103
2104 for (i = 0; i < WLAN_MAX_AC; i++) {
2105 if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) {
2106 hdd_err("put WMM AC attr failed");
2107 return -EINVAL;
2108 }
2109 }
2110
2111 nla_nest_end(skb, wmm_ac);
2112 return 0;
2113}
2114
2115/**
2116 * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats
2117 * @info: link layer stats
2118 * @skb: vendor event buffer
2119 *
2120 * Return: 0 Success, EINVAL failure
2121 */
2122static int
2123hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats,
2124 struct sk_buff *skb)
2125{
2126 uint32_t i;
2127 struct nlattr *peer, *peer_info, *channels, *channel_info;
2128
2129 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
2130 stats->trigger_cond_id) ||
2131 nla_put_u32(skb,
2132 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
2133 stats->cca_chgd_bitmap) ||
2134 nla_put_u32(skb,
2135 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
2136 stats->sig_chgd_bitmap) ||
2137 nla_put_u32(skb,
2138 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
2139 stats->tx_chgd_bitmap) ||
2140 nla_put_u32(skb,
2141 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
2142 stats->rx_chgd_bitmap) ||
2143 nla_put_u32(skb,
2144 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
2145 stats->channel_num) ||
2146 nla_put_u32(skb,
2147 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
2148 stats->peer_num)) {
2149 goto put_attr_fail;
2150 }
2151
2152 channels = nla_nest_start(skb,
2153 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS);
2154 if (!channels) {
2155 hdd_err("nla_nest_start failed");
2156 return -EINVAL;
2157 }
2158
2159 for (i = 0; i < stats->channel_num; i++) {
2160 channel_info = nla_nest_start(skb, i);
2161 if (!channel_info) {
2162 hdd_err("nla_nest_start failed");
2163 return -EINVAL;
2164 }
2165
2166 if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb))
2167 goto put_attr_fail;
2168 nla_nest_end(skb, channel_info);
2169 }
2170 nla_nest_end(skb, channels);
2171
2172 peer_info = nla_nest_start(skb,
2173 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER);
2174 if (!peer_info) {
2175 hdd_err("nla_nest_start failed");
2176 return -EINVAL;
2177 }
2178
2179 for (i = 0; i < stats->peer_num; i++) {
2180 peer = nla_nest_start(skb, i);
2181 if (!peer) {
2182 hdd_err("nla_nest_start failed");
2183 return -EINVAL;
2184 }
2185
2186 if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i],
2187 skb))
2188 goto put_attr_fail;
2189 nla_nest_end(skb, peer);
2190 }
2191
2192 nla_nest_end(skb, peer_info);
2193 return 0;
2194
2195put_attr_fail:
2196 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2197 return -EINVAL;
2198}
2199
2200/**
Zhang Qianca38fb12016-12-23 11:10:48 +08002201 * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
2202 * @ctx: HDD context
2203 * @rsp: msg from FW
2204 *
2205 * This function is an extension of
2206 * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
2207 * monitoring parameters offloaded to NL data and send the same to the
2208 * kernel/upper layers.
2209 *
2210 * Return: None
2211 */
2212void wlan_hdd_cfg80211_link_layer_stats_ext_callback(tHddHandle ctx,
2213 tSirLLStatsResults *rsp)
2214{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002215 struct hdd_context *hdd_ctx;
Zhang Qianca38fb12016-12-23 11:10:48 +08002216 struct sk_buff *skb = NULL;
2217 uint32_t param_id, index;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07002218 struct hdd_adapter *adapter = NULL;
Zhang Qianca38fb12016-12-23 11:10:48 +08002219 tSirLLStatsResults *linkLayer_stats_results;
2220 tSirWifiPeerStat *peer_stats;
2221 uint8_t *results;
2222 int status;
2223
2224 ENTER();
2225
2226 if (!ctx) {
2227 hdd_err("Invalid HDD context.");
2228 return;
2229 }
2230
2231 if (!rsp) {
2232 hdd_err("Invalid result.");
2233 return;
2234 }
2235
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002236 hdd_ctx = (struct hdd_context *)ctx;
Zhang Qianca38fb12016-12-23 11:10:48 +08002237 linkLayer_stats_results = rsp;
2238
2239 status = wlan_hdd_validate_context(hdd_ctx);
2240 if (0 != status)
2241 return;
2242
2243 adapter = hdd_get_adapter_by_vdev(hdd_ctx,
2244 linkLayer_stats_results->ifaceId);
2245
Zhang Qian4ead8f02017-03-27 14:21:47 +08002246 if (!adapter) {
Zhang Qianca38fb12016-12-23 11:10:48 +08002247 hdd_err("vdev_id %d does not exist with host.",
2248 linkLayer_stats_results->ifaceId);
2249 return;
2250 }
2251
2252 index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
2253 skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2254 NULL, LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
2255 index, GFP_KERNEL);
2256 if (!skb) {
2257 hdd_err("cfg80211_vendor_event_alloc failed.");
2258 return;
2259 }
2260
2261 results = linkLayer_stats_results->results;
2262 param_id = linkLayer_stats_results->paramId;
2263 hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %p",
2264 linkLayer_stats_results->paramId,
2265 linkLayer_stats_results->ifaceId,
2266 linkLayer_stats_results->results);
2267 if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
2268 peer_stats = (tSirWifiPeerStat *)results;
2269 status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
2270 } else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
2271 struct sir_wifi_iface_tx_fail *tx_fail;
2272
2273 tx_fail = (struct sir_wifi_iface_tx_fail *)results;
2274 status = hdd_populate_tx_failure_info(tx_fail, skb);
2275 } else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
2276 hdd_info("MAC counters stats");
Zhang Qian4ead8f02017-03-27 14:21:47 +08002277 status = hdd_populate_wifi_ll_ext_stats(
2278 (struct sir_wifi_ll_ext_stats *)
2279 rsp->results, skb);
Zhang Qianca38fb12016-12-23 11:10:48 +08002280 } else {
2281 hdd_info("Unknown link layer stats");
2282 status = -EINVAL;
2283 }
2284
2285 if (status == 0)
2286 cfg80211_vendor_event(skb, GFP_KERNEL);
2287 else
2288 kfree_skb(skb);
2289 EXIT();
2290}
2291
Zhang Qian4ead8f02017-03-27 14:21:47 +08002292static const struct nla_policy
2293qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = {
2294 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = {
2295 .type = NLA_U32
2296 },
2297 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = {
2298 .type = NLA_U32
2299 },
2300 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = {
2301 .type = NLA_U32
2302 },
2303 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = {
2304 .type = NLA_U32
2305 },
2306 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = {
2307 .type = NLA_U32
2308 },
2309 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = {
2310 .type = NLA_U32
2311 },
2312 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = {
2313 .type = NLA_U32
2314 },
2315 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = {
2316 .type = NLA_U32
2317 },
2318 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = {
2319 .type = NLA_U32
2320 },
2321 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = {
2322 .type = NLA_U32
2323 },
2324 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = {
2325 .type = NLA_U32
2326 },
2327 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = {
2328 .type = NLA_U32
2329 },
2330 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = {
2331 .type = NLA_U32
2332 },
2333 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = {
2334 .type = NLA_U32
2335 },
2336 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = {
2337 .type = NLA_U32
2338 },
2339 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = {
2340 .type = NLA_U32
2341 },
2342 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = {
2343 .type = NLA_U32
2344 },
2345 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = {
2346 .type = NLA_U32
2347 },
2348 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = {
2349 .type = NLA_U32
2350 },
2351 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = {
2352 .type = NLA_U32
2353 },
2354 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = {
2355 .type = NLA_U32
2356 },
2357 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = {
2358 .type = NLA_U32
2359 },
2360 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = {
2361 .type = NLA_U32
2362 },
2363 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = {
2364 .type = NLA_U32
2365 },
2366 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = {
2367 .type = NLA_U32
2368 },
2369 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = {
2370 .type = NLA_U32
2371 },
2372 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = {
2373 .type = NLA_U32
2374 },
2375 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = {
2376 .type = NLA_U32
2377 },
2378 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = {
2379 .type = NLA_U32
2380 },
2381 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = {
2382 .type = NLA_U32
2383 },
2384 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = {
2385 .type = NLA_U32
2386 },
2387 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = {
2388 .type = NLA_U32
2389 },
2390 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = {
2391 .type = NLA_U32
2392 },
2393 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = {
2394 .type = NLA_U32
2395 },
2396 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = {
2397 .type = NLA_U32
2398 },
2399 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = {
2400 .type = NLA_U32
2401 },
2402 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = {
2403 .type = NLA_U32
2404 },
2405 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = {
2406 .type = NLA_U32
2407 },
2408 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = {
2409 .type = NLA_U32
2410 },
2411 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = {
2412 .type = NLA_U32
2413 },
2414 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = {
2415 .type = NLA_U32
2416 },
2417 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = {
2418 .type = NLA_U32
2419 },
2420 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = {
2421 .type = NLA_U32
2422 },
2423 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = {
2424 .type = NLA_U32
2425 },
2426};
2427
2428/**
2429 * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2430 * @wiphy: wiphy handle
2431 * @wdev: wdev handle
2432 * @data: user layer input
2433 * @data_len: length of user layer input
2434 *
2435 * this function is called in ssr protected environment.
2436 *
2437 * return: 0 success, none zero for failure
2438 */
2439static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2440 struct wireless_dev *wdev,
2441 const void *data,
2442 int data_len)
2443{
2444 int status;
2445 uint32_t period;
2446 struct net_device *dev = wdev->netdev;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07002447 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002448 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Zhang Qian4ead8f02017-03-27 14:21:47 +08002449 struct sir_ll_ext_stats_threshold thresh = {0,};
2450 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1];
2451
2452 ENTER_DEV(dev);
2453
2454 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2455 hdd_warn("command not allowed in ftm mode");
2456 return -EPERM;
2457 }
2458
2459 status = wlan_hdd_validate_context(hdd_ctx);
2460 if (0 != status)
2461 return -EPERM;
2462
Dustin Brown3fb15042017-08-15 15:54:49 -07002463 if (hdd_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX,
2464 (struct nlattr *)data, data_len,
2465 qca_wlan_vendor_ll_ext_policy)) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08002466 hdd_err("maximum attribute not present");
2467 return -EPERM;
2468 }
2469
2470 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) {
2471 period = nla_get_u32(tb[
2472 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]);
2473
2474 if (period != 0 && period < LL_STATS_MIN_PERIOD)
2475 period = LL_STATS_MIN_PERIOD;
2476
2477 /*
2478 * Only enable/disbale counters.
2479 * Keep the last threshold settings.
2480 */
2481 goto set_period;
2482 }
2483
2484 /* global thresh is not enabled */
2485 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) {
2486 thresh.global = false;
2487 hdd_warn("global thresh is not set");
2488 } else {
2489 thresh.global_threshold = nla_get_u32(tb[
2490 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]);
2491 thresh.global = true;
2492 hdd_debug("globle thresh is %d", thresh.global_threshold);
2493 }
2494
2495 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) {
2496 thresh.global = false;
2497 hdd_warn("global thresh is not enabled");
2498 } else {
2499 thresh.global = nla_get_u32(tb[
2500 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]);
2501 hdd_debug("global is %d", thresh.global);
2502 }
2503
2504 thresh.enable_bitmap = false;
2505 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) {
2506 thresh.tx_bitmap = nla_get_u32(tb[
2507 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]);
2508 thresh.enable_bitmap = true;
2509 }
2510
2511 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) {
2512 thresh.rx_bitmap = nla_get_u32(tb[
2513 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]);
2514 thresh.enable_bitmap = true;
2515 }
2516
2517 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) {
2518 thresh.cca_bitmap = nla_get_u32(tb[
2519 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]);
2520 thresh.enable_bitmap = true;
2521 }
2522
2523 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) {
2524 thresh.signal_bitmap = nla_get_u32(tb[
2525 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]);
2526 thresh.enable_bitmap = true;
2527 }
2528
2529 if (!thresh.global && !thresh.enable_bitmap) {
2530 hdd_warn("threshold will be disabled.");
2531 thresh.enable = false;
2532
2533 /* Just disable threshold */
2534 goto set_thresh;
2535 } else {
2536 thresh.enable = true;
2537 }
2538
2539 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) {
2540 thresh.tx.msdu = nla_get_u32(tb[
2541 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]);
2542 }
2543
2544 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) {
2545 thresh.tx.mpdu = nla_get_u32(tb[
2546 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]);
2547 }
2548
2549 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) {
2550 thresh.tx.ppdu = nla_get_u32(tb[
2551 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]);
2552 }
2553
2554 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) {
2555 thresh.tx.bytes = nla_get_u32(tb[
2556 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]);
2557 }
2558
2559 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) {
2560 thresh.tx.msdu_drop = nla_get_u32(
2561 tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]);
2562 }
2563
2564 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) {
2565 thresh.tx.byte_drop = nla_get_u32(tb[
2566 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]);
2567 }
2568
2569 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) {
2570 thresh.tx.mpdu_retry = nla_get_u32(tb[
2571 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]);
2572 }
2573
2574 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) {
2575 thresh.tx.mpdu_fail = nla_get_u32(tb[
2576 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]);
2577 }
2578
2579 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) {
2580 thresh.tx.ppdu_fail = nla_get_u32(tb[
2581 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]);
2582 }
2583
2584 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) {
2585 thresh.tx.aggregation = nla_get_u32(tb[
2586 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]);
2587 }
2588
2589 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) {
2590 thresh.tx.succ_mcs = nla_get_u32(tb[
2591 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]);
2592 }
2593
2594 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) {
2595 thresh.tx.fail_mcs = nla_get_u32(tb[
2596 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]);
2597 }
2598
2599 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) {
2600 thresh.tx.delay = nla_get_u32(tb[
2601 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]);
2602 }
2603
2604 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) {
2605 thresh.rx.mpdu = nla_get_u32(tb[
2606 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]);
2607 }
2608
2609 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) {
2610 thresh.rx.bytes = nla_get_u32(tb[
2611 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]);
2612 }
2613
2614 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) {
2615 thresh.rx.ppdu = nla_get_u32(tb[
2616 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]);
2617 }
2618
2619 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) {
2620 thresh.rx.ppdu_bytes = nla_get_u32(tb[
2621 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]);
2622 }
2623
2624 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) {
2625 thresh.rx.mpdu_lost = nla_get_u32(tb[
2626 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]);
2627 }
2628
2629 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) {
2630 thresh.rx.mpdu_retry = nla_get_u32(tb[
2631 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]);
2632 }
2633
2634 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) {
2635 thresh.rx.mpdu_dup = nla_get_u32(tb[
2636 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]);
2637 }
2638
2639 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) {
2640 thresh.rx.mpdu_discard = nla_get_u32(tb[
2641 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]);
2642 }
2643
2644 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) {
2645 thresh.rx.aggregation = nla_get_u32(tb[
2646 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]);
2647 }
2648
2649 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) {
2650 thresh.rx.mcs = nla_get_u32(tb[
2651 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]);
2652 }
2653
2654 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) {
2655 thresh.rx.ps_inds = nla_get_u32(tb[
2656 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]);
2657 }
2658
2659 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) {
2660 thresh.rx.ps_durs = nla_get_u32(tb[
2661 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]);
2662 }
2663
2664 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) {
2665 thresh.rx.probe_reqs = nla_get_u32(tb[
2666 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]);
2667 }
2668
2669 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) {
2670 thresh.rx.other_mgmt = nla_get_u32(tb[
2671 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]);
2672 }
2673
2674 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) {
2675 thresh.cca.idle_time = nla_get_u32(tb[
2676 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]);
2677 }
2678
2679 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) {
2680 thresh.cca.tx_time = nla_get_u32(tb[
2681 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]);
2682 }
2683
2684 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) {
2685 thresh.cca.rx_in_bss_time = nla_get_u32(tb[
2686 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]);
2687 }
2688
2689 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) {
2690 thresh.cca.rx_out_bss_time = nla_get_u32(tb[
2691 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]);
2692 }
2693
2694 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) {
2695 thresh.cca.rx_busy_time = nla_get_u32(tb[
2696 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]);
2697 }
2698
2699 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) {
2700 thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[
2701 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]);
2702 }
2703
2704 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) {
2705 thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[
2706 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]);
2707 }
2708
2709 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) {
2710 thresh.cca.wlan_not_avail_time = nla_get_u32(tb[
2711 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]);
2712 }
2713
2714 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) {
2715 thresh.signal.snr = nla_get_u32(tb[
2716 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]);
2717 }
2718
2719 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) {
2720 thresh.signal.nf = nla_get_u32(tb[
2721 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]);
2722 }
2723
2724set_thresh:
2725 hdd_info("send thresh settings to target");
2726 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_thresh(hdd_ctx->hHal,
2727 &thresh)) {
2728 hdd_err("sme_ll_stats_set_thresh failed.");
2729 return -EINVAL;
2730 }
2731 return 0;
2732
2733set_period:
2734 hdd_info("send period to target");
2735 status = wma_cli_set_command(adapter->sessionId,
2736 WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD,
2737 period, PDEV_CMD);
2738 if (status) {
2739 hdd_err("wma_cli_set_command set_period failed.");
2740 return -EINVAL;
2741 }
2742 return 0;
2743}
2744
2745/**
2746 * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2747 * @wiphy: wiphy handle
2748 * @wdev: wdev handle
2749 * @data: user layer input
2750 * @data_len: length of user layer input
2751 *
2752 * return: 0 success, einval failure
2753 */
2754int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2755 struct wireless_dev *wdev,
2756 const void *data,
2757 int data_len)
2758{
2759 int ret;
2760
2761 cds_ssr_protect(__func__);
2762 ret = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev,
2763 data, data_len);
2764 cds_ssr_unprotect(__func__);
2765
2766 return ret;
2767}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002768#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
2769
2770#ifdef WLAN_FEATURE_STATS_EXT
2771/**
2772 * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2773 * @wiphy: Pointer to wiphy
2774 * @wdev: Pointer to wdev
2775 * @data: Pointer to data
2776 * @data_len: Data length
2777 *
2778 * Return: int
2779 */
2780static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2781 struct wireless_dev *wdev,
2782 const void *data,
2783 int data_len)
2784{
2785 tStatsExtRequestReq stats_ext_req;
2786 struct net_device *dev = wdev->netdev;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07002787 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002788 int ret_val;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302789 QDF_STATUS status;
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002790 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002791
Jeff Johnson1f61b612016-02-12 16:28:33 -08002792 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002793
2794 ret_val = wlan_hdd_validate_context(hdd_ctx);
2795 if (ret_val)
2796 return ret_val;
2797
Anurag Chouhan6d760662016-02-20 16:05:43 +05302798 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002799 hdd_err("Command not allowed in FTM mode");
2800 return -EPERM;
2801 }
2802
2803 stats_ext_req.request_data_len = data_len;
2804 stats_ext_req.request_data = (void *)data;
2805
2806 status = sme_stats_ext_request(pAdapter->sessionId, &stats_ext_req);
2807
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302808 if (QDF_STATUS_SUCCESS != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002809 ret_val = -EINVAL;
2810
2811 return ret_val;
2812}
2813
2814/**
2815 * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2816 * @wiphy: Pointer to wiphy
2817 * @wdev: Pointer to wdev
2818 * @data: Pointer to data
2819 * @data_len: Data length
2820 *
2821 * Return: int
2822 */
2823int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2824 struct wireless_dev *wdev,
2825 const void *data,
2826 int data_len)
2827{
2828 int ret;
2829
2830 cds_ssr_protect(__func__);
2831 ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
2832 data, data_len);
2833 cds_ssr_unprotect(__func__);
2834
2835 return ret;
2836}
2837
2838/**
2839 * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback
2840 * @ctx: Pointer to HDD context
2841 * @msg: Message received
2842 *
2843 * Return: nothing
2844 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05302845void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002846 tStatsExtEvent *msg)
2847{
2848
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002849 struct hdd_context *pHddCtx = (struct hdd_context *) ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002850 struct sk_buff *vendor_event;
2851 int status;
2852 int ret_val;
2853 tStatsExtEvent *data = msg;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07002854 struct hdd_adapter *pAdapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002855
2856 status = wlan_hdd_validate_context(pHddCtx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302857 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002858 return;
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302859
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002860 pAdapter = hdd_get_adapter_by_vdev(pHddCtx, data->vdev_id);
2861
2862 if (NULL == pAdapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002863 hdd_err("vdev_id %d does not exist with host", data->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002864 return;
2865 }
2866
2867 vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
2868 NULL,
2869 data->event_data_len +
2870 sizeof(uint32_t) +
2871 NLMSG_HDRLEN + NLMSG_HDRLEN,
2872 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2873 GFP_KERNEL);
2874
2875 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002876 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002877 return;
2878 }
2879
2880 ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
2881 pAdapter->dev->ifindex);
2882 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002883 hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002884 kfree_skb(vendor_event);
2885
2886 return;
2887 }
2888
2889 ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
2890 data->event_data_len, data->event_data);
2891
2892 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002893 hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002894 kfree_skb(vendor_event);
2895
2896 return;
2897 }
2898
2899 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2900
2901}
lifeng66831662017-05-19 16:01:35 +08002902
2903void wlan_hdd_cfg80211_stats_ext2_callback(void *ctx,
2904 struct sir_sme_rx_aggr_hole_ind *pmsg)
2905{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002906 struct hdd_context *hdd_ctx = (struct hdd_context *)ctx;
lifeng66831662017-05-19 16:01:35 +08002907 int status;
2908 uint32_t data_size, hole_info_size;
2909 struct sk_buff *vendor_event;
2910
2911 status = wlan_hdd_validate_context(hdd_ctx);
2912 if (0 != status)
2913 return;
2914
2915 if (NULL == pmsg) {
2916 hdd_err("msg received here is null");
2917 return;
2918 }
2919
2920 hole_info_size = (pmsg->hole_cnt)*sizeof(pmsg->hole_info_array[0]);
2921 data_size = sizeof(struct sir_sme_rx_aggr_hole_ind) + hole_info_size;
2922
2923 vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2924 NULL,
2925 data_size + NLMSG_HDRLEN + NLMSG_HDRLEN,
2926 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2927 GFP_KERNEL);
2928
2929 if (!vendor_event) {
2930 hdd_err("vendor_event_alloc failed for STATS_EXT2");
2931 return;
2932 }
2933
2934 if (nla_put_u32(vendor_event,
2935 QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM,
2936 pmsg->hole_cnt)) {
2937 hdd_err("%s put fail",
2938 "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM");
2939 kfree_skb(vendor_event);
2940 return;
2941 }
2942 if (nla_put(vendor_event,
2943 QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO,
2944 hole_info_size,
2945 (void *)(pmsg->hole_info_array))) {
2946 hdd_err("%s put fail",
2947 "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO");
2948 kfree_skb(vendor_event);
2949 return;
2950 }
2951
2952 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2953}
2954
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002955#endif /* End of WLAN_FEATURE_STATS_EXT */
2956
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05302957#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
2958static inline void wlan_hdd_fill_station_info_signal(struct station_info
2959 *sinfo)
2960{
2961 sinfo->filled |= STATION_INFO_SIGNAL;
2962}
2963#else
2964static inline void wlan_hdd_fill_station_info_signal(struct station_info
2965 *sinfo)
2966{
2967 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
2968}
2969#endif
2970
Dustin Brown32cb4792017-06-15 15:33:42 -07002971#ifdef LINKSPEED_DEBUG_ENABLED
2972#define linkspeed_dbg(format, args...) pr_info(format, ## args)
2973#else
2974#define linkspeed_dbg(format, args...)
2975#endif /* LINKSPEED_DEBUG_ENABLED */
2976
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002977/**
Dustin Brown0e4479e2017-07-14 14:47:39 -07002978 * wlan_hdd_fill_summary_stats() - populate station_info summary stats
2979 * @stats: summary stats to use as a source
2980 * @info: kernel station_info struct to use as a destination
2981 *
2982 * Return: None
2983 */
2984static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
2985 struct station_info *info)
2986{
2987 int i;
2988
2989 info->rx_packets = stats->rx_frm_cnt;
2990 info->tx_packets = 0;
2991 info->tx_retries = 0;
2992 info->tx_failed = 0;
2993
2994 for (i = 0; i < WIFI_MAX_AC; ++i) {
2995 info->tx_packets += stats->tx_frm_cnt[i];
2996 info->tx_retries += stats->multiple_retry_cnt[i];
2997 info->tx_failed += stats->fail_cnt[i];
2998 }
2999
3000#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
3001 info->filled |= STATION_INFO_TX_PACKETS |
3002 STATION_INFO_TX_RETRIES |
3003 STATION_INFO_TX_FAILED |
3004 STATION_INFO_RX_PACKETS;
3005#else
3006 info->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
3007 BIT(NL80211_STA_INFO_TX_PACKETS) |
3008 BIT(NL80211_STA_INFO_TX_RETRIES) |
3009 BIT(NL80211_STA_INFO_TX_FAILED);
3010#endif
3011}
3012
3013/**
3014 * wlan_hdd_get_sap_stats() - get aggregate SAP stats
3015 * @adapter: sap adapter to get stats for
3016 * @info: kernel station_info struct to populate
3017 *
3018 * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to
3019 * support "station dump" and "station get" for SAP vdevs, even though they
3020 * aren't technically stations.
3021 *
3022 * Return: errno
3023 */
3024static int
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003025wlan_hdd_get_sap_stats(struct hdd_adapter *adapter, struct station_info *info)
Dustin Brown0e4479e2017-07-14 14:47:39 -07003026{
3027 QDF_STATUS status;
3028
3029 status = wlan_hdd_get_station_stats(adapter);
3030 if (QDF_IS_STATUS_ERROR(status)) {
3031 hdd_err("Failed to get SAP stats; status:%d", status);
3032 return qdf_status_to_os_return(status);
3033 }
3034
3035 wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, info);
3036
3037 return 0;
3038}
3039
3040/**
Will Huang496b36c2017-07-11 16:38:50 +08003041 * hdd_get_max_rate_legacy() - get max rate for legacy mode
3042 * @stainfo: stainfo pointer
3043 * @rssidx: rssi index
3044 *
3045 * This function will get max rate for legacy mode
3046 *
3047 * Return: max rate on success, otherwise 0
3048 */
3049static uint32_t hdd_get_max_rate_legacy(hdd_station_info_t *stainfo,
3050 uint8_t rssidx)
3051{
3052 uint32_t maxrate = 0;
3053 /*Minimum max rate, 6Mbps*/
3054 int maxidx = 12;
3055 int i;
3056
3057 /* check supported rates */
3058 if (stainfo->max_supp_idx != 0xff &&
3059 maxidx < stainfo->max_supp_idx)
3060 maxidx = stainfo->max_supp_idx;
3061
3062 /* check extended rates */
3063 if (stainfo->max_ext_idx != 0xff &&
3064 maxidx < stainfo->max_ext_idx)
3065 maxidx = stainfo->max_ext_idx;
3066
3067 for (i = 0; QDF_ARRAY_SIZE(supported_data_rate); i++) {
3068 if (supported_data_rate[i].beacon_rate_index == maxidx)
3069 maxrate =
3070 supported_data_rate[i].supported_rate[rssidx];
3071 }
3072
3073 hdd_debug("maxrate %d", maxrate);
3074
3075 return maxrate;
3076}
3077
3078/**
3079 * hdd_get_max_rate_ht() - get max rate for ht mode
3080 * @stainfo: stainfo pointer
3081 * @stats: fw txrx status pointer
3082 * @rate_flags: rate flags
3083 * @nss: number of streams
3084 * @maxrate: returned max rate buffer pointer
3085 * @max_mcs_idx: max mcs idx
3086 * @report_max: report max rate or actual rate
3087 *
3088 * This function will get max rate for ht mode
3089 *
3090 * Return: None
3091 */
3092static void hdd_get_max_rate_ht(hdd_station_info_t *stainfo,
3093 struct hdd_fw_txrx_stats *stats,
3094 uint32_t rate_flags,
3095 uint8_t nss,
3096 uint32_t *maxrate,
3097 uint8_t *max_mcs_idx,
3098 bool report_max)
3099{
3100 struct index_data_rate_type *supported_mcs_rate;
3101 uint32_t tmprate;
3102 uint8_t flag = 0, mcsidx;
3103 int8_t rssi = stats->rssi;
3104 int mode;
3105 int i;
3106
3107 if (rate_flags & eHAL_TX_RATE_HT40)
3108 mode = 1;
3109 else
3110 mode = 0;
3111
3112 if (rate_flags & eHAL_TX_RATE_HT40)
3113 flag |= 1;
3114 if (rate_flags & eHAL_TX_RATE_SGI)
3115 flag |= 2;
3116
3117 supported_mcs_rate = (struct index_data_rate_type *)
3118 ((nss == 1) ? &supported_mcs_rate_nss1 :
3119 &supported_mcs_rate_nss2);
3120
3121 if (stainfo->max_mcs_idx == 0xff) {
3122 hdd_err("invalid max_mcs_idx");
3123 /* report real mcs idx */
3124 mcsidx = stats->tx_rate.mcs;
3125 } else {
3126 mcsidx = stainfo->max_mcs_idx;
3127 }
3128
3129 if (!report_max) {
3130 for (i = 0; i < mcsidx; i++) {
3131 if (rssi <= rssi_mcs_tbl[mode][i]) {
3132 mcsidx = i;
3133 break;
3134 }
3135 }
3136 if (mcsidx < stats->tx_rate.mcs)
3137 mcsidx = stats->tx_rate.mcs;
3138 }
3139
3140 tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
3141
3142 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3143
3144 *maxrate = tmprate;
3145 *max_mcs_idx = mcsidx;
3146}
3147
3148/**
3149 * hdd_get_max_rate_vht() - get max rate for vht mode
3150 * @stainfo: stainfo pointer
3151 * @stats: fw txrx status pointer
3152 * @rate_flags: rate flags
3153 * @nss: number of streams
3154 * @maxrate: returned max rate buffer pointer
3155 * @max_mcs_idx: max mcs idx
3156 * @report_max: report max rate or actual rate
3157 *
3158 * This function will get max rate for vht mode
3159 *
3160 * Return: None
3161 */
3162static void hdd_get_max_rate_vht(hdd_station_info_t *stainfo,
3163 struct hdd_fw_txrx_stats *stats,
3164 uint32_t rate_flags,
3165 uint8_t nss,
3166 uint32_t *maxrate,
3167 uint8_t *max_mcs_idx,
3168 bool report_max)
3169{
3170 struct index_vht_data_rate_type *supported_vht_mcs_rate;
3171 uint32_t tmprate = 0;
3172 uint32_t vht_max_mcs;
3173 uint8_t flag = 0, mcsidx = INVALID_MCS_IDX;
3174 int8_t rssi = stats->rssi;
3175 int mode;
3176 int i;
3177
3178 supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
3179 ((nss == 1) ?
3180 &supported_vht_mcs_rate_nss1 :
3181 &supported_vht_mcs_rate_nss2);
3182
3183 if (rate_flags & eHAL_TX_RATE_VHT80)
3184 mode = 2;
3185 else if (rate_flags & eHAL_TX_RATE_VHT40)
3186 mode = 1;
3187 else
3188 mode = 0;
3189
3190 if (rate_flags &
3191 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 | eHAL_TX_RATE_VHT80)) {
3192 vht_max_mcs =
3193 (enum data_rate_11ac_max_mcs)
3194 (stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK);
3195 if (rate_flags & eHAL_TX_RATE_SGI)
3196 flag |= 1;
3197
3198 if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) {
3199 mcsidx = 7;
3200 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) {
3201 mcsidx = 8;
3202 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) {
3203 /*
3204 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3205 * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6
3206 * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8
3207 */
3208 if ((rate_flags & eHAL_TX_RATE_VHT20) &&
3209 (nss != 3 && nss != 6))
3210 mcsidx = 8;
3211 else
3212 mcsidx = 9;
3213 } else {
3214 hdd_err("invalid vht_max_mcs");
3215 /* report real mcs idx */
3216 mcsidx = stats->tx_rate.mcs;
3217 }
3218
3219 if (!report_max) {
3220 for (i = 0; i <= mcsidx; i++) {
3221 if (rssi <= rssi_mcs_tbl[mode][i]) {
3222 mcsidx = i;
3223 break;
3224 }
3225 }
3226 if (mcsidx < stats->tx_rate.mcs)
3227 mcsidx = stats->tx_rate.mcs;
3228 }
3229
3230 if (rate_flags & eHAL_TX_RATE_VHT80)
3231 tmprate =
3232 supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag];
3233 else if (rate_flags & eHAL_TX_RATE_VHT40)
3234 tmprate =
3235 supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag];
3236 else if (rate_flags & eHAL_TX_RATE_VHT20)
3237 tmprate =
3238 supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag];
3239 }
3240
3241 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3242
3243 *maxrate = tmprate;
3244 *max_mcs_idx = mcsidx;
3245}
3246
3247#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
3248/**
3249 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3250 * @stainfo: stainfo pointer
3251 * @rate_flags: HDD rate flags
3252 * @mcsidx: mcs index
3253 * @nss: number of streams
3254 * @vht: vht mode or not
3255 *
3256 * This function will fill ch width and mcs flags
3257 *
3258 * Return: None
3259 */
3260static void hdd_fill_bw_mcs(struct station_info *sinfo,
3261 uint8_t rate_flags,
3262 uint8_t mcsidx,
3263 uint8_t nss,
3264 bool vht)
3265{
3266 if (vht) {
3267 sinfo->txrate.nss = nss;
3268 sinfo->txrate.mcs = mcsidx;
3269 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3270 if (rate_flags & eHAL_TX_RATE_VHT80)
3271 sinfo->txrate.bw = RATE_INFO_BW_80;
3272 else if (rate_flags & eHAL_TX_RATE_VHT40)
3273 sinfo->txrate.bw = RATE_INFO_BW_40;
3274 else if (rate_flags & eHAL_TX_RATE_VHT20)
3275 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3276 } else {
3277 sinfo->txrate.mcs = (nss - 1) << 3;
3278 sinfo->txrate.mcs |= mcsidx;
3279 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3280 if (rate_flags & eHAL_TX_RATE_HT40)
3281 sinfo->txrate.bw = RATE_INFO_BW_40;
3282 }
3283}
3284#else
3285/**
3286 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3287 * @stainfo: stainfo pointer
3288 * @rate_flags: HDD rate flags
3289 * @mcsidx: mcs index
3290 * @nss: number of streams
3291 * @vht: vht mode or not
3292 *
3293 * This function will fill ch width and mcs flags
3294 *
3295 * Return: None
3296 */
3297static void hdd_fill_bw_mcs(struct station_info *sinfo,
3298 uint8_t rate_flags,
3299 uint8_t mcsidx,
3300 uint8_t nss,
3301 bool vht)
3302{
3303 if (vht) {
3304 sinfo->txrate.nss = nss;
3305 sinfo->txrate.mcs = mcsidx;
3306 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3307 if (rate_flags & eHAL_TX_RATE_VHT80)
3308 sinfo->txrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
3309 else if (rate_flags & eHAL_TX_RATE_VHT40)
3310 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
3311 else if (rate_flags & eHAL_TX_RATE_VHT20)
3312 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3313 } else {
3314 sinfo->txrate.mcs = (nss - 1) << 3;
3315 sinfo->txrate.mcs |= mcsidx;
3316 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3317 if (rate_flags & eHAL_TX_RATE_HT40)
3318 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
3319 }
3320}
3321#endif
3322
3323/**
3324 * hdd_fill_bw_mcs_vht() - fill ch width and mcs flags for VHT mode
3325 * @stainfo: stainfo pointer
3326 * @rate_flags: HDD rate flags
3327 * @mcsidx: mcs index
3328 * @nss: number of streams
3329 *
3330 * This function will fill ch width and mcs flags for VHT mode
3331 *
3332 * Return: None
3333 */
3334static void hdd_fill_bw_mcs_vht(struct station_info *sinfo,
3335 uint8_t rate_flags,
3336 uint8_t mcsidx,
3337 uint8_t nss)
3338{
3339 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, true);
3340}
3341
3342/**
3343 * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
3344 * @sinfo: station_info struct pointer
3345 * @rate_flags: HDD rate flags
3346 * @mcsidx: mcs index
3347 * @nss: number of streams
3348 * @maxrate: data rate (kbps)
3349 *
3350 * This function will fill rate info of sinfo struct
3351 *
3352 * Return: None
3353 */
3354static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
3355 uint32_t rate_flags,
3356 uint8_t mcsidx,
3357 uint8_t nss,
3358 uint32_t maxrate)
3359{
3360 if (rate_flags & eHAL_TX_RATE_LEGACY) {
3361 /* provide to the UI in units of 100kbps */
3362 sinfo->txrate.legacy = maxrate;
3363 } else {
3364 /* must be MCS */
3365 if (rate_flags &
3366 (eHAL_TX_RATE_VHT80 |
3367 eHAL_TX_RATE_VHT40 |
3368 eHAL_TX_RATE_VHT20))
3369 hdd_fill_bw_mcs_vht(sinfo, rate_flags, mcsidx, nss);
3370
3371 if (rate_flags & (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40))
3372 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, false);
3373
3374 if (rate_flags & eHAL_TX_RATE_SGI) {
3375 if (!(sinfo->txrate.flags & RATE_INFO_FLAGS_VHT_MCS))
3376 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3377 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3378 }
3379 }
3380
3381 hdd_info("flag %x mcs %d legacy %d nss %d",
3382 sinfo->txrate.flags,
3383 sinfo->txrate.mcs,
3384 sinfo->txrate.legacy,
3385 sinfo->txrate.nss);
3386}
3387
3388/**
3389 * hdd_fill_station_info_flags() - fill flags of sinfo struct
3390 * @sinfo: station_info struct pointer
3391 *
3392 * This function will fill flags of sinfo struct
3393 *
3394 * Return: None
3395 */
3396static void hdd_fill_station_info_flags(struct station_info *sinfo)
3397{
3398 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) |
3399 BIT(NL80211_STA_INFO_TX_BYTES) |
3400 BIT(NL80211_STA_INFO_TX_BYTES64) |
3401 BIT(NL80211_STA_INFO_TX_BITRATE) |
3402 BIT(NL80211_STA_INFO_TX_PACKETS) |
3403 BIT(NL80211_STA_INFO_TX_RETRIES) |
3404 BIT(NL80211_STA_INFO_TX_FAILED) |
3405 BIT(NL80211_STA_INFO_RX_BYTES) |
3406 BIT(NL80211_STA_INFO_RX_BYTES64) |
3407 BIT(NL80211_STA_INFO_RX_PACKETS) |
3408 BIT(NL80211_STA_INFO_INACTIVE_TIME) |
3409 BIT(NL80211_STA_INFO_CONNECTED_TIME);
3410}
3411
3412/**
3413 * hdd_fill_rate_info() - fill rate info of sinfo
3414 * @sinfo: station_info struct pointer
3415 * @stainfo: stainfo pointer
3416 * @stats: fw txrx status pointer
3417 * @cfg: hdd config pointer
3418 *
3419 * This function will fill rate info of sinfo
3420 *
3421 * Return: None
3422 */
3423static void hdd_fill_rate_info(struct station_info *sinfo,
3424 hdd_station_info_t *stainfo,
3425 struct hdd_fw_txrx_stats *stats,
3426 struct hdd_config *cfg)
3427{
3428 uint8_t rate_flags;
3429 uint8_t mcsidx = 0xff;
3430 uint32_t myrate, maxrate, tmprate;
3431 int rssidx;
3432 int nss = 1;
3433
3434 hdd_info("reportMaxLinkSpeed %d", cfg->reportMaxLinkSpeed);
3435
3436 /* convert to 100kbps expected in rate table */
3437 myrate = stats->tx_rate.rate / 100;
3438 rate_flags = stainfo->rate_flags;
3439 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3440 nss = stainfo->nss;
3441 if (eHDD_LINK_SPEED_REPORT_ACTUAL == cfg->reportMaxLinkSpeed) {
3442 /* Get current rate flags if report actual */
3443 if (stats->tx_rate.rate_flags)
3444 rate_flags =
3445 stats->tx_rate.rate_flags;
3446 nss = stats->tx_rate.nss;
3447 }
3448
3449 if (stats->tx_rate.mcs == INVALID_MCS_IDX)
3450 rate_flags = eHAL_TX_RATE_LEGACY;
3451 }
3452
3453 if (eHDD_LINK_SPEED_REPORT_ACTUAL != cfg->reportMaxLinkSpeed) {
3454 /* we do not want to necessarily report the current speed */
3455 if (eHDD_LINK_SPEED_REPORT_MAX == cfg->reportMaxLinkSpeed) {
3456 /* report the max possible speed */
3457 rssidx = 0;
3458 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
3459 cfg->reportMaxLinkSpeed) {
3460 /* report the max possible speed with RSSI scaling */
3461 if (stats->rssi >= cfg->linkSpeedRssiHigh) {
3462 /* report the max possible speed */
3463 rssidx = 0;
3464 } else if (stats->rssi >=
3465 cfg->linkSpeedRssiMid) {
3466 /* report middle speed */
3467 rssidx = 1;
3468 } else if (stats->rssi >=
3469 cfg->linkSpeedRssiLow) {
3470 /* report middle speed */
3471 rssidx = 2;
3472 } else {
3473 /* report actual speed */
3474 rssidx = 3;
3475 }
3476 } else {
3477 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
3478 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
3479 cfg->reportMaxLinkSpeed);
3480 rssidx = 0;
3481 }
3482
3483 maxrate = hdd_get_max_rate_legacy(stainfo, rssidx);
3484
3485 /*
3486 * Get MCS Rate Set --
3487 * Only if we are connected in non legacy mode and not
3488 * reporting actual speed
3489 */
3490 if ((rssidx != 3) &&
3491 !(rate_flags & eHAL_TX_RATE_LEGACY)) {
3492 hdd_get_max_rate_vht(stainfo,
3493 stats,
3494 rate_flags,
3495 nss,
3496 &tmprate,
3497 &mcsidx,
3498 rssidx == 0);
3499
3500 if (maxrate < tmprate &&
3501 mcsidx != INVALID_MCS_IDX)
3502 maxrate = tmprate;
3503
3504 if (mcsidx == INVALID_MCS_IDX)
3505 hdd_get_max_rate_ht(stainfo,
3506 stats,
3507 rate_flags,
3508 nss,
3509 &tmprate,
3510 &mcsidx,
3511 rssidx == 0);
3512
3513 if (maxrate < tmprate &&
3514 mcsidx != INVALID_MCS_IDX)
3515 maxrate = tmprate;
3516 } else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3517 maxrate = myrate;
3518 mcsidx = stats->tx_rate.mcs;
3519 }
3520
3521 /*
3522 * make sure we report a value at least as big as our
3523 * current rate
3524 */
3525 if ((maxrate < myrate) || (maxrate == 0)) {
3526 maxrate = myrate;
3527 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
3528 mcsidx = stats->tx_rate.mcs;
3529 /*
3530 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3531 * - MCS9 is valid for VHT20 when Nss = 3 or
3532 * Nss = 6
3533 * - MCS9 is not valid for VHT20 when
3534 * Nss = 1,2,4,5,7,8
3535 */
3536 if ((rate_flags & eHAL_TX_RATE_VHT20) &&
3537 (mcsidx > 8) &&
3538 (nss != 3 && nss != 6))
3539 mcsidx = 8;
3540 }
3541 }
3542 } else {
3543 /* report current rate instead of max rate */
3544 maxrate = myrate;
3545 if (!(rate_flags & eHAL_TX_RATE_LEGACY))
3546 mcsidx = stats->tx_rate.mcs;
3547 }
3548
3549 hdd_fill_sinfo_rate_info(sinfo,
3550 rate_flags,
3551 mcsidx,
3552 nss,
3553 maxrate);
3554}
3555
3556/**
3557 * wlan_hdd_fill_station_info() - fill station_info struct
3558 * @sinfo: station_info struct pointer
3559 * @stainfo: stainfo pointer
3560 * @stats: fw txrx status pointer
3561 * @cfg: hdd config pointer
3562 *
3563 * This function will fill station_info struct
3564 *
3565 * Return: None
3566 */
3567static void wlan_hdd_fill_station_info(struct station_info *sinfo,
3568 hdd_station_info_t *stainfo,
3569 struct hdd_fw_txrx_stats *stats,
3570 struct hdd_config *cfg)
3571{
3572 qdf_time_t curr_time, dur;
3573
3574 curr_time = qdf_system_ticks();
3575 dur = curr_time - stainfo->assoc_ts;
3576 sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000;
3577 dur = curr_time - stainfo->last_tx_rx_ts;
3578 sinfo->inactive_time = qdf_system_ticks_to_msecs(dur);
3579 sinfo->signal = stats->rssi;
3580 sinfo->tx_bytes = stats->tx_bytes;
3581 sinfo->tx_packets = stats->tx_packets;
3582 sinfo->rx_bytes = stats->rx_bytes;
3583 sinfo->rx_packets = stats->rx_packets;
3584 sinfo->tx_failed = stats->tx_failed;
3585 sinfo->tx_retries = stats->tx_retries;
3586
3587 /* tx rate info */
3588 hdd_fill_rate_info(sinfo, stainfo, stats, cfg);
3589
3590 hdd_fill_station_info_flags(sinfo);
3591
3592 /* dump sta info*/
3593 hdd_info("dump stainfo");
3594 hdd_info("con_time %d inact_time %d tx_pkts %d rx_pkts %d",
3595 sinfo->connected_time, sinfo->inactive_time,
3596 sinfo->tx_packets, sinfo->rx_packets);
3597 hdd_info("failed %d retries %d tx_bytes %lld rx_bytes %lld",
3598 sinfo->tx_failed, sinfo->tx_retries,
3599 sinfo->tx_bytes, sinfo->rx_bytes);
3600 hdd_info("rssi %d mcs %d legacy %d nss %d flags %x",
3601 sinfo->signal, sinfo->txrate.mcs,
3602 sinfo->txrate.legacy, sinfo->txrate.nss,
3603 sinfo->txrate.flags);
3604}
3605
3606/**
3607 * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs
3608 * @rate: Data rate (100 kbps)
3609 * @nss: Number of streams
3610 * @mcs: HT mcs index
3611 *
3612 * This function is used to construct HT rate flag with rate, nss and mcs
3613 *
3614 * Return: rate flags for success, 0 on failure.
3615 */
3616static uint8_t hdd_get_rate_flags_ht(uint32_t rate,
3617 uint8_t nss,
3618 uint8_t mcs)
3619{
3620 struct index_data_rate_type *mcs_rate;
3621 uint8_t flags = 0;
3622
3623 mcs_rate = (struct index_data_rate_type *)
3624 ((nss == 1) ? &supported_mcs_rate_nss1 :
3625 &supported_mcs_rate_nss2);
3626
3627 if (rate == mcs_rate[mcs].supported_rate[0]) {
3628 flags |= eHAL_TX_RATE_HT20;
3629 } else if (rate == mcs_rate[mcs].supported_rate[1]) {
3630 flags |= eHAL_TX_RATE_HT40;
3631 } else if (rate == mcs_rate[mcs].supported_rate[2]) {
3632 flags |= eHAL_TX_RATE_HT20;
3633 flags |= eHAL_TX_RATE_SGI;
3634 } else if (rate == mcs_rate[mcs].supported_rate[3]) {
3635 flags |= eHAL_TX_RATE_HT40;
3636 flags |= eHAL_TX_RATE_SGI;
3637 } else {
3638 hdd_err("invalid params rate %d nss %d mcs %d",
3639 rate, nss, mcs);
3640 }
3641
3642 return flags;
3643}
3644
3645/**
3646 * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs
3647 * @rate: Data rate (100 kbps)
3648 * @nss: Number of streams
3649 * @mcs: VHT mcs index
3650 *
3651 * This function is used to construct VHT rate flag with rate, nss and mcs
3652 *
3653 * Return: rate flags for success, 0 on failure.
3654 */
3655static uint8_t hdd_get_rate_flags_vht(uint32_t rate,
3656 uint8_t nss,
3657 uint8_t mcs)
3658{
3659 struct index_vht_data_rate_type *mcs_rate;
3660 uint8_t flags = 0;
3661
3662 mcs_rate = (struct index_vht_data_rate_type *)
3663 ((nss == 1) ?
3664 &supported_vht_mcs_rate_nss1 :
3665 &supported_vht_mcs_rate_nss2);
3666
3667 if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
3668 flags |= eHAL_TX_RATE_VHT80;
3669 } else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
3670 flags |= eHAL_TX_RATE_VHT80;
3671 flags |= eHAL_TX_RATE_SGI;
3672 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
3673 flags |= eHAL_TX_RATE_VHT40;
3674 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
3675 flags |= eHAL_TX_RATE_VHT40;
3676 flags |= eHAL_TX_RATE_SGI;
3677 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
3678 flags |= eHAL_TX_RATE_VHT20;
3679 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
3680 flags |= eHAL_TX_RATE_VHT20;
3681 flags |= eHAL_TX_RATE_SGI;
3682 } else {
3683 hdd_err("invalid params rate %d nss %d mcs %d",
3684 rate, nss, mcs);
3685 }
3686
3687 return flags;
3688}
3689
3690/**
3691 * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs
3692 * @rate: Data rate (100 kbps)
3693 * @mode: Tx/Rx mode
3694 * @nss: Number of streams
3695 * @mcs: Mcs index
3696 *
3697 * This function is used to construct rate flag with rate, nss and mcs
3698 *
3699 * Return: rate flags for success, 0 on failure.
3700 */
3701static uint8_t hdd_get_rate_flags(uint32_t rate,
3702 uint8_t mode,
3703 uint8_t nss,
3704 uint8_t mcs)
3705{
3706 uint8_t flags = 0;
3707
3708 if (mode == SIR_SME_PHY_MODE_HT)
3709 flags = hdd_get_rate_flags_ht(rate, nss, mcs);
3710 else if (mode == SIR_SME_PHY_MODE_VHT)
3711 flags = hdd_get_rate_flags_vht(rate, nss, mcs);
3712 else
3713 hdd_err("invalid mode param %d", mode);
3714
3715 return flags;
3716}
3717
3718/**
3719 * wlan_hdd_fill_rate_info() - fill HDD rate info from SIR peer info
3720 * @ap_ctx: AP Context
3721 * @peer_info: SIR peer info pointer
3722 *
3723 * This function is used to fill HDD rate info rom SIR peer info
3724 *
3725 * Return: None
3726 */
Jeff Johnson87251032017-08-29 13:31:11 -07003727static void wlan_hdd_fill_rate_info(struct hdd_ap_ctx *ap_ctx,
Will Huang496b36c2017-07-11 16:38:50 +08003728 struct sir_peer_info_ext *peer_info)
3729{
3730 uint8_t flags;
3731 uint32_t rate_code;
3732
3733 /* tx rate info */
3734 ap_ctx->txrx_stats.tx_rate.rate = peer_info->tx_rate;
3735 rate_code = peer_info->tx_rate_code;
3736
3737 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3738 WMI_RATE_PREAMBLE_HT)
3739 ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_HT;
3740 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3741 WMI_RATE_PREAMBLE_VHT)
3742 ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_VHT;
3743 else
3744 ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
3745
3746 ap_ctx->txrx_stats.tx_rate.nss =
3747 WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3748 ap_ctx->txrx_stats.tx_rate.mcs =
3749 WMI_GET_HW_RATECODE_RATE_V1(rate_code);
3750
3751 flags = hdd_get_rate_flags(ap_ctx->txrx_stats.tx_rate.rate / 100,
3752 ap_ctx->txrx_stats.tx_rate.mode,
3753 ap_ctx->txrx_stats.tx_rate.nss,
3754 ap_ctx->txrx_stats.tx_rate.mcs);
3755
3756 ap_ctx->txrx_stats.tx_rate.rate_flags = flags;
3757
3758 hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x",
3759 ap_ctx->txrx_stats.tx_rate.mode,
3760 ap_ctx->txrx_stats.tx_rate.nss,
3761 ap_ctx->txrx_stats.tx_rate.mcs,
3762 ap_ctx->txrx_stats.tx_rate.rate_flags,
3763 flags);
3764
3765 /* rx rate info */
3766 ap_ctx->txrx_stats.rx_rate.rate = peer_info->rx_rate;
3767 rate_code = peer_info->rx_rate_code;
3768
3769 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3770 WMI_RATE_PREAMBLE_HT)
3771 ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_HT;
3772 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3773 WMI_RATE_PREAMBLE_VHT)
3774 ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_VHT;
3775 else
3776 ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
3777
3778 ap_ctx->txrx_stats.rx_rate.nss =
3779 WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3780 ap_ctx->txrx_stats.rx_rate.mcs =
3781 WMI_GET_HW_RATECODE_RATE_V1(rate_code);
3782
3783 flags = hdd_get_rate_flags(ap_ctx->txrx_stats.rx_rate.rate / 100,
3784 ap_ctx->txrx_stats.rx_rate.mode,
3785 ap_ctx->txrx_stats.rx_rate.nss,
3786 ap_ctx->txrx_stats.rx_rate.mcs);
3787
3788 ap_ctx->txrx_stats.rx_rate.rate_flags = flags;
3789
3790 hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x",
3791 ap_ctx->txrx_stats.rx_rate.mode,
3792 ap_ctx->txrx_stats.rx_rate.nss,
3793 ap_ctx->txrx_stats.rx_rate.mcs,
3794 ap_ctx->txrx_stats.rx_rate.rate_flags,
3795 flags);
3796}
3797
3798int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3799 struct net_device *dev,
3800 const u8 *mac,
3801 struct station_info *sinfo);
3802
3803/**
3804 * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
3805 * @wiphy: pointer to wiphy
3806 * @dev: pointer to net_device structure
3807 * @mac: request peer mac address
3808 * @sinfo: pointer to station_info struct
3809 *
3810 * This function will get remote peer info from fw and fill sinfo struct
3811 *
3812 * Return: 0 on success, otherwise error value
3813 */
3814int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3815 struct net_device *dev,
3816 const u8 *mac,
3817 struct station_info *sinfo)
3818{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003819 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07003820 struct hdd_context *hddctx = wiphy_priv(wiphy);
Jeff Johnson87251032017-08-29 13:31:11 -07003821 struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
Will Huang496b36c2017-07-11 16:38:50 +08003822 hdd_station_info_t *stainfo = NULL;
3823 struct hdd_config *cfg;
3824 struct qdf_mac_addr macaddr;
3825 struct sir_peer_info_ext peer_info;
3826 int status;
3827 int i;
3828
3829 status = wlan_hdd_validate_context(hddctx);
3830 if (status != 0)
3831 return status;
3832
3833 cfg = hddctx->config;
3834
3835 hdd_debug("get peer %pM info", mac);
3836
3837 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
3838 if (!qdf_mem_cmp(adapter->aStaInfo[i].macAddrSTA.bytes,
3839 mac,
3840 QDF_MAC_ADDR_SIZE)) {
3841 stainfo = &adapter->aStaInfo[i];
3842 break;
3843 }
3844 }
3845
3846 if (!stainfo) {
3847 hdd_err("peer %pM not found", mac);
3848 return -EINVAL;
3849 }
3850
3851 qdf_mem_copy(macaddr.bytes, mac, QDF_MAC_ADDR_SIZE);
3852 status = wlan_hdd_get_peer_info(adapter, macaddr, &peer_info);
3853 if (status) {
3854 hdd_err("fail to get peer info from fw");
3855 return -EPERM;
3856 }
3857
3858 qdf_mem_zero(&ap_ctx->txrx_stats, sizeof(ap_ctx->txrx_stats));
3859 ap_ctx->txrx_stats.tx_packets = peer_info.tx_packets;
3860 ap_ctx->txrx_stats.tx_bytes = peer_info.tx_bytes;
3861 ap_ctx->txrx_stats.rx_packets = peer_info.rx_packets;
3862 ap_ctx->txrx_stats.rx_bytes = peer_info.rx_bytes;
3863 ap_ctx->txrx_stats.tx_retries = peer_info.tx_retries;
3864 ap_ctx->txrx_stats.tx_failed = peer_info.tx_failed;
3865 ap_ctx->txrx_stats.rssi =
3866 peer_info.rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM;
3867 wlan_hdd_fill_rate_info(ap_ctx, &peer_info);
3868
3869 wlan_hdd_fill_station_info(sinfo, stainfo, &ap_ctx->txrx_stats, cfg);
3870
3871 return status;
3872}
3873
3874/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003875 * __wlan_hdd_cfg80211_get_station() - get station statistics
3876 * @wiphy: Pointer to wiphy
3877 * @dev: Pointer to network device
3878 * @mac: Pointer to mac
3879 * @sinfo: Pointer to station info
3880 *
3881 * Return: 0 for success, non-zero for failure
3882 */
3883static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
3884 struct net_device *dev,
3885 const uint8_t *mac,
3886 struct station_info *sinfo)
3887{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003888 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson40dae4e2017-08-29 14:00:25 -07003889 struct hdd_station_ctx *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003890 int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length;
3891 uint8_t rate_flags;
Dustin Brown905cdc72016-11-16 16:51:10 -08003892 uint8_t mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003893
Jeff Johnson5eb1e682017-08-28 11:42:15 -07003894 struct hdd_context *pHddCtx = (struct hdd_context *) wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003895 struct hdd_config *pCfg = pHddCtx->config;
3896
3897 uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
3898 uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX;
3899 uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
3900 uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
3901 uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET];
3902 uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET;
3903 uint16_t maxRate = 0;
Anurag Chouhan5de8d172016-07-13 14:44:28 +05303904 int8_t snr = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003905 uint16_t myRate;
3906 uint16_t currentRate = 0;
3907 uint8_t maxSpeedMCS = 0;
3908 uint8_t maxMCSIdx = 0;
3909 uint8_t rateFlag = 1;
3910 uint8_t i, j, rssidx;
3911 uint8_t nss = 1;
3912 int status, mode = 0, maxHtIdx;
3913 struct index_vht_data_rate_type *supported_vht_mcs_rate;
3914 struct index_data_rate_type *supported_mcs_rate;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05303915#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
3916 bool rssi_stats_valid = false;
3917#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003918
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003919 uint32_t vht_mcs_map;
Will Huang496b36c2017-07-11 16:38:50 +08003920 enum data_rate_11ac_max_mcs vht_max_mcs;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003921
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003922 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003923
Anurag Chouhan6d760662016-02-20 16:05:43 +05303924 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003925 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003926 return -EINVAL;
3927 }
3928
Dustin Brown0e4479e2017-07-14 14:47:39 -07003929 status = wlan_hdd_validate_context(pHddCtx);
3930 if (status)
3931 return status;
3932
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05303933 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
3934 hdd_err("invalid session id: %d", pAdapter->sessionId);
3935 return -EINVAL;
3936 }
3937
Dustin Brown0e4479e2017-07-14 14:47:39 -07003938 if (pAdapter->device_mode == QDF_SAP_MODE)
3939 return wlan_hdd_get_sap_stats(pAdapter, sinfo);
3940
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003941 if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) ||
3942 (0 == ssidlen)) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003943 hdd_debug("Not associated or Invalid ssidlen, %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003944 ssidlen);
3945 /*To keep GUI happy */
3946 return 0;
3947 }
3948
3949 if (true == pHddStaCtx->hdd_ReassocScenario) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003950 hdd_debug("Roaming is in progress, cannot continue with this request");
Sachin Ahujafeedeba2016-09-13 21:54:16 +05303951 /*
3952 * supplicant reports very low rssi to upper layer
3953 * and handover happens to cellular.
3954 * send the cached rssi when get_station
3955 */
3956 sinfo->signal = pAdapter->rssi;
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05303957 wlan_hdd_fill_station_info_signal(sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003958 return 0;
3959 }
3960
Naveen Rawat2cb788d2016-10-11 17:44:44 -07003961 wlan_hdd_get_station_stats(pAdapter);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05303962
3963 if (pAdapter->hdd_stats.summary_stat.rssi)
3964 pAdapter->rssi = pAdapter->hdd_stats.summary_stat.rssi;
3965
3966 /* for new connection there might be no valid previous RSSI */
3967 if (!pAdapter->rssi) {
3968 hdd_get_rssi_snr_by_bssid(pAdapter,
3969 pHddStaCtx->conn_info.bssId.bytes,
3970 &pAdapter->rssi, NULL);
3971 }
3972
3973 sinfo->signal = pAdapter->rssi;
Naveen Rawat2cb788d2016-10-11 17:44:44 -07003974 snr = pAdapter->hdd_stats.summary_stat.snr;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08003975 hdd_debug("snr: %d, rssi: %d",
Naveen Rawat2cb788d2016-10-11 17:44:44 -07003976 pAdapter->hdd_stats.summary_stat.snr,
3977 pAdapter->hdd_stats.summary_stat.rssi);
Anurag Chouhan5de8d172016-07-13 14:44:28 +05303978 pHddStaCtx->conn_info.signal = sinfo->signal;
3979 pHddStaCtx->conn_info.noise =
3980 pHddStaCtx->conn_info.signal - snr;
3981
Arun Kumar Khandavallibffbe052016-11-14 23:14:06 +05303982 wlan_hdd_fill_station_info_signal(sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003983
Jeff Johnson71396692016-09-23 15:41:52 -07003984 /*
3985 * we notify connect to lpass here instead of during actual
3986 * connect processing because rssi info is not accurate during
3987 * actual connection. lpass will ensure the notification is
3988 * only processed once per association.
3989 */
3990 hdd_lpass_notify_connect(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003991
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003992 rate_flags = pAdapter->hdd_stats.ClassA_stat.tx_rate_flags;
Dustin Brown905cdc72016-11-16 16:51:10 -08003993 mcs_index = pAdapter->hdd_stats.ClassA_stat.mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003994
3995 /* convert to the UI units of 100kbps */
3996 myRate = pAdapter->hdd_stats.ClassA_stat.tx_rate * 5;
3997 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
Jeff Johnsonad0b2c62017-03-16 14:37:38 -07003998 nss = pAdapter->hdd_stats.ClassA_stat.nss;
Liangwei Dong05475a72017-08-09 13:39:57 +09003999 if ((nss > 1) &&
4000 policy_mgr_is_current_hwmode_dbs(pHddCtx->hdd_psoc) &&
4001 !policy_mgr_is_hw_dbs_2x2_capable(pHddCtx->hdd_psoc)) {
4002 hdd_debug("Hw mode is DBS, Reduce nss(%d) to 1", nss);
Agrawal Ashish569ad262017-05-01 14:06:36 +05304003 nss--;
4004 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004005
4006 if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) {
4007 /* Get current rate flags if report actual */
Hanumanth Reddy Pothula063cbe92017-08-08 23:22:01 +05304008 /* WMA fails to find mcs_index for legacy tx rates */
4009 if (mcs_index == INVALID_MCS_IDX && myRate)
4010 rate_flags = eHAL_TX_RATE_LEGACY;
4011 else
4012 rate_flags =
4013 pAdapter->hdd_stats.ClassA_stat.mcs_rate_flags;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004014 }
4015
Dustin Brown905cdc72016-11-16 16:51:10 -08004016 if (mcs_index == INVALID_MCS_IDX)
4017 mcs_index = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004018 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004019
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004020 hdd_debug("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d",
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004021 sinfo->signal, pCfg->reportMaxLinkSpeed, myRate,
4022 (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid,
Dustin Brown905cdc72016-11-16 16:51:10 -08004023 (int)pCfg->linkSpeedRssiLow, (int)rate_flags, (int)mcs_index);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004024
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07004025 /* assume basic BW. anything else will override this later */
Dustin Brown32cb4792017-06-15 15:33:42 -07004026 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_20);
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07004027
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028 if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) {
4029 /* we do not want to necessarily report the current speed */
4030 if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) {
4031 /* report the max possible speed */
4032 rssidx = 0;
4033 } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED ==
4034 pCfg->reportMaxLinkSpeed) {
4035 /* report the max possible speed with RSSI scaling */
4036 if (sinfo->signal >= pCfg->linkSpeedRssiHigh) {
4037 /* report the max possible speed */
4038 rssidx = 0;
4039 } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) {
4040 /* report middle speed */
4041 rssidx = 1;
4042 } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) {
4043 /* report middle speed */
4044 rssidx = 2;
4045 } else {
4046 /* report actual speed */
4047 rssidx = 3;
4048 }
4049 } else {
4050 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004051 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004052 pCfg->reportMaxLinkSpeed);
4053 rssidx = 0;
4054 }
4055
4056 maxRate = 0;
4057
4058 /* Get Basic Rate Set */
4059 if (0 !=
4060 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
4061 WNI_CFG_OPERATIONAL_RATE_SET,
4062 OperationalRates,
4063 &ORLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004064 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004065 /*To keep GUI happy */
4066 return 0;
4067 }
4068
4069 for (i = 0; i < ORLeng; i++) {
4070 for (j = 0;
4071 j < ARRAY_SIZE(supported_data_rate); j++) {
4072 /* Validate Rate Set */
4073 if (supported_data_rate[j].beacon_rate_index ==
4074 (OperationalRates[i] & 0x7F)) {
4075 currentRate =
4076 supported_data_rate[j].
4077 supported_rate[rssidx];
4078 break;
4079 }
4080 }
4081 /* Update MAX rate */
4082 maxRate =
4083 (currentRate > maxRate) ? currentRate : maxRate;
4084 }
4085
4086 /* Get Extended Rate Set */
4087 if (0 !=
4088 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
4089 WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
4090 ExtendedRates, &ERLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004091 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004092 /*To keep GUI happy */
4093 return 0;
4094 }
4095
4096 for (i = 0; i < ERLeng; i++) {
4097 for (j = 0;
4098 j < ARRAY_SIZE(supported_data_rate); j++) {
4099 if (supported_data_rate[j].beacon_rate_index ==
4100 (ExtendedRates[i] & 0x7F)) {
4101 currentRate =
4102 supported_data_rate[j].
4103 supported_rate[rssidx];
4104 break;
4105 }
4106 }
4107 /* Update MAX rate */
4108 maxRate =
4109 (currentRate > maxRate) ? currentRate : maxRate;
4110 }
Jeff Johnson8bb78c32017-01-12 08:42:50 -08004111 /*
4112 * Get MCS Rate Set --
4113 * Only if we are connected in non legacy mode and not
4114 * reporting actual speed
4115 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004116 if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) {
4117 if (0 !=
4118 sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter),
4119 WNI_CFG_CURRENT_MCS_SET, MCSRates,
4120 &MCSLeng)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004121 hdd_err("cfg get returned failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004122 /*To keep GUI happy */
4123 return 0;
4124 }
4125 rateFlag = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004126 supported_vht_mcs_rate =
4127 (struct index_vht_data_rate_type *)
4128 ((nss ==
4129 1) ? &supported_vht_mcs_rate_nss1 :
4130 &supported_vht_mcs_rate_nss2);
4131
4132 if (rate_flags & eHAL_TX_RATE_VHT80)
4133 mode = 2;
4134 else if ((rate_flags & eHAL_TX_RATE_VHT40) ||
4135 (rate_flags & eHAL_TX_RATE_HT40))
4136 mode = 1;
4137 else
4138 mode = 0;
4139
4140 /* VHT80 rate has seperate rate table */
4141 if (rate_flags &
4142 (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
4143 eHAL_TX_RATE_VHT80)) {
4144 sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter),
4145 WNI_CFG_VHT_TX_MCS_MAP,
4146 &vht_mcs_map);
Will Huang496b36c2017-07-11 16:38:50 +08004147 vht_max_mcs = (enum data_rate_11ac_max_mcs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004148 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
4149 if (rate_flags & eHAL_TX_RATE_SGI)
4150 rateFlag |= 1;
Dustin Brown32cb4792017-06-15 15:33:42 -07004151
Will Huang496b36c2017-07-11 16:38:50 +08004152 if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004153 maxMCSIdx = 7;
Will Huang496b36c2017-07-11 16:38:50 +08004154 else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004155 maxMCSIdx = 8;
Will Huang496b36c2017-07-11 16:38:50 +08004156 else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs)
Dustin Brown32cb4792017-06-15 15:33:42 -07004157 maxMCSIdx = 9;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004158
4159 if (rssidx != 0) {
4160 for (i = 0; i <= maxMCSIdx; i++) {
4161 if (sinfo->signal <=
4162 rssi_mcs_tbl[mode][i]) {
4163 maxMCSIdx = i;
4164 break;
4165 }
4166 }
4167 }
4168
4169 if (rate_flags & eHAL_TX_RATE_VHT80) {
4170 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08004171 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004172 supported_VHT80_rate[rateFlag];
4173 maxRate =
4174 supported_vht_mcs_rate[maxMCSIdx].
4175 supported_VHT80_rate[rateFlag];
4176 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
4177 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08004178 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004179 supported_VHT40_rate[rateFlag];
4180 maxRate =
4181 supported_vht_mcs_rate[maxMCSIdx].
4182 supported_VHT40_rate[rateFlag];
4183 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
4184 currentRate =
Dustin Brown905cdc72016-11-16 16:51:10 -08004185 supported_vht_mcs_rate[mcs_index].
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004186 supported_VHT20_rate[rateFlag];
4187 maxRate =
4188 supported_vht_mcs_rate[maxMCSIdx].
4189 supported_VHT20_rate[rateFlag];
4190 }
4191
4192 maxSpeedMCS = 1;
4193 if (currentRate > maxRate)
4194 maxRate = currentRate;
4195
Kiran Kumar Lokere9a733a72016-02-17 19:01:15 -08004196 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004197 if (rate_flags & eHAL_TX_RATE_HT40)
4198 rateFlag |= 1;
4199 if (rate_flags & eHAL_TX_RATE_SGI)
4200 rateFlag |= 2;
4201
4202 supported_mcs_rate =
4203 (struct index_data_rate_type *)
4204 ((nss ==
4205 1) ? &supported_mcs_rate_nss1 :
4206 &supported_mcs_rate_nss2);
4207
4208 maxHtIdx = MAX_HT_MCS_IDX;
4209 if (rssidx != 0) {
4210 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
4211 if (sinfo->signal <=
4212 rssi_mcs_tbl[mode][i]) {
4213 maxHtIdx = i + 1;
4214 break;
4215 }
4216 }
4217 }
4218
4219 for (i = 0; i < MCSLeng; i++) {
4220 for (j = 0; j < maxHtIdx; j++) {
4221 if (supported_mcs_rate[j].
4222 beacon_rate_index ==
4223 MCSRates[i]) {
4224 currentRate =
4225 supported_mcs_rate[j].
4226 supported_rate
4227 [rateFlag];
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05304228 maxMCSIdx =
4229 supported_mcs_rate[j].
4230 beacon_rate_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004231 break;
4232 }
4233 }
4234
4235 if ((j < MAX_HT_MCS_IDX)
4236 && (currentRate > maxRate)) {
4237 maxRate = currentRate;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004238 }
Hanumantha Reddy Pothula616dfbe2015-10-01 14:14:46 +05304239 maxSpeedMCS = 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004240 }
4241 }
4242 }
4243
4244 else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
4245 maxRate = myRate;
4246 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08004247 maxMCSIdx = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004248 }
4249 /* report a value at least as big as current rate */
4250 if ((maxRate < myRate) || (0 == maxRate)) {
4251 maxRate = myRate;
4252 if (rate_flags & eHAL_TX_RATE_LEGACY) {
4253 maxSpeedMCS = 0;
4254 } else {
4255 maxSpeedMCS = 1;
Dustin Brown905cdc72016-11-16 16:51:10 -08004256 maxMCSIdx = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004257 }
4258 }
4259
4260 if (rate_flags & eHAL_TX_RATE_LEGACY) {
4261 sinfo->txrate.legacy = maxRate;
Dustin Brown32cb4792017-06-15 15:33:42 -07004262 linkspeed_dbg("Reporting legacy rate %d\n",
4263 sinfo->txrate.legacy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004264 } else {
4265 sinfo->txrate.mcs = maxMCSIdx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004266 sinfo->txrate.nss = nss;
Dustin Brown32cb4792017-06-15 15:33:42 -07004267 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
4268
4269 if (rate_flags & eHAL_TX_RATE_VHT80)
4270 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_80);
4271 else if (rate_flags & eHAL_TX_RATE_VHT40)
4272 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_40);
4273
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004274 if (rate_flags &
4275 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
4276 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Dustin Brown32cb4792017-06-15 15:33:42 -07004277 if (rate_flags & eHAL_TX_RATE_HT40)
4278 hdd_set_rate_bw(&sinfo->txrate,
4279 HDD_RATE_BW_40);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004280 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004281
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004282 if (rate_flags & eHAL_TX_RATE_SGI) {
4283 if (!
4284 (sinfo->txrate.
4285 flags & RATE_INFO_FLAGS_VHT_MCS))
4286 sinfo->txrate.flags |=
4287 RATE_INFO_FLAGS_MCS;
4288 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
4289 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004290 linkspeed_dbg("Reporting MCS rate %d flags %x\n",
4291 sinfo->txrate.mcs, sinfo->txrate.flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004292 }
4293 } else {
4294 /* report current rate instead of max rate */
4295
4296 if (rate_flags & eHAL_TX_RATE_LEGACY) {
4297 /* provide to the UI in units of 100kbps */
4298 sinfo->txrate.legacy = myRate;
Dustin Brown32cb4792017-06-15 15:33:42 -07004299 linkspeed_dbg("Reporting actual legacy rate %d\n",
4300 sinfo->txrate.legacy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004301 } else {
4302 /* must be MCS */
Dustin Brown905cdc72016-11-16 16:51:10 -08004303 sinfo->txrate.mcs = mcs_index;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004304 sinfo->txrate.nss = nss;
4305 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Dustin Brown32cb4792017-06-15 15:33:42 -07004306
4307 if (rate_flags & eHAL_TX_RATE_VHT80)
4308 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_80);
4309 else if (rate_flags & eHAL_TX_RATE_VHT40)
4310 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_40);
4311
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004312 if (rate_flags &
4313 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
4314 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Dustin Brown32cb4792017-06-15 15:33:42 -07004315 if (rate_flags & eHAL_TX_RATE_HT40)
4316 hdd_set_rate_bw(&sinfo->txrate,
4317 HDD_RATE_BW_40);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004318 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004319
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004320 if (rate_flags & eHAL_TX_RATE_SGI) {
4321 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
4322 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
4323 }
Dustin Brown32cb4792017-06-15 15:33:42 -07004324
4325 linkspeed_dbg("Reporting actual MCS rate %d flags %x\n",
4326 sinfo->txrate.mcs, sinfo->txrate.flags);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004327 }
4328 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004329
Dustin Brown0e4479e2017-07-14 14:47:39 -07004330 wlan_hdd_fill_summary_stats(&pAdapter->hdd_stats.summary_stat, sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004331 sinfo->tx_bytes = pAdapter->stats.tx_bytes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004332 sinfo->rx_bytes = pAdapter->stats.rx_bytes;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004333 sinfo->rx_packets = pAdapter->stats.rx_packets;
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004334
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304335 qdf_mem_copy(&pHddStaCtx->conn_info.txrate,
4336 &sinfo->txrate, sizeof(sinfo->txrate));
4337
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004338#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
4339 sinfo->filled |= STATION_INFO_TX_BITRATE |
4340 STATION_INFO_TX_BYTES |
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004341 STATION_INFO_RX_BYTES |
4342 STATION_INFO_RX_PACKETS;
4343#else
Dustin Brown0e4479e2017-07-14 14:47:39 -07004344 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE) |
4345 BIT(NL80211_STA_INFO_TX_BYTES) |
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004346 BIT(NL80211_STA_INFO_RX_BYTES) |
4347 BIT(NL80211_STA_INFO_RX_PACKETS);
4348#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004349
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304350 if (rate_flags & eHAL_TX_RATE_LEGACY)
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004351 hdd_debug("Reporting legacy rate %d pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304352 sinfo->txrate.legacy, sinfo->tx_packets,
4353 sinfo->rx_packets);
4354 else
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004355 hdd_debug("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304356 sinfo->txrate.mcs, sinfo->txrate.flags,
4357 sinfo->tx_packets, sinfo->rx_packets);
4358
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304359#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
4360 sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
4361 for (i = 0; i < NUM_CHAINS_MAX; i++) {
4362 sinfo->chain_signal_avg[i] =
4363 pAdapter->hdd_stats.per_chain_rssi_stats.rssi[i];
4364 sinfo->chains |= 1 << i;
4365 if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
4366 sinfo->chain_signal_avg[i] != 0)
4367 sinfo->signal_avg = sinfo->chain_signal_avg[i];
4368
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004369 hdd_debug("RSSI for chain %d, vdev_id %d is %d",
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304370 i, pAdapter->sessionId, sinfo->chain_signal_avg[i]);
4371
4372 if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
4373 rssi_stats_valid = true;
4374 }
4375
4376 if (rssi_stats_valid) {
4377#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
4378 sinfo->filled |= STATION_INFO_CHAIN_SIGNAL_AVG;
4379 sinfo->filled |= STATION_INFO_SIGNAL_AVG;
4380#else
4381 sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
4382 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
4383#endif
4384 }
4385#endif
4386
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05304387 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004388 TRACE_CODE_HDD_CFG80211_GET_STA,
4389 pAdapter->sessionId, maxRate));
Dustin Brown32cb4792017-06-15 15:33:42 -07004390
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004391 EXIT();
Dustin Brown32cb4792017-06-15 15:33:42 -07004392
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004393 return 0;
4394}
4395
4396/**
4397 * wlan_hdd_cfg80211_get_station() - get station statistics
4398 * @wiphy: Pointer to wiphy
4399 * @dev: Pointer to network device
4400 * @mac: Pointer to mac
4401 * @sinfo: Pointer to station info
4402 *
4403 * Return: 0 for success, non-zero for failure
4404 */
4405#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
4406int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4407 struct net_device *dev, const uint8_t *mac,
4408 struct station_info *sinfo)
4409#else
4410int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4411 struct net_device *dev, uint8_t *mac,
4412 struct station_info *sinfo)
4413#endif
4414{
4415 int ret;
4416
4417 cds_ssr_protect(__func__);
4418 ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4419 cds_ssr_unprotect(__func__);
4420
4421 return ret;
4422}
4423
4424/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304425 * __wlan_hdd_cfg80211_dump_station() - dump station statistics
4426 * @wiphy: Pointer to wiphy
4427 * @dev: Pointer to network device
4428 * @idx: variable to determine whether to get stats or not
4429 * @mac: Pointer to mac
4430 * @sinfo: Pointer to station info
4431 *
4432 * Return: 0 for success, non-zero for failure
4433 */
4434static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4435 struct net_device *dev,
4436 int idx, u8 *mac,
4437 struct station_info *sinfo)
4438{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07004439 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304440
4441 hdd_debug("%s: idx %d", __func__, idx);
4442 if (idx != 0)
4443 return -ENOENT;
4444 qdf_mem_copy(mac, hdd_ctx->config->intfMacAddr[0].bytes,
4445 QDF_MAC_ADDR_SIZE);
4446 return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4447}
4448
4449/**
4450 * wlan_hdd_cfg80211_dump_station() - dump station statistics
4451 * @wiphy: Pointer to wiphy
4452 * @dev: Pointer to network device
4453 * @idx: variable to determine whether to get stats or not
4454 * @mac: Pointer to mac
4455 * @sinfo: Pointer to station info
4456 *
4457 * Return: 0 for success, non-zero for failure
4458 */
4459int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4460 struct net_device *dev,
4461 int idx, u8 *mac,
4462 struct station_info *sinfo)
4463{
4464 int ret;
4465
4466 cds_ssr_protect(__func__);
4467 ret = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
4468 cds_ssr_unprotect(__func__);
4469 return ret;
4470}
4471
4472/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004473 * hdd_get_stats() - Function to retrieve interface statistics
4474 * @dev: pointer to network device
4475 *
4476 * This function is the ndo_get_stats method for all netdevs
4477 * registered with the kernel
4478 *
4479 * Return: pointer to net_device_stats structure
4480 */
4481struct net_device_stats *hdd_get_stats(struct net_device *dev)
4482{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07004483 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004484
Jeff Johnson3c3994a2016-02-11 08:12:30 -08004485 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004486 return &adapter->stats;
4487}
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304488
4489
4490/*
4491 * time = cycle_count * cycle
4492 * cycle = 1 / clock_freq
4493 * Since the unit of clock_freq reported from
4494 * FW is MHZ, and we want to calculate time in
4495 * ms level, the result is
4496 * time = cycle / (clock_freq * 1000)
4497 */
4498#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
4499static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4500 struct scan_chan_info *chan_info,
4501 struct ieee80211_channel *channels)
4502{
4503 uint64_t clock_freq = chan_info->clock_freq * 1000;
4504
4505 if (channels->center_freq != (uint16_t)chan_info->freq)
4506 return false;
4507
4508 survey->channel = channels;
4509 survey->noise = chan_info->noise_floor;
4510 survey->filled = SURVEY_INFO_NOISE_DBM;
4511
4512 if (opfreq == chan_info->freq)
4513 survey->filled |= SURVEY_INFO_IN_USE;
4514
4515 if (clock_freq == 0)
4516 return true;
4517
4518 survey->time = chan_info->cycle_count / clock_freq;
4519 survey->time_busy = chan_info->rx_clear_count / clock_freq;
4520 survey->time_tx = chan_info->tx_frame_count / clock_freq;
4521
4522 survey->filled |= SURVEY_INFO_TIME |
4523 SURVEY_INFO_TIME_BUSY |
4524 SURVEY_INFO_TIME_TX;
4525 return true;
4526}
4527#else
4528static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4529 struct scan_chan_info *chan_info,
4530 struct ieee80211_channel *channels)
4531{
4532 uint64_t clock_freq = chan_info->clock_freq * 1000;
4533
4534 if (channels->center_freq != (uint16_t)chan_info->freq)
4535 return false;
4536
4537 survey->channel = channels;
4538 survey->noise = chan_info->noise_floor;
4539 survey->filled = SURVEY_INFO_NOISE_DBM;
4540
4541 if (opfreq == chan_info->freq)
4542 survey->filled |= SURVEY_INFO_IN_USE;
4543
4544 if (clock_freq == 0)
4545 return true;
4546
4547 survey->channel_time = chan_info->cycle_count / clock_freq;
4548 survey->channel_time_busy = chan_info->rx_clear_count / clock_freq;
4549 survey->channel_time_tx = chan_info->tx_frame_count / clock_freq;
4550
4551 survey->filled |= SURVEY_INFO_CHANNEL_TIME |
4552 SURVEY_INFO_CHANNEL_TIME_BUSY |
4553 SURVEY_INFO_CHANNEL_TIME_TX;
4554 return true;
4555}
4556#endif
4557
4558static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
Jeff Johnsona11f94b2017-08-29 14:21:35 -07004559 struct hdd_adapter *pAdapter, struct survey_info *survey, int idx)
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304560{
4561 bool filled = false;
4562 int i, j = 0;
4563 uint32_t channel = 0, opfreq; /* Initialization Required */
Jeff Johnson5eb1e682017-08-28 11:42:15 -07004564 struct hdd_context *pHddCtx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304565
4566 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
4567 sme_get_operation_channel(pHddCtx->hHal, &channel, pAdapter->sessionId);
4568 hdd_wlan_get_freq(channel, &opfreq);
4569
4570 mutex_lock(&pHddCtx->chan_info_lock);
4571
Srinivas Girigowda5da651b2017-08-04 11:22:54 -07004572 for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) {
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304573 if (wiphy->bands[i] == NULL)
4574 continue;
4575
4576 for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
4577 struct ieee80211_supported_band *band = wiphy->bands[i];
4578 filled = wlan_fill_survey_result(survey, opfreq,
4579 &pHddCtx->chan_info[idx],
4580 &band->channels[j]);
4581 }
4582 }
4583 mutex_unlock(&pHddCtx->chan_info_lock);
4584
4585 return filled;
4586}
4587
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004588/**
4589 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
4590 * @wiphy: Pointer to wiphy
4591 * @dev: Pointer to network device
4592 * @idx: Index
4593 * @survey: Pointer to survey info
4594 *
4595 * Return: 0 for success, non-zero for failure
4596 */
4597static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4598 struct net_device *dev,
4599 int idx, struct survey_info *survey)
4600{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07004601 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07004602 struct hdd_context *pHddCtx;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07004603 struct hdd_station_ctx *pHddStaCtx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304604 int status;
4605 bool filled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004606
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004607 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004608
Srinivas Girigowda6598eea2017-07-06 19:26:19 -07004609 hdd_debug("dump survey index: %d", idx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304610 if (idx > QDF_MAX_NUM_CHAN - 1)
4611 return -EINVAL;
4612
4613 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
4614 status = wlan_hdd_validate_context(pHddCtx);
4615 if (0 != status)
4616 return status;
4617
4618 if (pHddCtx->chan_info == NULL) {
4619 hdd_err("chan_info is NULL");
4620 return -EINVAL;
4621 }
4622
4623 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004624 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004625 return -EINVAL;
4626 }
4627
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004628 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
4629
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304630 if (pHddCtx->config->fEnableSNRMonitoring == 0)
4631 return -ENONET;
4632
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304633 if (pHddStaCtx->hdd_ReassocScenario) {
4634 hdd_info("Roaming in progress, hence return");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004635 return -ENONET;
4636 }
4637
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304638 filled = wlan_hdd_update_survey_info(wiphy, pAdapter, survey, idx);
4639
4640 if (!filled)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004641 return -ENONET;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304642 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004643 return 0;
4644}
4645
4646/**
4647 * wlan_hdd_cfg80211_dump_survey() - get survey related info
4648 * @wiphy: Pointer to wiphy
4649 * @dev: Pointer to network device
4650 * @idx: Index
4651 * @survey: Pointer to survey info
4652 *
4653 * Return: 0 for success, non-zero for failure
4654 */
4655int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4656 struct net_device *dev,
4657 int idx, struct survey_info *survey)
4658{
4659 int ret;
4660
4661 cds_ssr_protect(__func__);
4662 ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
4663 cds_ssr_unprotect(__func__);
4664
4665 return ret;
4666}
4667/**
4668 * hdd_init_ll_stats_ctx() - initialize link layer stats context
4669 *
4670 * Return: none
4671 */
4672inline void hdd_init_ll_stats_ctx(void)
4673{
4674 spin_lock_init(&ll_stats_context.context_lock);
4675 init_completion(&ll_stats_context.response_event);
4676 ll_stats_context.request_bitmap = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004677}
Nirav Shahbf1b0332016-05-25 14:27:39 +05304678
4679/**
4680 * hdd_display_hif_stats() - display hif stats
4681 *
4682 * Return: none
4683 *
4684 */
4685void hdd_display_hif_stats(void)
4686{
4687 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
4688
4689 if (!hif_ctx)
4690 return;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -07004691
Nirav Shahbf1b0332016-05-25 14:27:39 +05304692 hif_display_stats(hif_ctx);
4693}
4694
4695/**
4696 * hdd_clear_hif_stats() - clear hif stats
4697 *
4698 * Return: none
4699 */
4700void hdd_clear_hif_stats(void)
4701{
4702 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
4703
4704 if (!hif_ctx)
4705 return;
4706 hif_clear_stats(hif_ctx);
4707}