blob: 66d0c9c8a35515d51d7ac729049843ecf25e6007 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Sourav Mohapatrad204a812019-01-09 09:45:08 +05302 * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/**
20 * DOC : wlan_hdd_stats.c
21 *
22 * WLAN Host Device Driver statistics related implementation
23 *
24 */
25
26#include "wlan_hdd_stats.h"
27#include "sme_api.h"
28#include "cds_sched.h"
Dustin Browna09acf42018-11-08 12:32:26 +053029#include "osif_sync.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080030#include "wlan_hdd_trace.h"
Jeff Johnson2b0a7b82016-05-18 15:08:02 -070031#include "wlan_hdd_lpass.h"
Nirav Shahbf1b0332016-05-25 14:27:39 +053032#include "hif.h"
Sandeep Puligillafdd201e2017-02-02 18:43:46 -080033#include <qca_vendor.h>
Zhang Qian4ead8f02017-03-27 14:21:47 +080034#include "wma_api.h"
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +053035#include "wlan_hdd_hostapd.h"
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -070036#include "wlan_osif_request_manager.h"
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -080037#include "wlan_hdd_debugfs_llstat.h"
Jeff Johnson32bd9742018-03-29 13:42:31 -070038#include "wlan_reg_services_api.h"
Yu Wangc0b46f82018-03-09 16:04:15 +080039#include <wlan_cfg80211_mc_cp_stats.h>
Ashish Kumar Dhanotiya017e5022019-07-23 20:58:11 +053040#include "wlan_cp_stats_mc_ucfg_api.h"
Abhinav Kumarb074f2f2018-09-15 15:32:11 +053041#include "wlan_mlme_ucfg_api.h"
42#include "wlan_mlme_ucfg_api.h"
Sourav Mohapatra43e6dea2019-08-18 11:39:23 +053043#include "wlan_hdd_sta_info.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080044
Naveen Rawat23183d62018-04-12 11:19:01 -070045#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
46#define HDD_INFO_SIGNAL STATION_INFO_SIGNAL
47#define HDD_INFO_SIGNAL_AVG STATION_INFO_SIGNAL_AVG
48#define HDD_INFO_TX_PACKETS STATION_INFO_TX_PACKETS
49#define HDD_INFO_TX_RETRIES STATION_INFO_TX_RETRIES
50#define HDD_INFO_TX_FAILED STATION_INFO_TX_FAILED
51#define HDD_INFO_TX_BITRATE STATION_INFO_TX_BITRATE
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +053052#define HDD_INFO_RX_BITRATE STATION_INFO_RX_BITRATE
Naveen Rawat23183d62018-04-12 11:19:01 -070053#define HDD_INFO_TX_BYTES STATION_INFO_TX_BYTES
54#define HDD_INFO_CHAIN_SIGNAL_AVG STATION_INFO_CHAIN_SIGNAL_AVG
55#define HDD_INFO_RX_BYTES STATION_INFO_RX_BYTES
56#define HDD_INFO_RX_PACKETS STATION_INFO_RX_PACKETS
57#define HDD_INFO_TX_BYTES64 0
58#define HDD_INFO_RX_BYTES64 0
59#define HDD_INFO_INACTIVE_TIME 0
60#define HDD_INFO_CONNECTED_TIME 0
Ashish Kumar Dhanotiya14923e62019-06-19 14:58:18 +053061#define HDD_INFO_RX_MPDUS 0
62#define HDD_INFO_FCS_ERROR_COUNT 0
Naveen Rawat23183d62018-04-12 11:19:01 -070063#else
64#define HDD_INFO_SIGNAL BIT(NL80211_STA_INFO_SIGNAL)
65#define HDD_INFO_SIGNAL_AVG BIT(NL80211_STA_INFO_SIGNAL_AVG)
66#define HDD_INFO_TX_PACKETS BIT(NL80211_STA_INFO_TX_PACKETS)
67#define HDD_INFO_TX_RETRIES BIT(NL80211_STA_INFO_TX_RETRIES)
68#define HDD_INFO_TX_FAILED BIT(NL80211_STA_INFO_TX_FAILED)
69#define HDD_INFO_TX_BITRATE BIT(NL80211_STA_INFO_TX_BITRATE)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +053070#define HDD_INFO_RX_BITRATE BIT(NL80211_STA_INFO_RX_BITRATE)
Naveen Rawat23183d62018-04-12 11:19:01 -070071#define HDD_INFO_TX_BYTES BIT(NL80211_STA_INFO_TX_BYTES)
72#define HDD_INFO_CHAIN_SIGNAL_AVG BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
73#define HDD_INFO_RX_BYTES BIT(NL80211_STA_INFO_RX_BYTES)
74#define HDD_INFO_RX_PACKETS BIT(NL80211_STA_INFO_RX_PACKETS)
75#define HDD_INFO_TX_BYTES64 BIT(NL80211_STA_INFO_TX_BYTES64)
76#define HDD_INFO_RX_BYTES64 BIT(NL80211_STA_INFO_RX_BYTES64)
77#define HDD_INFO_INACTIVE_TIME BIT(NL80211_STA_INFO_INACTIVE_TIME)
78#define HDD_INFO_CONNECTED_TIME BIT(NL80211_STA_INFO_CONNECTED_TIME)
Ashish Kumar Dhanotiyab6f487b2019-07-04 11:20:37 +053079#define HDD_INFO_RX_MPDUS BIT_ULL(NL80211_STA_INFO_RX_MPDUS)
80#define HDD_INFO_FCS_ERROR_COUNT BIT_ULL(NL80211_STA_INFO_FCS_ERROR_COUNT)
Naveen Rawat23183d62018-04-12 11:19:01 -070081#endif /* kernel version less than 4.0.0 && no_backport */
82
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080083/* 11B, 11G Rate table include Basic rate and Extended rate
84 * The IDX field is the rate index
85 * The HI field is the rate when RSSI is strong or being ignored
86 * (in this case we report actual rate)
87 * The MID field is the rate when RSSI is moderate
88 * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
89 * The LO field is the rate when RSSI is low
90 * (in this case we don't report rates, actual current rate used)
91 */
Will Huang496b36c2017-07-11 16:38:50 +080092static const struct index_data_rate_type supported_data_rate[] = {
93 /* IDX HI HM LM LO (RSSI-based index */
94 {2, { 10, 10, 10, 0} },
95 {4, { 20, 20, 10, 0} },
96 {11, { 55, 20, 10, 0} },
97 {12, { 60, 55, 20, 0} },
98 {18, { 90, 55, 20, 0} },
99 {22, {110, 55, 20, 0} },
100 {24, {120, 90, 60, 0} },
101 {36, {180, 120, 60, 0} },
102 {44, {220, 180, 60, 0} },
103 {48, {240, 180, 90, 0} },
104 {66, {330, 180, 90, 0} },
105 {72, {360, 240, 90, 0} },
106 {96, {480, 240, 120, 0} },
107 {108, {540, 240, 120, 0} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800108};
109/* MCS Based rate table HT MCS parameters with Nss = 1 */
110static struct index_data_rate_type supported_mcs_rate_nss1[] = {
111/* MCS L20 L40 S20 S40 */
112 {0, {65, 135, 72, 150} },
113 {1, {130, 270, 144, 300} },
114 {2, {195, 405, 217, 450} },
115 {3, {260, 540, 289, 600} },
116 {4, {390, 810, 433, 900} },
117 {5, {520, 1080, 578, 1200} },
118 {6, {585, 1215, 650, 1350} },
119 {7, {650, 1350, 722, 1500} }
120};
121
122/* HT MCS parameters with Nss = 2 */
123static struct index_data_rate_type supported_mcs_rate_nss2[] = {
124/* MCS L20 L40 S20 S40 */
125 {0, {130, 270, 144, 300} },
126 {1, {260, 540, 289, 600} },
127 {2, {390, 810, 433, 900} },
128 {3, {520, 1080, 578, 1200} },
129 {4, {780, 1620, 867, 1800} },
130 {5, {1040, 2160, 1156, 2400} },
131 {6, {1170, 2430, 1300, 2700} },
132 {7, {1300, 2700, 1444, 3000} }
133};
134
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800135/* MCS Based VHT rate table MCS parameters with Nss = 1*/
136static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
137/* MCS L80 S80 L40 S40 L20 S40*/
138 {0, {293, 325}, {135, 150}, {65, 72} },
139 {1, {585, 650}, {270, 300}, {130, 144} },
140 {2, {878, 975}, {405, 450}, {195, 217} },
141 {3, {1170, 1300}, {540, 600}, {260, 289} },
142 {4, {1755, 1950}, {810, 900}, {390, 433} },
143 {5, {2340, 2600}, {1080, 1200}, {520, 578} },
144 {6, {2633, 2925}, {1215, 1350}, {585, 650} },
145 {7, {2925, 3250}, {1350, 1500}, {650, 722} },
146 {8, {3510, 3900}, {1620, 1800}, {780, 867} },
147 {9, {3900, 4333}, {1800, 2000}, {780, 867} }
148};
149
150/*MCS parameters with Nss = 2*/
151static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
152/* MCS L80 S80 L40 S40 L20 S40*/
153 {0, {585, 650}, {270, 300}, {130, 144} },
154 {1, {1170, 1300}, {540, 600}, {260, 289} },
155 {2, {1755, 1950}, {810, 900}, {390, 433} },
156 {3, {2340, 2600}, {1080, 1200}, {520, 578} },
157 {4, {3510, 3900}, {1620, 1800}, {780, 867} },
158 {5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
159 {6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
160 {7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
161 {8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
162 {9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
163};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164
165/*array index ponints to MCS and array value points respective rssi*/
166static int rssi_mcs_tbl[][10] = {
167/*MCS 0 1 2 3 4 5 6 7 8 9*/
168 {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */
169 {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */
170 {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */
171};
172
173
174#ifdef WLAN_FEATURE_LINK_LAYER_STATS
Dundi Ravitejae232cf12018-05-16 18:34:34 +0530175
176/**
177 * struct hdd_ll_stats_priv - hdd link layer stats private
178 * @request_id: userspace-assigned link layer stats request id
179 * @request_bitmap: userspace-assigned link layer stats request bitmap
180 */
181struct hdd_ll_stats_priv {
182 uint32_t request_id;
183 uint32_t request_bitmap;
184};
185
186/*
187 * Used to allocate the size of 4096 for the link layer stats.
188 * The size of 4096 is considered assuming that all data per
189 * respective event fit with in the limit.Please take a call
190 * on the limit based on the data requirements on link layer
191 * statistics.
192 */
193#define LL_STATS_EVENT_BUF_SIZE 4096
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194
195/**
196 * put_wifi_rate_stat() - put wifi rate stats
197 * @stats: Pointer to stats context
198 * @vendor_event: Pointer to vendor event
199 *
200 * Return: bool
201 */
Jeff Johnsond3b3b112019-03-28 12:56:04 -0700202static bool put_wifi_rate_stat(struct wifi_rate_stat *stats,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800203 struct sk_buff *vendor_event)
204{
205 if (nla_put_u8(vendor_event,
206 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
207 stats->rate.preamble) ||
208 nla_put_u8(vendor_event,
209 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
210 stats->rate.nss) ||
211 nla_put_u8(vendor_event,
212 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
213 stats->rate.bw) ||
214 nla_put_u8(vendor_event,
215 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
Jeff Johnsonb67be242019-03-30 10:25:53 -0700216 stats->rate.rate_or_mcs_index) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800217 nla_put_u32(vendor_event,
218 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
219 stats->rate.bitrate) ||
220 nla_put_u32(vendor_event,
Jeff Johnsonb67be242019-03-30 10:25:53 -0700221 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
222 stats->tx_mpdu) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 nla_put_u32(vendor_event,
Jeff Johnsonb67be242019-03-30 10:25:53 -0700224 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
225 stats->rx_mpdu) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800226 nla_put_u32(vendor_event,
Jeff Johnsonb67be242019-03-30 10:25:53 -0700227 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
228 stats->mpdu_lost) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800229 nla_put_u32(vendor_event,
Jeff Johnsonb67be242019-03-30 10:25:53 -0700230 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
231 stats->retries) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 nla_put_u32(vendor_event,
Jeff Johnsonb67be242019-03-30 10:25:53 -0700233 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
234 stats->retries_short) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800235 nla_put_u32(vendor_event,
Jeff Johnsonb67be242019-03-30 10:25:53 -0700236 QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
237 stats->retries_long)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700238 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800239 return false;
240 }
241
242 return true;
243}
244
245/**
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700246 * put_wifi_peer_rates() - put wifi peer rate info
247 * @stats: Pointer to stats context
248 * @vendor_event: Pointer to vendor event
249 *
250 * Return: bool
251 */
Jeff Johnson10495032019-03-28 13:51:59 -0700252static bool put_wifi_peer_rates(struct wifi_peer_info *stats,
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700253 struct sk_buff *vendor_event)
254{
255 uint32_t i;
Jeff Johnsond3b3b112019-03-28 12:56:04 -0700256 struct wifi_rate_stat *rate_stat;
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700257 int nest_id;
258 struct nlattr *info;
259 struct nlattr *rates;
260
261 /* no rates is ok */
Jeff Johnson10495032019-03-28 13:51:59 -0700262 if (!stats->num_rate)
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700263 return true;
264
265 nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO;
266 info = nla_nest_start(vendor_event, nest_id);
267 if (!info)
268 return false;
269
Jeff Johnson10495032019-03-28 13:51:59 -0700270 for (i = 0; i < stats->num_rate; i++) {
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700271 rates = nla_nest_start(vendor_event, i);
272 if (!rates)
273 return false;
Jeff Johnson10495032019-03-28 13:51:59 -0700274 rate_stat = &stats->rate_stats[i];
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700275 if (!put_wifi_rate_stat(rate_stat, vendor_event)) {
276 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
277 return false;
278 }
279 nla_nest_end(vendor_event, rates);
280 }
281 nla_nest_end(vendor_event, info);
282
283 return true;
284}
285
286/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800287 * put_wifi_peer_info() - put wifi peer info
288 * @stats: Pointer to stats context
289 * @vendor_event: Pointer to vendor event
290 *
291 * Return: bool
292 */
Jeff Johnson10495032019-03-28 13:51:59 -0700293static bool put_wifi_peer_info(struct wifi_peer_info *stats,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800294 struct sk_buff *vendor_event)
295{
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700296 if (nla_put_u32(vendor_event,
297 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
298 wmi_to_sir_peer_type(stats->type)) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800299 nla_put(vendor_event,
300 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
Jeff Johnson10495032019-03-28 13:51:59 -0700301 QDF_MAC_ADDR_SIZE, &stats->peer_macaddr.bytes[0]) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800302 nla_put_u32(vendor_event,
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700303 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
304 stats->capabilities) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800305 nla_put_u32(vendor_event,
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700306 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
Jeff Johnson10495032019-03-28 13:51:59 -0700307 stats->num_rate)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700308 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700309 return false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800310 }
311
Jeff Johnson43b0c6a2019-03-27 15:08:19 -0700312 return put_wifi_peer_rates(stats, vendor_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800313}
314
315/**
316 * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
317 * @stats: Pointer to stats context
318 * @vendor_event: Pointer to vendor event
319 *
320 * Return: bool
321 */
Min Liuffb250d2018-07-11 17:35:32 +0800322static bool put_wifi_wmm_ac_stat(wmi_wmm_ac_stats *stats,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800323 struct sk_buff *vendor_event)
324{
325 if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
Min Liuffb250d2018-07-11 17:35:32 +0800326 stats->ac_type) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800327 nla_put_u32(vendor_event,
328 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
Min Liuffb250d2018-07-11 17:35:32 +0800329 stats->tx_mpdu) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800330 nla_put_u32(vendor_event,
331 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
Min Liuffb250d2018-07-11 17:35:32 +0800332 stats->rx_mpdu) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800333 nla_put_u32(vendor_event,
334 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
Min Liuffb250d2018-07-11 17:35:32 +0800335 stats->tx_mcast) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800336 nla_put_u32(vendor_event,
337 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
Min Liuffb250d2018-07-11 17:35:32 +0800338 stats->rx_mcast) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800339 nla_put_u32(vendor_event,
340 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
Min Liuffb250d2018-07-11 17:35:32 +0800341 stats->rx_ampdu) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800342 nla_put_u32(vendor_event,
343 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
Min Liuffb250d2018-07-11 17:35:32 +0800344 stats->tx_ampdu) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800345 nla_put_u32(vendor_event,
346 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
Min Liuffb250d2018-07-11 17:35:32 +0800347 stats->mpdu_lost) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800348 nla_put_u32(vendor_event,
349 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
350 stats->retries) ||
351 nla_put_u32(vendor_event,
352 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
Min Liuffb250d2018-07-11 17:35:32 +0800353 stats->retries_short) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800354 nla_put_u32(vendor_event,
355 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
Min Liuffb250d2018-07-11 17:35:32 +0800356 stats->retries_long) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800357 nla_put_u32(vendor_event,
358 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
Min Liuffb250d2018-07-11 17:35:32 +0800359 stats->contention_time_min) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800360 nla_put_u32(vendor_event,
361 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
Min Liuffb250d2018-07-11 17:35:32 +0800362 stats->contention_time_max) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800363 nla_put_u32(vendor_event,
364 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
Min Liuffb250d2018-07-11 17:35:32 +0800365 stats->contention_time_avg) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800366 nla_put_u32(vendor_event,
367 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
Min Liuffb250d2018-07-11 17:35:32 +0800368 stats->contention_num_samples)) {
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 return true;
374}
375
376/**
377 * put_wifi_interface_info() - put wifi interface info
378 * @stats: Pointer to stats context
379 * @vendor_event: Pointer to vendor event
380 *
381 * Return: bool
382 */
Jeff Johnsonc9770ee2019-03-08 15:56:52 -0800383static bool put_wifi_interface_info(struct wifi_interface_info *stats,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800384 struct sk_buff *vendor_event)
385{
386 if (nla_put_u32(vendor_event,
387 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
388 stats->mode) ||
389 nla_put(vendor_event,
390 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530391 QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800392 nla_put_u32(vendor_event,
393 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
394 stats->state) ||
395 nla_put_u32(vendor_event,
396 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
397 stats->roaming) ||
398 nla_put_u32(vendor_event,
399 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
400 stats->capabilities) ||
401 nla_put(vendor_event,
402 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
403 strlen(stats->ssid), stats->ssid) ||
404 nla_put(vendor_event,
405 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530406 QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800407 nla_put(vendor_event,
408 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
Wu Gaoaa155142019-01-14 15:09:26 +0800409 CFG_COUNTRY_CODE_LEN, stats->apCountryStr) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800410 nla_put(vendor_event,
411 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
Wu Gaoaa155142019-01-14 15:09:26 +0800412 CFG_COUNTRY_CODE_LEN, stats->countryStr)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700413 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800414 return false;
415 }
416
417 return true;
418}
419
420/**
421 * put_wifi_iface_stats() - put wifi interface stats
Jeff Johnson84396672019-03-26 15:31:55 -0700422 * @if_stat: Pointer to interface stats context
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423 * @num_peer: Number of peers
424 * @vendor_event: Pointer to vendor event
425 *
426 * Return: bool
427 */
Jeff Johnsonaf545282019-04-01 12:18:59 -0700428static bool put_wifi_iface_stats(struct wifi_interface_stats *if_stat,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800429 u32 num_peers, struct sk_buff *vendor_event)
430{
431 int i = 0;
Jeff Johnson0dc42112019-03-26 15:28:23 -0700432 struct nlattr *wmm_info;
433 struct nlattr *wmm_stats;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800434 u64 average_tsf_offset;
Jeff Johnson84396672019-03-26 15:31:55 -0700435 wmi_iface_link_stats *link_stats = &if_stat->link_stats;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800436
Jeff Johnson84396672019-03-26 15:31:55 -0700437 if (!put_wifi_interface_info(&if_stat->info, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700438 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800439 return false;
440
441 }
442
Min Liuffb250d2018-07-11 17:35:32 +0800443 average_tsf_offset = link_stats->avg_bcn_spread_offset_high;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800444 average_tsf_offset = (average_tsf_offset << 32) |
Min Liuffb250d2018-07-11 17:35:32 +0800445 link_stats->avg_bcn_spread_offset_low;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800446
447 if (nla_put_u32(vendor_event,
448 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
449 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) ||
450 nla_put_u32(vendor_event,
451 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
452 num_peers) ||
453 nla_put_u32(vendor_event,
454 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
Min Liuffb250d2018-07-11 17:35:32 +0800455 link_stats->beacon_rx) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800456 nla_put_u32(vendor_event,
457 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
Min Liuffb250d2018-07-11 17:35:32 +0800458 link_stats->mgmt_rx) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800459 nla_put_u32(vendor_event,
460 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
Min Liuffb250d2018-07-11 17:35:32 +0800461 link_stats->mgmt_action_rx) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800462 nla_put_u32(vendor_event,
463 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
Min Liuffb250d2018-07-11 17:35:32 +0800464 link_stats->mgmt_action_tx) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800465 nla_put_u32(vendor_event,
466 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
Min Liuffb250d2018-07-11 17:35:32 +0800467 link_stats->rssi_mgmt) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800468 nla_put_u32(vendor_event,
469 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
Min Liuffb250d2018-07-11 17:35:32 +0800470 link_stats->rssi_data) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800471 nla_put_u32(vendor_event,
472 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
Min Liuffb250d2018-07-11 17:35:32 +0800473 link_stats->rssi_ack) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474 nla_put_u32(vendor_event,
475 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
Min Liuffb250d2018-07-11 17:35:32 +0800476 link_stats->is_leaky_ap) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477 nla_put_u32(vendor_event,
478 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
Min Liuffb250d2018-07-11 17:35:32 +0800479 link_stats->avg_rx_frms_leaked) ||
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800480 nla_put_u32(vendor_event,
481 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
Min Liuffb250d2018-07-11 17:35:32 +0800482 link_stats->rx_leak_window) ||
Dustin Brownbb7e2f52016-10-17 12:16:35 -0700483 hdd_wlan_nla_put_u64(vendor_event,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800484 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
gaolezb432ed92017-03-16 18:40:04 +0800485 average_tsf_offset) ||
486 nla_put_u32(vendor_event,
487 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT,
Jeff Johnson84396672019-03-26 15:31:55 -0700488 if_stat->rts_succ_cnt) ||
gaolezb432ed92017-03-16 18:40:04 +0800489 nla_put_u32(vendor_event,
490 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT,
Jeff Johnson84396672019-03-26 15:31:55 -0700491 if_stat->rts_fail_cnt) ||
gaolezb432ed92017-03-16 18:40:04 +0800492 nla_put_u32(vendor_event,
493 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT,
Jeff Johnson84396672019-03-26 15:31:55 -0700494 if_stat->ppdu_succ_cnt) ||
gaolezb432ed92017-03-16 18:40:04 +0800495 nla_put_u32(vendor_event,
496 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT,
Jeff Johnson84396672019-03-26 15:31:55 -0700497 if_stat->ppdu_fail_cnt)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700498 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800499 return false;
500 }
501
Jeff Johnson0dc42112019-03-26 15:28:23 -0700502 wmm_info = nla_nest_start(vendor_event,
503 QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
504 if (!wmm_info)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800505 return false;
506
507 for (i = 0; i < WIFI_AC_MAX; i++) {
Jeff Johnson0dc42112019-03-26 15:28:23 -0700508 wmm_stats = nla_nest_start(vendor_event, i);
509 if (!wmm_stats)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800510 return false;
511
Jeff Johnson84396672019-03-26 15:31:55 -0700512 if (!put_wifi_wmm_ac_stat(&if_stat->ac_stats[i],
513 vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700514 hdd_err("put_wifi_wmm_ac_stat Fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800515 return false;
516 }
517
Jeff Johnson0dc42112019-03-26 15:28:23 -0700518 nla_nest_end(vendor_event, wmm_stats);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800519 }
Jeff Johnson0dc42112019-03-26 15:28:23 -0700520 nla_nest_end(vendor_event, wmm_info);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800521 return true;
522}
523
524/**
525 * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
Jeff Johnson2acf0092019-03-31 14:34:53 -0700526 * @device_mode: Device mode
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800527 *
528 * Return: interface mode
529 */
Jeff Johnson2acf0092019-03-31 14:34:53 -0700530static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800531{
Jeff Johnson2acf0092019-03-31 14:34:53 -0700532 switch (device_mode) {
Krunal Sonif07bb382016-03-10 13:02:11 -0800533 case QDF_STA_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800534 return WIFI_INTERFACE_STA;
Krunal Sonif07bb382016-03-10 13:02:11 -0800535 case QDF_SAP_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800536 return WIFI_INTERFACE_SOFTAP;
Krunal Sonif07bb382016-03-10 13:02:11 -0800537 case QDF_P2P_CLIENT_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800538 return WIFI_INTERFACE_P2P_CLIENT;
Krunal Sonif07bb382016-03-10 13:02:11 -0800539 case QDF_P2P_GO_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800540 return WIFI_INTERFACE_P2P_GO;
Krunal Sonif07bb382016-03-10 13:02:11 -0800541 case QDF_IBSS_MODE:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800542 return WIFI_INTERFACE_IBSS;
543 default:
544 /* Return Interface Mode as STA for all the unsupported modes */
545 return WIFI_INTERFACE_STA;
546 }
547}
548
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700549bool hdd_get_interface_info(struct hdd_adapter *adapter,
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700550 struct wifi_interface_info *info)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800551{
Jeff Johnsond377dce2017-10-04 10:32:42 -0700552 struct hdd_station_ctx *sta_ctx;
Jeff Johnson003f7392018-06-12 20:45:47 -0700553 mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle;
554 /* pre-existing layering violation */
Jeff Johnson034f3c92018-11-09 10:46:21 -0800555 struct mac_context *mac = MAC_CONTEXT(mac_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800556
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700557 info->mode = hdd_map_device_to_ll_iface_mode(adapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800558
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700559 qdf_copy_macaddr(&info->macAddr, &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800560
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700561 if (((QDF_STA_MODE == adapter->device_mode) ||
562 (QDF_P2P_CLIENT_MODE == adapter->device_mode) ||
563 (QDF_P2P_DEVICE_MODE == adapter->device_mode))) {
Jeff Johnsond377dce2017-10-04 10:32:42 -0700564 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800565 if (eConnectionState_NotConnected ==
Jeff Johnsone7951512019-02-27 10:02:51 -0800566 sta_ctx->conn_info.conn_state) {
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700567 info->state = WIFI_DISCONNECTED;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800568 }
569 if (eConnectionState_Connecting ==
Jeff Johnsone7951512019-02-27 10:02:51 -0800570 sta_ctx->conn_info.conn_state) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700571 hdd_err("Session ID %d, Connection is in progress",
Jeff Johnson1abc5662019-02-04 14:27:02 -0800572 adapter->vdev_id);
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700573 info->state = WIFI_ASSOCIATING;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800574 }
575 if ((eConnectionState_Associated ==
Jeff Johnson84396672019-03-26 15:31:55 -0700576 sta_ctx->conn_info.conn_state) &&
577 (!sta_ctx->conn_info.is_authenticated)) {
Srinivas Girigowdacb7b8b82019-04-10 14:27:47 -0700578 hdd_err("client " QDF_MAC_ADDR_STR
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700579 " is in the middle of WPS/EAPOL exchange.",
Srinivas Girigowda34fbba02019-04-08 12:07:44 -0700580 QDF_MAC_ADDR_ARRAY(adapter->mac_addr.bytes));
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700581 info->state = WIFI_AUTHENTICATING;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800582 }
583 if (eConnectionState_Associated ==
Jeff Johnsone7951512019-02-27 10:02:51 -0800584 sta_ctx->conn_info.conn_state) {
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700585 info->state = WIFI_ASSOCIATED;
586 qdf_copy_macaddr(&info->bssid,
Jeff Johnsone04b6992019-02-27 14:06:55 -0800587 &sta_ctx->conn_info.bssid);
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700588 qdf_mem_copy(info->ssid,
Jeff Johnson4aea1802019-02-27 10:21:33 -0800589 sta_ctx->conn_info.ssid.SSID.ssId,
590 sta_ctx->conn_info.ssid.SSID.length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800591 /*
592 * NULL Terminate the string
593 */
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700594 info->ssid[sta_ctx->conn_info.ssid.SSID.length] = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800595 }
596 }
597
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700598 qdf_mem_copy(info->countryStr,
Wu Gaoaa155142019-01-14 15:09:26 +0800599 mac->scan.countryCodeCurrent, CFG_COUNTRY_CODE_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800600
Jeff Johnson0bbf3832019-03-31 12:19:36 -0700601 qdf_mem_copy(info->apCountryStr,
Wu Gaoaa155142019-01-14 15:09:26 +0800602 mac->scan.countryCodeCurrent, CFG_COUNTRY_CODE_LEN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800603
604 return true;
605}
606
607/**
608 * hdd_link_layer_process_peer_stats() - This function is called after
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700609 * @adapter: Pointer to device adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800610 * @more_data: More data
Jeff Johnsonb16fd942019-03-31 11:30:37 -0700611 * @peer_stat: Pointer to stats data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800612 *
613 * Receiving Link Layer Peer statistics from FW.This function converts
614 * the firmware data to the NL data and sends the same to the kernel/upper
615 * layers.
616 *
617 * Return: None
618 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700619static void hdd_link_layer_process_peer_stats(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800620 u32 more_data,
Jeff Johnsonb16fd942019-03-31 11:30:37 -0700621 struct wifi_peer_stat *peer_stat)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800622{
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700623 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson10495032019-03-28 13:51:59 -0700624 struct wifi_peer_info *peer_info;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800625 struct sk_buff *vendor_event;
Sushant Kaushik7a535882015-11-02 13:31:21 +0530626 int status, i;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800627 struct nlattr *peers;
Jeff Johnson10495032019-03-28 13:51:59 -0700628 int num_rate;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800629
Dustin Brown491d54b2018-03-14 12:39:11 -0700630 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530631
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700632 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530633 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800634 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800635
Jeff Johnsonfcb078d2019-03-28 14:34:01 -0700636 hdd_debug("LL_STATS_PEER_ALL : num_peers %u, more data = %u",
637 peer_stat->num_peers, more_data);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800638
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800639 /*
640 * Allocate a size of 4096 for the peer stats comprising
Jeff Johnson10495032019-03-28 13:51:59 -0700641 * each of size = sizeof (struct wifi_peer_info) + num_rate *
Jeff Johnsond3b3b112019-03-28 12:56:04 -0700642 * sizeof (struct wifi_rate_stat).Each field is put with an
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800643 * NL attribute.The size of 4096 is considered assuming
644 * that number of rates shall not exceed beyond 50 with
Jeff Johnsond3b3b112019-03-28 12:56:04 -0700645 * the sizeof (struct wifi_rate_stat) being 32.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800646 */
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700647 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800648 LL_STATS_EVENT_BUF_SIZE);
649
650 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700651 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800652 return;
653 }
654
655 if (nla_put_u32(vendor_event,
656 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
657 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
658 nla_put_u32(vendor_event,
659 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
660 more_data) ||
661 nla_put_u32(vendor_event,
662 QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
Jeff Johnsonfcb078d2019-03-28 14:34:01 -0700663 peer_stat->num_peers)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700664 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800665
666 kfree_skb(vendor_event);
667 return;
668 }
669
Jeff Johnson10495032019-03-28 13:51:59 -0700670 peer_info = (struct wifi_peer_info *) ((uint8_t *)
Jeff Johnsonfcb078d2019-03-28 14:34:01 -0700671 peer_stat->peer_info);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800672
Jeff Johnsonfcb078d2019-03-28 14:34:01 -0700673 if (peer_stat->num_peers) {
674 struct nlattr *peer_nest;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700675
Jeff Johnsonfcb078d2019-03-28 14:34:01 -0700676 peer_nest = nla_nest_start(vendor_event,
677 QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO);
678 if (!peer_nest) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700679 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800680 kfree_skb(vendor_event);
681 return;
682 }
683
Jeff Johnsonfcb078d2019-03-28 14:34:01 -0700684 for (i = 1; i <= peer_stat->num_peers; i++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800685 peers = nla_nest_start(vendor_event, i);
Jeff Johnsond36fa332019-03-18 13:42:25 -0700686 if (!peers) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700687 hdd_err("nla_nest_start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800688 kfree_skb(vendor_event);
689 return;
690 }
691
Jeff Johnson10495032019-03-28 13:51:59 -0700692 num_rate = peer_info->num_rate;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800693
Jeff Johnson35a70252019-03-26 15:40:40 -0700694 if (!put_wifi_peer_info(peer_info, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700695 hdd_err("put_wifi_peer_info fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800696 kfree_skb(vendor_event);
697 return;
698 }
699
Jeff Johnson10495032019-03-28 13:51:59 -0700700 peer_info = (struct wifi_peer_info *)
Jeff Johnsonfcb078d2019-03-28 14:34:01 -0700701 ((uint8_t *)peer_stat->peer_info +
Jeff Johnson10495032019-03-28 13:51:59 -0700702 (i * sizeof(struct wifi_peer_info)) +
703 (num_rate * sizeof(struct wifi_rate_stat)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800704 nla_nest_end(vendor_event, peers);
705 }
Jeff Johnsonfcb078d2019-03-28 14:34:01 -0700706 nla_nest_end(vendor_event, peer_nest);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800707 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -0700708
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800709 cfg80211_vendor_cmd_reply(vendor_event);
Dustin Browne74003f2018-03-14 12:51:58 -0700710 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800711}
712
713/**
714 * hdd_link_layer_process_iface_stats() - This function is called after
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700715 * @adapter: Pointer to device adapter
Jeff Johnsonb16fd942019-03-31 11:30:37 -0700716 * @if_stat: Pointer to stats data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800717 * @num_peers: Number of peers
718 *
719 * Receiving Link Layer Interface statistics from FW.This function converts
720 * the firmware data to the NL data and sends the same to the kernel/upper
721 * layers.
722 *
723 * Return: None
724 */
Jeff Johnsonaf545282019-04-01 12:18:59 -0700725static void
726hdd_link_layer_process_iface_stats(struct hdd_adapter *adapter,
727 struct wifi_interface_stats *if_stat,
728 u32 num_peers)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800729{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800730 struct sk_buff *vendor_event;
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700731 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732 int status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800733
Dustin Brown491d54b2018-03-14 12:39:11 -0700734 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530735
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700736 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530737 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800738 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800739
740 /*
741 * Allocate a size of 4096 for the interface stats comprising
Jeff Johnsonaf545282019-04-01 12:18:59 -0700742 * sizeof (struct wifi_interface_stats *).The size of 4096 is considered
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800743 * assuming that all these fit with in the limit.Please take
744 * a call on the limit based on the data requirements on
745 * interface statistics.
746 */
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700747 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800748 LL_STATS_EVENT_BUF_SIZE);
749
750 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700751 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800752 return;
753 }
754
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800755 hdd_debug("WMI_LINK_STATS_IFACE Data");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800756
Jeff Johnson84396672019-03-26 15:31:55 -0700757 if (!hdd_get_interface_info(adapter, &if_stat->info)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700758 hdd_err("hdd_get_interface_info get fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800759 kfree_skb(vendor_event);
760 return;
761 }
762
Jeff Johnson84396672019-03-26 15:31:55 -0700763 if (!put_wifi_iface_stats(if_stat, num_peers, vendor_event)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -0700764 hdd_err("put_wifi_iface_stats fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800765 kfree_skb(vendor_event);
766 return;
767 }
768
769 cfg80211_vendor_cmd_reply(vendor_event);
Dustin Browne74003f2018-03-14 12:51:58 -0700770 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800771}
772
773/**
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700774 * hdd_llstats_radio_fill_channels() - radio stats fill channels
775 * @adapter: Pointer to device adapter
776 * @radiostat: Pointer to stats data
777 * @vendor_event: vendor event
778 *
779 * Return: 0 on success; errno on failure
780 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700781static int hdd_llstats_radio_fill_channels(struct hdd_adapter *adapter,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700782 struct wifi_radio_stats *radiostat,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700783 struct sk_buff *vendor_event)
784{
Jeff Johnson4ee14f42019-03-30 10:43:37 -0700785 struct wifi_channel_stats *channel_stats;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700786 struct nlattr *chlist;
787 struct nlattr *chinfo;
788 int i;
789
790 chlist = nla_nest_start(vendor_event,
791 QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
Jeff Johnsond36fa332019-03-18 13:42:25 -0700792 if (!chlist) {
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700793 hdd_err("nla_nest_start failed");
794 return -EINVAL;
795 }
796
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700797 for (i = 0; i < radiostat->num_channels; i++) {
Jeff Johnson4ee14f42019-03-30 10:43:37 -0700798 channel_stats = (struct wifi_channel_stats *) ((uint8_t *)
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700799 radiostat->channels +
Jeff Johnson4ee14f42019-03-30 10:43:37 -0700800 (i * sizeof(struct wifi_channel_stats)));
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700801
802 chinfo = nla_nest_start(vendor_event, i);
Jeff Johnsond36fa332019-03-18 13:42:25 -0700803 if (!chinfo) {
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700804 hdd_err("nla_nest_start failed");
805 return -EINVAL;
806 }
807
808 if (nla_put_u32(vendor_event,
809 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
810 channel_stats->channel.width) ||
811 nla_put_u32(vendor_event,
812 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
Jeff Johnson17ba70a2019-03-30 08:34:14 -0700813 channel_stats->channel.center_freq) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700814 nla_put_u32(vendor_event,
815 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
Jeff Johnson17ba70a2019-03-30 08:34:14 -0700816 channel_stats->channel.center_freq0) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700817 nla_put_u32(vendor_event,
818 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
Jeff Johnson17ba70a2019-03-30 08:34:14 -0700819 channel_stats->channel.center_freq1) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700820 nla_put_u32(vendor_event,
821 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
Jeff Johnson4ee14f42019-03-30 10:43:37 -0700822 channel_stats->on_time) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700823 nla_put_u32(vendor_event,
824 QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
Jeff Johnson4ee14f42019-03-30 10:43:37 -0700825 channel_stats->cca_busy_time)) {
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700826 hdd_err("nla_put failed");
827 return -EINVAL;
828 }
829 nla_nest_end(vendor_event, chinfo);
830 }
831 nla_nest_end(vendor_event, chlist);
832
833 return 0;
834}
835
836/**
837 * hdd_llstats_post_radio_stats() - post radio stats
838 * @adapter: Pointer to device adapter
839 * @more_data: More data
840 * @radiostat: Pointer to stats data
841 * @num_radio: Number of radios
842 *
843 * Return: 0 on success; errno on failure
844 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -0700845static int hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700846 u32 more_data,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700847 struct wifi_radio_stats *radiostat,
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700848 u32 num_radio)
849{
850 struct sk_buff *vendor_event;
Jeff Johnson5eb1e682017-08-28 11:42:15 -0700851 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700852 int ret;
853
854 /*
855 * Allocate a size of 4096 for the Radio stats comprising
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700856 * sizeof (struct wifi_radio_stats) + num_channels * sizeof
Jeff Johnson4ee14f42019-03-30 10:43:37 -0700857 * (struct wifi_channel_stats).Each channel data is put with an
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700858 * NL attribute.The size of 4096 is considered assuming that
859 * number of channels shall not exceed beyond 60 with the
Jeff Johnson4ee14f42019-03-30 10:43:37 -0700860 * sizeof (struct wifi_channel_stats) being 24 bytes.
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700861 */
862
863 vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(
864 hdd_ctx->wiphy,
865 LL_STATS_EVENT_BUF_SIZE);
866
867 if (!vendor_event) {
868 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
869 return -ENOMEM;
870 }
871
872 if (nla_put_u32(vendor_event,
873 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
874 QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
875 nla_put_u32(vendor_event,
876 QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
877 more_data) ||
878 nla_put_u32(vendor_event,
879 QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
880 num_radio) ||
881 nla_put_u32(vendor_event,
882 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
883 radiostat->radio) ||
884 nla_put_u32(vendor_event,
885 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700886 radiostat->on_time) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700887 nla_put_u32(vendor_event,
888 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700889 radiostat->tx_time) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700890 nla_put_u32(vendor_event,
891 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700892 radiostat->rx_time) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700893 nla_put_u32(vendor_event,
894 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700895 radiostat->on_time_scan) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700896 nla_put_u32(vendor_event,
897 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700898 radiostat->on_time_nbd) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700899 nla_put_u32(vendor_event,
900 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700901 radiostat->on_time_gscan) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700902 nla_put_u32(vendor_event,
903 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700904 radiostat->on_time_roam_scan) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700905 nla_put_u32(vendor_event,
906 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700907 radiostat->on_time_pno_scan) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700908 nla_put_u32(vendor_event,
909 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700910 radiostat->on_time_hs20) ||
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700911 nla_put_u32(vendor_event,
912 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
913 radiostat->total_num_tx_power_levels) ||
914 nla_put_u32(vendor_event,
915 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700916 radiostat->num_channels)) {
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700917 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
918 goto failure;
919 }
920
921 if (radiostat->total_num_tx_power_levels) {
922 if (nla_put(vendor_event,
923 QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
924 sizeof(u32) *
925 radiostat->total_num_tx_power_levels,
926 radiostat->tx_time_per_power_level)) {
927 hdd_err("nla_put fail");
928 goto failure;
929 }
930 }
931
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700932 if (radiostat->num_channels) {
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700933 ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
934 vendor_event);
935 if (ret)
936 goto failure;
937 }
938
939 cfg80211_vendor_cmd_reply(vendor_event);
940 return 0;
941
942failure:
943 kfree_skb(vendor_event);
944 return -EINVAL;
945}
946
947/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800948 * hdd_link_layer_process_radio_stats() - This function is called after
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700949 * @adapter: Pointer to device adapter
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800950 * @more_data: More data
Jeff Johnsonb16fd942019-03-31 11:30:37 -0700951 * @radio_stat: Pointer to stats data
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800952 * @num_radios: Number of radios
953 *
954 * Receiving Link Layer Radio statistics from FW.This function converts
955 * the firmware data to the NL data and sends the same to the kernel/upper
956 * layers.
957 *
958 * Return: None
959 */
Jeff Johnsonb16fd942019-03-31 11:30:37 -0700960static void
961hdd_link_layer_process_radio_stats(struct hdd_adapter *adapter,
962 u32 more_data,
963 struct wifi_radio_stats *radio_stat,
964 u32 num_radio)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800965{
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700966 int status, i, nr, ret;
Jeff Johnsonb16fd942019-03-31 11:30:37 -0700967 struct wifi_radio_stats *radio_stat_save = radio_stat;
Jeff Johnsona86e78e2017-10-02 13:23:05 -0700968 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800969
Dustin Brown491d54b2018-03-14 12:39:11 -0700970 hdd_enter();
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530971
Jeff Johnsonf645abf2017-09-03 09:07:46 -0700972 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530973 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800974 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800975
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800976 hdd_debug("LL_STATS_RADIO: number of radios: %u", num_radio);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800977
Srinivas Girigowda57b450e2016-10-27 21:00:46 -0700978 for (i = 0; i < num_radio; i++) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -0800979 hdd_debug("LL_STATS_RADIO"
Jeff Johnsone4bba7c2019-03-30 11:58:51 -0700980 " radio: %u on_time: %u tx_time: %u rx_time: %u"
981 " on_time_scan: %u on_time_nbd: %u"
982 " on_time_gscan: %u on_time_roam_scan: %u"
983 " on_time_pno_scan: %u on_time_hs20: %u"
984 " num_channels: %u total_num_tx_pwr_levels: %u"
Krishna Kumaar Natarajan7bff29b2017-03-08 16:05:05 -0800985 " on_time_host_scan: %u, on_time_lpi_scan: %u",
Jeff Johnson05bf6d12019-03-31 11:22:45 -0700986 radio_stat->radio, radio_stat->on_time,
987 radio_stat->tx_time, radio_stat->rx_time,
988 radio_stat->on_time_scan, radio_stat->on_time_nbd,
989 radio_stat->on_time_gscan,
990 radio_stat->on_time_roam_scan,
991 radio_stat->on_time_pno_scan,
992 radio_stat->on_time_hs20,
993 radio_stat->num_channels,
994 radio_stat->total_num_tx_power_levels,
995 radio_stat->on_time_host_scan,
996 radio_stat->on_time_lpi_scan);
997 radio_stat++;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800998 }
999
Jeff Johnsonb16fd942019-03-31 11:30:37 -07001000 radio_stat = radio_stat_save;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001001 for (nr = 0; nr < num_radio; nr++) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001002 ret = hdd_llstats_post_radio_stats(adapter, more_data,
Jeff Johnson05bf6d12019-03-31 11:22:45 -07001003 radio_stat, num_radio);
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001004 if (ret)
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001005 return;
Srinivas Girigowda57b450e2016-10-27 21:00:46 -07001006
Jeff Johnson05bf6d12019-03-31 11:22:45 -07001007 radio_stat++;
Srinivas Girigowdaad874a82016-10-25 14:08:00 -07001008 }
Srinivas Girigowda557d2e42017-03-25 14:07:59 -07001009
Dustin Browne74003f2018-03-14 12:51:58 -07001010 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011}
1012
1013/**
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001014 * hdd_ll_process_radio_stats() - Wrapper function for cfg80211/debugfs
1015 * @adapter: Pointer to device adapter
1016 * @more_data: More data
1017 * @data: Pointer to stats data
1018 * @num_radios: Number of radios
1019 * @resp_id: Response ID from FW
1020 *
1021 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1022 * function which calls cfg80211/debugfs functions based on the response ID.
1023 *
1024 * Return: None
1025 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001026static void hdd_ll_process_radio_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001027 uint32_t more_data, void *data, uint32_t num_radio,
1028 uint32_t resp_id)
1029{
1030 if (DEBUGFS_LLSTATS_REQID == resp_id)
1031 hdd_debugfs_process_radio_stats(adapter, more_data,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -07001032 (struct wifi_radio_stats *)data, num_radio);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001033 else
1034 hdd_link_layer_process_radio_stats(adapter, more_data,
Jeff Johnsone4bba7c2019-03-30 11:58:51 -07001035 (struct wifi_radio_stats *)data, num_radio);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001036}
1037
1038/**
1039 * hdd_ll_process_iface_stats() - Wrapper function for cfg80211/debugfs
1040 * @adapter: Pointer to device adapter
1041 * @data: Pointer to stats data
1042 * @num_peers: Number of peers
1043 * @resp_id: Response ID from FW
1044 *
1045 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1046 * function which calls cfg80211/debugfs functions based on the response ID.
1047 *
1048 * Return: None
1049 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001050static void hdd_ll_process_iface_stats(struct hdd_adapter *adapter,
Jeff Johnsonaf545282019-04-01 12:18:59 -07001051 void *data, uint32_t num_peers,
1052 uint32_t resp_id)
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001053{
1054 if (DEBUGFS_LLSTATS_REQID == resp_id)
Jeff Johnsonaf545282019-04-01 12:18:59 -07001055 hdd_debugfs_process_iface_stats(adapter, data, num_peers);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001056 else
Jeff Johnsonaf545282019-04-01 12:18:59 -07001057 hdd_link_layer_process_iface_stats(adapter, data, num_peers);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001058}
1059
1060/**
1061 * hdd_ll_process_peer_stats() - Wrapper function for cfg80211/debugfs
1062 * @adapter: Pointer to device adapter
1063 * @more_data: More data
1064 * @data: Pointer to stats data
1065 * @resp_id: Response ID from FW
1066 *
1067 * Receiving Link Layer Radio statistics from FW. This function is a wrapper
1068 * function which calls cfg80211/debugfs functions based on the response ID.
1069 *
1070 * Return: None
1071 */
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001072static void hdd_ll_process_peer_stats(struct hdd_adapter *adapter,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001073 uint32_t more_data, void *data, uint32_t resp_id)
1074{
1075 if (DEBUGFS_LLSTATS_REQID == resp_id)
1076 hdd_debugfs_process_peer_stats(adapter, data);
1077 else
Jeff Johnsonfcb078d2019-03-28 14:34:01 -07001078 hdd_link_layer_process_peer_stats(adapter, more_data, data);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001079}
1080
Jeff Johnson959f3692018-07-03 17:30:40 -07001081void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
1082 int indication_type,
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301083 tSirLLStatsResults *results,
1084 void *cookie)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001085{
Jeff Johnson959f3692018-07-03 17:30:40 -07001086 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301087 struct hdd_ll_stats_priv *priv;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001088 struct hdd_adapter *adapter = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001089 int status;
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301090 struct osif_request *request;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001091
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001092 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301093 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001094 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001095
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001096 adapter = hdd_get_adapter_by_vdev(hdd_ctx,
Jeff Johnson959f3692018-07-03 17:30:40 -07001097 results->ifaceId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301099 if (!adapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001100 hdd_err("vdev_id %d does not exist with host",
Jeff Johnson959f3692018-07-03 17:30:40 -07001101 results->ifaceId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001102 return;
1103 }
1104
Jeff Johnson959f3692018-07-03 17:30:40 -07001105 hdd_debug("Link Layer Indication Type: %d", indication_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106
Jeff Johnson959f3692018-07-03 17:30:40 -07001107 switch (indication_type) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108 case SIR_HAL_LL_STATS_RESULTS_RSP:
1109 {
Jeff Johnson36e74c42017-09-18 08:15:42 -07001110 hdd_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %pK",
Jeff Johnson959f3692018-07-03 17:30:40 -07001111 results->paramId,
1112 results->ifaceId,
1113 results->rspId,
1114 results->moreResultToFollow,
1115 results->num_radio,
1116 results->results);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301118 request = osif_request_get(cookie);
1119 if (!request) {
1120 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001121 return;
1122 }
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301123
1124 priv = osif_request_priv(request);
1125
1126 /* validate response received from target */
1127 if ((priv->request_id != results->rspId) ||
1128 !(priv->request_bitmap & results->paramId)) {
1129 hdd_err("Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
1130 priv->request_id, results->rspId,
1131 priv->request_bitmap, results->paramId);
1132 osif_request_put(request);
1133 return;
1134 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001135
Jeff Johnson959f3692018-07-03 17:30:40 -07001136 if (results->paramId & WMI_LINK_STATS_RADIO) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001137 hdd_ll_process_radio_stats(adapter,
Jeff Johnson959f3692018-07-03 17:30:40 -07001138 results->moreResultToFollow,
1139 results->results,
1140 results->num_radio,
1141 results->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142
Jeff Johnson959f3692018-07-03 17:30:40 -07001143 if (!results->moreResultToFollow)
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301144 priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145
Jeff Johnson959f3692018-07-03 17:30:40 -07001146 } else if (results->paramId &
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001147 WMI_LINK_STATS_IFACE) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001148 hdd_ll_process_iface_stats(adapter,
Jeff Johnson959f3692018-07-03 17:30:40 -07001149 results->results,
1150 results->num_peers,
1151 results->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001152
Srinivas Dasari6946a792015-09-28 15:01:49 +05301153 /* Firmware doesn't send peerstats event if no peers are
1154 * connected. HDD should not wait for any peerstats in
1155 * this case and return the status to middleware after
1156 * receiving iface stats
1157 */
Jeff Johnson959f3692018-07-03 17:30:40 -07001158 if (!results->num_peers)
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301159 priv->request_bitmap &=
Srinivas Dasari6946a792015-09-28 15:01:49 +05301160 ~(WMI_LINK_STATS_ALL_PEER);
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301161 priv->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001162
Jeff Johnson959f3692018-07-03 17:30:40 -07001163 } else if (results->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001164 paramId & WMI_LINK_STATS_ALL_PEER) {
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001165 hdd_ll_process_peer_stats(adapter,
Jeff Johnson959f3692018-07-03 17:30:40 -07001166 results->moreResultToFollow,
1167 results->results,
1168 results->rspId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001169
Jeff Johnson959f3692018-07-03 17:30:40 -07001170 if (!results->moreResultToFollow)
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301171 priv->request_bitmap &=
1172 ~(WMI_LINK_STATS_ALL_PEER);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001173
1174 } else {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001175 hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001176 }
1177
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001178 /* complete response event if all requests are completed */
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301179 if (!priv->request_bitmap)
1180 osif_request_complete(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001181
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301182 osif_request_put(request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001183 break;
1184 }
1185 default:
Jeff Johnson959f3692018-07-03 17:30:40 -07001186 hdd_warn("invalid event type %d", indication_type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001187 break;
1188 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001189}
1190
Jeff Johnsondc198ec2018-07-04 17:39:53 -07001191void hdd_lost_link_info_cb(hdd_handle_t hdd_handle,
1192 struct sir_lost_link_info *lost_link_info)
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301193{
Jeff Johnsondc198ec2018-07-04 17:39:53 -07001194 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301195 int status;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001196 struct hdd_adapter *adapter;
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301197
1198 status = wlan_hdd_validate_context(hdd_ctx);
Jeff Johnsondc198ec2018-07-04 17:39:53 -07001199 if (status)
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301200 return;
1201
Jeff Johnsondc198ec2018-07-04 17:39:53 -07001202 if (!lost_link_info) {
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301203 hdd_err("lost_link_info is NULL");
1204 return;
1205 }
1206
1207 adapter = hdd_get_adapter_by_vdev(hdd_ctx, lost_link_info->vdev_id);
Jeff Johnsondc198ec2018-07-04 17:39:53 -07001208 if (!adapter) {
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301209 hdd_err("invalid adapter");
1210 return;
1211 }
1212
1213 adapter->rssi_on_disconnect = lost_link_info->rssi;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001214 hdd_debug("rssi on disconnect %d", adapter->rssi_on_disconnect);
Sreelakshmi Konamki58c72432016-11-09 17:06:44 +05301215}
1216
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217const struct
1218nla_policy
1219 qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
1220 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = {
1221 .type = NLA_U32},
1222 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = {
1223 .type = NLA_U32},
1224};
1225
1226/**
1227 * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
1228 * @wiphy: Pointer to wiphy
1229 * @wdev: Pointer to wdev
1230 * @data: Pointer to data
1231 * @data_len: Data length
1232 *
1233 * Return: int
1234 */
1235static int
1236__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1237 struct wireless_dev *wdev,
1238 const void *data,
1239 int data_len)
1240{
1241 int status;
1242 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
Jeff Johnsonc4238ba2019-03-03 09:44:32 -08001243 tSirLLStatsSetReq req;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001244 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001245 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001246 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001247
Dustin Brownfdf17c12018-03-14 12:55:34 -07001248 hdd_enter_dev(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301249
Anurag Chouhan6d760662016-02-20 16:05:43 +05301250 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001251 hdd_err("Command not allowed in FTM mode");
1252 return -EPERM;
1253 }
1254
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001255 status = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301256 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001258
Dustin Browna8700cc2018-08-07 12:04:47 -07001259 if (hdd_validate_adapter(adapter))
Vignesh Viswanathan769866e2018-06-28 19:38:06 +05301260 return -EINVAL;
Vignesh Viswanathan769866e2018-06-28 19:38:06 +05301261
1262 if (adapter->device_mode != QDF_STA_MODE) {
1263 hdd_debug("Cannot set LL_STATS for device mode %d",
1264 adapter->device_mode);
1265 return -EINVAL;
1266 }
1267
Dustin Brown4ea21db2018-01-05 14:13:17 -08001268 if (wlan_cfg80211_nla_parse(tb_vendor,
1269 QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
1270 (struct nlattr *)data, data_len,
1271 qca_wlan_vendor_ll_set_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001272 hdd_err("maximum attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001273 return -EINVAL;
1274 }
1275
1276 if (!tb_vendor
1277 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001278 hdd_err("MPDU size Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001279 return -EINVAL;
1280 }
1281
1282 if (!tb_vendor
1283 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001284 hdd_err("Stats Gathering Not Present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001285 return -EINVAL;
1286 }
1287
1288 /* Shall take the request Id if the Upper layers pass. 1 For now. */
Jeff Johnsonc4238ba2019-03-03 09:44:32 -08001289 req.reqId = 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001290
Jeff Johnsonc4238ba2019-03-03 09:44:32 -08001291 req.mpduSizeThreshold =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001292 nla_get_u32(tb_vendor
1293 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
1294
Jeff Johnsonc4238ba2019-03-03 09:44:32 -08001295 req.aggressiveStatisticsGathering =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001296 nla_get_u32(tb_vendor
1297 [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
1298
Jeff Johnsonc4238ba2019-03-03 09:44:32 -08001299 req.staId = adapter->vdev_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001300
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001301 hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
Jeff Johnsonc4238ba2019-03-03 09:44:32 -08001302 req.reqId, req.staId,
1303 req.mpduSizeThreshold,
1304 req.aggressiveStatisticsGathering);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305
Jeff Johnson003f7392018-06-12 20:45:47 -07001306 if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(hdd_ctx->mac_handle,
Jeff Johnsonc4238ba2019-03-03 09:44:32 -08001307 &req)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001308 hdd_err("sme_ll_stats_set_req Failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001309 return -EINVAL;
1310 }
1311
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001312 adapter->is_link_layer_stats_set = true;
Dustin Browne74003f2018-03-14 12:51:58 -07001313 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001314 return 0;
1315}
1316
1317/**
1318 * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
1319 * @wiphy: Pointer to wiphy
1320 * @wdev: Pointer to wdev
1321 * @data: Pointer to data
1322 * @data_len: Data length
1323 *
1324 * Return: 0 if success, non-zero for failure
1325 */
1326int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
1327 struct wireless_dev *wdev,
1328 const void *data,
1329 int data_len)
1330{
Dustin Browna09acf42018-11-08 12:32:26 +05301331 int errno;
1332 struct osif_vdev_sync *vdev_sync;
1333
1334 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
1335 if (errno)
1336 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001337
Dustin Browna09acf42018-11-08 12:32:26 +05301338 errno = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001339
Dustin Browna09acf42018-11-08 12:32:26 +05301340 osif_vdev_sync_op_stop(vdev_sync);
1341
1342 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001343}
1344
1345const struct
1346nla_policy
1347 qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
1348 /* Unsigned 32bit value provided by the caller issuing the GET stats
1349 * command. When reporting
1350 * the stats results, the driver uses the same value to indicate
1351 * which GET request the results
1352 * correspond to.
1353 */
1354 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
1355
1356 /* Unsigned 32bit value . bit mask to identify what statistics are
Jeff Johnson8bb78c32017-01-12 08:42:50 -08001357 * requested for retrieval
1358 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001359 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
1360};
1361
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001362static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001363 tSirLLStatsGetReq *req)
1364{
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301365 int ret;
1366 struct hdd_ll_stats_priv *priv;
1367 struct osif_request *request;
1368 void *cookie;
1369 static const struct osif_request_params params = {
1370 .priv_size = sizeof(*priv),
1371 .timeout_ms = WLAN_WAIT_TIME_LL_STATS,
1372 };
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001373
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301374 hdd_enter();
1375
1376 request = osif_request_alloc(&params);
1377 if (!request) {
1378 hdd_err("Request Allocation Failure");
1379 return -ENOMEM;
1380 }
1381
1382 cookie = osif_request_cookie(request);
1383
1384 priv = osif_request_priv(request);
1385
1386 priv->request_id = req->reqId;
1387 priv->request_bitmap = req->paramIdMask;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001388
1389 if (QDF_STATUS_SUCCESS !=
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301390 sme_ll_stats_get_req(hdd_ctx->mac_handle, req,
1391 cookie)) {
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001392 hdd_err("sme_ll_stats_get_req Failed");
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301393 ret = -EINVAL;
1394 goto exit;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001395 }
1396
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301397 ret = osif_request_wait_for_response(request);
1398 if (ret) {
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001399 hdd_err("Target response timed out request id %d request bitmap 0x%x",
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301400 priv->request_id, priv->request_bitmap);
1401 ret = -ETIMEDOUT;
1402 goto exit;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001403 }
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301404 hdd_exit();
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001405
Dundi Ravitejae232cf12018-05-16 18:34:34 +05301406exit:
1407 osif_request_put(request);
1408 return ret;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001409}
1410
Jeff Johnsona11f94b2017-08-29 14:21:35 -07001411int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id,
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001412 uint32_t req_mask)
1413{
Dustin Brown06fed352018-08-31 12:19:52 -07001414 int errno;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001415 tSirLLStatsGetReq get_req;
Jeff Johnson40dae4e2017-08-29 14:00:25 -07001416 struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07001417 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001418
Dustin Brown491d54b2018-03-14 12:39:11 -07001419 hdd_enter();
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001420
1421 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1422 hdd_warn("Command not allowed in FTM mode");
1423 return -EPERM;
1424 }
1425
Jeff Johnson690fe952017-10-25 11:48:39 -07001426 if (hddstactx->hdd_reassoc_scenario) {
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001427 hdd_err("Roaming in progress, cannot process the request");
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001428 return -EBUSY;
1429 }
1430
Vignesh Viswanathan769866e2018-06-28 19:38:06 +05301431 if (!adapter->is_link_layer_stats_set) {
1432 hdd_info("LL_STATs not set");
1433 return -EINVAL;
1434 }
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001435
1436 get_req.reqId = req_id;
1437 get_req.paramIdMask = req_mask;
Jeff Johnson1abc5662019-02-04 14:27:02 -08001438 get_req.staId = adapter->vdev_id;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001439
1440 rtnl_lock();
Dustin Brown06fed352018-08-31 12:19:52 -07001441 errno = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001442 rtnl_unlock();
Dustin Brown06fed352018-08-31 12:19:52 -07001443 if (errno)
Varun Reddy Yeturu7d472592017-04-20 17:51:54 -07001444 hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
Jeff Johnson1abc5662019-02-04 14:27:02 -08001445 req_id, req_mask, adapter->vdev_id);
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001446
Dustin Browne74003f2018-03-14 12:51:58 -07001447 hdd_exit();
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001448
Dustin Brown06fed352018-08-31 12:19:52 -07001449 return errno;
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001450}
1451
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001452/**
1453 * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
1454 * @wiphy: Pointer to wiphy
1455 * @wdev: Pointer to wdev
1456 * @data: Pointer to data
1457 * @data_len: Data length
1458 *
1459 * Return: int
1460 */
1461static int
1462__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
1463 struct wireless_dev *wdev,
1464 const void *data,
1465 int data_len)
1466{
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001467 int ret;
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001468 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001469 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
1470 tSirLLStatsGetReq LinkLayerStatsGetReq;
1471 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001472 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1473 struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001474
Kapil Guptabf4943c2016-10-13 12:15:39 +05301475 /* ENTER() intentionally not used in a frequently invoked API */
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301476
Anurag Chouhan6d760662016-02-20 16:05:43 +05301477 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001478 hdd_err("Command not allowed in FTM mode");
1479 return -EPERM;
1480 }
1481
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001482 ret = wlan_hdd_validate_context(hdd_ctx);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001483 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001484 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001485
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001486 if (!adapter->is_link_layer_stats_set) {
1487 hdd_warn("is_link_layer_stats_set: %d",
1488 adapter->is_link_layer_stats_set);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001489 return -EINVAL;
1490 }
1491
Jeff Johnson690fe952017-10-25 11:48:39 -07001492 if (hddstactx->hdd_reassoc_scenario) {
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001493 hdd_err("Roaming in progress, cannot process the request");
Anurag Chouhan22520002016-09-03 16:20:32 +05301494 return -EBUSY;
1495 }
1496
Dustin Brown4ea21db2018-01-05 14:13:17 -08001497 if (wlan_cfg80211_nla_parse(tb_vendor,
1498 QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
1499 (struct nlattr *)data, data_len,
1500 qca_wlan_vendor_ll_get_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001501 hdd_err("max attribute not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001502 return -EINVAL;
1503 }
1504
1505 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001506 hdd_err("Request Id Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001507 return -EINVAL;
1508 }
1509
1510 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001511 hdd_err("Req Mask Not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001512 return -EINVAL;
1513 }
1514
1515 LinkLayerStatsGetReq.reqId =
1516 nla_get_u32(tb_vendor
1517 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
1518 LinkLayerStatsGetReq.paramIdMask =
1519 nla_get_u32(tb_vendor
1520 [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
1521
Jeff Johnson1abc5662019-02-04 14:27:02 -08001522 LinkLayerStatsGetReq.staId = adapter->vdev_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523
Jeff Johnson48363022019-02-24 16:26:51 -08001524 if (wlan_hdd_validate_vdev_id(adapter->vdev_id))
yeshwanth sriram guntuka08e995b2017-04-26 12:32:12 +05301525 return -EINVAL;
yeshwanth sriram guntuka08e995b2017-04-26 12:32:12 +05301526
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001527 ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &LinkLayerStatsGetReq);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001528 if (0 != ret) {
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001529 hdd_err("Failed to send LL stats request (id:%u)",
1530 LinkLayerStatsGetReq.reqId);
Varun Reddy Yeturu9c1f0dc2017-05-14 16:23:35 -07001531 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001532 }
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -08001533
Dustin Browne74003f2018-03-14 12:51:58 -07001534 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001535 return 0;
1536}
1537
1538/**
1539 * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
1540 * @wiphy: Pointer to wiphy
1541 * @wdev: Pointer to wdev
1542 * @data: Pointer to data
1543 * @data_len: Data length
1544 *
1545 * Return: 0 if success, non-zero for failure
1546 */
1547int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
Dustin Brown4376fed2019-03-06 11:00:38 -08001548 struct wireless_dev *wdev,
1549 const void *data,
1550 int data_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001551{
Dustin Brown4376fed2019-03-06 11:00:38 -08001552 struct osif_vdev_sync *vdev_sync;
1553 int errno;
Manikandan Mohan1baadae2019-08-23 08:32:56 -07001554 qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001555
Manikandan Mohan1f380142019-09-26 18:03:25 -07001556 if (!qdf_ctx)
1557 return -EINVAL;
1558
Dustin Brown4376fed2019-03-06 11:00:38 -08001559 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
1560 if (errno)
1561 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001562
Manikandan Mohan1baadae2019-08-23 08:32:56 -07001563 errno = pld_qmi_send_get(qdf_ctx->dev);
1564 if (errno)
1565 goto end;
1566
Dustin Brown4376fed2019-03-06 11:00:38 -08001567 errno = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
1568
Manikandan Mohan1baadae2019-08-23 08:32:56 -07001569 pld_qmi_send_put(qdf_ctx->dev);
1570
1571end:
Dustin Brown4376fed2019-03-06 11:00:38 -08001572 osif_vdev_sync_op_stop(vdev_sync);
1573
1574 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001575}
1576
1577const struct
1578nla_policy
1579 qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
1580 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
1581 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
1582 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
1583 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
1584};
1585
1586/**
1587 * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
1588 * @wiphy: Pointer to wiphy
1589 * @wdev: Pointer to wdev
1590 * @data: Pointer to data
1591 * @data_len: Data length
1592 *
1593 * Return: int
1594 */
1595static int
1596__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1597 struct wireless_dev *wdev,
1598 const void *data,
1599 int data_len)
1600{
Jeff Johnsonf645abf2017-09-03 09:07:46 -07001601 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001602 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
1603 tSirLLStatsClearReq LinkLayerStatsClearReq;
1604 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07001605 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001606 u32 statsClearReqMask;
1607 u8 stopReq;
Jeff Johnson003f7392018-06-12 20:45:47 -07001608 int errno;
1609 QDF_STATUS status;
1610 struct sk_buff *skb;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611
Dustin Brownfdf17c12018-03-14 12:55:34 -07001612 hdd_enter_dev(dev);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301613
Anurag Chouhan6d760662016-02-20 16:05:43 +05301614 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001615 hdd_err("Command not allowed in FTM mode");
1616 return -EPERM;
1617 }
1618
Jeff Johnson003f7392018-06-12 20:45:47 -07001619 errno = wlan_hdd_validate_context(hdd_ctx);
1620 if (errno)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001621 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001622
Jeff Johnsond30ee4b2017-10-28 15:38:32 -07001623 if (!adapter->is_link_layer_stats_set) {
1624 hdd_warn("is_link_layer_stats_set : %d",
1625 adapter->is_link_layer_stats_set);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626 return -EINVAL;
1627 }
1628
Dustin Brown4ea21db2018-01-05 14:13:17 -08001629 if (wlan_cfg80211_nla_parse(tb_vendor,
1630 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
1631 (struct nlattr *)data, data_len,
1632 qca_wlan_vendor_ll_clr_policy)) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001633 hdd_err("STATS_CLR_MAX is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634 return -EINVAL;
1635 }
1636
1637 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
1638 !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07001639 hdd_err("Error in LL_STATS CLR CONFIG PARA");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001640 return -EINVAL;
1641 }
1642
1643 statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
1644 nla_get_u32(tb_vendor
1645 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
1646
1647 stopReq = LinkLayerStatsClearReq.stopReq =
1648 nla_get_u8(tb_vendor
1649 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
1650
1651 /*
1652 * Shall take the request Id if the Upper layers pass. 1 For now.
1653 */
1654 LinkLayerStatsClearReq.reqId = 1;
1655
Jeff Johnson1abc5662019-02-04 14:27:02 -08001656 LinkLayerStatsClearReq.staId = adapter->vdev_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001657
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08001658 hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
Sushant Kaushik7a535882015-11-02 13:31:21 +05301659 LinkLayerStatsClearReq.reqId,
1660 LinkLayerStatsClearReq.staId,
1661 LinkLayerStatsClearReq.statsClearReqMask,
1662 LinkLayerStatsClearReq.stopReq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001663
Jeff Johnson003f7392018-06-12 20:45:47 -07001664 status = sme_ll_stats_clear_req(hdd_ctx->mac_handle,
1665 &LinkLayerStatsClearReq);
1666 if (QDF_IS_STATUS_ERROR(status)) {
1667 hdd_err("stats clear request failed, %d", status);
1668 return -EINVAL;
1669 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670
Jeff Johnson003f7392018-06-12 20:45:47 -07001671 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1672 2 * sizeof(u32) +
1673 2 * NLMSG_HDRLEN);
1674 if (!skb) {
1675 hdd_err("skb allocation failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001676 return -ENOMEM;
1677 }
1678
Jeff Johnson003f7392018-06-12 20:45:47 -07001679 if (nla_put_u32(skb,
1680 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
1681 statsClearReqMask) ||
1682 nla_put_u32(skb,
1683 QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
1684 stopReq)) {
1685 hdd_err("LL_STATS_CLR put fail");
1686 kfree_skb(skb);
1687 return -EINVAL;
1688 }
1689
1690 /* If the ask is to stop the stats collection
1691 * as part of clear (stopReq = 1), ensure
1692 * that no further requests of get go to the
1693 * firmware by having is_link_layer_stats_set set
1694 * to 0. However it the stopReq as part of
1695 * the clear request is 0, the request to get
1696 * the statistics are honoured as in this case
1697 * the firmware is just asked to clear the
1698 * statistics.
1699 */
1700 if (stopReq == 1)
1701 adapter->is_link_layer_stats_set = false;
1702
1703 hdd_exit();
1704
1705 return cfg80211_vendor_cmd_reply(skb);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001706}
1707
1708/**
1709 * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
1710 * @wiphy: Pointer to wiphy
1711 * @wdev: Pointer to wdev
1712 * @data: Pointer to data
1713 * @data_len: Data length
1714 *
1715 * Return: 0 if success, non-zero for failure
1716 */
1717int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
1718 struct wireless_dev *wdev,
1719 const void *data,
1720 int data_len)
1721{
Dustin Browna09acf42018-11-08 12:32:26 +05301722 int errno;
1723 struct osif_vdev_sync *vdev_sync;
1724
1725 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
1726 if (errno)
1727 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001728
Dustin Browna09acf42018-11-08 12:32:26 +05301729 errno = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001730
Dustin Browna09acf42018-11-08 12:32:26 +05301731 osif_vdev_sync_op_stop(vdev_sync);
1732
1733 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734}
1735
Zhang Qianca38fb12016-12-23 11:10:48 +08001736/**
Qiwei Cai3719efe2018-06-11 21:09:29 +08001737 * wlan_hdd_clear_link_layer_stats() - clear link layer stats
1738 * @adapter: pointer to adapter
1739 *
1740 * Wrapper function to clear link layer stats.
1741 * return - void
1742 */
1743void wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter)
1744{
1745 tSirLLStatsClearReq link_layer_stats_clear_req;
Jeff Johnson6dca9b32018-06-12 20:45:47 -07001746 mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle;
Qiwei Cai3719efe2018-06-11 21:09:29 +08001747
1748 link_layer_stats_clear_req.statsClearReqMask = WIFI_STATS_IFACE_AC |
1749 WIFI_STATS_IFACE_ALL_PEER;
1750 link_layer_stats_clear_req.stopReq = 0;
1751 link_layer_stats_clear_req.reqId = 1;
Jeff Johnson1abc5662019-02-04 14:27:02 -08001752 link_layer_stats_clear_req.staId = adapter->vdev_id;
Jeff Johnson6dca9b32018-06-12 20:45:47 -07001753 sme_ll_stats_clear_req(mac_handle, &link_layer_stats_clear_req);
Qiwei Cai3719efe2018-06-11 21:09:29 +08001754}
1755
1756/**
Zhang Qianca38fb12016-12-23 11:10:48 +08001757 * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
1758 * @wifi_peer_info: peer information
1759 * @vendor_event: buffer for vendor event
1760 *
1761 * Return: 0 success
1762 */
1763static inline int
Jeff Johnson10495032019-03-28 13:51:59 -07001764hdd_populate_per_peer_ps_info(struct wifi_peer_info *wifi_peer_info,
Zhang Qianca38fb12016-12-23 11:10:48 +08001765 struct sk_buff *vendor_event)
1766{
1767 if (!wifi_peer_info) {
1768 hdd_err("Invalid pointer to peer info.");
1769 return -EINVAL;
1770 }
1771
1772 if (nla_put_u32(vendor_event,
1773 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
1774 wifi_peer_info->power_saving) ||
1775 nla_put(vendor_event,
1776 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
Jeff Johnson10495032019-03-28 13:51:59 -07001777 QDF_MAC_ADDR_SIZE, &wifi_peer_info->peer_macaddr)) {
Zhang Qianca38fb12016-12-23 11:10:48 +08001778 hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
1779 return -EINVAL;
1780 }
1781 return 0;
1782}
1783
1784/**
1785 * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
1786 * @data: stats for peer STA
1787 * @vendor_event: buffer for vendor event
1788 *
1789 * Return: 0 success
1790 */
Jeff Johnsonfcb078d2019-03-28 14:34:01 -07001791static int hdd_populate_wifi_peer_ps_info(struct wifi_peer_stat *data,
Zhang Qianca38fb12016-12-23 11:10:48 +08001792 struct sk_buff *vendor_event)
1793{
1794 uint32_t peer_num, i;
Jeff Johnson10495032019-03-28 13:51:59 -07001795 struct wifi_peer_info *wifi_peer_info;
Zhang Qianca38fb12016-12-23 11:10:48 +08001796 struct nlattr *peer_info, *peers;
1797
1798 if (!data) {
1799 hdd_err("Invalid pointer to Wifi peer stat.");
1800 return -EINVAL;
1801 }
1802
Jeff Johnsonfcb078d2019-03-28 14:34:01 -07001803 peer_num = data->num_peers;
Zhang Qianca38fb12016-12-23 11:10:48 +08001804 if (peer_num == 0) {
1805 hdd_err("Peer number is zero.");
1806 return -EINVAL;
1807 }
1808
1809 if (nla_put_u32(vendor_event,
1810 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
1811 peer_num)) {
1812 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1813 return -EINVAL;
1814 }
1815
1816 peer_info = nla_nest_start(vendor_event,
1817 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
Jeff Johnsond36fa332019-03-18 13:42:25 -07001818 if (!peer_info) {
Zhang Qianca38fb12016-12-23 11:10:48 +08001819 hdd_err("nla_nest_start failed");
1820 return -EINVAL;
1821 }
1822
1823 for (i = 0; i < peer_num; i++) {
Jeff Johnsonfcb078d2019-03-28 14:34:01 -07001824 wifi_peer_info = &data->peer_info[i];
Zhang Qianca38fb12016-12-23 11:10:48 +08001825 peers = nla_nest_start(vendor_event, i);
1826
Jeff Johnsond36fa332019-03-18 13:42:25 -07001827 if (!peers) {
Zhang Qianca38fb12016-12-23 11:10:48 +08001828 hdd_err("nla_nest_start failed");
1829 return -EINVAL;
1830 }
1831
1832 if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
1833 return -EINVAL;
1834
1835 nla_nest_end(vendor_event, peers);
1836 }
1837 nla_nest_end(vendor_event, peer_info);
1838
1839 return 0;
1840}
1841
1842/**
1843 * hdd_populate_tx_failure_info() - populate TX failure info
1844 * @tx_fail: TX failure info
1845 * @skb: buffer for vendor event
1846 *
1847 * Return: 0 Success
1848 */
1849static inline int
1850hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
1851 struct sk_buff *skb)
1852{
1853 int status = 0;
1854
Jeff Johnsond36fa332019-03-18 13:42:25 -07001855 if (!tx_fail || !skb)
Zhang Qianca38fb12016-12-23 11:10:48 +08001856 return -EINVAL;
1857
1858 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
1859 tx_fail->tid) ||
1860 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
1861 tx_fail->msdu_num) ||
1862 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
1863 tx_fail->status)) {
1864 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1865 status = -EINVAL;
1866 }
1867
1868 return status;
1869}
1870
1871/**
Zhang Qian4ead8f02017-03-27 14:21:47 +08001872 * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event
1873 * @info: cca info array for all channels
1874 * @vendor_event: vendor event buffer
1875 *
1876 * Return: 0 Success, EINVAL failure
1877 */
1878static int
1879hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca,
1880 struct sk_buff *vendor_event)
1881{
1882 /* There might be no CCA info for a channel */
1883 if (!cca)
1884 return 0;
1885
1886 if (nla_put_u32(vendor_event,
1887 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
1888 cca->idle_time) ||
1889 nla_put_u32(vendor_event,
1890 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
1891 cca->tx_time) ||
1892 nla_put_u32(vendor_event,
1893 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
1894 cca->rx_in_bss_time) ||
1895 nla_put_u32(vendor_event,
1896 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
1897 cca->rx_out_bss_time) ||
1898 nla_put_u32(vendor_event,
1899 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
1900 cca->rx_busy_time) ||
1901 nla_put_u32(vendor_event,
1902 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
1903 cca->rx_in_bad_cond_time) ||
1904 nla_put_u32(vendor_event,
1905 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
1906 cca->tx_in_bad_cond_time) ||
1907 nla_put_u32(vendor_event,
1908 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
1909 cca->wlan_not_avail_time) ||
1910 nla_put_u32(vendor_event,
1911 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
1912 cca->vdev_id)) {
1913 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1914 return -EINVAL;
1915 }
1916 return 0;
1917}
1918
1919/**
1920 * hdd_populate_wifi_signal_info - put chain signal info
1921 * @info: RF chain signal info
1922 * @skb: vendor event buffer
1923 *
1924 * Return: 0 Success, EINVAL failure
1925 */
1926static int
1927hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal,
1928 struct sk_buff *skb)
1929{
Zhang Qian303ebe92017-05-18 13:59:07 +08001930 uint32_t i, chain_count;
Zhang Qian4ead8f02017-03-27 14:21:47 +08001931 struct nlattr *chains, *att;
1932
1933 /* There might be no signal info for a peer */
1934 if (!peer_signal)
1935 return 0;
1936
Zhang Qian303ebe92017-05-18 13:59:07 +08001937 chain_count = peer_signal->num_chain < WIFI_MAX_CHAINS ?
1938 peer_signal->num_chain : WIFI_MAX_CHAINS;
Zhang Qian4ead8f02017-03-27 14:21:47 +08001939 if (nla_put_u32(skb,
1940 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
Zhang Qian303ebe92017-05-18 13:59:07 +08001941 chain_count)) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001942 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1943 return -EINVAL;
1944 }
1945
1946 att = nla_nest_start(skb,
1947 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL);
1948 if (!att) {
1949 hdd_err("nla_nest_start failed");
1950 return -EINVAL;
1951 }
1952
Zhang Qian303ebe92017-05-18 13:59:07 +08001953 for (i = 0; i < chain_count; i++) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001954 chains = nla_nest_start(skb, i);
1955
1956 if (!chains) {
1957 hdd_err("nla_nest_start failed");
1958 return -EINVAL;
1959 }
1960
Zhang Qian303ebe92017-05-18 13:59:07 +08001961 hdd_debug("SNR=%d, NF=%d, Rx=%d, Tx=%d",
1962 peer_signal->per_ant_snr[i],
1963 peer_signal->nf[i],
1964 peer_signal->per_ant_rx_mpdus[i],
1965 peer_signal->per_ant_tx_mpdus[i]);
Zhang Qian4ead8f02017-03-27 14:21:47 +08001966 if (nla_put_u32(skb,
1967 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
1968 peer_signal->per_ant_snr[i]) ||
1969 nla_put_u32(skb,
1970 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
Zhang Qian303ebe92017-05-18 13:59:07 +08001971 peer_signal->nf[i]) ||
1972 nla_put_u32(skb,
1973 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
1974 peer_signal->per_ant_rx_mpdus[i]) ||
1975 nla_put_u32(skb,
1976 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
1977 peer_signal->per_ant_tx_mpdus[i])) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08001978 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1979 return -EINVAL;
1980 }
1981 nla_nest_end(skb, chains);
1982 }
1983 nla_nest_end(skb, att);
1984
1985 return 0;
1986}
1987
1988/**
1989 * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info
1990 * @info: tx info
1991 * @skb: vendor event buffer
1992 *
1993 * Return: 0 Success, EINVAL failure
1994 */
1995static int
1996hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats,
1997 struct sk_buff *skb)
1998{
1999 uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay;
2000
2001 /* There might be no TX info for a peer */
2002 if (!tx_stats)
2003 return 0;
2004
2005 agg_size = tx_stats->mpdu_aggr_size;
2006 succ_mcs = tx_stats->success_mcs;
2007 fail_mcs = tx_stats->fail_mcs;
2008 delay = tx_stats->delay;
2009
2010 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
2011 tx_stats->msdus) ||
2012 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
2013 tx_stats->mpdus) ||
2014 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
2015 tx_stats->ppdus) ||
2016 nla_put_u32(skb,
2017 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
2018 tx_stats->bytes) ||
2019 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
2020 tx_stats->drops) ||
2021 nla_put_u32(skb,
2022 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
2023 tx_stats->drop_bytes) ||
2024 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
2025 tx_stats->retries) ||
2026 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
2027 tx_stats->failed) ||
2028 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
2029 tx_stats->aggr_len) ||
2030 nla_put_u32(skb,
2031 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
2032 tx_stats->success_mcs_len) ||
2033 nla_put_u32(skb,
2034 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
2035 tx_stats->fail_mcs_len) ||
2036 nla_put_u32(skb,
2037 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
2038 tx_stats->delay_len))
2039 goto put_attr_fail;
2040
2041 if (agg_size) {
2042 if (nla_put(skb,
2043 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
2044 tx_stats->aggr_len, agg_size))
2045 goto put_attr_fail;
2046 }
2047
2048 if (succ_mcs) {
2049 if (nla_put(skb,
2050 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
2051 tx_stats->success_mcs_len, succ_mcs))
2052 goto put_attr_fail;
2053 }
2054
2055 if (fail_mcs) {
2056 if (nla_put(skb,
2057 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
2058 tx_stats->fail_mcs_len, fail_mcs))
2059 goto put_attr_fail;
2060 }
2061
2062 if (delay) {
2063 if (nla_put(skb,
2064 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
2065 tx_stats->delay_len, delay))
2066 goto put_attr_fail;
2067 }
2068 return 0;
2069
2070put_attr_fail:
2071 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2072 return -EINVAL;
2073}
2074
2075/**
2076 * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info
2077 * @info: rx info
2078 * @skb: vendor event buffer
2079 *
2080 * Return: 0 Success, EINVAL failure
2081 */
2082static int
2083hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats,
2084 struct sk_buff *skb)
2085{
2086 uint32_t *mcs, *aggr;
2087
2088 /* There might be no RX info for a peer */
2089 if (!rx_stats)
2090 return 0;
2091
2092 aggr = rx_stats->mpdu_aggr;
2093 mcs = rx_stats->mcs;
2094
2095 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
2096 rx_stats->mpdus) ||
2097 nla_put_u32(skb,
2098 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
2099 rx_stats->bytes) ||
2100 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
2101 rx_stats->ppdus) ||
2102 nla_put_u32(skb,
2103 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
2104 rx_stats->ppdu_bytes) ||
2105 nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
2106 rx_stats->mpdu_lost) ||
2107 nla_put_u32(skb,
2108 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
2109 rx_stats->mpdu_retry) ||
2110 nla_put_u32(skb,
2111 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
2112 rx_stats->mpdu_dup) ||
2113 nla_put_u32(skb,
2114 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
2115 rx_stats->mpdu_discard) ||
2116 nla_put_u32(skb,
2117 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
2118 rx_stats->aggr_len) ||
2119 nla_put_u32(skb,
2120 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
2121 rx_stats->mcs_len))
2122 goto put_attr_fail;
2123
2124 if (aggr) {
2125 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
2126 rx_stats->aggr_len, aggr))
2127 goto put_attr_fail;
2128 }
2129
2130 if (mcs) {
2131 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
2132 rx_stats->mcs_len, mcs))
2133 goto put_attr_fail;
2134 }
2135
2136 return 0;
2137
2138put_attr_fail:
2139 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2140 return -EINVAL;
2141}
2142
2143/**
2144 * hdd_populate_wifi_wmm_ac_info() - put WMM AC info
2145 * @info: per AC stats
2146 * @skb: vendor event buffer
2147 *
2148 * Return: 0 Success, EINVAL failure
2149 */
2150static int
2151hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats,
2152 struct sk_buff *skb)
2153{
2154 struct nlattr *wmm;
2155
2156 wmm = nla_nest_start(skb, ac_stats->type);
2157 if (!wmm)
2158 goto nest_start_fail;
2159
2160 if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) ||
2161 hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb))
2162 goto put_attr_fail;
2163
2164 nla_nest_end(skb, wmm);
2165 return 0;
2166
2167nest_start_fail:
2168 hdd_err("nla_nest_start failed");
2169 return -EINVAL;
2170
2171put_attr_fail:
2172 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2173 return -EINVAL;
2174}
2175
2176/**
2177 * hdd_populate_wifi_ll_ext_peer_info() - put per peer info
2178 * @info: peer stats
2179 * @skb: vendor event buffer
2180 *
2181 * Return: 0 Success, EINVAL failure
2182 */
2183static int
2184hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers,
2185 struct sk_buff *skb)
2186{
2187 uint32_t i;
2188 struct nlattr *wmm_ac;
2189
2190 if (nla_put_u32(skb,
2191 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
2192 peers->peer_id) ||
2193 nla_put_u32(skb,
2194 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
2195 peers->vdev_id) ||
2196 nla_put_u32(skb,
2197 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
2198 peers->sta_ps_inds) ||
2199 nla_put_u32(skb,
2200 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
2201 peers->sta_ps_durs) ||
2202 nla_put_u32(skb,
2203 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
2204 peers->rx_probe_reqs) ||
2205 nla_put_u32(skb,
2206 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
2207 peers->rx_oth_mgmts) ||
2208 nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
2209 QDF_MAC_ADDR_SIZE, peers->mac_address) ||
2210 hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) {
2211 hdd_err("put peer signal attr failed");
2212 return -EINVAL;
2213 }
2214
2215 wmm_ac = nla_nest_start(skb,
2216 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS);
2217 if (!wmm_ac) {
2218 hdd_err("nla_nest_start failed");
2219 return -EINVAL;
2220 }
2221
2222 for (i = 0; i < WLAN_MAX_AC; i++) {
2223 if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) {
2224 hdd_err("put WMM AC attr failed");
2225 return -EINVAL;
2226 }
2227 }
2228
2229 nla_nest_end(skb, wmm_ac);
2230 return 0;
2231}
2232
2233/**
2234 * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats
2235 * @info: link layer stats
2236 * @skb: vendor event buffer
2237 *
2238 * Return: 0 Success, EINVAL failure
2239 */
2240static int
2241hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats,
2242 struct sk_buff *skb)
2243{
2244 uint32_t i;
2245 struct nlattr *peer, *peer_info, *channels, *channel_info;
2246
2247 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
2248 stats->trigger_cond_id) ||
2249 nla_put_u32(skb,
2250 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
2251 stats->cca_chgd_bitmap) ||
2252 nla_put_u32(skb,
2253 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
2254 stats->sig_chgd_bitmap) ||
2255 nla_put_u32(skb,
2256 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
2257 stats->tx_chgd_bitmap) ||
2258 nla_put_u32(skb,
2259 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
2260 stats->rx_chgd_bitmap) ||
2261 nla_put_u32(skb,
2262 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
2263 stats->channel_num) ||
2264 nla_put_u32(skb,
2265 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
2266 stats->peer_num)) {
2267 goto put_attr_fail;
2268 }
2269
2270 channels = nla_nest_start(skb,
2271 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS);
2272 if (!channels) {
2273 hdd_err("nla_nest_start failed");
2274 return -EINVAL;
2275 }
2276
2277 for (i = 0; i < stats->channel_num; i++) {
2278 channel_info = nla_nest_start(skb, i);
2279 if (!channel_info) {
2280 hdd_err("nla_nest_start failed");
2281 return -EINVAL;
2282 }
2283
2284 if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb))
2285 goto put_attr_fail;
2286 nla_nest_end(skb, channel_info);
2287 }
2288 nla_nest_end(skb, channels);
2289
2290 peer_info = nla_nest_start(skb,
2291 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER);
2292 if (!peer_info) {
2293 hdd_err("nla_nest_start failed");
2294 return -EINVAL;
2295 }
2296
2297 for (i = 0; i < stats->peer_num; i++) {
2298 peer = nla_nest_start(skb, i);
2299 if (!peer) {
2300 hdd_err("nla_nest_start failed");
2301 return -EINVAL;
2302 }
2303
2304 if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i],
2305 skb))
2306 goto put_attr_fail;
2307 nla_nest_end(skb, peer);
2308 }
2309
2310 nla_nest_end(skb, peer_info);
2311 return 0;
2312
2313put_attr_fail:
2314 hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2315 return -EINVAL;
2316}
2317
2318/**
Zhang Qianca38fb12016-12-23 11:10:48 +08002319 * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
2320 * @ctx: HDD context
2321 * @rsp: msg from FW
2322 *
2323 * This function is an extension of
2324 * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
2325 * monitoring parameters offloaded to NL data and send the same to the
2326 * kernel/upper layers.
2327 *
2328 * Return: None
2329 */
Jeff Johnson2d292122018-06-02 21:02:02 -07002330void wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx,
Zhang Qianca38fb12016-12-23 11:10:48 +08002331 tSirLLStatsResults *rsp)
2332{
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002333 struct hdd_context *hdd_ctx;
Jeff Johnson5d9a70f2019-04-01 09:26:35 -07002334 struct sk_buff *skb;
Zhang Qianca38fb12016-12-23 11:10:48 +08002335 uint32_t param_id, index;
Jeff Johnson5d9a70f2019-04-01 09:26:35 -07002336 struct hdd_adapter *adapter;
Jeff Johnsonfcb078d2019-03-28 14:34:01 -07002337 struct wifi_peer_stat *peer_stats;
Zhang Qianca38fb12016-12-23 11:10:48 +08002338 uint8_t *results;
2339 int status;
2340
Dustin Brown491d54b2018-03-14 12:39:11 -07002341 hdd_enter();
Zhang Qianca38fb12016-12-23 11:10:48 +08002342
Zhang Qianca38fb12016-12-23 11:10:48 +08002343 if (!rsp) {
2344 hdd_err("Invalid result.");
2345 return;
2346 }
2347
Jeff Johnsonea70b942018-07-02 09:42:31 -07002348 hdd_ctx = hdd_handle_to_context(ctx);
Zhang Qianca38fb12016-12-23 11:10:48 +08002349 status = wlan_hdd_validate_context(hdd_ctx);
2350 if (0 != status)
2351 return;
2352
Jeff Johnson5d9a70f2019-04-01 09:26:35 -07002353 adapter = hdd_get_adapter_by_vdev(hdd_ctx, rsp->ifaceId);
Zhang Qianca38fb12016-12-23 11:10:48 +08002354
Zhang Qian4ead8f02017-03-27 14:21:47 +08002355 if (!adapter) {
Zhang Qianca38fb12016-12-23 11:10:48 +08002356 hdd_err("vdev_id %d does not exist with host.",
Jeff Johnson5d9a70f2019-04-01 09:26:35 -07002357 rsp->ifaceId);
Zhang Qianca38fb12016-12-23 11:10:48 +08002358 return;
2359 }
2360
2361 index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
2362 skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2363 NULL, LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
2364 index, GFP_KERNEL);
2365 if (!skb) {
2366 hdd_err("cfg80211_vendor_event_alloc failed.");
2367 return;
2368 }
2369
Jeff Johnson5d9a70f2019-04-01 09:26:35 -07002370 results = rsp->results;
2371 param_id = rsp->paramId;
Jeff Johnson36e74c42017-09-18 08:15:42 -07002372 hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %pK",
Jeff Johnson5d9a70f2019-04-01 09:26:35 -07002373 rsp->paramId, rsp->ifaceId, rsp->results);
Zhang Qianca38fb12016-12-23 11:10:48 +08002374 if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
Jeff Johnsonfcb078d2019-03-28 14:34:01 -07002375 peer_stats = (struct wifi_peer_stat *)results;
Zhang Qianca38fb12016-12-23 11:10:48 +08002376 status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
2377 } else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
2378 struct sir_wifi_iface_tx_fail *tx_fail;
2379
2380 tx_fail = (struct sir_wifi_iface_tx_fail *)results;
2381 status = hdd_populate_tx_failure_info(tx_fail, skb);
2382 } else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
2383 hdd_info("MAC counters stats");
Zhang Qian4ead8f02017-03-27 14:21:47 +08002384 status = hdd_populate_wifi_ll_ext_stats(
2385 (struct sir_wifi_ll_ext_stats *)
2386 rsp->results, skb);
Zhang Qianca38fb12016-12-23 11:10:48 +08002387 } else {
2388 hdd_info("Unknown link layer stats");
2389 status = -EINVAL;
2390 }
2391
2392 if (status == 0)
2393 cfg80211_vendor_event(skb, GFP_KERNEL);
2394 else
2395 kfree_skb(skb);
Dustin Browne74003f2018-03-14 12:51:58 -07002396 hdd_exit();
Zhang Qianca38fb12016-12-23 11:10:48 +08002397}
2398
Zhang Qian4ead8f02017-03-27 14:21:47 +08002399static const struct nla_policy
2400qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = {
2401 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = {
2402 .type = NLA_U32
2403 },
2404 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = {
2405 .type = NLA_U32
2406 },
2407 [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = {
2408 .type = NLA_U32
2409 },
2410 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = {
2411 .type = NLA_U32
2412 },
2413 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = {
2414 .type = NLA_U32
2415 },
2416 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = {
2417 .type = NLA_U32
2418 },
2419 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = {
2420 .type = NLA_U32
2421 },
2422 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = {
2423 .type = NLA_U32
2424 },
2425 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = {
2426 .type = NLA_U32
2427 },
2428 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = {
2429 .type = NLA_U32
2430 },
2431 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = {
2432 .type = NLA_U32
2433 },
2434 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = {
2435 .type = NLA_U32
2436 },
2437 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = {
2438 .type = NLA_U32
2439 },
2440 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = {
2441 .type = NLA_U32
2442 },
2443 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = {
2444 .type = NLA_U32
2445 },
2446 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = {
2447 .type = NLA_U32
2448 },
2449 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = {
2450 .type = NLA_U32
2451 },
2452 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = {
2453 .type = NLA_U32
2454 },
2455 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = {
2456 .type = NLA_U32
2457 },
2458 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = {
2459 .type = NLA_U32
2460 },
2461 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = {
2462 .type = NLA_U32
2463 },
2464 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = {
2465 .type = NLA_U32
2466 },
2467 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = {
2468 .type = NLA_U32
2469 },
2470 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = {
2471 .type = NLA_U32
2472 },
2473 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = {
2474 .type = NLA_U32
2475 },
2476 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = {
2477 .type = NLA_U32
2478 },
2479 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = {
2480 .type = NLA_U32
2481 },
2482 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = {
2483 .type = NLA_U32
2484 },
2485 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = {
2486 .type = NLA_U32
2487 },
2488 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = {
2489 .type = NLA_U32
2490 },
2491 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = {
2492 .type = NLA_U32
2493 },
2494 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = {
2495 .type = NLA_U32
2496 },
2497 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = {
2498 .type = NLA_U32
2499 },
2500 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = {
2501 .type = NLA_U32
2502 },
2503 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = {
2504 .type = NLA_U32
2505 },
2506 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = {
2507 .type = NLA_U32
2508 },
2509 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = {
2510 .type = NLA_U32
2511 },
2512 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = {
2513 .type = NLA_U32
2514 },
2515 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = {
2516 .type = NLA_U32
2517 },
2518 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = {
2519 .type = NLA_U32
2520 },
2521 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = {
2522 .type = NLA_U32
2523 },
2524 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = {
2525 .type = NLA_U32
2526 },
2527 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = {
2528 .type = NLA_U32
2529 },
2530 [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = {
2531 .type = NLA_U32
2532 },
2533};
2534
2535/**
2536 * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2537 * @wiphy: wiphy handle
2538 * @wdev: wdev handle
2539 * @data: user layer input
2540 * @data_len: length of user layer input
2541 *
2542 * this function is called in ssr protected environment.
2543 *
2544 * return: 0 success, none zero for failure
2545 */
2546static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2547 struct wireless_dev *wdev,
2548 const void *data,
2549 int data_len)
2550{
Jeff Johnson003f7392018-06-12 20:45:47 -07002551 QDF_STATUS status;
2552 int errno;
Zhang Qian4ead8f02017-03-27 14:21:47 +08002553 uint32_t period;
2554 struct net_device *dev = wdev->netdev;
Jeff Johnsona11f94b2017-08-29 14:21:35 -07002555 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002556 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Zhang Qian4ead8f02017-03-27 14:21:47 +08002557 struct sir_ll_ext_stats_threshold thresh = {0,};
2558 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1];
2559
Dustin Brownfdf17c12018-03-14 12:55:34 -07002560 hdd_enter_dev(dev);
Zhang Qian4ead8f02017-03-27 14:21:47 +08002561
2562 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2563 hdd_warn("command not allowed in ftm mode");
2564 return -EPERM;
2565 }
2566
Jeff Johnson003f7392018-06-12 20:45:47 -07002567 errno = wlan_hdd_validate_context(hdd_ctx);
2568 if (errno)
Zhang Qian4ead8f02017-03-27 14:21:47 +08002569 return -EPERM;
2570
Dustin Brown4ea21db2018-01-05 14:13:17 -08002571 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX,
2572 (struct nlattr *)data, data_len,
2573 qca_wlan_vendor_ll_ext_policy)) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08002574 hdd_err("maximum attribute not present");
2575 return -EPERM;
2576 }
2577
2578 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) {
2579 period = nla_get_u32(tb[
2580 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]);
2581
2582 if (period != 0 && period < LL_STATS_MIN_PERIOD)
2583 period = LL_STATS_MIN_PERIOD;
2584
2585 /*
2586 * Only enable/disbale counters.
2587 * Keep the last threshold settings.
2588 */
2589 goto set_period;
2590 }
2591
2592 /* global thresh is not enabled */
2593 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) {
2594 thresh.global = false;
2595 hdd_warn("global thresh is not set");
2596 } else {
2597 thresh.global_threshold = nla_get_u32(tb[
2598 QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]);
2599 thresh.global = true;
2600 hdd_debug("globle thresh is %d", thresh.global_threshold);
2601 }
2602
2603 if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) {
2604 thresh.global = false;
2605 hdd_warn("global thresh is not enabled");
2606 } else {
2607 thresh.global = nla_get_u32(tb[
2608 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]);
2609 hdd_debug("global is %d", thresh.global);
2610 }
2611
2612 thresh.enable_bitmap = false;
2613 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) {
2614 thresh.tx_bitmap = nla_get_u32(tb[
2615 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]);
2616 thresh.enable_bitmap = true;
2617 }
2618
2619 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) {
2620 thresh.rx_bitmap = nla_get_u32(tb[
2621 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]);
2622 thresh.enable_bitmap = true;
2623 }
2624
2625 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) {
2626 thresh.cca_bitmap = nla_get_u32(tb[
2627 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]);
2628 thresh.enable_bitmap = true;
2629 }
2630
2631 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) {
2632 thresh.signal_bitmap = nla_get_u32(tb[
2633 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]);
2634 thresh.enable_bitmap = true;
2635 }
2636
2637 if (!thresh.global && !thresh.enable_bitmap) {
2638 hdd_warn("threshold will be disabled.");
2639 thresh.enable = false;
2640
2641 /* Just disable threshold */
2642 goto set_thresh;
2643 } else {
2644 thresh.enable = true;
2645 }
2646
2647 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) {
2648 thresh.tx.msdu = nla_get_u32(tb[
2649 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]);
2650 }
2651
2652 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) {
2653 thresh.tx.mpdu = nla_get_u32(tb[
2654 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]);
2655 }
2656
2657 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) {
2658 thresh.tx.ppdu = nla_get_u32(tb[
2659 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]);
2660 }
2661
2662 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) {
2663 thresh.tx.bytes = nla_get_u32(tb[
2664 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]);
2665 }
2666
2667 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) {
2668 thresh.tx.msdu_drop = nla_get_u32(
2669 tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]);
2670 }
2671
2672 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) {
2673 thresh.tx.byte_drop = nla_get_u32(tb[
2674 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]);
2675 }
2676
2677 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) {
2678 thresh.tx.mpdu_retry = nla_get_u32(tb[
2679 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]);
2680 }
2681
2682 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) {
2683 thresh.tx.mpdu_fail = nla_get_u32(tb[
2684 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]);
2685 }
2686
2687 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) {
2688 thresh.tx.ppdu_fail = nla_get_u32(tb[
2689 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]);
2690 }
2691
2692 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) {
2693 thresh.tx.aggregation = nla_get_u32(tb[
2694 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]);
2695 }
2696
2697 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) {
2698 thresh.tx.succ_mcs = nla_get_u32(tb[
2699 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]);
2700 }
2701
2702 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) {
2703 thresh.tx.fail_mcs = nla_get_u32(tb[
2704 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]);
2705 }
2706
2707 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) {
2708 thresh.tx.delay = nla_get_u32(tb[
2709 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]);
2710 }
2711
2712 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) {
2713 thresh.rx.mpdu = nla_get_u32(tb[
2714 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]);
2715 }
2716
2717 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) {
2718 thresh.rx.bytes = nla_get_u32(tb[
2719 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]);
2720 }
2721
2722 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) {
2723 thresh.rx.ppdu = nla_get_u32(tb[
2724 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]);
2725 }
2726
2727 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) {
2728 thresh.rx.ppdu_bytes = nla_get_u32(tb[
2729 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]);
2730 }
2731
2732 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) {
2733 thresh.rx.mpdu_lost = nla_get_u32(tb[
2734 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]);
2735 }
2736
2737 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) {
2738 thresh.rx.mpdu_retry = nla_get_u32(tb[
2739 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]);
2740 }
2741
2742 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) {
2743 thresh.rx.mpdu_dup = nla_get_u32(tb[
2744 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]);
2745 }
2746
2747 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) {
2748 thresh.rx.mpdu_discard = nla_get_u32(tb[
2749 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]);
2750 }
2751
2752 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) {
2753 thresh.rx.aggregation = nla_get_u32(tb[
2754 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]);
2755 }
2756
2757 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) {
2758 thresh.rx.mcs = nla_get_u32(tb[
2759 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]);
2760 }
2761
2762 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) {
2763 thresh.rx.ps_inds = nla_get_u32(tb[
2764 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]);
2765 }
2766
2767 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) {
2768 thresh.rx.ps_durs = nla_get_u32(tb[
2769 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]);
2770 }
2771
2772 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) {
2773 thresh.rx.probe_reqs = nla_get_u32(tb[
2774 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]);
2775 }
2776
2777 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) {
2778 thresh.rx.other_mgmt = nla_get_u32(tb[
2779 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]);
2780 }
2781
2782 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) {
2783 thresh.cca.idle_time = nla_get_u32(tb[
2784 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]);
2785 }
2786
2787 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) {
2788 thresh.cca.tx_time = nla_get_u32(tb[
2789 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]);
2790 }
2791
2792 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) {
2793 thresh.cca.rx_in_bss_time = nla_get_u32(tb[
2794 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]);
2795 }
2796
2797 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) {
2798 thresh.cca.rx_out_bss_time = nla_get_u32(tb[
2799 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]);
2800 }
2801
2802 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) {
2803 thresh.cca.rx_busy_time = nla_get_u32(tb[
2804 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]);
2805 }
2806
2807 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) {
2808 thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[
2809 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]);
2810 }
2811
2812 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) {
2813 thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[
2814 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]);
2815 }
2816
2817 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) {
2818 thresh.cca.wlan_not_avail_time = nla_get_u32(tb[
2819 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]);
2820 }
2821
2822 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) {
2823 thresh.signal.snr = nla_get_u32(tb[
2824 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]);
2825 }
2826
2827 if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) {
2828 thresh.signal.nf = nla_get_u32(tb[
2829 QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]);
2830 }
2831
2832set_thresh:
2833 hdd_info("send thresh settings to target");
Jeff Johnson003f7392018-06-12 20:45:47 -07002834 status = sme_ll_stats_set_thresh(hdd_ctx->mac_handle, &thresh);
2835 if (QDF_IS_STATUS_ERROR(status)) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08002836 hdd_err("sme_ll_stats_set_thresh failed.");
2837 return -EINVAL;
2838 }
2839 return 0;
2840
2841set_period:
2842 hdd_info("send period to target");
Jeff Johnson1abc5662019-02-04 14:27:02 -08002843 errno = wma_cli_set_command(adapter->vdev_id,
Jeff Johnson003f7392018-06-12 20:45:47 -07002844 WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD,
2845 period, PDEV_CMD);
2846 if (errno) {
Zhang Qian4ead8f02017-03-27 14:21:47 +08002847 hdd_err("wma_cli_set_command set_period failed.");
2848 return -EINVAL;
2849 }
2850 return 0;
2851}
2852
2853/**
2854 * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
2855 * @wiphy: wiphy handle
2856 * @wdev: wdev handle
2857 * @data: user layer input
2858 * @data_len: length of user layer input
2859 *
2860 * return: 0 success, einval failure
2861 */
2862int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
2863 struct wireless_dev *wdev,
2864 const void *data,
2865 int data_len)
2866{
Dustin Browna09acf42018-11-08 12:32:26 +05302867 int errno;
2868 struct osif_vdev_sync *vdev_sync;
2869
2870 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
2871 if (errno)
2872 return errno;
Zhang Qian4ead8f02017-03-27 14:21:47 +08002873
Dustin Browna09acf42018-11-08 12:32:26 +05302874 errno = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev,
2875 data, data_len);
Zhang Qian4ead8f02017-03-27 14:21:47 +08002876
Dustin Browna09acf42018-11-08 12:32:26 +05302877 osif_vdev_sync_op_stop(vdev_sync);
2878
2879 return errno;
Zhang Qian4ead8f02017-03-27 14:21:47 +08002880}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002881#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
2882
2883#ifdef WLAN_FEATURE_STATS_EXT
2884/**
2885 * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2886 * @wiphy: Pointer to wiphy
2887 * @wdev: Pointer to wdev
2888 * @data: Pointer to data
2889 * @data_len: Data length
2890 *
2891 * Return: int
2892 */
2893static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2894 struct wireless_dev *wdev,
2895 const void *data,
2896 int data_len)
2897{
2898 tStatsExtRequestReq stats_ext_req;
2899 struct net_device *dev = wdev->netdev;
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002900 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002901 int ret_val;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302902 QDF_STATUS status;
Jeff Johnson5eb1e682017-08-28 11:42:15 -07002903 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002904
Dustin Brownfdf17c12018-03-14 12:55:34 -07002905 hdd_enter_dev(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002906
2907 ret_val = wlan_hdd_validate_context(hdd_ctx);
2908 if (ret_val)
2909 return ret_val;
2910
Anurag Chouhan6d760662016-02-20 16:05:43 +05302911 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002912 hdd_err("Command not allowed in FTM mode");
2913 return -EPERM;
2914 }
2915
2916 stats_ext_req.request_data_len = data_len;
2917 stats_ext_req.request_data = (void *)data;
2918
Jeff Johnson1abc5662019-02-04 14:27:02 -08002919 status = sme_stats_ext_request(adapter->vdev_id, &stats_ext_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002920
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302921 if (QDF_STATUS_SUCCESS != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002922 ret_val = -EINVAL;
2923
2924 return ret_val;
2925}
2926
2927/**
2928 * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
2929 * @wiphy: Pointer to wiphy
2930 * @wdev: Pointer to wdev
2931 * @data: Pointer to data
2932 * @data_len: Data length
2933 *
2934 * Return: int
2935 */
2936int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
2937 struct wireless_dev *wdev,
2938 const void *data,
2939 int data_len)
2940{
Dustin Browna09acf42018-11-08 12:32:26 +05302941 int errno;
2942 struct osif_vdev_sync *vdev_sync;
2943
2944 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
2945 if (errno)
2946 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002947
Dustin Browna09acf42018-11-08 12:32:26 +05302948 errno = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
2949 data, data_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002950
Dustin Browna09acf42018-11-08 12:32:26 +05302951 osif_vdev_sync_op_stop(vdev_sync);
2952
2953 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002954}
2955
Jeff Johnson45843652018-07-04 12:47:34 -07002956void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,
2957 struct stats_ext_event *data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002958{
Jeff Johnson45843652018-07-04 12:47:34 -07002959 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002960 struct sk_buff *vendor_event;
2961 int status;
2962 int ret_val;
Jeff Johnson45843652018-07-04 12:47:34 -07002963 struct hdd_adapter *adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002964
Jeff Johnsonf645abf2017-09-03 09:07:46 -07002965 status = wlan_hdd_validate_context(hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302966 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002967 return;
Abhishek Singh23edd1c2016-05-05 11:56:06 +05302968
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002969 adapter = hdd_get_adapter_by_vdev(hdd_ctx, data->vdev_id);
Jeff Johnson45843652018-07-04 12:47:34 -07002970 if (!adapter) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002971 hdd_err("vdev_id %d does not exist with host", data->vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002972 return;
2973 }
2974
Jeff Johnsonf645abf2017-09-03 09:07:46 -07002975 vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002976 NULL,
2977 data->event_data_len +
2978 sizeof(uint32_t) +
2979 NLMSG_HDRLEN + NLMSG_HDRLEN,
2980 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
2981 GFP_KERNEL);
2982
2983 if (!vendor_event) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002984 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002985 return;
2986 }
2987
2988 ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
Jeff Johnsona86e78e2017-10-02 13:23:05 -07002989 adapter->dev->ifindex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002990 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07002991 hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002992 kfree_skb(vendor_event);
2993
2994 return;
2995 }
2996
2997 ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
2998 data->event_data_len, data->event_data);
2999
3000 if (ret_val) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07003001 hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003002 kfree_skb(vendor_event);
3003
3004 return;
3005 }
3006
3007 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
3008
3009}
lifeng66831662017-05-19 16:01:35 +08003010
Jeff Johnson45843652018-07-04 12:47:34 -07003011void
3012wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,
3013 struct sir_sme_rx_aggr_hole_ind *pmsg)
lifeng66831662017-05-19 16:01:35 +08003014{
Jeff Johnson45843652018-07-04 12:47:34 -07003015 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
lifeng66831662017-05-19 16:01:35 +08003016 int status;
3017 uint32_t data_size, hole_info_size;
3018 struct sk_buff *vendor_event;
3019
3020 status = wlan_hdd_validate_context(hdd_ctx);
3021 if (0 != status)
3022 return;
3023
Jeff Johnsond36fa332019-03-18 13:42:25 -07003024 if (!pmsg) {
lifeng66831662017-05-19 16:01:35 +08003025 hdd_err("msg received here is null");
3026 return;
3027 }
3028
3029 hole_info_size = (pmsg->hole_cnt)*sizeof(pmsg->hole_info_array[0]);
3030 data_size = sizeof(struct sir_sme_rx_aggr_hole_ind) + hole_info_size;
3031
3032 vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
3033 NULL,
3034 data_size + NLMSG_HDRLEN + NLMSG_HDRLEN,
3035 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX,
3036 GFP_KERNEL);
3037
3038 if (!vendor_event) {
3039 hdd_err("vendor_event_alloc failed for STATS_EXT2");
3040 return;
3041 }
3042
3043 if (nla_put_u32(vendor_event,
3044 QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM,
3045 pmsg->hole_cnt)) {
3046 hdd_err("%s put fail",
3047 "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM");
3048 kfree_skb(vendor_event);
3049 return;
3050 }
3051 if (nla_put(vendor_event,
3052 QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO,
3053 hole_info_size,
3054 (void *)(pmsg->hole_info_array))) {
3055 hdd_err("%s put fail",
3056 "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO");
3057 kfree_skb(vendor_event);
3058 return;
3059 }
3060
3061 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
3062}
3063
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003064#endif /* End of WLAN_FEATURE_STATS_EXT */
3065
Dustin Brown32cb4792017-06-15 15:33:42 -07003066#ifdef LINKSPEED_DEBUG_ENABLED
3067#define linkspeed_dbg(format, args...) pr_info(format, ## args)
3068#else
3069#define linkspeed_dbg(format, args...)
3070#endif /* LINKSPEED_DEBUG_ENABLED */
3071
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003072/**
Dustin Brown0e4479e2017-07-14 14:47:39 -07003073 * wlan_hdd_fill_summary_stats() - populate station_info summary stats
3074 * @stats: summary stats to use as a source
3075 * @info: kernel station_info struct to use as a destination
3076 *
3077 * Return: None
3078 */
3079static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
3080 struct station_info *info)
3081{
3082 int i;
3083
3084 info->rx_packets = stats->rx_frm_cnt;
3085 info->tx_packets = 0;
3086 info->tx_retries = 0;
3087 info->tx_failed = 0;
3088
3089 for (i = 0; i < WIFI_MAX_AC; ++i) {
3090 info->tx_packets += stats->tx_frm_cnt[i];
3091 info->tx_retries += stats->multiple_retry_cnt[i];
3092 info->tx_failed += stats->fail_cnt[i];
3093 }
3094
Naveen Rawat23183d62018-04-12 11:19:01 -07003095 info->filled |= HDD_INFO_TX_PACKETS |
3096 HDD_INFO_TX_RETRIES |
3097 HDD_INFO_TX_FAILED |
3098 HDD_INFO_RX_PACKETS;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003099}
3100
3101/**
3102 * wlan_hdd_get_sap_stats() - get aggregate SAP stats
3103 * @adapter: sap adapter to get stats for
3104 * @info: kernel station_info struct to populate
3105 *
3106 * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to
3107 * support "station dump" and "station get" for SAP vdevs, even though they
3108 * aren't technically stations.
3109 *
3110 * Return: errno
3111 */
3112static int
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003113wlan_hdd_get_sap_stats(struct hdd_adapter *adapter, struct station_info *info)
Dustin Brown0e4479e2017-07-14 14:47:39 -07003114{
Naveen Rawatfa2a1002018-05-17 16:06:37 -07003115 int ret;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003116
Naveen Rawatfa2a1002018-05-17 16:06:37 -07003117 ret = wlan_hdd_get_station_stats(adapter);
3118 if (ret) {
3119 hdd_err("Failed to get SAP stats; status:%d", ret);
3120 return ret;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003121 }
3122
3123 wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, info);
3124
3125 return 0;
3126}
3127
3128/**
Will Huang496b36c2017-07-11 16:38:50 +08003129 * hdd_get_max_rate_legacy() - get max rate for legacy mode
3130 * @stainfo: stainfo pointer
3131 * @rssidx: rssi index
3132 *
3133 * This function will get max rate for legacy mode
3134 *
3135 * Return: max rate on success, otherwise 0
3136 */
Jeff Johnson82155922017-09-30 16:54:14 -07003137static uint32_t hdd_get_max_rate_legacy(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003138 uint8_t rssidx)
3139{
3140 uint32_t maxrate = 0;
3141 /*Minimum max rate, 6Mbps*/
3142 int maxidx = 12;
3143 int i;
3144
3145 /* check supported rates */
3146 if (stainfo->max_supp_idx != 0xff &&
3147 maxidx < stainfo->max_supp_idx)
3148 maxidx = stainfo->max_supp_idx;
3149
3150 /* check extended rates */
3151 if (stainfo->max_ext_idx != 0xff &&
3152 maxidx < stainfo->max_ext_idx)
3153 maxidx = stainfo->max_ext_idx;
3154
Will Huangcc571d42019-04-01 11:49:21 +08003155 for (i = 0; i < QDF_ARRAY_SIZE(supported_data_rate); i++) {
Will Huang496b36c2017-07-11 16:38:50 +08003156 if (supported_data_rate[i].beacon_rate_index == maxidx)
3157 maxrate =
3158 supported_data_rate[i].supported_rate[rssidx];
3159 }
3160
3161 hdd_debug("maxrate %d", maxrate);
3162
3163 return maxrate;
3164}
3165
3166/**
3167 * hdd_get_max_rate_ht() - get max rate for ht mode
3168 * @stainfo: stainfo pointer
3169 * @stats: fw txrx status pointer
3170 * @rate_flags: rate flags
3171 * @nss: number of streams
3172 * @maxrate: returned max rate buffer pointer
3173 * @max_mcs_idx: max mcs idx
3174 * @report_max: report max rate or actual rate
3175 *
3176 * This function will get max rate for ht mode
3177 *
3178 * Return: None
3179 */
Jeff Johnson82155922017-09-30 16:54:14 -07003180static void hdd_get_max_rate_ht(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003181 struct hdd_fw_txrx_stats *stats,
3182 uint32_t rate_flags,
3183 uint8_t nss,
3184 uint32_t *maxrate,
3185 uint8_t *max_mcs_idx,
3186 bool report_max)
3187{
3188 struct index_data_rate_type *supported_mcs_rate;
3189 uint32_t tmprate;
3190 uint8_t flag = 0, mcsidx;
3191 int8_t rssi = stats->rssi;
3192 int mode;
3193 int i;
3194
Naveen Rawatea1564b2018-05-17 15:56:11 -07003195 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003196 mode = 1;
3197 else
3198 mode = 0;
3199
Naveen Rawatea1564b2018-05-17 15:56:11 -07003200 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003201 flag |= 1;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003202 if (rate_flags & TX_RATE_SGI)
Will Huang496b36c2017-07-11 16:38:50 +08003203 flag |= 2;
3204
3205 supported_mcs_rate = (struct index_data_rate_type *)
3206 ((nss == 1) ? &supported_mcs_rate_nss1 :
3207 &supported_mcs_rate_nss2);
3208
3209 if (stainfo->max_mcs_idx == 0xff) {
3210 hdd_err("invalid max_mcs_idx");
3211 /* report real mcs idx */
3212 mcsidx = stats->tx_rate.mcs;
3213 } else {
3214 mcsidx = stainfo->max_mcs_idx;
3215 }
3216
3217 if (!report_max) {
3218 for (i = 0; i < mcsidx; i++) {
3219 if (rssi <= rssi_mcs_tbl[mode][i]) {
3220 mcsidx = i;
3221 break;
3222 }
3223 }
3224 if (mcsidx < stats->tx_rate.mcs)
3225 mcsidx = stats->tx_rate.mcs;
3226 }
3227
3228 tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
3229
3230 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3231
3232 *maxrate = tmprate;
3233 *max_mcs_idx = mcsidx;
3234}
3235
3236/**
3237 * hdd_get_max_rate_vht() - get max rate for vht mode
3238 * @stainfo: stainfo pointer
3239 * @stats: fw txrx status pointer
3240 * @rate_flags: rate flags
3241 * @nss: number of streams
3242 * @maxrate: returned max rate buffer pointer
3243 * @max_mcs_idx: max mcs idx
3244 * @report_max: report max rate or actual rate
3245 *
3246 * This function will get max rate for vht mode
3247 *
3248 * Return: None
3249 */
Jeff Johnson82155922017-09-30 16:54:14 -07003250static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003251 struct hdd_fw_txrx_stats *stats,
3252 uint32_t rate_flags,
3253 uint8_t nss,
3254 uint32_t *maxrate,
3255 uint8_t *max_mcs_idx,
3256 bool report_max)
3257{
3258 struct index_vht_data_rate_type *supported_vht_mcs_rate;
3259 uint32_t tmprate = 0;
3260 uint32_t vht_max_mcs;
3261 uint8_t flag = 0, mcsidx = INVALID_MCS_IDX;
3262 int8_t rssi = stats->rssi;
3263 int mode;
3264 int i;
3265
3266 supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
3267 ((nss == 1) ?
3268 &supported_vht_mcs_rate_nss1 :
3269 &supported_vht_mcs_rate_nss2);
3270
Naveen Rawatea1564b2018-05-17 15:56:11 -07003271 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003272 mode = 2;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003273 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003274 mode = 1;
3275 else
3276 mode = 0;
3277
3278 if (rate_flags &
Naveen Rawatea1564b2018-05-17 15:56:11 -07003279 (TX_RATE_VHT20 | TX_RATE_VHT40 | TX_RATE_VHT80)) {
Will Huang496b36c2017-07-11 16:38:50 +08003280 vht_max_mcs =
3281 (enum data_rate_11ac_max_mcs)
3282 (stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK);
Naveen Rawatea1564b2018-05-17 15:56:11 -07003283 if (rate_flags & TX_RATE_SGI)
Will Huang496b36c2017-07-11 16:38:50 +08003284 flag |= 1;
3285
3286 if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) {
3287 mcsidx = 7;
3288 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) {
3289 mcsidx = 8;
3290 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) {
3291 /*
3292 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3293 * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6
3294 * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8
3295 */
Naveen Rawatea1564b2018-05-17 15:56:11 -07003296 if ((rate_flags & TX_RATE_VHT20) &&
Will Huang496b36c2017-07-11 16:38:50 +08003297 (nss != 3 && nss != 6))
3298 mcsidx = 8;
3299 else
3300 mcsidx = 9;
3301 } else {
3302 hdd_err("invalid vht_max_mcs");
3303 /* report real mcs idx */
3304 mcsidx = stats->tx_rate.mcs;
3305 }
3306
3307 if (!report_max) {
3308 for (i = 0; i <= mcsidx; i++) {
3309 if (rssi <= rssi_mcs_tbl[mode][i]) {
3310 mcsidx = i;
3311 break;
3312 }
3313 }
3314 if (mcsidx < stats->tx_rate.mcs)
3315 mcsidx = stats->tx_rate.mcs;
3316 }
3317
Naveen Rawatea1564b2018-05-17 15:56:11 -07003318 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003319 tmprate =
3320 supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag];
Naveen Rawatea1564b2018-05-17 15:56:11 -07003321 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003322 tmprate =
3323 supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag];
Naveen Rawatea1564b2018-05-17 15:56:11 -07003324 else if (rate_flags & TX_RATE_VHT20)
Will Huang496b36c2017-07-11 16:38:50 +08003325 tmprate =
3326 supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag];
3327 }
3328
3329 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3330
3331 *maxrate = tmprate;
3332 *max_mcs_idx = mcsidx;
3333}
3334
3335#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
3336/**
3337 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3338 * @stainfo: stainfo pointer
3339 * @rate_flags: HDD rate flags
3340 * @mcsidx: mcs index
3341 * @nss: number of streams
3342 * @vht: vht mode or not
3343 *
3344 * This function will fill ch width and mcs flags
3345 *
3346 * Return: None
3347 */
3348static void hdd_fill_bw_mcs(struct station_info *sinfo,
3349 uint8_t rate_flags,
3350 uint8_t mcsidx,
3351 uint8_t nss,
3352 bool vht)
3353{
3354 if (vht) {
3355 sinfo->txrate.nss = nss;
3356 sinfo->txrate.mcs = mcsidx;
3357 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003358 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003359 sinfo->txrate.bw = RATE_INFO_BW_80;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003360 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003361 sinfo->txrate.bw = RATE_INFO_BW_40;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003362 else if (rate_flags & TX_RATE_VHT20)
Will Huang496b36c2017-07-11 16:38:50 +08003363 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3364 } else {
3365 sinfo->txrate.mcs = (nss - 1) << 3;
3366 sinfo->txrate.mcs |= mcsidx;
3367 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003368 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003369 sinfo->txrate.bw = RATE_INFO_BW_40;
3370 }
3371}
3372#else
3373/**
3374 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3375 * @stainfo: stainfo pointer
3376 * @rate_flags: HDD rate flags
3377 * @mcsidx: mcs index
3378 * @nss: number of streams
3379 * @vht: vht mode or not
3380 *
3381 * This function will fill ch width and mcs flags
3382 *
3383 * Return: None
3384 */
3385static void hdd_fill_bw_mcs(struct station_info *sinfo,
3386 uint8_t rate_flags,
3387 uint8_t mcsidx,
3388 uint8_t nss,
3389 bool vht)
3390{
3391 if (vht) {
3392 sinfo->txrate.nss = nss;
3393 sinfo->txrate.mcs = mcsidx;
3394 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003395 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003396 sinfo->txrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003397 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003398 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003399 else if (rate_flags & TX_RATE_VHT20)
Will Huang496b36c2017-07-11 16:38:50 +08003400 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3401 } else {
3402 sinfo->txrate.mcs = (nss - 1) << 3;
3403 sinfo->txrate.mcs |= mcsidx;
3404 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003405 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003406 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
3407 }
3408}
3409#endif
3410
3411/**
3412 * hdd_fill_bw_mcs_vht() - fill ch width and mcs flags for VHT mode
3413 * @stainfo: stainfo pointer
3414 * @rate_flags: HDD rate flags
3415 * @mcsidx: mcs index
3416 * @nss: number of streams
3417 *
3418 * This function will fill ch width and mcs flags for VHT mode
3419 *
3420 * Return: None
3421 */
3422static void hdd_fill_bw_mcs_vht(struct station_info *sinfo,
3423 uint8_t rate_flags,
3424 uint8_t mcsidx,
3425 uint8_t nss)
3426{
3427 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, true);
3428}
3429
3430/**
3431 * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
3432 * @sinfo: station_info struct pointer
3433 * @rate_flags: HDD rate flags
3434 * @mcsidx: mcs index
3435 * @nss: number of streams
3436 * @maxrate: data rate (kbps)
3437 *
3438 * This function will fill rate info of sinfo struct
3439 *
3440 * Return: None
3441 */
3442static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
3443 uint32_t rate_flags,
3444 uint8_t mcsidx,
3445 uint8_t nss,
3446 uint32_t maxrate)
3447{
Naveen Rawatea1564b2018-05-17 15:56:11 -07003448 if (rate_flags & TX_RATE_LEGACY) {
Will Huang496b36c2017-07-11 16:38:50 +08003449 /* provide to the UI in units of 100kbps */
3450 sinfo->txrate.legacy = maxrate;
3451 } else {
3452 /* must be MCS */
3453 if (rate_flags &
Naveen Rawatea1564b2018-05-17 15:56:11 -07003454 (TX_RATE_VHT80 |
3455 TX_RATE_VHT40 |
3456 TX_RATE_VHT20))
Will Huang496b36c2017-07-11 16:38:50 +08003457 hdd_fill_bw_mcs_vht(sinfo, rate_flags, mcsidx, nss);
3458
Naveen Rawatea1564b2018-05-17 15:56:11 -07003459 if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40))
Will Huang496b36c2017-07-11 16:38:50 +08003460 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, false);
3461
Naveen Rawatea1564b2018-05-17 15:56:11 -07003462 if (rate_flags & TX_RATE_SGI) {
Will Huang496b36c2017-07-11 16:38:50 +08003463 if (!(sinfo->txrate.flags & RATE_INFO_FLAGS_VHT_MCS))
3464 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3465 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3466 }
3467 }
3468
3469 hdd_info("flag %x mcs %d legacy %d nss %d",
3470 sinfo->txrate.flags,
3471 sinfo->txrate.mcs,
3472 sinfo->txrate.legacy,
3473 sinfo->txrate.nss);
3474}
3475
3476/**
3477 * hdd_fill_station_info_flags() - fill flags of sinfo struct
3478 * @sinfo: station_info struct pointer
3479 *
3480 * This function will fill flags of sinfo struct
3481 *
3482 * Return: None
3483 */
3484static void hdd_fill_station_info_flags(struct station_info *sinfo)
3485{
Naveen Rawat23183d62018-04-12 11:19:01 -07003486 sinfo->filled |= HDD_INFO_SIGNAL |
3487 HDD_INFO_TX_BYTES |
3488 HDD_INFO_TX_BYTES64 |
3489 HDD_INFO_TX_BITRATE |
3490 HDD_INFO_TX_PACKETS |
3491 HDD_INFO_TX_RETRIES |
3492 HDD_INFO_TX_FAILED |
3493 HDD_INFO_RX_BYTES |
3494 HDD_INFO_RX_BYTES64 |
3495 HDD_INFO_RX_PACKETS |
3496 HDD_INFO_INACTIVE_TIME |
3497 HDD_INFO_CONNECTED_TIME;
Will Huang496b36c2017-07-11 16:38:50 +08003498}
3499
3500/**
3501 * hdd_fill_rate_info() - fill rate info of sinfo
Arif Hussaincca60432018-12-03 19:45:12 -08003502 * @psoc: psoc context
Will Huang496b36c2017-07-11 16:38:50 +08003503 * @sinfo: station_info struct pointer
3504 * @stainfo: stainfo pointer
3505 * @stats: fw txrx status pointer
Will Huang496b36c2017-07-11 16:38:50 +08003506 *
3507 * This function will fill rate info of sinfo
3508 *
3509 * Return: None
3510 */
Arif Hussaincca60432018-12-03 19:45:12 -08003511static void hdd_fill_rate_info(struct wlan_objmgr_psoc *psoc,
3512 struct station_info *sinfo,
Jeff Johnson82155922017-09-30 16:54:14 -07003513 struct hdd_station_info *stainfo,
Arif Hussaincca60432018-12-03 19:45:12 -08003514 struct hdd_fw_txrx_stats *stats)
Will Huang496b36c2017-07-11 16:38:50 +08003515{
3516 uint8_t rate_flags;
3517 uint8_t mcsidx = 0xff;
3518 uint32_t myrate, maxrate, tmprate;
3519 int rssidx;
3520 int nss = 1;
Arif Hussaincca60432018-12-03 19:45:12 -08003521 int link_speed_rssi_high = 0;
3522 int link_speed_rssi_mid = 0;
3523 int link_speed_rssi_low = 0;
3524 uint32_t link_speed_rssi_report = 0;
Will Huang496b36c2017-07-11 16:38:50 +08003525
Arif Hussaincca60432018-12-03 19:45:12 -08003526 ucfg_mlme_stats_get_cfg_values(psoc,
3527 &link_speed_rssi_high,
3528 &link_speed_rssi_mid,
3529 &link_speed_rssi_low,
3530 &link_speed_rssi_report);
Will Huang496b36c2017-07-11 16:38:50 +08003531
Arif Hussaincca60432018-12-03 19:45:12 -08003532 hdd_info("reportMaxLinkSpeed %d", link_speed_rssi_report);
Will Huang496b36c2017-07-11 16:38:50 +08003533 /* convert to 100kbps expected in rate table */
3534 myrate = stats->tx_rate.rate / 100;
3535 rate_flags = stainfo->rate_flags;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003536 if (!(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003537 nss = stainfo->nss;
Arif Hussaincca60432018-12-03 19:45:12 -08003538 if (ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
Will Huang496b36c2017-07-11 16:38:50 +08003539 /* Get current rate flags if report actual */
3540 if (stats->tx_rate.rate_flags)
3541 rate_flags =
3542 stats->tx_rate.rate_flags;
3543 nss = stats->tx_rate.nss;
3544 }
3545
3546 if (stats->tx_rate.mcs == INVALID_MCS_IDX)
Naveen Rawatea1564b2018-05-17 15:56:11 -07003547 rate_flags = TX_RATE_LEGACY;
Will Huang496b36c2017-07-11 16:38:50 +08003548 }
3549
Arif Hussaincca60432018-12-03 19:45:12 -08003550 if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
Will Huang496b36c2017-07-11 16:38:50 +08003551 /* we do not want to necessarily report the current speed */
Arif Hussaincca60432018-12-03 19:45:12 -08003552 if (ucfg_mlme_stats_is_link_speed_report_max(psoc)) {
Will Huang496b36c2017-07-11 16:38:50 +08003553 /* report the max possible speed */
3554 rssidx = 0;
Arif Hussaincca60432018-12-03 19:45:12 -08003555 } else if (ucfg_mlme_stats_is_link_speed_report_max_scaled(
3556 psoc)) {
Will Huang496b36c2017-07-11 16:38:50 +08003557 /* report the max possible speed with RSSI scaling */
Arif Hussaincca60432018-12-03 19:45:12 -08003558 if (stats->rssi >= link_speed_rssi_high) {
Will Huang496b36c2017-07-11 16:38:50 +08003559 /* report the max possible speed */
3560 rssidx = 0;
Arif Hussaincca60432018-12-03 19:45:12 -08003561 } else if (stats->rssi >= link_speed_rssi_mid) {
Will Huang496b36c2017-07-11 16:38:50 +08003562 /* report middle speed */
3563 rssidx = 1;
Arif Hussaincca60432018-12-03 19:45:12 -08003564 } else if (stats->rssi >= link_speed_rssi_low) {
Will Huang496b36c2017-07-11 16:38:50 +08003565 /* report middle speed */
3566 rssidx = 2;
3567 } else {
3568 /* report actual speed */
3569 rssidx = 3;
3570 }
3571 } else {
3572 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
3573 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
Arif Hussaincca60432018-12-03 19:45:12 -08003574 link_speed_rssi_report);
Will Huang496b36c2017-07-11 16:38:50 +08003575 rssidx = 0;
3576 }
3577
3578 maxrate = hdd_get_max_rate_legacy(stainfo, rssidx);
3579
3580 /*
3581 * Get MCS Rate Set --
3582 * Only if we are connected in non legacy mode and not
3583 * reporting actual speed
3584 */
3585 if ((rssidx != 3) &&
Naveen Rawatea1564b2018-05-17 15:56:11 -07003586 !(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003587 hdd_get_max_rate_vht(stainfo,
3588 stats,
3589 rate_flags,
3590 nss,
3591 &tmprate,
3592 &mcsidx,
3593 rssidx == 0);
3594
3595 if (maxrate < tmprate &&
3596 mcsidx != INVALID_MCS_IDX)
3597 maxrate = tmprate;
3598
3599 if (mcsidx == INVALID_MCS_IDX)
3600 hdd_get_max_rate_ht(stainfo,
3601 stats,
3602 rate_flags,
3603 nss,
3604 &tmprate,
3605 &mcsidx,
3606 rssidx == 0);
3607
3608 if (maxrate < tmprate &&
3609 mcsidx != INVALID_MCS_IDX)
3610 maxrate = tmprate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003611 } else if (!(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003612 maxrate = myrate;
3613 mcsidx = stats->tx_rate.mcs;
3614 }
3615
3616 /*
3617 * make sure we report a value at least as big as our
3618 * current rate
3619 */
3620 if ((maxrate < myrate) || (maxrate == 0)) {
3621 maxrate = myrate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003622 if (!(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003623 mcsidx = stats->tx_rate.mcs;
3624 /*
3625 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3626 * - MCS9 is valid for VHT20 when Nss = 3 or
3627 * Nss = 6
3628 * - MCS9 is not valid for VHT20 when
3629 * Nss = 1,2,4,5,7,8
3630 */
Naveen Rawatea1564b2018-05-17 15:56:11 -07003631 if ((rate_flags & TX_RATE_VHT20) &&
Will Huang496b36c2017-07-11 16:38:50 +08003632 (mcsidx > 8) &&
3633 (nss != 3 && nss != 6))
3634 mcsidx = 8;
3635 }
3636 }
3637 } else {
3638 /* report current rate instead of max rate */
3639 maxrate = myrate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003640 if (!(rate_flags & TX_RATE_LEGACY))
Will Huang496b36c2017-07-11 16:38:50 +08003641 mcsidx = stats->tx_rate.mcs;
3642 }
3643
3644 hdd_fill_sinfo_rate_info(sinfo,
3645 rate_flags,
3646 mcsidx,
3647 nss,
3648 maxrate);
3649}
3650
3651/**
3652 * wlan_hdd_fill_station_info() - fill station_info struct
Arif Hussaincca60432018-12-03 19:45:12 -08003653 * @psoc: psoc context
Will Huang496b36c2017-07-11 16:38:50 +08003654 * @sinfo: station_info struct pointer
3655 * @stainfo: stainfo pointer
3656 * @stats: fw txrx status pointer
Will Huang496b36c2017-07-11 16:38:50 +08003657 *
3658 * This function will fill station_info struct
3659 *
3660 * Return: None
3661 */
Arif Hussaincca60432018-12-03 19:45:12 -08003662static void wlan_hdd_fill_station_info(struct wlan_objmgr_psoc *psoc,
3663 struct station_info *sinfo,
Jeff Johnson82155922017-09-30 16:54:14 -07003664 struct hdd_station_info *stainfo,
Arif Hussaincca60432018-12-03 19:45:12 -08003665 struct hdd_fw_txrx_stats *stats)
Will Huang496b36c2017-07-11 16:38:50 +08003666{
3667 qdf_time_t curr_time, dur;
3668
3669 curr_time = qdf_system_ticks();
3670 dur = curr_time - stainfo->assoc_ts;
3671 sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000;
3672 dur = curr_time - stainfo->last_tx_rx_ts;
3673 sinfo->inactive_time = qdf_system_ticks_to_msecs(dur);
3674 sinfo->signal = stats->rssi;
3675 sinfo->tx_bytes = stats->tx_bytes;
3676 sinfo->tx_packets = stats->tx_packets;
3677 sinfo->rx_bytes = stats->rx_bytes;
3678 sinfo->rx_packets = stats->rx_packets;
3679 sinfo->tx_failed = stats->tx_failed;
3680 sinfo->tx_retries = stats->tx_retries;
3681
3682 /* tx rate info */
Arif Hussaincca60432018-12-03 19:45:12 -08003683 hdd_fill_rate_info(psoc, sinfo, stainfo, stats);
Will Huang496b36c2017-07-11 16:38:50 +08003684
3685 hdd_fill_station_info_flags(sinfo);
3686
3687 /* dump sta info*/
3688 hdd_info("dump stainfo");
3689 hdd_info("con_time %d inact_time %d tx_pkts %d rx_pkts %d",
3690 sinfo->connected_time, sinfo->inactive_time,
3691 sinfo->tx_packets, sinfo->rx_packets);
3692 hdd_info("failed %d retries %d tx_bytes %lld rx_bytes %lld",
3693 sinfo->tx_failed, sinfo->tx_retries,
3694 sinfo->tx_bytes, sinfo->rx_bytes);
3695 hdd_info("rssi %d mcs %d legacy %d nss %d flags %x",
3696 sinfo->signal, sinfo->txrate.mcs,
3697 sinfo->txrate.legacy, sinfo->txrate.nss,
3698 sinfo->txrate.flags);
3699}
3700
3701/**
3702 * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs
3703 * @rate: Data rate (100 kbps)
3704 * @nss: Number of streams
3705 * @mcs: HT mcs index
3706 *
3707 * This function is used to construct HT rate flag with rate, nss and mcs
3708 *
3709 * Return: rate flags for success, 0 on failure.
3710 */
3711static uint8_t hdd_get_rate_flags_ht(uint32_t rate,
3712 uint8_t nss,
3713 uint8_t mcs)
3714{
3715 struct index_data_rate_type *mcs_rate;
3716 uint8_t flags = 0;
3717
3718 mcs_rate = (struct index_data_rate_type *)
3719 ((nss == 1) ? &supported_mcs_rate_nss1 :
3720 &supported_mcs_rate_nss2);
3721
3722 if (rate == mcs_rate[mcs].supported_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003723 flags |= TX_RATE_HT20;
Will Huang496b36c2017-07-11 16:38:50 +08003724 } else if (rate == mcs_rate[mcs].supported_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003725 flags |= TX_RATE_HT40;
Will Huang496b36c2017-07-11 16:38:50 +08003726 } else if (rate == mcs_rate[mcs].supported_rate[2]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003727 flags |= TX_RATE_HT20;
3728 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003729 } else if (rate == mcs_rate[mcs].supported_rate[3]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003730 flags |= TX_RATE_HT40;
3731 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003732 } else {
3733 hdd_err("invalid params rate %d nss %d mcs %d",
3734 rate, nss, mcs);
3735 }
3736
3737 return flags;
3738}
3739
3740/**
3741 * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs
3742 * @rate: Data rate (100 kbps)
3743 * @nss: Number of streams
3744 * @mcs: VHT mcs index
3745 *
3746 * This function is used to construct VHT rate flag with rate, nss and mcs
3747 *
3748 * Return: rate flags for success, 0 on failure.
3749 */
3750static uint8_t hdd_get_rate_flags_vht(uint32_t rate,
3751 uint8_t nss,
3752 uint8_t mcs)
3753{
3754 struct index_vht_data_rate_type *mcs_rate;
3755 uint8_t flags = 0;
3756
3757 mcs_rate = (struct index_vht_data_rate_type *)
3758 ((nss == 1) ?
3759 &supported_vht_mcs_rate_nss1 :
3760 &supported_vht_mcs_rate_nss2);
3761
3762 if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003763 flags |= TX_RATE_VHT80;
Will Huang496b36c2017-07-11 16:38:50 +08003764 } else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003765 flags |= TX_RATE_VHT80;
3766 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003767 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003768 flags |= TX_RATE_VHT40;
Will Huang496b36c2017-07-11 16:38:50 +08003769 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003770 flags |= TX_RATE_VHT40;
3771 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003772 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003773 flags |= TX_RATE_VHT20;
Will Huang496b36c2017-07-11 16:38:50 +08003774 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003775 flags |= TX_RATE_VHT20;
3776 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003777 } else {
3778 hdd_err("invalid params rate %d nss %d mcs %d",
3779 rate, nss, mcs);
3780 }
3781
3782 return flags;
3783}
3784
3785/**
3786 * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs
3787 * @rate: Data rate (100 kbps)
3788 * @mode: Tx/Rx mode
3789 * @nss: Number of streams
3790 * @mcs: Mcs index
3791 *
3792 * This function is used to construct rate flag with rate, nss and mcs
3793 *
3794 * Return: rate flags for success, 0 on failure.
3795 */
3796static uint8_t hdd_get_rate_flags(uint32_t rate,
3797 uint8_t mode,
3798 uint8_t nss,
3799 uint8_t mcs)
3800{
3801 uint8_t flags = 0;
3802
3803 if (mode == SIR_SME_PHY_MODE_HT)
3804 flags = hdd_get_rate_flags_ht(rate, nss, mcs);
3805 else if (mode == SIR_SME_PHY_MODE_VHT)
3806 flags = hdd_get_rate_flags_vht(rate, nss, mcs);
3807 else
3808 hdd_err("invalid mode param %d", mode);
3809
3810 return flags;
3811}
3812
3813/**
3814 * wlan_hdd_fill_rate_info() - fill HDD rate info from SIR peer info
Will Huangb9cb1242019-04-02 14:52:17 +08003815 * @txrx_stats: pointer to txrx stats to be filled with rate info
Will Huang496b36c2017-07-11 16:38:50 +08003816 * @peer_info: SIR peer info pointer
3817 *
3818 * This function is used to fill HDD rate info rom SIR peer info
3819 *
3820 * Return: None
3821 */
Will Huangb9cb1242019-04-02 14:52:17 +08003822static void wlan_hdd_fill_rate_info(struct hdd_fw_txrx_stats *txrx_stats,
Will Huang496b36c2017-07-11 16:38:50 +08003823 struct sir_peer_info_ext *peer_info)
3824{
3825 uint8_t flags;
3826 uint32_t rate_code;
3827
3828 /* tx rate info */
Will Huangb9cb1242019-04-02 14:52:17 +08003829 txrx_stats->tx_rate.rate = peer_info->tx_rate;
Will Huang496b36c2017-07-11 16:38:50 +08003830 rate_code = peer_info->tx_rate_code;
3831
3832 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3833 WMI_RATE_PREAMBLE_HT)
Will Huangb9cb1242019-04-02 14:52:17 +08003834 txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_HT;
Will Huang496b36c2017-07-11 16:38:50 +08003835 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3836 WMI_RATE_PREAMBLE_VHT)
Will Huangb9cb1242019-04-02 14:52:17 +08003837 txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_VHT;
Will Huang496b36c2017-07-11 16:38:50 +08003838 else
Will Huangb9cb1242019-04-02 14:52:17 +08003839 txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
Will Huang496b36c2017-07-11 16:38:50 +08003840
Will Huangb9cb1242019-04-02 14:52:17 +08003841 txrx_stats->tx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3842 txrx_stats->tx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
Will Huang496b36c2017-07-11 16:38:50 +08003843
Will Huangb9cb1242019-04-02 14:52:17 +08003844 flags = hdd_get_rate_flags(txrx_stats->tx_rate.rate / 100,
3845 txrx_stats->tx_rate.mode,
3846 txrx_stats->tx_rate.nss,
3847 txrx_stats->tx_rate.mcs);
Will Huang496b36c2017-07-11 16:38:50 +08003848
Will Huangb9cb1242019-04-02 14:52:17 +08003849 txrx_stats->tx_rate.rate_flags = flags;
Will Huang496b36c2017-07-11 16:38:50 +08003850
3851 hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x",
Will Huangb9cb1242019-04-02 14:52:17 +08003852 txrx_stats->tx_rate.mode,
3853 txrx_stats->tx_rate.nss,
3854 txrx_stats->tx_rate.mcs,
3855 txrx_stats->tx_rate.rate_flags,
Will Huang496b36c2017-07-11 16:38:50 +08003856 flags);
3857
3858 /* rx rate info */
Will Huangb9cb1242019-04-02 14:52:17 +08003859 txrx_stats->rx_rate.rate = peer_info->rx_rate;
Will Huang496b36c2017-07-11 16:38:50 +08003860 rate_code = peer_info->rx_rate_code;
3861
3862 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3863 WMI_RATE_PREAMBLE_HT)
Will Huangb9cb1242019-04-02 14:52:17 +08003864 txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_HT;
Will Huang496b36c2017-07-11 16:38:50 +08003865 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3866 WMI_RATE_PREAMBLE_VHT)
Will Huangb9cb1242019-04-02 14:52:17 +08003867 txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_VHT;
Will Huang496b36c2017-07-11 16:38:50 +08003868 else
Will Huangb9cb1242019-04-02 14:52:17 +08003869 txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
Will Huang496b36c2017-07-11 16:38:50 +08003870
Will Huangb9cb1242019-04-02 14:52:17 +08003871 txrx_stats->rx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3872 txrx_stats->rx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
Will Huang496b36c2017-07-11 16:38:50 +08003873
Will Huangb9cb1242019-04-02 14:52:17 +08003874 flags = hdd_get_rate_flags(txrx_stats->rx_rate.rate / 100,
3875 txrx_stats->rx_rate.mode,
3876 txrx_stats->rx_rate.nss,
3877 txrx_stats->rx_rate.mcs);
Will Huang496b36c2017-07-11 16:38:50 +08003878
Will Huangb9cb1242019-04-02 14:52:17 +08003879 txrx_stats->rx_rate.rate_flags = flags;
Will Huang496b36c2017-07-11 16:38:50 +08003880
3881 hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x",
Will Huangb9cb1242019-04-02 14:52:17 +08003882 txrx_stats->rx_rate.mode,
3883 txrx_stats->rx_rate.nss,
3884 txrx_stats->rx_rate.mcs,
3885 txrx_stats->rx_rate.rate_flags,
Will Huang496b36c2017-07-11 16:38:50 +08003886 flags);
3887}
3888
Will Huang496b36c2017-07-11 16:38:50 +08003889/**
3890 * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
3891 * @wiphy: pointer to wiphy
3892 * @dev: pointer to net_device structure
3893 * @mac: request peer mac address
3894 * @sinfo: pointer to station_info struct
3895 *
3896 * This function will get remote peer info from fw and fill sinfo struct
3897 *
3898 * Return: 0 on success, otherwise error value
3899 */
Will Huangb9cb1242019-04-02 14:52:17 +08003900static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3901 struct net_device *dev,
3902 const u8 *mac,
3903 struct station_info *sinfo)
Will Huang496b36c2017-07-11 16:38:50 +08003904{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003905 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07003906 struct hdd_context *hddctx = wiphy_priv(wiphy);
Jeff Johnson82155922017-09-30 16:54:14 -07003907 struct hdd_station_info *stainfo = NULL;
Will Huang496b36c2017-07-11 16:38:50 +08003908 struct qdf_mac_addr macaddr;
3909 struct sir_peer_info_ext peer_info;
Will Huangb9cb1242019-04-02 14:52:17 +08003910 struct hdd_fw_txrx_stats txrx_stats;
Will Huang496b36c2017-07-11 16:38:50 +08003911 int status;
Will Huang496b36c2017-07-11 16:38:50 +08003912
3913 status = wlan_hdd_validate_context(hddctx);
3914 if (status != 0)
3915 return status;
3916
Will Huang496b36c2017-07-11 16:38:50 +08003917 hdd_debug("get peer %pM info", mac);
3918
Sourav Mohapatra43e6dea2019-08-18 11:39:23 +05303919 stainfo = hdd_get_sta_info_by_mac(&adapter->sta_info_list, mac);
Will Huang496b36c2017-07-11 16:38:50 +08003920 if (!stainfo) {
3921 hdd_err("peer %pM not found", mac);
3922 return -EINVAL;
3923 }
3924
3925 qdf_mem_copy(macaddr.bytes, mac, QDF_MAC_ADDR_SIZE);
3926 status = wlan_hdd_get_peer_info(adapter, macaddr, &peer_info);
3927 if (status) {
3928 hdd_err("fail to get peer info from fw");
3929 return -EPERM;
3930 }
3931
Will Huangb9cb1242019-04-02 14:52:17 +08003932 qdf_mem_zero(&txrx_stats, sizeof(txrx_stats));
3933 txrx_stats.tx_packets = peer_info.tx_packets;
3934 txrx_stats.tx_bytes = peer_info.tx_bytes;
3935 txrx_stats.rx_packets = peer_info.rx_packets;
3936 txrx_stats.rx_bytes = peer_info.rx_bytes;
3937 txrx_stats.tx_retries = peer_info.tx_retries;
3938 txrx_stats.tx_failed = peer_info.tx_failed;
3939 txrx_stats.rssi = peer_info.rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM;
3940 wlan_hdd_fill_rate_info(&txrx_stats, &peer_info);
3941 wlan_hdd_fill_station_info(hddctx->psoc, sinfo, stainfo, &txrx_stats);
Will Huang496b36c2017-07-11 16:38:50 +08003942
3943 return status;
3944}
3945
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05303946bool hdd_report_max_rate(mac_handle_t mac_handle,
3947 struct rate_info *rate,
3948 int8_t signal,
3949 uint8_t rate_flags,
3950 uint8_t mcs_index,
3951 uint16_t fw_rate, uint8_t nss)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303952{
3953 uint8_t i, j, rssidx;
3954 uint16_t max_rate = 0;
3955 uint32_t vht_mcs_map;
Sourav Mohapatra22ff4c62019-05-16 12:04:59 +05303956 bool is_vht20_mcs9 = false;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303957 uint16_t current_rate = 0;
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05303958 qdf_size_t or_leng = CSR_DOT11_SUPPORTED_RATES_MAX;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303959 uint8_t operational_rates[CSR_DOT11_SUPPORTED_RATES_MAX];
3960 uint8_t extended_rates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05303961 qdf_size_t er_leng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303962 uint8_t mcs_rates[SIZE_OF_BASIC_MCS_SET];
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05303963 qdf_size_t mcs_leng = SIZE_OF_BASIC_MCS_SET;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303964 struct index_vht_data_rate_type *supported_vht_mcs_rate;
3965 struct index_data_rate_type *supported_mcs_rate;
3966 enum data_rate_11ac_max_mcs vht_max_mcs;
3967 uint8_t max_speed_mcs = 0;
3968 uint8_t max_mcs_idx = 0;
3969 uint8_t rate_flag = 1;
3970 int mode = 0, max_ht_idx;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05303971 QDF_STATUS stat = QDF_STATUS_E_FAILURE;
3972 struct hdd_context *hdd_ctx;
Arif Hussaincca60432018-12-03 19:45:12 -08003973 int link_speed_rssi_high = 0;
3974 int link_speed_rssi_mid = 0;
3975 int link_speed_rssi_low = 0;
3976 uint32_t link_speed_rssi_report = 0;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05303977
3978 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
3979 if (!hdd_ctx) {
3980 hdd_err("HDD context is NULL");
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05303981 return false;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05303982 }
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303983
Arif Hussaincca60432018-12-03 19:45:12 -08003984 ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
3985 &link_speed_rssi_high,
3986 &link_speed_rssi_mid,
3987 &link_speed_rssi_low,
3988 &link_speed_rssi_report);
3989
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303990 /* we do not want to necessarily report the current speed */
Arif Hussaincca60432018-12-03 19:45:12 -08003991 if (ucfg_mlme_stats_is_link_speed_report_max(hdd_ctx->psoc)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303992 /* report the max possible speed */
3993 rssidx = 0;
Arif Hussaincca60432018-12-03 19:45:12 -08003994 } else if (ucfg_mlme_stats_is_link_speed_report_max_scaled(
3995 hdd_ctx->psoc)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303996 /* report the max possible speed with RSSI scaling */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05303997 if (signal >= link_speed_rssi_high) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05303998 /* report the max possible speed */
3999 rssidx = 0;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304000 } else if (signal >= link_speed_rssi_mid) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304001 /* report middle speed */
4002 rssidx = 1;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304003 } else if (signal >= link_speed_rssi_low) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304004 /* report middle speed */
4005 rssidx = 2;
4006 } else {
4007 /* report actual speed */
4008 rssidx = 3;
4009 }
4010 } else {
4011 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
4012 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
Arif Hussaincca60432018-12-03 19:45:12 -08004013 link_speed_rssi_report);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304014 rssidx = 0;
4015 }
4016
4017 max_rate = 0;
4018
4019 /* Get Basic Rate Set */
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05304020 if (0 != ucfg_mlme_get_opr_rate_set(hdd_ctx->psoc,
4021 operational_rates, &or_leng)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304022 hdd_err("cfg get returned failure");
4023 /*To keep GUI happy */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304024 return false;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304025 }
4026
4027 for (i = 0; i < or_leng; i++) {
4028 for (j = 0;
4029 j < ARRAY_SIZE(supported_data_rate); j++) {
4030 /* Validate Rate Set */
4031 if (supported_data_rate[j].beacon_rate_index ==
4032 (operational_rates[i] & 0x7F)) {
4033 current_rate =
4034 supported_data_rate[j].
4035 supported_rate[rssidx];
4036 break;
4037 }
4038 }
4039 /* Update MAX rate */
4040 max_rate = (current_rate > max_rate) ? current_rate : max_rate;
4041 }
4042
4043 /* Get Extended Rate Set */
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05304044 if (0 != ucfg_mlme_get_ext_opr_rate_set(hdd_ctx->psoc,
4045 extended_rates,
4046 &er_leng)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304047 hdd_err("cfg get returned failure");
4048 /*To keep GUI happy */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304049 return false;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304050 }
4051
4052 for (i = 0; i < er_leng; i++) {
4053 for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) {
4054 if (supported_data_rate[j].beacon_rate_index ==
4055 (extended_rates[i] & 0x7F)) {
4056 current_rate = supported_data_rate[j].
4057 supported_rate[rssidx];
4058 break;
4059 }
4060 }
4061 /* Update MAX rate */
4062 max_rate = (current_rate > max_rate) ? current_rate : max_rate;
4063 }
4064 /* Get MCS Rate Set --
4065 * Only if we are connected in non legacy mode and not reporting
4066 * actual speed
4067 */
Sourav Mohapatra22ff4c62019-05-16 12:04:59 +05304068
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304069 if ((3 != rssidx) && !(rate_flags & TX_RATE_LEGACY)) {
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05304070 if (0 != ucfg_mlme_get_current_mcs_set(hdd_ctx->psoc,
4071 mcs_rates,
4072 &mcs_leng)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304073 hdd_err("cfg get returned failure");
4074 /*To keep GUI happy */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304075 return false;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304076 }
4077 rate_flag = 0;
4078 supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304079 ((nss == 1) ?
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304080 &supported_vht_mcs_rate_nss1 :
4081 &supported_vht_mcs_rate_nss2);
4082
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304083 if (rate_flags & TX_RATE_VHT80)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304084 mode = 2;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304085 else if ((rate_flags & TX_RATE_VHT40) ||
4086 (rate_flags & TX_RATE_HT40))
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304087 mode = 1;
4088 else
4089 mode = 0;
4090
4091 /* VHT80 rate has separate rate table */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304092 if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 |
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304093 TX_RATE_VHT80)) {
Abhinav Kumare057b412018-10-09 17:28:16 +05304094 stat = ucfg_mlme_cfg_get_vht_tx_mcs_map(hdd_ctx->psoc,
4095 &vht_mcs_map);
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05304096 if (QDF_IS_STATUS_ERROR(stat))
4097 hdd_err("failed to get tx_mcs_map");
Sourav Mohapatra22ff4c62019-05-16 12:04:59 +05304098
4099 stat = ucfg_mlme_get_vht20_mcs9(hdd_ctx->psoc,
4100 &is_vht20_mcs9);
4101 if (QDF_IS_STATUS_ERROR(stat))
4102 hdd_err("Failed to get VHT20 MCS9 enable val");
4103
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304104 vht_max_mcs = (enum data_rate_11ac_max_mcs)
4105 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304106 if (rate_flags & TX_RATE_SGI)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304107 rate_flag |= 1;
4108
4109 if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs) {
4110 max_mcs_idx = 7;
4111 } else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs) {
4112 max_mcs_idx = 8;
4113 } else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs) {
Sourav Mohapatra22ff4c62019-05-16 12:04:59 +05304114 /*
4115 * If the ini enable_vht20_mcs9 is disabled,
4116 * then max mcs index should not be set to 9
4117 * for TX_RATE_VHT20
4118 */
4119 if (!is_vht20_mcs9 &&
4120 (rate_flags & TX_RATE_VHT20))
4121 max_mcs_idx = 8;
4122 else
4123 max_mcs_idx = 9;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304124 }
4125
4126 if (rssidx != 0) {
4127 for (i = 0; i <= max_mcs_idx; i++) {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304128 if (signal <= rssi_mcs_tbl[mode][i]) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304129 max_mcs_idx = i;
4130 break;
4131 }
4132 }
4133 }
4134
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304135 if (rate_flags & TX_RATE_VHT80) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304136 current_rate =
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304137 supported_vht_mcs_rate[mcs_index].
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304138 supported_VHT80_rate[rate_flag];
4139 max_rate =
4140 supported_vht_mcs_rate[max_mcs_idx].
4141 supported_VHT80_rate[rate_flag];
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304142 } else if (rate_flags & TX_RATE_VHT40) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304143 current_rate =
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304144 supported_vht_mcs_rate[mcs_index].
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304145 supported_VHT40_rate[rate_flag];
4146 max_rate =
4147 supported_vht_mcs_rate[max_mcs_idx].
4148 supported_VHT40_rate[rate_flag];
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304149 } else if (rate_flags & TX_RATE_VHT20) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304150 current_rate =
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304151 supported_vht_mcs_rate[mcs_index].
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304152 supported_VHT20_rate[rate_flag];
4153 max_rate =
4154 supported_vht_mcs_rate[max_mcs_idx].
4155 supported_VHT20_rate[rate_flag];
4156 }
4157
4158 max_speed_mcs = 1;
4159 if (current_rate > max_rate)
4160 max_rate = current_rate;
4161
4162 } else {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304163 if (rate_flags & TX_RATE_HT40)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304164 rate_flag |= 1;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304165 if (rate_flags & TX_RATE_SGI)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304166 rate_flag |= 2;
4167
4168 supported_mcs_rate =
4169 (struct index_data_rate_type *)
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304170 ((nss == 1) ? &supported_mcs_rate_nss1 :
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304171 &supported_mcs_rate_nss2);
4172
4173 max_ht_idx = MAX_HT_MCS_IDX;
4174 if (rssidx != 0) {
4175 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304176 if (signal <= rssi_mcs_tbl[mode][i]) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304177 max_ht_idx = i + 1;
4178 break;
4179 }
4180 }
4181 }
4182
4183 for (i = 0; i < mcs_leng; i++) {
4184 for (j = 0; j < max_ht_idx; j++) {
4185 if (supported_mcs_rate[j].
4186 beacon_rate_index ==
4187 mcs_rates[i]) {
4188 current_rate =
4189 supported_mcs_rate[j].
4190 supported_rate
4191 [rate_flag];
4192 max_mcs_idx =
4193 supported_mcs_rate[j].
4194 beacon_rate_index;
4195 break;
4196 }
4197 }
4198
4199 if ((j < MAX_HT_MCS_IDX) &&
4200 (current_rate > max_rate)) {
4201 max_rate = current_rate;
4202 }
4203 max_speed_mcs = 1;
4204 }
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304205 if (nss == 2)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304206 max_mcs_idx += MAX_HT_MCS_IDX;
4207 }
4208 }
4209
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304210 else if (!(rate_flags & TX_RATE_LEGACY)) {
4211 max_rate = fw_rate;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304212 max_speed_mcs = 1;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304213 max_mcs_idx = mcs_index;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304214 }
4215 /* report a value at least as big as current rate */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304216 if ((max_rate < fw_rate) || (0 == max_rate)) {
4217 max_rate = fw_rate;
4218 if (rate_flags & TX_RATE_LEGACY) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304219 max_speed_mcs = 0;
4220 } else {
4221 max_speed_mcs = 1;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304222 max_mcs_idx = mcs_index;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304223 }
4224 }
4225
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304226 if (rate_flags & TX_RATE_LEGACY) {
4227 rate->legacy = max_rate;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304228
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304229 hdd_info("Reporting legacy rate %d", rate->legacy);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304230 } else {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304231 rate->mcs = max_mcs_idx;
4232 rate->nss = nss;
4233 if (rate_flags & TX_RATE_VHT80)
4234 hdd_set_rate_bw(rate, HDD_RATE_BW_80);
4235 else if (rate_flags & TX_RATE_VHT40)
4236 hdd_set_rate_bw(rate, HDD_RATE_BW_40);
4237 else if (rate_flags & TX_RATE_VHT20)
4238 hdd_set_rate_bw(rate, HDD_RATE_BW_20);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304239
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304240 if (rate_flags &
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304241 (TX_RATE_HT20 | TX_RATE_HT40)) {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304242 rate->flags |= RATE_INFO_FLAGS_MCS;
4243 if (rate_flags & TX_RATE_HT40)
4244 hdd_set_rate_bw(rate,
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304245 HDD_RATE_BW_40);
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304246 else if (rate_flags & TX_RATE_HT20)
4247 hdd_set_rate_bw(rate,
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304248 HDD_RATE_BW_20);
4249 } else {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304250 rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304251 }
4252
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304253 if (rate_flags & TX_RATE_SGI) {
4254 if (!(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
4255 rate->flags |= RATE_INFO_FLAGS_MCS;
4256 rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304257 }
4258 linkspeed_dbg("Reporting MCS rate %d flags %x\n",
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304259 rate->mcs, rate->flags);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304260 }
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304261
4262 return true;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304263}
4264
4265/**
4266 * hdd_report_actual_rate() - Fill the actual rate stats.
4267 *
4268 * @rate_flags: The rate flags computed from rate
4269 * @my_rate: The rate from fw stats
4270 * @rate: The station_info struct member strust rate_info to be filled
4271 * @mcs_index; The mcs index computed from rate
4272 * @nss: The NSS from fw stats
4273 *
4274 * Return: None
4275 */
4276static void hdd_report_actual_rate(uint8_t rate_flags, uint16_t my_rate,
4277 struct rate_info *rate, uint8_t mcs_index,
4278 uint8_t nss)
4279{
4280 /* report current rate instead of max rate */
4281
4282 if (rate_flags & TX_RATE_LEGACY) {
4283 /* provide to the UI in units of 100kbps */
4284 rate->legacy = my_rate;
4285 linkspeed_dbg("Reporting actual legacy rate %d",
4286 rate->legacy);
4287 } else {
4288 /* must be MCS */
4289 rate->mcs = mcs_index;
4290 rate->nss = nss;
4291
4292 if (rate_flags & TX_RATE_VHT80)
4293 hdd_set_rate_bw(rate, HDD_RATE_BW_80);
4294 else if (rate_flags & TX_RATE_VHT40)
4295 hdd_set_rate_bw(rate, HDD_RATE_BW_40);
4296
4297 if (rate_flags &
4298 (TX_RATE_HT20 | TX_RATE_HT40)) {
4299 rate->flags |= RATE_INFO_FLAGS_MCS;
4300 if (rate_flags & TX_RATE_HT40)
4301 hdd_set_rate_bw(rate, HDD_RATE_BW_40);
4302 } else {
4303 rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
4304 }
4305
4306 if (rate_flags & TX_RATE_SGI) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304307 rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
4308 }
4309
4310 linkspeed_dbg("Reporting actual MCS rate %d flags %x\n",
4311 rate->mcs, rate->flags);
4312 }
4313}
4314
4315/**
4316 * hdd_wlan_fill_per_chain_rssi_stats() - Fill per chain rssi stats
4317 *
4318 * @sinfo: The station_info structure to be filled.
4319 * @adapter: The HDD adapter structure
4320 *
4321 * Return: None
4322 */
4323#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
4324static inline
4325void hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
4326 struct hdd_adapter *adapter)
4327{
4328 bool rssi_stats_valid = false;
4329 uint8_t i;
4330
4331 sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
4332 for (i = 0; i < NUM_CHAINS_MAX; i++) {
4333 sinfo->chain_signal_avg[i] =
4334 adapter->hdd_stats.per_chain_rssi_stats.rssi[i];
4335 sinfo->chains |= 1 << i;
4336 if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
4337 sinfo->chain_signal_avg[i] != 0)
4338 sinfo->signal_avg = sinfo->chain_signal_avg[i];
4339
4340 hdd_debug("RSSI for chain %d, vdev_id %d is %d",
Jeff Johnson1abc5662019-02-04 14:27:02 -08004341 i, adapter->vdev_id, sinfo->chain_signal_avg[i]);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304342
4343 if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
4344 rssi_stats_valid = true;
4345 }
4346
4347 if (rssi_stats_valid) {
4348 sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG;
4349 sinfo->filled |= HDD_INFO_SIGNAL_AVG;
4350 }
4351}
4352
4353#else
4354
4355static inline
4356void hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
4357 struct hdd_adapter *adapter)
4358{
4359}
4360
4361#endif
4362
Ashish Kumar Dhanotiyaed6d0272019-04-15 12:13:24 +05304363#if defined(CFG80211_RX_FCS_ERROR_REPORTING_SUPPORT)
4364static void hdd_fill_fcs_and_mpdu_count(struct hdd_adapter *adapter,
4365 struct station_info *sinfo)
4366{
4367 sinfo->rx_mpdu_count = adapter->hdd_stats.peer_stats.rx_count;
4368 sinfo->fcs_err_count = adapter->hdd_stats.peer_stats.fcs_count;
4369 hdd_debug("RX mpdu count %d fcs_err_count %d",
4370 sinfo->rx_mpdu_count, sinfo->fcs_err_count);
Ashish Kumar Dhanotiya14923e62019-06-19 14:58:18 +05304371 sinfo->filled |= HDD_INFO_FCS_ERROR_COUNT | HDD_INFO_RX_MPDUS;
Ashish Kumar Dhanotiyaed6d0272019-04-15 12:13:24 +05304372}
4373#else
4374static void hdd_fill_fcs_and_mpdu_count(struct hdd_adapter *adapter,
4375 struct station_info *sinfo)
4376{
4377}
4378#endif
4379
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304380/**
Naveen Rawat374d7982018-04-12 10:56:09 -07004381 * wlan_hdd_get_sta_stats() - get aggregate STA stats
4382 * @wiphy: wireless phy
4383 * @adapter: STA adapter to get stats for
4384 * @mac: mac address of sta
4385 * @sinfo: kernel station_info struct to populate
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004386 *
Naveen Rawat374d7982018-04-12 10:56:09 -07004387 * Fetch the vdev-level aggregate stats for the given STA adapter. This is to
4388 * support "station dump" and "station get" for STA vdevs
4389 *
4390 * Return: errno
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004391 */
Naveen Rawat374d7982018-04-12 10:56:09 -07004392static int wlan_hdd_get_sta_stats(struct wiphy *wiphy,
4393 struct hdd_adapter *adapter,
4394 const uint8_t *mac,
4395 struct station_info *sinfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004396{
Jeff Johnsond377dce2017-10-04 10:32:42 -07004397 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304398 uint8_t rate_flags, tx_rate_flags, rx_rate_flags;
4399 uint8_t tx_mcs_index, rx_mcs_index;
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004400 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Jeff Johnson003f7392018-06-12 20:45:47 -07004401 mac_handle_t mac_handle;
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304402 int8_t snr = 0;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304403 uint16_t my_tx_rate, my_rx_rate;
4404 uint8_t tx_nss = 1, rx_nss = 1;
Rajeev Kumar Sirasanagandlab13b7772017-01-24 15:28:29 +05304405 int32_t rcpi_value;
Arif Hussaincca60432018-12-03 19:45:12 -08004406 int link_speed_rssi_high = 0;
4407 int link_speed_rssi_mid = 0;
4408 int link_speed_rssi_low = 0;
4409 uint32_t link_speed_rssi_report = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004410
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304411 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
4412 TRACE_CODE_HDD_CFG80211_GET_STA,
Jeff Johnson1abc5662019-02-04 14:27:02 -08004413 adapter->vdev_id, 0);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304414
Jeff Johnsone7951512019-02-27 10:02:51 -08004415 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Paul Zhang9ffb0432018-08-03 10:32:34 +08004416 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417 /*To keep GUI happy */
4418 return 0;
4419 }
4420
Jeff Johnson690fe952017-10-25 11:48:39 -07004421 if (sta_ctx->hdd_reassoc_scenario) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004422 hdd_debug("Roaming is in progress, cannot continue with this request");
Sachin Ahujafeedeba2016-09-13 21:54:16 +05304423 /*
4424 * supplicant reports very low rssi to upper layer
4425 * and handover happens to cellular.
4426 * send the cached rssi when get_station
4427 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004428 sinfo->signal = adapter->rssi;
Naveen Rawat23183d62018-04-12 11:19:01 -07004429 sinfo->filled |= HDD_INFO_SIGNAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004430 return 0;
4431 }
4432
Arif Hussaincca60432018-12-03 19:45:12 -08004433 ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
4434 &link_speed_rssi_high,
4435 &link_speed_rssi_mid,
4436 &link_speed_rssi_low,
4437 &link_speed_rssi_report);
4438
Rajeev Kumar Sirasanagandlab13b7772017-01-24 15:28:29 +05304439 if (hdd_ctx->rcpi_enabled)
4440 wlan_hdd_get_rcpi(adapter, (uint8_t *)mac, &rcpi_value,
4441 RCPI_MEASUREMENT_TYPE_AVG_MGMT);
4442
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004443 wlan_hdd_get_station_stats(adapter);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05304444
Paul Zhangb1f35df2018-04-16 12:19:01 +08004445 adapter->rssi = adapter->hdd_stats.summary_stat.rssi;
4446 snr = adapter->hdd_stats.summary_stat.snr;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05304447
4448 /* for new connection there might be no valid previous RSSI */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004449 if (!adapter->rssi) {
4450 hdd_get_rssi_snr_by_bssid(adapter,
Jeff Johnsone04b6992019-02-27 14:06:55 -08004451 sta_ctx->conn_info.bssid.bytes,
Paul Zhangb1f35df2018-04-16 12:19:01 +08004452 &adapter->rssi, &snr);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05304453 }
4454
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004455 sinfo->signal = adapter->rssi;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004456 hdd_debug("snr: %d, rssi: %d",
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004457 adapter->hdd_stats.summary_stat.snr,
4458 adapter->hdd_stats.summary_stat.rssi);
Jeff Johnsond377dce2017-10-04 10:32:42 -07004459 sta_ctx->conn_info.signal = sinfo->signal;
4460 sta_ctx->conn_info.noise =
4461 sta_ctx->conn_info.signal - snr;
Ashish Kumar Dhanotiya36d19b02018-02-22 00:59:49 +05304462 sta_ctx->cache_conn_info.signal = sinfo->signal;
4463 sta_ctx->cache_conn_info.noise = sta_ctx->conn_info.noise;
Naveen Rawat23183d62018-04-12 11:19:01 -07004464 sinfo->filled |= HDD_INFO_SIGNAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004465
Jeff Johnson71396692016-09-23 15:41:52 -07004466 /*
4467 * we notify connect to lpass here instead of during actual
4468 * connect processing because rssi info is not accurate during
4469 * actual connection. lpass will ensure the notification is
4470 * only processed once per association.
4471 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004472 hdd_lpass_notify_connect(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004473
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304474 rate_flags = adapter->hdd_stats.class_a_stat.tx_rx_rate_flags;
4475 tx_rate_flags = rx_rate_flags = rate_flags;
4476
4477 tx_mcs_index = adapter->hdd_stats.class_a_stat.tx_mcs_index;
4478 rx_mcs_index = adapter->hdd_stats.class_a_stat.rx_mcs_index;
Jeff Johnson003f7392018-06-12 20:45:47 -07004479 mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004480
4481 /* convert to the UI units of 100kbps */
Sourav Mohapatrad204a812019-01-09 09:45:08 +05304482 my_tx_rate = adapter->hdd_stats.class_a_stat.tx_rate;
4483 my_rx_rate = adapter->hdd_stats.class_a_stat.rx_rate;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304484
Naveen Rawatea1564b2018-05-17 15:56:11 -07004485 if (!(rate_flags & TX_RATE_LEGACY)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304486 tx_nss = adapter->hdd_stats.class_a_stat.tx_nss;
4487 rx_nss = adapter->hdd_stats.class_a_stat.rx_nss;
4488
4489 if ((tx_nss > 1) &&
Dustin Brown05d81302018-09-11 16:49:22 -07004490 policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
4491 !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304492 hdd_debug("Hw mode is DBS, Reduce nss(%d) to 1",
4493 tx_nss);
4494 tx_nss--;
4495 }
4496
4497 if ((rx_nss > 1) &&
Dustin Brown05d81302018-09-11 16:49:22 -07004498 policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
4499 !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304500 hdd_debug("Hw mode is DBS, Reduce nss(%d) to 1",
4501 rx_nss);
4502 rx_nss--;
Agrawal Ashish569ad262017-05-01 14:06:36 +05304503 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004504
Arif Hussaincca60432018-12-03 19:45:12 -08004505 if (ucfg_mlme_stats_is_link_speed_report_actual(
4506 hdd_ctx->psoc)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004507 /* Get current rate flags if report actual */
Hanumanth Reddy Pothula063cbe92017-08-08 23:22:01 +05304508 /* WMA fails to find mcs_index for legacy tx rates */
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304509 if (tx_mcs_index == INVALID_MCS_IDX && my_tx_rate)
4510 tx_rate_flags = TX_RATE_LEGACY;
Hanumanth Reddy Pothula063cbe92017-08-08 23:22:01 +05304511 else
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304512 tx_rate_flags =
4513 adapter->hdd_stats.class_a_stat.tx_mcs_rate_flags;
4514
4515 if (rx_mcs_index == INVALID_MCS_IDX && my_rx_rate)
4516 rx_rate_flags = TX_RATE_LEGACY;
4517 else
4518 rx_rate_flags =
4519 adapter->hdd_stats.class_a_stat.rx_mcs_rate_flags;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004520 }
4521
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304522 if (tx_mcs_index == INVALID_MCS_IDX)
4523 tx_mcs_index = 0;
4524 if (rx_mcs_index == INVALID_MCS_IDX)
4525 rx_mcs_index = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004526 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004527
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304528 hdd_debug("RSSI %d, RLMS %u, rssi high %d, rssi mid %d, rssi low %d",
Arif Hussaincca60432018-12-03 19:45:12 -08004529 sinfo->signal, link_speed_rssi_report,
4530 link_speed_rssi_high, link_speed_rssi_mid,
4531 link_speed_rssi_low);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304532 hdd_debug("Rate info: TX: %d, RX: %d", my_tx_rate, my_rx_rate);
4533 hdd_debug("Rate flags: TX: 0x%x, RX: 0x%x", (int)tx_rate_flags,
4534 (int)rx_rate_flags);
4535 hdd_debug("MCS Index: TX: %d, RX: %d", (int)tx_mcs_index,
4536 (int)rx_mcs_index);
Sourav Mohapatrab22d2692018-09-21 18:11:45 +05304537 hdd_debug("NSS: TX: %d, RX: %d", (int)tx_nss, (int)rx_nss);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004538
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07004539 /* assume basic BW. anything else will override this later */
Dustin Brown32cb4792017-06-15 15:33:42 -07004540 hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_20);
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07004541
Arif Hussaincca60432018-12-03 19:45:12 -08004542 if (!ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304543 bool tx_rate_calc;
4544 bool rx_rate_calc;
4545
4546 tx_rate_calc = hdd_report_max_rate(mac_handle, &sinfo->txrate,
4547 sinfo->signal,
4548 tx_rate_flags,
4549 tx_mcs_index,
4550 my_tx_rate,
4551 tx_nss);
4552
4553 rx_rate_calc = hdd_report_max_rate(mac_handle, &sinfo->rxrate,
4554 sinfo->signal,
4555 rx_rate_flags,
4556 rx_mcs_index,
4557 my_rx_rate,
4558 rx_nss);
4559
4560 if (!tx_rate_calc || !rx_rate_calc)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304561 /* Keep GUI happy */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004562 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004564
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304565 /* Fill TX stats */
4566 hdd_report_actual_rate(tx_rate_flags, my_tx_rate,
4567 &sinfo->txrate, tx_mcs_index, tx_nss);
Dustin Brown32cb4792017-06-15 15:33:42 -07004568
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304569 /* Fill RX stats */
4570 hdd_report_actual_rate(rx_rate_flags, my_rx_rate,
4571 &sinfo->rxrate, rx_mcs_index, rx_nss);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004572 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004573
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004574 wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, sinfo);
4575 sinfo->tx_bytes = adapter->stats.tx_bytes;
Ashish Kumar Dhanotiyaed6d0272019-04-15 12:13:24 +05304576 sinfo->rx_bytes = adapter->stats.rx_bytes;
4577 sinfo->rx_packets = adapter->stats.rx_packets;
4578
4579 hdd_fill_fcs_and_mpdu_count(adapter, sinfo);
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004580
Jeff Johnsond377dce2017-10-04 10:32:42 -07004581 qdf_mem_copy(&sta_ctx->conn_info.txrate,
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304582 &sinfo->txrate, sizeof(sinfo->txrate));
Ashish Kumar Dhanotiya36d19b02018-02-22 00:59:49 +05304583 qdf_mem_copy(&sta_ctx->cache_conn_info.txrate,
4584 &sinfo->txrate, sizeof(sinfo->txrate));
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304585
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304586 qdf_mem_copy(&sta_ctx->conn_info.rxrate,
4587 &sinfo->rxrate, sizeof(sinfo->rxrate));
4588
Naveen Rawat23183d62018-04-12 11:19:01 -07004589 sinfo->filled |= HDD_INFO_TX_BITRATE |
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304590 HDD_INFO_RX_BITRATE |
Naveen Rawat23183d62018-04-12 11:19:01 -07004591 HDD_INFO_TX_BYTES |
4592 HDD_INFO_RX_BYTES |
4593 HDD_INFO_RX_PACKETS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004594
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304595 if (tx_rate_flags & TX_RATE_LEGACY)
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004596 hdd_debug("Reporting legacy rate %d pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304597 sinfo->txrate.legacy, sinfo->tx_packets,
4598 sinfo->rx_packets);
4599 else
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004600 hdd_debug("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d",
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304601 sinfo->txrate.mcs, sinfo->txrate.flags,
4602 sinfo->tx_packets, sinfo->rx_packets);
4603
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304604 hdd_wlan_fill_per_chain_rssi_stats(sinfo, adapter);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304605
Dustin Browne74003f2018-03-14 12:51:58 -07004606 hdd_exit();
Dustin Brown32cb4792017-06-15 15:33:42 -07004607
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004608 return 0;
4609}
4610
4611/**
Naveen Rawat374d7982018-04-12 10:56:09 -07004612 * __wlan_hdd_cfg80211_get_station() - get station statistics
4613 * @wiphy: Pointer to wiphy
4614 * @dev: Pointer to network device
4615 * @mac: Pointer to mac
4616 * @sinfo: Pointer to station info
4617 *
4618 * Return: 0 for success, non-zero for failure
4619 */
4620static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4621 struct net_device *dev,
4622 const uint8_t *mac,
4623 struct station_info *sinfo)
4624{
4625 int status;
4626 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Will Huangb9cb1242019-04-02 14:52:17 +08004627 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
4628 bool get_peer_info_enable;
4629 QDF_STATUS qdf_status;
Naveen Rawat374d7982018-04-12 10:56:09 -07004630
4631 hdd_enter_dev(dev);
4632
4633 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
4634 hdd_err("Command not allowed in FTM mode");
4635 return -EINVAL;
4636 }
4637
4638 status = wlan_hdd_validate_context(hdd_ctx);
4639 if (status)
4640 return status;
4641
Jeff Johnson48363022019-02-24 16:26:51 -08004642 if (wlan_hdd_validate_vdev_id(adapter->vdev_id))
Naveen Rawat374d7982018-04-12 10:56:09 -07004643 return -EINVAL;
Naveen Rawat374d7982018-04-12 10:56:09 -07004644
Will Huangb9cb1242019-04-02 14:52:17 +08004645 if (adapter->device_mode == QDF_SAP_MODE) {
4646 qdf_status = ucfg_mlme_get_sap_get_peer_info(
4647 hdd_ctx->psoc, &get_peer_info_enable);
4648 if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) {
4649 status = wlan_hdd_get_station_remote(wiphy, dev,
4650 mac, sinfo);
4651 if (!status)
4652 return 0;
4653 }
Naveen Rawat374d7982018-04-12 10:56:09 -07004654 return wlan_hdd_get_sap_stats(adapter, sinfo);
Will Huangb9cb1242019-04-02 14:52:17 +08004655 } else {
Naveen Rawat374d7982018-04-12 10:56:09 -07004656 return wlan_hdd_get_sta_stats(wiphy, adapter, mac, sinfo);
Will Huangb9cb1242019-04-02 14:52:17 +08004657 }
Naveen Rawat374d7982018-04-12 10:56:09 -07004658}
4659
4660/**
Yue Ma1c1d0f72019-08-01 19:21:05 -07004661 * _wlan_hdd_cfg80211_get_station() - get station statistics
4662 *
4663 * @wiphy: Pointer to wiphy
4664 * @dev: Pointer to network device
4665 * @mac: Pointer to mac
4666 * @sinfo: Pointer to station info
4667 *
4668 * This API tries runtime PM suspend right away after getting station
4669 * statistics.
4670 *
4671 * Return: 0 for success, non-zero for failure
4672 */
4673static int _wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4674 struct net_device *dev,
4675 const uint8_t *mac,
4676 struct station_info *sinfo)
4677{
Sravan Kumar Kairam10ed0e82019-08-21 20:52:09 +05304678 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Manikandan Mohan1baadae2019-08-23 08:32:56 -07004679 qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
Yue Ma1c1d0f72019-08-01 19:21:05 -07004680 int errno;
4681
Sravan Kumar Kairam10ed0e82019-08-21 20:52:09 +05304682 errno = wlan_hdd_validate_context(hdd_ctx);
4683 if (errno)
4684 return errno;
4685
Manikandan Mohan1f380142019-09-26 18:03:25 -07004686 if (!qdf_ctx)
4687 return -EINVAL;
4688
Manikandan Mohan1baadae2019-08-23 08:32:56 -07004689 errno = pld_qmi_send_get(qdf_ctx->dev);
Yue Ma1c1d0f72019-08-01 19:21:05 -07004690 if (errno)
4691 return errno;
4692
4693 errno = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4694
Manikandan Mohan1baadae2019-08-23 08:32:56 -07004695 pld_qmi_send_put(qdf_ctx->dev);
Yue Ma1c1d0f72019-08-01 19:21:05 -07004696
4697 return errno;
4698}
4699
4700/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004701 * wlan_hdd_cfg80211_get_station() - get station statistics
4702 * @wiphy: Pointer to wiphy
4703 * @dev: Pointer to network device
4704 * @mac: Pointer to mac
4705 * @sinfo: Pointer to station info
4706 *
4707 * Return: 0 for success, non-zero for failure
4708 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004709int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4710 struct net_device *dev, const uint8_t *mac,
4711 struct station_info *sinfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004712{
Dustin Brown1d31b082018-11-22 14:41:20 +05304713 int errno;
4714 struct osif_vdev_sync *vdev_sync;
4715
4716 errno = osif_vdev_sync_op_start(dev, &vdev_sync);
4717 if (errno)
4718 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004719
Yue Ma1c1d0f72019-08-01 19:21:05 -07004720 errno = _wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004721
Dustin Brown1d31b082018-11-22 14:41:20 +05304722 osif_vdev_sync_op_stop(vdev_sync);
4723
4724 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004725}
4726
4727/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304728 * __wlan_hdd_cfg80211_dump_station() - dump station statistics
4729 * @wiphy: Pointer to wiphy
4730 * @dev: Pointer to network device
4731 * @idx: variable to determine whether to get stats or not
4732 * @mac: Pointer to mac
4733 * @sinfo: Pointer to station info
4734 *
4735 * Return: 0 for success, non-zero for failure
4736 */
4737static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4738 struct net_device *dev,
4739 int idx, u8 *mac,
4740 struct station_info *sinfo)
4741{
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304742 hdd_debug("%s: idx %d", __func__, idx);
4743 if (idx != 0)
4744 return -ENOENT;
Ashish Kumar Dhanotiyafa55c182019-06-03 19:14:55 +05304745 qdf_mem_copy(mac, dev->dev_addr, QDF_MAC_ADDR_SIZE);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304746 return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4747}
4748
4749/**
4750 * wlan_hdd_cfg80211_dump_station() - dump station statistics
4751 * @wiphy: Pointer to wiphy
4752 * @dev: Pointer to network device
4753 * @idx: variable to determine whether to get stats or not
4754 * @mac: Pointer to mac
4755 * @sinfo: Pointer to station info
4756 *
4757 * Return: 0 for success, non-zero for failure
4758 */
4759int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4760 struct net_device *dev,
4761 int idx, u8 *mac,
4762 struct station_info *sinfo)
4763{
Dustin Brown1d31b082018-11-22 14:41:20 +05304764 int errno;
4765 struct osif_vdev_sync *vdev_sync;
4766
4767 errno = osif_vdev_sync_op_start(dev, &vdev_sync);
4768 if (errno)
4769 return errno;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304770
Dustin Brown1d31b082018-11-22 14:41:20 +05304771 errno = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
Dustin Brown1d31b082018-11-22 14:41:20 +05304772
4773 osif_vdev_sync_op_stop(vdev_sync);
4774
4775 return errno;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304776}
4777
4778/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004779 * hdd_get_stats() - Function to retrieve interface statistics
4780 * @dev: pointer to network device
4781 *
4782 * This function is the ndo_get_stats method for all netdevs
4783 * registered with the kernel
4784 *
4785 * Return: pointer to net_device_stats structure
4786 */
4787struct net_device_stats *hdd_get_stats(struct net_device *dev)
4788{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07004789 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004790
Dustin Brownfdf17c12018-03-14 12:55:34 -07004791 hdd_enter_dev(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004792 return &adapter->stats;
4793}
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304794
4795
4796/*
4797 * time = cycle_count * cycle
4798 * cycle = 1 / clock_freq
4799 * Since the unit of clock_freq reported from
4800 * FW is MHZ, and we want to calculate time in
4801 * ms level, the result is
4802 * time = cycle / (clock_freq * 1000)
4803 */
4804#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
4805static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4806 struct scan_chan_info *chan_info,
4807 struct ieee80211_channel *channels)
4808{
4809 uint64_t clock_freq = chan_info->clock_freq * 1000;
4810
4811 if (channels->center_freq != (uint16_t)chan_info->freq)
4812 return false;
4813
4814 survey->channel = channels;
4815 survey->noise = chan_info->noise_floor;
4816 survey->filled = SURVEY_INFO_NOISE_DBM;
4817
4818 if (opfreq == chan_info->freq)
4819 survey->filled |= SURVEY_INFO_IN_USE;
4820
4821 if (clock_freq == 0)
4822 return true;
4823
Nirav Shaheb017be2018-02-15 11:20:58 +05304824 survey->time = qdf_do_div(chan_info->cycle_count, clock_freq);
4825
4826 survey->time_busy = qdf_do_div(chan_info->rx_clear_count, clock_freq);
4827
4828 survey->time_tx = qdf_do_div(chan_info->tx_frame_count, clock_freq);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304829
4830 survey->filled |= SURVEY_INFO_TIME |
4831 SURVEY_INFO_TIME_BUSY |
4832 SURVEY_INFO_TIME_TX;
4833 return true;
4834}
4835#else
4836static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4837 struct scan_chan_info *chan_info,
4838 struct ieee80211_channel *channels)
4839{
4840 uint64_t clock_freq = chan_info->clock_freq * 1000;
4841
4842 if (channels->center_freq != (uint16_t)chan_info->freq)
4843 return false;
4844
4845 survey->channel = channels;
4846 survey->noise = chan_info->noise_floor;
4847 survey->filled = SURVEY_INFO_NOISE_DBM;
4848
4849 if (opfreq == chan_info->freq)
4850 survey->filled |= SURVEY_INFO_IN_USE;
4851
4852 if (clock_freq == 0)
4853 return true;
4854
Nirav Shaheb017be2018-02-15 11:20:58 +05304855 survey->channel_time = qdf_do_div(chan_info->cycle_count, clock_freq);
4856
4857 survey->channel_time_busy = qdf_do_div(chan_info->rx_clear_count,
4858 clock_freq);
4859
4860 survey->channel_time_tx = qdf_do_div(chan_info->tx_frame_count,
4861 clock_freq);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304862
4863 survey->filled |= SURVEY_INFO_CHANNEL_TIME |
4864 SURVEY_INFO_CHANNEL_TIME_BUSY |
4865 SURVEY_INFO_CHANNEL_TIME_TX;
4866 return true;
4867}
4868#endif
4869
4870static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
Jeff Johnson32bd9742018-03-29 13:42:31 -07004871 struct hdd_adapter *adapter,
4872 struct survey_info *survey, int idx)
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304873{
4874 bool filled = false;
4875 int i, j = 0;
4876 uint32_t channel = 0, opfreq; /* Initialization Required */
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004877 struct hdd_context *hdd_ctx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304878
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004879 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson003f7392018-06-12 20:45:47 -07004880 sme_get_operation_channel(hdd_ctx->mac_handle, &channel,
Jeff Johnson1abc5662019-02-04 14:27:02 -08004881 adapter->vdev_id);
Dustin Brown07901ec2018-09-07 11:02:41 -07004882 opfreq = wlan_reg_chan_to_freq(hdd_ctx->pdev, channel);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304883
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004884 mutex_lock(&hdd_ctx->chan_info_lock);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304885
Srinivas Girigowda5da651b2017-08-04 11:22:54 -07004886 for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) {
Jeff Johnsond36fa332019-03-18 13:42:25 -07004887 if (!wiphy->bands[i])
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304888 continue;
4889
4890 for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
4891 struct ieee80211_supported_band *band = wiphy->bands[i];
Jeff Johnson4f7f7c62017-10-05 08:53:41 -07004892
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304893 filled = wlan_fill_survey_result(survey, opfreq,
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004894 &hdd_ctx->chan_info[idx],
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304895 &band->channels[j]);
4896 }
4897 }
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004898 mutex_unlock(&hdd_ctx->chan_info_lock);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304899
4900 return filled;
4901}
4902
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004903/**
4904 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
4905 * @wiphy: Pointer to wiphy
4906 * @dev: Pointer to network device
4907 * @idx: Index
4908 * @survey: Pointer to survey info
4909 *
4910 * Return: 0 for success, non-zero for failure
4911 */
4912static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4913 struct net_device *dev,
4914 int idx, struct survey_info *survey)
4915{
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004916 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004917 struct hdd_context *hdd_ctx;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004918 struct hdd_station_ctx *sta_ctx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304919 int status;
4920 bool filled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004921
Dustin Brownfdf17c12018-03-14 12:55:34 -07004922 hdd_enter_dev(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004923
Srinivas Girigowda6598eea2017-07-06 19:26:19 -07004924 hdd_debug("dump survey index: %d", idx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304925 if (idx > QDF_MAX_NUM_CHAN - 1)
4926 return -EINVAL;
4927
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004928 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004929 status = wlan_hdd_validate_context(hdd_ctx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304930 if (0 != status)
4931 return status;
4932
Jeff Johnsond36fa332019-03-18 13:42:25 -07004933 if (!hdd_ctx->chan_info) {
Tushnim Bhattacharyya929afa42018-06-01 15:04:44 -07004934 hdd_debug("chan_info is NULL");
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304935 return -EINVAL;
4936 }
4937
4938 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004939 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004940 return -EINVAL;
4941 }
4942
Jeff Johnsond377dce2017-10-04 10:32:42 -07004943 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004944
Jeff Johnsona8fef4e2019-03-11 14:38:49 -07004945 if (!hdd_ctx->config->enable_snr_monitoring)
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304946 return -ENONET;
4947
Jeff Johnson690fe952017-10-25 11:48:39 -07004948 if (sta_ctx->hdd_reassoc_scenario) {
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304949 hdd_info("Roaming in progress, hence return");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004950 return -ENONET;
4951 }
4952
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004953 filled = wlan_hdd_update_survey_info(wiphy, adapter, survey, idx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304954
4955 if (!filled)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004956 return -ENONET;
Dustin Browne74003f2018-03-14 12:51:58 -07004957 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004958 return 0;
4959}
4960
4961/**
4962 * wlan_hdd_cfg80211_dump_survey() - get survey related info
4963 * @wiphy: Pointer to wiphy
4964 * @dev: Pointer to network device
4965 * @idx: Index
4966 * @survey: Pointer to survey info
4967 *
4968 * Return: 0 for success, non-zero for failure
4969 */
4970int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4971 struct net_device *dev,
4972 int idx, struct survey_info *survey)
4973{
Dustin Brown1d31b082018-11-22 14:41:20 +05304974 int errno;
4975 struct osif_vdev_sync *vdev_sync;
4976
4977 errno = osif_vdev_sync_op_start(dev, &vdev_sync);
4978 if (errno)
4979 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004980
Dustin Brown1d31b082018-11-22 14:41:20 +05304981 errno = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004982
Dustin Brown1d31b082018-11-22 14:41:20 +05304983 osif_vdev_sync_op_stop(vdev_sync);
4984
4985 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004986}
Nirav Shahbf1b0332016-05-25 14:27:39 +05304987
4988/**
4989 * hdd_display_hif_stats() - display hif stats
4990 *
4991 * Return: none
4992 *
4993 */
4994void hdd_display_hif_stats(void)
4995{
4996 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
4997
4998 if (!hif_ctx)
4999 return;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -07005000
Nirav Shahbf1b0332016-05-25 14:27:39 +05305001 hif_display_stats(hif_ctx);
5002}
5003
5004/**
5005 * hdd_clear_hif_stats() - clear hif stats
5006 *
5007 * Return: none
5008 */
5009void hdd_clear_hif_stats(void)
5010{
5011 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
5012
5013 if (!hif_ctx)
5014 return;
5015 hif_clear_stats(hif_ctx);
5016}
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305017
5018/**
5019 * hdd_is_rcpi_applicable() - validates RCPI request
5020 * @adapter: adapter upon which the measurement is requested
5021 * @mac_addr: peer addr for which measurement is requested
5022 * @rcpi_value: pointer to where the RCPI should be returned
5023 * @reassoc: used to return cached RCPI during reassoc
5024 *
5025 * Return: true for success, false for failure
5026 */
5027
5028static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter,
5029 struct qdf_mac_addr *mac_addr,
5030 int32_t *rcpi_value,
5031 bool *reassoc)
5032{
5033 struct hdd_station_ctx *hdd_sta_ctx;
5034
5035 if (adapter->device_mode == QDF_STA_MODE ||
5036 adapter->device_mode == QDF_P2P_CLIENT_MODE) {
5037 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsone7951512019-02-27 10:02:51 -08005038 if (hdd_sta_ctx->conn_info.conn_state !=
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305039 eConnectionState_Associated)
5040 return false;
5041
5042 if (hdd_sta_ctx->hdd_reassoc_scenario) {
5043 /* return the cached rcpi, if mac addr matches */
5044 hdd_debug("Roaming in progress, return cached RCPI");
5045 if (!qdf_mem_cmp(&adapter->rcpi.mac_addr,
5046 mac_addr, sizeof(*mac_addr))) {
5047 *rcpi_value = adapter->rcpi.rcpi;
5048 *reassoc = true;
5049 return true;
5050 }
5051 return false;
5052 }
5053
Jeff Johnsone04b6992019-02-27 14:06:55 -08005054 if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssid,
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305055 sizeof(*mac_addr))) {
5056 hdd_err("mac addr is different from bssid connected");
5057 return false;
5058 }
5059 } else if (adapter->device_mode == QDF_SAP_MODE ||
5060 adapter->device_mode == QDF_P2P_GO_MODE) {
5061 if (!test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) {
5062 hdd_err("Invalid rcpi request, softap not started");
5063 return false;
5064 }
5065
5066 /* check if peer mac addr is associated to softap */
5067 if (!hdd_is_peer_associated(adapter, mac_addr)) {
5068 hdd_err("invalid peer mac-addr: not associated");
5069 return false;
5070 }
5071 } else {
5072 hdd_err("Invalid rcpi request");
5073 return false;
5074 }
5075
5076 *reassoc = false;
5077 return true;
5078}
5079
5080/**
5081 * wlan_hdd_get_rcpi_cb() - callback function for rcpi response
5082 * @context: Pointer to rcpi context
5083 * @rcpi_req: Pointer to rcpi response
5084 *
5085 * Return: None
5086 */
5087static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr,
5088 int32_t rcpi, QDF_STATUS status)
5089{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005090 struct osif_request *request;
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305091 struct rcpi_info *priv;
5092
5093 if (!context) {
5094 hdd_err("No rcpi context");
5095 return;
5096 }
5097
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005098 request = osif_request_get(context);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305099 if (!request) {
5100 hdd_err("Obsolete RCPI request");
5101 return;
5102 }
5103
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005104 priv = osif_request_priv(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305105 priv->mac_addr = mac_addr;
5106
5107 if (!QDF_IS_STATUS_SUCCESS(status)) {
5108 priv->rcpi = 0;
5109 hdd_err("Error in computing RCPI");
5110 } else {
5111 priv->rcpi = rcpi;
5112 }
5113
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005114 osif_request_complete(request);
5115 osif_request_put(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305116}
5117
5118/**
Dustin Brown96b98dd2019-03-06 12:39:37 -08005119 * wlan_hdd_get_rcpi() - local function to get RCPI
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305120 * @adapter: adapter upon which the measurement is requested
5121 * @mac: peer addr for which measurement is requested
5122 * @rcpi_value: pointer to where the RCPI should be returned
5123 * @measurement_type: type of rcpi measurement
5124 *
5125 * Return: 0 for success, non-zero for failure
5126 */
Dustin Brown96b98dd2019-03-06 12:39:37 -08005127int wlan_hdd_get_rcpi(struct hdd_adapter *adapter,
5128 uint8_t *mac,
5129 int32_t *rcpi_value,
5130 enum rcpi_measurement_type measurement_type)
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305131{
5132 struct hdd_context *hdd_ctx;
5133 int status = 0, ret = 0;
5134 struct qdf_mac_addr mac_addr;
5135 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
5136 struct sme_rcpi_req *rcpi_req;
5137 void *cookie;
5138 struct rcpi_info *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005139 struct osif_request *request;
5140 static const struct osif_request_params params = {
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305141 .priv_size = sizeof(*priv),
5142 .timeout_ms = WLAN_WAIT_TIME_RCPI,
5143 };
5144 bool reassoc;
5145
Dustin Brown491d54b2018-03-14 12:39:11 -07005146 hdd_enter();
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305147
5148 /* initialize the rcpi value to zero, useful in error cases */
5149 *rcpi_value = 0;
5150
5151 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
5152 hdd_err("Command not allowed in FTM mode");
5153 return -EINVAL;
5154 }
5155
5156 if (!adapter) {
5157 hdd_warn("adapter context is NULL");
5158 return -EINVAL;
5159 }
5160
5161 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5162 status = wlan_hdd_validate_context(hdd_ctx);
5163 if (status)
5164 return -EINVAL;
5165
5166 if (!hdd_ctx->rcpi_enabled) {
5167 hdd_debug("RCPI not supported");
5168 return -EINVAL;
5169 }
5170
5171 if (!mac) {
5172 hdd_warn("RCPI peer mac-addr is NULL");
5173 return -EINVAL;
5174 }
5175
5176 qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE);
5177
5178 if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc))
5179 return -EINVAL;
5180 if (reassoc)
5181 return 0;
5182
5183 rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
Min Liu74a1a502018-10-10 19:59:07 +08005184 if (!rcpi_req)
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305185 return -EINVAL;
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305186
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005187 request = osif_request_alloc(&params);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305188 if (!request) {
5189 hdd_err("Request allocation failure");
5190 qdf_mem_free(rcpi_req);
5191 return -ENOMEM;
5192 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005193 cookie = osif_request_cookie(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305194
5195 rcpi_req->mac_addr = mac_addr;
Jeff Johnson1abc5662019-02-04 14:27:02 -08005196 rcpi_req->session_id = adapter->vdev_id;
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305197 rcpi_req->measurement_type = measurement_type;
5198 rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb;
5199 rcpi_req->rcpi_context = cookie;
5200
Jeff Johnson003f7392018-06-12 20:45:47 -07005201 qdf_status = sme_get_rcpi(hdd_ctx->mac_handle, rcpi_req);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305202 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
5203 hdd_err("Unable to retrieve RCPI");
5204 status = qdf_status_to_os_return(qdf_status);
5205 goto out;
5206 }
5207
5208 /* request was sent -- wait for the response */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005209 ret = osif_request_wait_for_response(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305210 if (ret) {
5211 hdd_err("SME timed out while retrieving RCPI");
5212 status = -EINVAL;
5213 goto out;
5214 }
5215
5216 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005217 priv = osif_request_priv(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305218 adapter->rcpi.mac_addr = priv->mac_addr;
5219 adapter->rcpi.rcpi = priv->rcpi;
5220 if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) {
5221 hdd_err("mis match of mac addr from call-back");
5222 status = -EINVAL;
5223 goto out;
5224 }
5225
5226 *rcpi_value = adapter->rcpi.rcpi;
5227 hdd_debug("RCPI = %d", *rcpi_value);
5228out:
5229 qdf_mem_free(rcpi_req);
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005230 osif_request_put(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305231
Dustin Browne74003f2018-03-14 12:51:58 -07005232 hdd_exit();
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305233 return status;
5234}
5235
Yu Wangc0b46f82018-03-09 16:04:15 +08005236QDF_STATUS wlan_hdd_get_rssi(struct hdd_adapter *adapter, int8_t *rssi_value)
5237{
Arif Hussain8b54a032018-08-03 14:37:01 -07005238 int ret = 0, i;
Yu Wangc0b46f82018-03-09 16:04:15 +08005239 struct hdd_station_ctx *sta_ctx;
Arif Hussain8b54a032018-08-03 14:37:01 -07005240 struct stats_event *rssi_info;
Yu Wangc0b46f82018-03-09 16:04:15 +08005241
Jeff Johnsond36fa332019-03-18 13:42:25 -07005242 if (!adapter) {
Yu Wangc0b46f82018-03-09 16:04:15 +08005243 hdd_err("Invalid context, adapter");
5244 return QDF_STATUS_E_FAULT;
5245 }
5246 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
5247 hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
5248 cds_get_driver_state());
5249 /* return a cached value */
5250 *rssi_value = adapter->rssi;
5251 return QDF_STATUS_SUCCESS;
5252 }
5253
5254 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5255
Jeff Johnsone7951512019-02-27 10:02:51 -08005256 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Yu Wangc0b46f82018-03-09 16:04:15 +08005257 hdd_debug("Not associated!, rssi on disconnect %d",
5258 adapter->rssi_on_disconnect);
5259 *rssi_value = adapter->rssi_on_disconnect;
5260 return QDF_STATUS_SUCCESS;
5261 }
5262
5263 if (sta_ctx->hdd_reassoc_scenario) {
5264 hdd_debug("Roaming in progress, return cached RSSI");
5265 *rssi_value = adapter->rssi;
5266 return QDF_STATUS_SUCCESS;
5267 }
5268
Arif Hussain8b54a032018-08-03 14:37:01 -07005269 rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi(
Dustin Brown89fa06e2018-09-07 10:47:27 -07005270 adapter->vdev,
Jeff Johnsone04b6992019-02-27 14:06:55 -08005271 sta_ctx->conn_info.bssid.bytes,
Arif Hussain8b54a032018-08-03 14:37:01 -07005272 &ret);
5273 if (ret || !rssi_info) {
5274 wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
Yu Wangc0b46f82018-03-09 16:04:15 +08005275 return ret;
5276 }
5277
Arif Hussain8b54a032018-08-03 14:37:01 -07005278 for (i = 0; i < rssi_info->num_peer_stats; i++) {
5279 if (!qdf_mem_cmp(rssi_info->peer_stats[i].peer_macaddr,
Jeff Johnsone04b6992019-02-27 14:06:55 -08005280 sta_ctx->conn_info.bssid.bytes,
Srinivas Girigowdaa47b45f2019-02-27 12:29:02 -08005281 QDF_MAC_ADDR_SIZE)) {
Arif Hussain8b54a032018-08-03 14:37:01 -07005282 *rssi_value = rssi_info->peer_stats[i].peer_rssi;
Yu Wangc0b46f82018-03-09 16:04:15 +08005283 hdd_debug("RSSI = %d", *rssi_value);
Arif Hussain8b54a032018-08-03 14:37:01 -07005284 wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
Yu Wangc0b46f82018-03-09 16:04:15 +08005285 return QDF_STATUS_SUCCESS;
5286 }
5287 }
5288
Arif Hussain8b54a032018-08-03 14:37:01 -07005289 wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
Yu Wangc0b46f82018-03-09 16:04:15 +08005290 hdd_err("bss peer not present in returned result");
5291 return QDF_STATUS_E_FAULT;
5292}
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005293
5294struct snr_priv {
5295 int8_t snr;
5296};
5297
5298/**
5299 * hdd_get_snr_cb() - "Get SNR" callback function
5300 * @snr: Current SNR of the station
5301 * @sta_id: ID of the station
5302 * @context: opaque context originally passed to SME. HDD always passes
5303 * a cookie for the request context
5304 *
5305 * Return: None
5306 */
Sourav Mohapatra05a52ed2019-08-06 16:07:05 +05305307static void hdd_get_snr_cb(int8_t snr, void *context)
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005308{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005309 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005310 struct snr_priv *priv;
5311
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005312 request = osif_request_get(context);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005313 if (!request) {
5314 hdd_err("Obsolete request");
5315 return;
5316 }
5317
5318 /* propagate response back to requesting thread */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005319 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005320 priv->snr = snr;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005321 osif_request_complete(request);
5322 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005323}
5324
5325QDF_STATUS wlan_hdd_get_snr(struct hdd_adapter *adapter, int8_t *snr)
5326{
5327 struct hdd_context *hdd_ctx;
5328 struct hdd_station_ctx *sta_ctx;
Jeff Johnson003f7392018-06-12 20:45:47 -07005329 QDF_STATUS status;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005330 int ret;
5331 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005332 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005333 struct snr_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005334 static const struct osif_request_params params = {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005335 .priv_size = sizeof(*priv),
5336 .timeout_ms = WLAN_WAIT_TIME_STATS,
5337 };
5338
5339 hdd_enter();
5340
Jeff Johnsond36fa332019-03-18 13:42:25 -07005341 if (!adapter) {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005342 hdd_err("Invalid context, adapter");
5343 return QDF_STATUS_E_FAULT;
5344 }
5345
5346 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5347
Jeff Johnson003f7392018-06-12 20:45:47 -07005348 ret = wlan_hdd_validate_context(hdd_ctx);
5349 if (ret)
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005350 return QDF_STATUS_E_FAULT;
5351
5352 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5353
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005354 request = osif_request_alloc(&params);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005355 if (!request) {
5356 hdd_err("Request allocation failure");
5357 return QDF_STATUS_E_FAULT;
5358 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005359 cookie = osif_request_cookie(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005360
Jeff Johnson003f7392018-06-12 20:45:47 -07005361 status = sme_get_snr(hdd_ctx->mac_handle, hdd_get_snr_cb,
Jeff Johnsone04b6992019-02-27 14:06:55 -08005362 sta_ctx->conn_info.bssid, cookie);
Jeff Johnson003f7392018-06-12 20:45:47 -07005363 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005364 hdd_err("Unable to retrieve RSSI");
5365 /* we'll returned a cached value below */
5366 } else {
5367 /* request was sent -- wait for the response */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005368 ret = osif_request_wait_for_response(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005369 if (ret) {
5370 hdd_err("SME timed out while retrieving SNR");
5371 /* we'll now returned a cached value below */
5372 } else {
5373 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005374 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005375 adapter->snr = priv->snr;
5376 }
5377 }
5378
5379 /*
5380 * either we never sent a request, we sent a request and
5381 * received a response or we sent a request and timed out.
5382 * regardless we are done with the request.
5383 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005384 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005385
5386 *snr = adapter->snr;
5387 hdd_exit();
5388 return QDF_STATUS_SUCCESS;
5389}
5390
5391struct linkspeed_priv {
Jeff Johnsone943bca2019-02-08 22:45:17 -08005392 struct link_speed_info linkspeed_info;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005393};
5394
5395static void
Jeff Johnsone943bca2019-02-08 22:45:17 -08005396hdd_get_link_speed_cb(struct link_speed_info *linkspeed_info, void *context)
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005397{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005398 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005399 struct linkspeed_priv *priv;
5400
5401 if (!linkspeed_info) {
5402 hdd_err("NULL linkspeed");
5403 return;
5404 }
5405
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005406 request = osif_request_get(context);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005407 if (!request) {
5408 hdd_err("Obsolete request");
5409 return;
5410 }
5411
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005412 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005413 priv->linkspeed_info = *linkspeed_info;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005414 osif_request_complete(request);
5415 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005416}
5417
5418int wlan_hdd_get_linkspeed_for_peermac(struct hdd_adapter *adapter,
5419 struct qdf_mac_addr *mac_address,
5420 uint32_t *linkspeed)
5421{
5422 int ret;
5423 QDF_STATUS status;
5424 void *cookie;
Jeff Johnsone943bca2019-02-08 22:45:17 -08005425 struct link_speed_info *linkspeed_info;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005426 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005427 struct linkspeed_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005428 static const struct osif_request_params params = {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005429 .priv_size = sizeof(*priv),
5430 .timeout_ms = WLAN_WAIT_TIME_STATS,
5431 };
5432
5433 if ((!adapter) || (!linkspeed)) {
5434 hdd_err("NULL argument");
5435 return -EINVAL;
5436 }
5437
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005438 request = osif_request_alloc(&params);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005439 if (!request) {
5440 hdd_err("Request allocation failure");
5441 ret = -ENOMEM;
5442 goto return_cached_value;
5443 }
5444
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005445 cookie = osif_request_cookie(request);
5446 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005447
5448 linkspeed_info = &priv->linkspeed_info;
5449 qdf_copy_macaddr(&linkspeed_info->peer_macaddr, mac_address);
Jeff Johnson003f7392018-06-12 20:45:47 -07005450 status = sme_get_link_speed(adapter->hdd_ctx->mac_handle,
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005451 linkspeed_info,
5452 cookie, hdd_get_link_speed_cb);
5453 if (QDF_IS_STATUS_ERROR(status)) {
5454 hdd_err("Unable to retrieve statistics for link speed");
5455 ret = qdf_status_to_os_return(status);
5456 goto cleanup;
5457 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005458 ret = osif_request_wait_for_response(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005459 if (ret) {
5460 hdd_err("SME timed out while retrieving link speed");
5461 goto cleanup;
5462 }
5463 adapter->estimated_linkspeed = linkspeed_info->estLinkSpeed;
5464
5465cleanup:
5466 /*
5467 * either we never sent a request, we sent a request and
5468 * received a response or we sent a request and timed out.
5469 * regardless we are done with the request.
5470 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005471 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005472
5473return_cached_value:
5474 *linkspeed = adapter->estimated_linkspeed;
5475
5476 return ret;
5477}
5478
5479int wlan_hdd_get_link_speed(struct hdd_adapter *adapter, uint32_t *link_speed)
5480{
5481 struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter);
5482 struct hdd_station_ctx *hdd_stactx =
5483 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5484 int ret;
5485
5486 ret = wlan_hdd_validate_context(hddctx);
5487 if (ret)
5488 return ret;
5489
5490 /* Linkspeed is allowed only for P2P mode */
5491 if (adapter->device_mode != QDF_P2P_CLIENT_MODE) {
5492 hdd_err("Link Speed is not allowed in Device mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005493 qdf_opmode_str(adapter->device_mode),
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005494 adapter->device_mode);
5495 return -ENOTSUPP;
5496 }
5497
Jeff Johnsone7951512019-02-27 10:02:51 -08005498 if (eConnectionState_Associated != hdd_stactx->conn_info.conn_state) {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005499 /* we are not connected so we don't have a classAstats */
5500 *link_speed = 0;
5501 } else {
5502 struct qdf_mac_addr bssid;
5503
Jeff Johnsone04b6992019-02-27 14:06:55 -08005504 qdf_copy_macaddr(&bssid, &hdd_stactx->conn_info.bssid);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005505
5506 ret = wlan_hdd_get_linkspeed_for_peermac(adapter, &bssid,
5507 link_speed);
5508 if (ret) {
5509 hdd_err("Unable to retrieve SME linkspeed");
5510 return ret;
5511 }
5512 /* linkspeed in units of 500 kbps */
5513 *link_speed = (*link_speed) / 500;
5514 }
5515 return 0;
5516}
5517
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005518struct peer_info_priv {
5519 struct sir_peer_sta_ext_info peer_sta_ext_info;
5520};
5521
5522/**
5523 * wlan_hdd_get_peer_info_cb() - get peer info callback
5524 * @sta_info: pointer of peer information
5525 * @context: get peer info callback context
5526 *
5527 * This function will fill stats info to peer info priv
5528 *
5529 */
5530static void wlan_hdd_get_peer_info_cb(struct sir_peer_info_ext_resp *sta_info,
5531 void *context)
5532{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005533 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005534 struct peer_info_priv *priv;
5535 uint8_t sta_num;
5536
5537 if ((!sta_info) || (!context)) {
5538 hdd_err("Bad param, sta_info [%pK] context [%pK]",
5539 sta_info, context);
5540 return;
5541 }
5542
5543 if (!sta_info->count) {
5544 hdd_err("Fail to get remote peer info");
5545 return;
5546 }
5547
5548 if (sta_info->count > MAX_PEER_STA) {
5549 hdd_warn("Exceed max peer number %d", sta_info->count);
5550 sta_num = MAX_PEER_STA;
5551 } else {
5552 sta_num = sta_info->count;
5553 }
5554
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005555 request = osif_request_get(context);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005556 if (!request) {
5557 hdd_err("Obsolete request");
5558 return;
5559 }
5560
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005561 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005562
5563 priv->peer_sta_ext_info.sta_num = sta_num;
5564 qdf_mem_copy(&priv->peer_sta_ext_info.info,
5565 sta_info->info,
5566 sta_num * sizeof(sta_info->info[0]));
5567
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005568 osif_request_complete(request);
5569 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005570}
5571
5572int wlan_hdd_get_peer_info(struct hdd_adapter *adapter,
5573 struct qdf_mac_addr macaddress,
5574 struct sir_peer_info_ext *peer_info_ext)
5575{
5576 QDF_STATUS status;
5577 void *cookie;
5578 int ret;
5579 struct sir_peer_info_ext_req peer_info_req;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005580 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005581 struct peer_info_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005582 static const struct osif_request_params params = {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005583 .priv_size = sizeof(*priv),
5584 .timeout_ms = WLAN_WAIT_TIME_STATS,
5585 };
5586
5587 if (!adapter) {
5588 hdd_err("adapter is NULL");
5589 return -EFAULT;
5590 }
5591
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005592 request = osif_request_alloc(&params);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005593 if (!request) {
5594 hdd_err("Request allocation failure");
5595 return -ENOMEM;
5596 }
5597
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005598 cookie = osif_request_cookie(request);
5599 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005600
5601 qdf_mem_copy(&peer_info_req.peer_macaddr, &macaddress,
5602 QDF_MAC_ADDR_SIZE);
Jeff Johnson1abc5662019-02-04 14:27:02 -08005603 peer_info_req.sessionid = adapter->vdev_id;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005604 peer_info_req.reset_after_request = 0;
Jeff Johnson003f7392018-06-12 20:45:47 -07005605 status = sme_get_peer_info_ext(adapter->hdd_ctx->mac_handle,
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005606 &peer_info_req,
5607 cookie,
5608 wlan_hdd_get_peer_info_cb);
5609 if (status != QDF_STATUS_SUCCESS) {
5610 hdd_err("Unable to retrieve statistics for peer info");
5611 ret = -EFAULT;
5612 } else {
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005613 ret = osif_request_wait_for_response(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005614 if (ret) {
5615 hdd_err("SME timed out while retrieving peer info");
5616 ret = -EFAULT;
5617 } else {
5618 /* only support one peer by now */
5619 *peer_info_ext = priv->peer_sta_ext_info.info[0];
5620 ret = 0;
5621 }
5622 }
5623
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005624 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005625
5626 return ret;
5627}
5628
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005629int wlan_hdd_get_station_stats(struct hdd_adapter *adapter)
5630{
Arif Hussain8b54a032018-08-03 14:37:01 -07005631 int ret = 0;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005632 uint8_t mcs_rate_flags;
Arif Hussain8b54a032018-08-03 14:37:01 -07005633 struct stats_event *stats;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005634
Dustin Brown89fa06e2018-09-07 10:47:27 -07005635 stats = wlan_cfg80211_mc_cp_stats_get_station_stats(adapter->vdev,
Arif Hussain8b54a032018-08-03 14:37:01 -07005636 &ret);
5637 if (ret || !stats) {
5638 wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
5639 return ret;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005640 }
5641
5642 /* save summary stats to legacy location */
5643 qdf_mem_copy(adapter->hdd_stats.summary_stat.retry_cnt,
Arif Hussain8b54a032018-08-03 14:37:01 -07005644 stats->vdev_summary_stats[0].stats.retry_cnt,
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005645 sizeof(adapter->hdd_stats.summary_stat.retry_cnt));
5646 qdf_mem_copy(adapter->hdd_stats.summary_stat.multiple_retry_cnt,
Arif Hussain8b54a032018-08-03 14:37:01 -07005647 stats->vdev_summary_stats[0].stats.multiple_retry_cnt,
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005648 sizeof(adapter->hdd_stats.summary_stat.multiple_retry_cnt));
5649 qdf_mem_copy(adapter->hdd_stats.summary_stat.tx_frm_cnt,
Arif Hussain8b54a032018-08-03 14:37:01 -07005650 stats->vdev_summary_stats[0].stats.tx_frm_cnt,
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005651 sizeof(adapter->hdd_stats.summary_stat.tx_frm_cnt));
5652 qdf_mem_copy(adapter->hdd_stats.summary_stat.fail_cnt,
Arif Hussain8b54a032018-08-03 14:37:01 -07005653 stats->vdev_summary_stats[0].stats.fail_cnt,
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005654 sizeof(adapter->hdd_stats.summary_stat.fail_cnt));
5655 adapter->hdd_stats.summary_stat.snr =
Arif Hussain8b54a032018-08-03 14:37:01 -07005656 stats->vdev_summary_stats[0].stats.snr;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005657 adapter->hdd_stats.summary_stat.rssi =
Arif Hussain8b54a032018-08-03 14:37:01 -07005658 stats->vdev_summary_stats[0].stats.rssi;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005659 adapter->hdd_stats.summary_stat.rx_frm_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005660 stats->vdev_summary_stats[0].stats.rx_frm_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005661 adapter->hdd_stats.summary_stat.frm_dup_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005662 stats->vdev_summary_stats[0].stats.frm_dup_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005663 adapter->hdd_stats.summary_stat.rts_fail_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005664 stats->vdev_summary_stats[0].stats.rts_fail_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005665 adapter->hdd_stats.summary_stat.ack_fail_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005666 stats->vdev_summary_stats[0].stats.ack_fail_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005667 adapter->hdd_stats.summary_stat.rts_succ_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005668 stats->vdev_summary_stats[0].stats.rts_succ_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005669 adapter->hdd_stats.summary_stat.rx_discard_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005670 stats->vdev_summary_stats[0].stats.rx_discard_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005671 adapter->hdd_stats.summary_stat.rx_error_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005672 stats->vdev_summary_stats[0].stats.rx_error_cnt;
Sourav Mohapatra9c398f02018-09-03 11:10:37 +05305673 adapter->hdd_stats.peer_stats.rx_count =
5674 stats->peer_adv_stats->rx_count;
5675 adapter->hdd_stats.peer_stats.rx_bytes =
5676 stats->peer_adv_stats->rx_bytes;
5677 adapter->hdd_stats.peer_stats.fcs_count =
5678 stats->peer_adv_stats->fcs_count;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005679
5680 /* save class a stats to legacy location */
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05305681 adapter->hdd_stats.class_a_stat.tx_nss =
Dustin Brown89fa06e2018-09-07 10:47:27 -07005682 wlan_vdev_mlme_get_nss(adapter->vdev);
Sourav Mohapatraa3da1c42018-12-13 12:20:26 +05305683 adapter->hdd_stats.class_a_stat.rx_nss =
5684 wlan_vdev_mlme_get_nss(adapter->vdev);
Arif Hussain8b54a032018-08-03 14:37:01 -07005685 adapter->hdd_stats.class_a_stat.tx_rate = stats->tx_rate;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05305686 adapter->hdd_stats.class_a_stat.rx_rate = stats->rx_rate;
5687 adapter->hdd_stats.class_a_stat.tx_rx_rate_flags = stats->tx_rate_flags;
5688 adapter->hdd_stats.class_a_stat.tx_mcs_index =
Sourav Mohapatrad204a812019-01-09 09:45:08 +05305689 sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags,
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05305690 &adapter->hdd_stats.class_a_stat.tx_nss,
Arif Hussain8b54a032018-08-03 14:37:01 -07005691 &mcs_rate_flags);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05305692 adapter->hdd_stats.class_a_stat.tx_mcs_rate_flags = mcs_rate_flags;
5693 adapter->hdd_stats.class_a_stat.rx_mcs_index =
Sourav Mohapatrad204a812019-01-09 09:45:08 +05305694 sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags,
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05305695 &adapter->hdd_stats.class_a_stat.rx_nss,
5696 &mcs_rate_flags);
5697 adapter->hdd_stats.class_a_stat.rx_mcs_rate_flags = mcs_rate_flags;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005698
5699 /* save per chain rssi to legacy location */
5700 qdf_mem_copy(adapter->hdd_stats.per_chain_rssi_stats.rssi,
Arif Hussain8b54a032018-08-03 14:37:01 -07005701 stats->vdev_chain_rssi[0].chain_rssi,
5702 sizeof(stats->vdev_chain_rssi[0].chain_rssi));
5703 wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005704
Arif Hussain8b54a032018-08-03 14:37:01 -07005705 return 0;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005706}
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005707
5708struct temperature_priv {
5709 int temperature;
5710};
5711
5712/**
5713 * hdd_get_temperature_cb() - "Get Temperature" callback function
5714 * @temperature: measured temperature
5715 * @context: callback context
5716 *
5717 * This function is passed to sme_get_temperature() as the callback
5718 * function to be invoked when the temperature measurement is
5719 * available.
5720 *
5721 * Return: None
5722 */
5723static void hdd_get_temperature_cb(int temperature, void *context)
5724{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005725 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005726 struct temperature_priv *priv;
5727
5728 hdd_enter();
5729
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005730 request = osif_request_get(context);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005731 if (!request) {
5732 hdd_err("Obsolete request");
5733 return;
5734 }
5735
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005736 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005737 priv->temperature = temperature;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005738 osif_request_complete(request);
5739 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005740 hdd_exit();
5741}
5742
5743int wlan_hdd_get_temperature(struct hdd_adapter *adapter, int *temperature)
5744{
5745 QDF_STATUS status;
5746 int ret;
5747 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005748 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005749 struct temperature_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005750 static const struct osif_request_params params = {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005751 .priv_size = sizeof(*priv),
5752 .timeout_ms = WLAN_WAIT_TIME_STATS,
5753 };
5754
5755 hdd_enter();
Jeff Johnsond36fa332019-03-18 13:42:25 -07005756 if (!adapter) {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005757 hdd_err("adapter is NULL");
5758 return -EPERM;
5759 }
5760
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005761 request = osif_request_alloc(&params);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005762 if (!request) {
5763 hdd_err("Request allocation failure");
5764 return -ENOMEM;
5765 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005766 cookie = osif_request_cookie(request);
Jeff Johnson003f7392018-06-12 20:45:47 -07005767 status = sme_get_temperature(adapter->hdd_ctx->mac_handle, cookie,
5768 hdd_get_temperature_cb);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005769 if (QDF_STATUS_SUCCESS != status) {
5770 hdd_err("Unable to retrieve temperature");
5771 } else {
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005772 ret = osif_request_wait_for_response(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005773 if (ret) {
5774 hdd_err("SME timed out while retrieving temperature");
5775 } else {
5776 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005777 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005778 if (priv->temperature)
5779 adapter->temperature = priv->temperature;
5780 }
5781 }
5782
5783 /*
5784 * either we never sent a request, we sent a request and
5785 * received a response or we sent a request and timed out.
5786 * regardless we are done with the request.
5787 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005788 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005789
5790 *temperature = adapter->temperature;
5791 hdd_exit();
5792 return 0;
5793}
Mohit Khanna70322002018-05-15 19:21:32 -07005794
Mohit Khanna81418772018-10-30 14:14:46 -07005795void wlan_hdd_display_txrx_stats(struct hdd_context *ctx)
Mohit Khanna70322002018-05-15 19:21:32 -07005796{
5797 struct hdd_adapter *adapter = NULL;
5798 struct hdd_tx_rx_stats *stats;
5799 int i = 0;
5800 uint32_t total_rx_pkt, total_rx_dropped,
5801 total_rx_delv, total_rx_refused;
5802
Mohit Khanna81418772018-10-30 14:14:46 -07005803 hdd_for_each_adapter(ctx, adapter) {
Mohit Khanna70322002018-05-15 19:21:32 -07005804 total_rx_pkt = 0;
5805 total_rx_dropped = 0;
5806 total_rx_delv = 0;
5807 total_rx_refused = 0;
5808 stats = &adapter->hdd_stats.tx_rx_stats;
Mohit Khannaf0620ce2019-07-28 21:31:05 -07005809
5810 if (adapter->vdev_id == INVAL_VDEV_ID)
5811 continue;
5812
Jeff Johnson1abc5662019-02-04 14:27:02 -08005813 hdd_debug("adapter: %u", adapter->vdev_id);
Mohit Khanna70322002018-05-15 19:21:32 -07005814 for (; i < NUM_CPUS; i++) {
5815 total_rx_pkt += stats->rx_packets[i];
5816 total_rx_dropped += stats->rx_dropped[i];
5817 total_rx_delv += stats->rx_delivered[i];
5818 total_rx_refused += stats->rx_refused[i];
5819 }
5820
Mohit Khanna81418772018-10-30 14:14:46 -07005821 hdd_debug("TX - called %u, dropped %u orphan %u",
Mohit Khannab8ccd6e2018-08-31 18:03:39 -07005822 stats->tx_called, stats->tx_dropped,
5823 stats->tx_orphaned);
Mohit Khanna70322002018-05-15 19:21:32 -07005824
5825 for (i = 0; i < NUM_CPUS; i++) {
5826 if (stats->rx_packets[i] == 0)
5827 continue;
Mohit Khannab8ccd6e2018-08-31 18:03:39 -07005828 hdd_debug("Rx CPU[%d]: packets %u, dropped %u, delivered %u, refused %u",
5829 i, stats->rx_packets[i], stats->rx_dropped[i],
5830 stats->rx_delivered[i], stats->rx_refused[i]);
Mohit Khanna70322002018-05-15 19:21:32 -07005831 }
Jinwei Chen0dc383e2019-08-23 00:43:04 +08005832 hdd_debug("RX - packets %u, dropped %u, unsolict_arp_n_mcast_drp %u, delivered %u, refused %u GRO - agg %u drop %u non-agg %u flush_skip %u low_tput_flush %u disabled(conc %u low-tput %u)",
Manjunathappa Prakashf39d2372019-02-25 18:18:57 -08005833 total_rx_pkt, total_rx_dropped,
5834 qdf_atomic_read(&stats->rx_usolict_arp_n_mcast_drp),
5835 total_rx_delv,
Mohit Khanna81418772018-10-30 14:14:46 -07005836 total_rx_refused, stats->rx_aggregated,
Manjunathappa Prakash78b6a882019-03-28 19:59:23 -07005837 stats->rx_gro_dropped, stats->rx_non_aggregated,
Jinwei Chenb681a482019-08-14 15:24:06 +08005838 stats->rx_gro_flush_skip,
Jinwei Chen0dc383e2019-08-23 00:43:04 +08005839 stats->rx_gro_low_tput_flush,
Mohit Khanna81418772018-10-30 14:14:46 -07005840 qdf_atomic_read(&ctx->disable_rx_ol_in_concurrency),
5841 qdf_atomic_read(&ctx->disable_rx_ol_in_low_tput));
Mohit Khanna70322002018-05-15 19:21:32 -07005842 }
5843}
Ashish Kumar Dhanotiya017e5022019-07-23 20:58:11 +05305844
Hangtian Zhucf89c862019-08-28 10:48:52 +08005845#ifdef QCA_SUPPORT_CP_STATS
Ashish Kumar Dhanotiya017e5022019-07-23 20:58:11 +05305846/**
5847 * hdd_lost_link_cp_stats_info_cb() - callback function to get lost
5848 * link information
5849 * @stats_ev: Stats event pointer
5850 * FW sends vdev stats on vdev down, this callback is registered
5851 * with cp_stats component to get the last available vdev stats
5852 * From the FW.
5853 *
5854 * Return: None
5855 */
5856
5857static void hdd_lost_link_cp_stats_info_cb(void *stats_ev)
5858{
5859 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
5860 struct hdd_adapter *adapter;
5861 struct stats_event *ev = stats_ev;
5862 uint8_t i;
5863 struct hdd_station_ctx *sta_ctx;
5864
5865 if (wlan_hdd_validate_context(hdd_ctx))
5866 return;
5867
5868 for (i = 0; i < ev->num_summary_stats; i++) {
5869 adapter = hdd_get_adapter_by_vdev(
5870 hdd_ctx,
5871 ev->vdev_summary_stats[i].vdev_id);
5872 if (!adapter) {
5873 hdd_debug("invalid adapter");
5874 continue;
5875 }
5876 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5877 if ((sta_ctx) &&
5878 (eConnectionState_Associated !=
5879 sta_ctx->conn_info.conn_state)) {
5880 adapter->rssi_on_disconnect =
5881 ev->vdev_summary_stats[i].stats.rssi;
5882 hdd_debug("rssi on disconnect %d for " QDF_MAC_ADDR_STR,
5883 adapter->rssi_on_disconnect,
5884 QDF_MAC_ADDR_ARRAY(adapter->mac_addr.bytes));
5885 }
5886 }
5887}
5888
5889void wlan_hdd_register_cp_stats_cb(struct hdd_context *hdd_ctx)
5890{
5891 ucfg_mc_cp_stats_register_lost_link_info_cb(
5892 hdd_ctx->psoc,
5893 hdd_lost_link_cp_stats_info_cb);
5894}
Hangtian Zhucf89c862019-08-28 10:48:52 +08005895#endif
Ashish Kumar Dhanotiya017e5022019-07-23 20:58:11 +05305896