blob: e753add4b3c3c52b9fab8dc77ba989364b0454f1 [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"
tinlin9abd17f2019-08-14 13:29:44 +080038#include "wlan_hdd_debugfs_mibstat.h"
Jeff Johnson32bd9742018-03-29 13:42:31 -070039#include "wlan_reg_services_api.h"
Yu Wangc0b46f82018-03-09 16:04:15 +080040#include <wlan_cfg80211_mc_cp_stats.h>
Ashish Kumar Dhanotiya017e5022019-07-23 20:58:11 +053041#include "wlan_cp_stats_mc_ucfg_api.h"
Abhinav Kumarb074f2f2018-09-15 15:32:11 +053042#include "wlan_mlme_ucfg_api.h"
43#include "wlan_mlme_ucfg_api.h"
Sourav Mohapatra43e6dea2019-08-18 11:39:23 +053044#include "wlan_hdd_sta_info.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080045
Naveen Rawat23183d62018-04-12 11:19:01 -070046#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
47#define HDD_INFO_SIGNAL STATION_INFO_SIGNAL
48#define HDD_INFO_SIGNAL_AVG STATION_INFO_SIGNAL_AVG
49#define HDD_INFO_TX_PACKETS STATION_INFO_TX_PACKETS
50#define HDD_INFO_TX_RETRIES STATION_INFO_TX_RETRIES
51#define HDD_INFO_TX_FAILED STATION_INFO_TX_FAILED
52#define HDD_INFO_TX_BITRATE STATION_INFO_TX_BITRATE
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +053053#define HDD_INFO_RX_BITRATE STATION_INFO_RX_BITRATE
Naveen Rawat23183d62018-04-12 11:19:01 -070054#define HDD_INFO_TX_BYTES STATION_INFO_TX_BYTES
55#define HDD_INFO_CHAIN_SIGNAL_AVG STATION_INFO_CHAIN_SIGNAL_AVG
56#define HDD_INFO_RX_BYTES STATION_INFO_RX_BYTES
57#define HDD_INFO_RX_PACKETS STATION_INFO_RX_PACKETS
58#define HDD_INFO_TX_BYTES64 0
59#define HDD_INFO_RX_BYTES64 0
60#define HDD_INFO_INACTIVE_TIME 0
61#define HDD_INFO_CONNECTED_TIME 0
Ashish Kumar Dhanotiya14923e62019-06-19 14:58:18 +053062#define HDD_INFO_RX_MPDUS 0
63#define HDD_INFO_FCS_ERROR_COUNT 0
Naveen Rawat23183d62018-04-12 11:19:01 -070064#else
65#define HDD_INFO_SIGNAL BIT(NL80211_STA_INFO_SIGNAL)
66#define HDD_INFO_SIGNAL_AVG BIT(NL80211_STA_INFO_SIGNAL_AVG)
67#define HDD_INFO_TX_PACKETS BIT(NL80211_STA_INFO_TX_PACKETS)
68#define HDD_INFO_TX_RETRIES BIT(NL80211_STA_INFO_TX_RETRIES)
69#define HDD_INFO_TX_FAILED BIT(NL80211_STA_INFO_TX_FAILED)
70#define HDD_INFO_TX_BITRATE BIT(NL80211_STA_INFO_TX_BITRATE)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +053071#define HDD_INFO_RX_BITRATE BIT(NL80211_STA_INFO_RX_BITRATE)
Naveen Rawat23183d62018-04-12 11:19:01 -070072#define HDD_INFO_TX_BYTES BIT(NL80211_STA_INFO_TX_BYTES)
73#define HDD_INFO_CHAIN_SIGNAL_AVG BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
74#define HDD_INFO_RX_BYTES BIT(NL80211_STA_INFO_RX_BYTES)
75#define HDD_INFO_RX_PACKETS BIT(NL80211_STA_INFO_RX_PACKETS)
76#define HDD_INFO_TX_BYTES64 BIT(NL80211_STA_INFO_TX_BYTES64)
77#define HDD_INFO_RX_BYTES64 BIT(NL80211_STA_INFO_RX_BYTES64)
78#define HDD_INFO_INACTIVE_TIME BIT(NL80211_STA_INFO_INACTIVE_TIME)
79#define HDD_INFO_CONNECTED_TIME BIT(NL80211_STA_INFO_CONNECTED_TIME)
Ashish Kumar Dhanotiyab6f487b2019-07-04 11:20:37 +053080#define HDD_INFO_RX_MPDUS BIT_ULL(NL80211_STA_INFO_RX_MPDUS)
81#define HDD_INFO_FCS_ERROR_COUNT BIT_ULL(NL80211_STA_INFO_FCS_ERROR_COUNT)
Naveen Rawat23183d62018-04-12 11:19:01 -070082#endif /* kernel version less than 4.0.0 && no_backport */
83
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080084/* 11B, 11G Rate table include Basic rate and Extended rate
85 * The IDX field is the rate index
86 * The HI field is the rate when RSSI is strong or being ignored
87 * (in this case we report actual rate)
88 * The MID field is the rate when RSSI is moderate
89 * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
90 * The LO field is the rate when RSSI is low
91 * (in this case we don't report rates, actual current rate used)
92 */
Will Huang496b36c2017-07-11 16:38:50 +080093static const struct index_data_rate_type supported_data_rate[] = {
94 /* IDX HI HM LM LO (RSSI-based index */
95 {2, { 10, 10, 10, 0} },
96 {4, { 20, 20, 10, 0} },
97 {11, { 55, 20, 10, 0} },
98 {12, { 60, 55, 20, 0} },
99 {18, { 90, 55, 20, 0} },
100 {22, {110, 55, 20, 0} },
101 {24, {120, 90, 60, 0} },
102 {36, {180, 120, 60, 0} },
103 {44, {220, 180, 60, 0} },
104 {48, {240, 180, 90, 0} },
105 {66, {330, 180, 90, 0} },
106 {72, {360, 240, 90, 0} },
107 {96, {480, 240, 120, 0} },
108 {108, {540, 240, 120, 0} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800109};
110/* MCS Based rate table HT MCS parameters with Nss = 1 */
111static struct index_data_rate_type supported_mcs_rate_nss1[] = {
112/* MCS L20 L40 S20 S40 */
113 {0, {65, 135, 72, 150} },
114 {1, {130, 270, 144, 300} },
115 {2, {195, 405, 217, 450} },
116 {3, {260, 540, 289, 600} },
117 {4, {390, 810, 433, 900} },
118 {5, {520, 1080, 578, 1200} },
119 {6, {585, 1215, 650, 1350} },
120 {7, {650, 1350, 722, 1500} }
121};
122
123/* HT MCS parameters with Nss = 2 */
124static struct index_data_rate_type supported_mcs_rate_nss2[] = {
125/* MCS L20 L40 S20 S40 */
126 {0, {130, 270, 144, 300} },
127 {1, {260, 540, 289, 600} },
128 {2, {390, 810, 433, 900} },
129 {3, {520, 1080, 578, 1200} },
130 {4, {780, 1620, 867, 1800} },
131 {5, {1040, 2160, 1156, 2400} },
132 {6, {1170, 2430, 1300, 2700} },
133 {7, {1300, 2700, 1444, 3000} }
134};
135
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800136/* MCS Based VHT rate table MCS parameters with Nss = 1*/
137static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
138/* MCS L80 S80 L40 S40 L20 S40*/
139 {0, {293, 325}, {135, 150}, {65, 72} },
140 {1, {585, 650}, {270, 300}, {130, 144} },
141 {2, {878, 975}, {405, 450}, {195, 217} },
142 {3, {1170, 1300}, {540, 600}, {260, 289} },
143 {4, {1755, 1950}, {810, 900}, {390, 433} },
144 {5, {2340, 2600}, {1080, 1200}, {520, 578} },
145 {6, {2633, 2925}, {1215, 1350}, {585, 650} },
146 {7, {2925, 3250}, {1350, 1500}, {650, 722} },
147 {8, {3510, 3900}, {1620, 1800}, {780, 867} },
148 {9, {3900, 4333}, {1800, 2000}, {780, 867} }
149};
150
151/*MCS parameters with Nss = 2*/
152static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
153/* MCS L80 S80 L40 S40 L20 S40*/
154 {0, {585, 650}, {270, 300}, {130, 144} },
155 {1, {1170, 1300}, {540, 600}, {260, 289} },
156 {2, {1755, 1950}, {810, 900}, {390, 433} },
157 {3, {2340, 2600}, {1080, 1200}, {520, 578} },
158 {4, {3510, 3900}, {1620, 1800}, {780, 867} },
159 {5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
160 {6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
161 {7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
162 {8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
Sourav Mohapatra9a6d5e52019-10-17 09:48:01 +0530163 {9, {7800, 8667}, {3600, 4000}, {1730, 1920} }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165
Jingxiang Gef1d81592019-10-20 12:03:22 +0800166/*array index points to MCS and array value points respective rssi*/
167static int rssi_mcs_tbl[][12] = {
168/* MCS 0 1 2 3 4 5 6 7 8 9 10 11*/
169 {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57, -52, -48}, /* 20 */
170 {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54, -49, -45}, /* 40 */
171 {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51, -46, -42} /* 80 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800172};
173
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174#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
Will Huang136ca8d2019-12-05 13:12:07 +08003076 * @vdev_id: stats get from which vdev id
Dustin Brown0e4479e2017-07-14 14:47:39 -07003077 *
3078 * Return: None
3079 */
3080static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
Will Huang136ca8d2019-12-05 13:12:07 +08003081 struct station_info *info,
3082 uint8_t vdev_id)
Dustin Brown0e4479e2017-07-14 14:47:39 -07003083{
3084 int i;
Will Huang136ca8d2019-12-05 13:12:07 +08003085 struct cds_vdev_dp_stats dp_stats;
3086 uint32_t orig_cnt;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003087
3088 info->rx_packets = stats->rx_frm_cnt;
3089 info->tx_packets = 0;
3090 info->tx_retries = 0;
3091 info->tx_failed = 0;
3092
3093 for (i = 0; i < WIFI_MAX_AC; ++i) {
3094 info->tx_packets += stats->tx_frm_cnt[i];
3095 info->tx_retries += stats->multiple_retry_cnt[i];
3096 info->tx_failed += stats->fail_cnt[i];
3097 }
3098
Will Huang136ca8d2019-12-05 13:12:07 +08003099 if (cds_dp_get_vdev_stats(vdev_id, &dp_stats)) {
3100 orig_cnt = info->tx_retries;
3101 info->tx_retries = dp_stats.tx_retries;
3102 hdd_debug("vdev %d tx retries adjust from %d to %d",
3103 vdev_id, orig_cnt, info->tx_retries);
3104 }
3105
Naveen Rawat23183d62018-04-12 11:19:01 -07003106 info->filled |= HDD_INFO_TX_PACKETS |
3107 HDD_INFO_TX_RETRIES |
3108 HDD_INFO_TX_FAILED |
3109 HDD_INFO_RX_PACKETS;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003110}
3111
3112/**
3113 * wlan_hdd_get_sap_stats() - get aggregate SAP stats
3114 * @adapter: sap adapter to get stats for
3115 * @info: kernel station_info struct to populate
3116 *
3117 * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to
3118 * support "station dump" and "station get" for SAP vdevs, even though they
3119 * aren't technically stations.
3120 *
3121 * Return: errno
3122 */
3123static int
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003124wlan_hdd_get_sap_stats(struct hdd_adapter *adapter, struct station_info *info)
Dustin Brown0e4479e2017-07-14 14:47:39 -07003125{
Naveen Rawatfa2a1002018-05-17 16:06:37 -07003126 int ret;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003127
Naveen Rawatfa2a1002018-05-17 16:06:37 -07003128 ret = wlan_hdd_get_station_stats(adapter);
3129 if (ret) {
3130 hdd_err("Failed to get SAP stats; status:%d", ret);
3131 return ret;
Dustin Brown0e4479e2017-07-14 14:47:39 -07003132 }
3133
Will Huang136ca8d2019-12-05 13:12:07 +08003134 wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat,
3135 info,
3136 adapter->vdev_id);
Dustin Brown0e4479e2017-07-14 14:47:39 -07003137
3138 return 0;
3139}
3140
3141/**
Will Huang496b36c2017-07-11 16:38:50 +08003142 * hdd_get_max_rate_legacy() - get max rate for legacy mode
3143 * @stainfo: stainfo pointer
3144 * @rssidx: rssi index
3145 *
3146 * This function will get max rate for legacy mode
3147 *
3148 * Return: max rate on success, otherwise 0
3149 */
Jeff Johnson82155922017-09-30 16:54:14 -07003150static uint32_t hdd_get_max_rate_legacy(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003151 uint8_t rssidx)
3152{
3153 uint32_t maxrate = 0;
3154 /*Minimum max rate, 6Mbps*/
3155 int maxidx = 12;
3156 int i;
3157
3158 /* check supported rates */
3159 if (stainfo->max_supp_idx != 0xff &&
3160 maxidx < stainfo->max_supp_idx)
3161 maxidx = stainfo->max_supp_idx;
3162
3163 /* check extended rates */
3164 if (stainfo->max_ext_idx != 0xff &&
3165 maxidx < stainfo->max_ext_idx)
3166 maxidx = stainfo->max_ext_idx;
3167
Will Huangcc571d42019-04-01 11:49:21 +08003168 for (i = 0; i < QDF_ARRAY_SIZE(supported_data_rate); i++) {
Will Huang496b36c2017-07-11 16:38:50 +08003169 if (supported_data_rate[i].beacon_rate_index == maxidx)
3170 maxrate =
3171 supported_data_rate[i].supported_rate[rssidx];
3172 }
3173
3174 hdd_debug("maxrate %d", maxrate);
3175
3176 return maxrate;
3177}
3178
3179/**
3180 * hdd_get_max_rate_ht() - get max rate for ht mode
3181 * @stainfo: stainfo pointer
3182 * @stats: fw txrx status pointer
3183 * @rate_flags: rate flags
3184 * @nss: number of streams
3185 * @maxrate: returned max rate buffer pointer
3186 * @max_mcs_idx: max mcs idx
3187 * @report_max: report max rate or actual rate
3188 *
3189 * This function will get max rate for ht mode
3190 *
3191 * Return: None
3192 */
Jeff Johnson82155922017-09-30 16:54:14 -07003193static void hdd_get_max_rate_ht(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003194 struct hdd_fw_txrx_stats *stats,
3195 uint32_t rate_flags,
3196 uint8_t nss,
3197 uint32_t *maxrate,
3198 uint8_t *max_mcs_idx,
3199 bool report_max)
3200{
3201 struct index_data_rate_type *supported_mcs_rate;
3202 uint32_t tmprate;
3203 uint8_t flag = 0, mcsidx;
3204 int8_t rssi = stats->rssi;
3205 int mode;
3206 int i;
3207
Naveen Rawatea1564b2018-05-17 15:56:11 -07003208 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003209 mode = 1;
3210 else
3211 mode = 0;
3212
Naveen Rawatea1564b2018-05-17 15:56:11 -07003213 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003214 flag |= 1;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003215 if (rate_flags & TX_RATE_SGI)
Will Huang496b36c2017-07-11 16:38:50 +08003216 flag |= 2;
3217
3218 supported_mcs_rate = (struct index_data_rate_type *)
3219 ((nss == 1) ? &supported_mcs_rate_nss1 :
3220 &supported_mcs_rate_nss2);
3221
3222 if (stainfo->max_mcs_idx == 0xff) {
3223 hdd_err("invalid max_mcs_idx");
3224 /* report real mcs idx */
3225 mcsidx = stats->tx_rate.mcs;
3226 } else {
3227 mcsidx = stainfo->max_mcs_idx;
3228 }
3229
3230 if (!report_max) {
3231 for (i = 0; i < mcsidx; i++) {
3232 if (rssi <= rssi_mcs_tbl[mode][i]) {
3233 mcsidx = i;
3234 break;
3235 }
3236 }
3237 if (mcsidx < stats->tx_rate.mcs)
3238 mcsidx = stats->tx_rate.mcs;
3239 }
3240
3241 tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
3242
3243 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3244
3245 *maxrate = tmprate;
3246 *max_mcs_idx = mcsidx;
3247}
3248
3249/**
3250 * hdd_get_max_rate_vht() - get max rate for vht mode
3251 * @stainfo: stainfo pointer
3252 * @stats: fw txrx status pointer
3253 * @rate_flags: rate flags
3254 * @nss: number of streams
3255 * @maxrate: returned max rate buffer pointer
3256 * @max_mcs_idx: max mcs idx
3257 * @report_max: report max rate or actual rate
3258 *
3259 * This function will get max rate for vht mode
3260 *
3261 * Return: None
3262 */
Jeff Johnson82155922017-09-30 16:54:14 -07003263static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo,
Will Huang496b36c2017-07-11 16:38:50 +08003264 struct hdd_fw_txrx_stats *stats,
3265 uint32_t rate_flags,
3266 uint8_t nss,
3267 uint32_t *maxrate,
3268 uint8_t *max_mcs_idx,
3269 bool report_max)
3270{
3271 struct index_vht_data_rate_type *supported_vht_mcs_rate;
3272 uint32_t tmprate = 0;
3273 uint32_t vht_max_mcs;
3274 uint8_t flag = 0, mcsidx = INVALID_MCS_IDX;
3275 int8_t rssi = stats->rssi;
3276 int mode;
3277 int i;
3278
3279 supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
3280 ((nss == 1) ?
3281 &supported_vht_mcs_rate_nss1 :
3282 &supported_vht_mcs_rate_nss2);
3283
Naveen Rawatea1564b2018-05-17 15:56:11 -07003284 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003285 mode = 2;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003286 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003287 mode = 1;
3288 else
3289 mode = 0;
3290
3291 if (rate_flags &
Naveen Rawatea1564b2018-05-17 15:56:11 -07003292 (TX_RATE_VHT20 | TX_RATE_VHT40 | TX_RATE_VHT80)) {
Will Huang496b36c2017-07-11 16:38:50 +08003293 vht_max_mcs =
3294 (enum data_rate_11ac_max_mcs)
3295 (stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK);
Naveen Rawatea1564b2018-05-17 15:56:11 -07003296 if (rate_flags & TX_RATE_SGI)
Will Huang496b36c2017-07-11 16:38:50 +08003297 flag |= 1;
3298
3299 if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) {
3300 mcsidx = 7;
3301 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) {
3302 mcsidx = 8;
3303 } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) {
3304 /*
3305 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3306 * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6
3307 * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8
3308 */
Naveen Rawatea1564b2018-05-17 15:56:11 -07003309 if ((rate_flags & TX_RATE_VHT20) &&
Will Huang496b36c2017-07-11 16:38:50 +08003310 (nss != 3 && nss != 6))
3311 mcsidx = 8;
3312 else
3313 mcsidx = 9;
3314 } else {
3315 hdd_err("invalid vht_max_mcs");
3316 /* report real mcs idx */
3317 mcsidx = stats->tx_rate.mcs;
3318 }
3319
3320 if (!report_max) {
3321 for (i = 0; i <= mcsidx; i++) {
3322 if (rssi <= rssi_mcs_tbl[mode][i]) {
3323 mcsidx = i;
3324 break;
3325 }
3326 }
3327 if (mcsidx < stats->tx_rate.mcs)
3328 mcsidx = stats->tx_rate.mcs;
3329 }
3330
Naveen Rawatea1564b2018-05-17 15:56:11 -07003331 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003332 tmprate =
3333 supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag];
Naveen Rawatea1564b2018-05-17 15:56:11 -07003334 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003335 tmprate =
3336 supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag];
Naveen Rawatea1564b2018-05-17 15:56:11 -07003337 else if (rate_flags & TX_RATE_VHT20)
Will Huang496b36c2017-07-11 16:38:50 +08003338 tmprate =
3339 supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag];
3340 }
3341
3342 hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
3343
3344 *maxrate = tmprate;
3345 *max_mcs_idx = mcsidx;
3346}
3347
3348#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
3349/**
3350 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3351 * @stainfo: stainfo pointer
3352 * @rate_flags: HDD rate flags
3353 * @mcsidx: mcs index
3354 * @nss: number of streams
3355 * @vht: vht mode or not
3356 *
3357 * This function will fill ch width and mcs flags
3358 *
3359 * Return: None
3360 */
3361static void hdd_fill_bw_mcs(struct station_info *sinfo,
Jingxiang Gef1d81592019-10-20 12:03:22 +08003362 enum tx_rate_info rate_flags,
Will Huang496b36c2017-07-11 16:38:50 +08003363 uint8_t mcsidx,
3364 uint8_t nss,
3365 bool vht)
3366{
3367 if (vht) {
3368 sinfo->txrate.nss = nss;
3369 sinfo->txrate.mcs = mcsidx;
3370 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003371 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003372 sinfo->txrate.bw = RATE_INFO_BW_80;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003373 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003374 sinfo->txrate.bw = RATE_INFO_BW_40;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003375 else if (rate_flags & TX_RATE_VHT20)
Will Huang496b36c2017-07-11 16:38:50 +08003376 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3377 } else {
3378 sinfo->txrate.mcs = (nss - 1) << 3;
3379 sinfo->txrate.mcs |= mcsidx;
3380 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003381 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003382 sinfo->txrate.bw = RATE_INFO_BW_40;
3383 }
3384}
3385#else
3386/**
3387 * hdd_fill_bw_mcs() - fill ch width and mcs flags
3388 * @stainfo: stainfo pointer
3389 * @rate_flags: HDD rate flags
3390 * @mcsidx: mcs index
3391 * @nss: number of streams
3392 * @vht: vht mode or not
3393 *
3394 * This function will fill ch width and mcs flags
3395 *
3396 * Return: None
3397 */
3398static void hdd_fill_bw_mcs(struct station_info *sinfo,
Jingxiang Gef1d81592019-10-20 12:03:22 +08003399 enum tx_rate_info rate_flags,
Will Huang496b36c2017-07-11 16:38:50 +08003400 uint8_t mcsidx,
3401 uint8_t nss,
3402 bool vht)
3403{
3404 if (vht) {
3405 sinfo->txrate.nss = nss;
3406 sinfo->txrate.mcs = mcsidx;
3407 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003408 if (rate_flags & TX_RATE_VHT80)
Will Huang496b36c2017-07-11 16:38:50 +08003409 sinfo->txrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003410 else if (rate_flags & TX_RATE_VHT40)
Will Huang496b36c2017-07-11 16:38:50 +08003411 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003412 else if (rate_flags & TX_RATE_VHT20)
Will Huang496b36c2017-07-11 16:38:50 +08003413 sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
3414 } else {
3415 sinfo->txrate.mcs = (nss - 1) << 3;
3416 sinfo->txrate.mcs |= mcsidx;
3417 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003418 if (rate_flags & TX_RATE_HT40)
Will Huang496b36c2017-07-11 16:38:50 +08003419 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
3420 }
3421}
3422#endif
3423
3424/**
3425 * hdd_fill_bw_mcs_vht() - fill ch width and mcs flags for VHT mode
3426 * @stainfo: stainfo pointer
3427 * @rate_flags: HDD rate flags
3428 * @mcsidx: mcs index
3429 * @nss: number of streams
3430 *
3431 * This function will fill ch width and mcs flags for VHT mode
3432 *
3433 * Return: None
3434 */
3435static void hdd_fill_bw_mcs_vht(struct station_info *sinfo,
Jingxiang Gef1d81592019-10-20 12:03:22 +08003436 enum tx_rate_info rate_flags,
Will Huang496b36c2017-07-11 16:38:50 +08003437 uint8_t mcsidx,
3438 uint8_t nss)
3439{
3440 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, true);
3441}
3442
3443/**
3444 * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
3445 * @sinfo: station_info struct pointer
3446 * @rate_flags: HDD rate flags
3447 * @mcsidx: mcs index
3448 * @nss: number of streams
3449 * @maxrate: data rate (kbps)
3450 *
3451 * This function will fill rate info of sinfo struct
3452 *
3453 * Return: None
3454 */
3455static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
3456 uint32_t rate_flags,
3457 uint8_t mcsidx,
3458 uint8_t nss,
3459 uint32_t maxrate)
3460{
Naveen Rawatea1564b2018-05-17 15:56:11 -07003461 if (rate_flags & TX_RATE_LEGACY) {
Will Huang496b36c2017-07-11 16:38:50 +08003462 /* provide to the UI in units of 100kbps */
3463 sinfo->txrate.legacy = maxrate;
3464 } else {
3465 /* must be MCS */
3466 if (rate_flags &
Naveen Rawatea1564b2018-05-17 15:56:11 -07003467 (TX_RATE_VHT80 |
3468 TX_RATE_VHT40 |
3469 TX_RATE_VHT20))
Will Huang496b36c2017-07-11 16:38:50 +08003470 hdd_fill_bw_mcs_vht(sinfo, rate_flags, mcsidx, nss);
3471
Naveen Rawatea1564b2018-05-17 15:56:11 -07003472 if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40))
Will Huang496b36c2017-07-11 16:38:50 +08003473 hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, false);
3474
Naveen Rawatea1564b2018-05-17 15:56:11 -07003475 if (rate_flags & TX_RATE_SGI) {
Will Huang496b36c2017-07-11 16:38:50 +08003476 if (!(sinfo->txrate.flags & RATE_INFO_FLAGS_VHT_MCS))
3477 sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
3478 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3479 }
3480 }
3481
3482 hdd_info("flag %x mcs %d legacy %d nss %d",
3483 sinfo->txrate.flags,
3484 sinfo->txrate.mcs,
3485 sinfo->txrate.legacy,
3486 sinfo->txrate.nss);
3487}
3488
3489/**
3490 * hdd_fill_station_info_flags() - fill flags of sinfo struct
3491 * @sinfo: station_info struct pointer
3492 *
3493 * This function will fill flags of sinfo struct
3494 *
3495 * Return: None
3496 */
3497static void hdd_fill_station_info_flags(struct station_info *sinfo)
3498{
Naveen Rawat23183d62018-04-12 11:19:01 -07003499 sinfo->filled |= HDD_INFO_SIGNAL |
3500 HDD_INFO_TX_BYTES |
3501 HDD_INFO_TX_BYTES64 |
3502 HDD_INFO_TX_BITRATE |
3503 HDD_INFO_TX_PACKETS |
3504 HDD_INFO_TX_RETRIES |
3505 HDD_INFO_TX_FAILED |
3506 HDD_INFO_RX_BYTES |
3507 HDD_INFO_RX_BYTES64 |
3508 HDD_INFO_RX_PACKETS |
3509 HDD_INFO_INACTIVE_TIME |
3510 HDD_INFO_CONNECTED_TIME;
Will Huang496b36c2017-07-11 16:38:50 +08003511}
3512
3513/**
3514 * hdd_fill_rate_info() - fill rate info of sinfo
Arif Hussaincca60432018-12-03 19:45:12 -08003515 * @psoc: psoc context
Will Huang496b36c2017-07-11 16:38:50 +08003516 * @sinfo: station_info struct pointer
3517 * @stainfo: stainfo pointer
3518 * @stats: fw txrx status pointer
Will Huang496b36c2017-07-11 16:38:50 +08003519 *
3520 * This function will fill rate info of sinfo
3521 *
3522 * Return: None
3523 */
Arif Hussaincca60432018-12-03 19:45:12 -08003524static void hdd_fill_rate_info(struct wlan_objmgr_psoc *psoc,
3525 struct station_info *sinfo,
Jeff Johnson82155922017-09-30 16:54:14 -07003526 struct hdd_station_info *stainfo,
Arif Hussaincca60432018-12-03 19:45:12 -08003527 struct hdd_fw_txrx_stats *stats)
Will Huang496b36c2017-07-11 16:38:50 +08003528{
Jingxiang Gef1d81592019-10-20 12:03:22 +08003529 enum tx_rate_info rate_flags;
Will Huang496b36c2017-07-11 16:38:50 +08003530 uint8_t mcsidx = 0xff;
3531 uint32_t myrate, maxrate, tmprate;
3532 int rssidx;
3533 int nss = 1;
Arif Hussaincca60432018-12-03 19:45:12 -08003534 int link_speed_rssi_high = 0;
3535 int link_speed_rssi_mid = 0;
3536 int link_speed_rssi_low = 0;
3537 uint32_t link_speed_rssi_report = 0;
Will Huang496b36c2017-07-11 16:38:50 +08003538
Arif Hussaincca60432018-12-03 19:45:12 -08003539 ucfg_mlme_stats_get_cfg_values(psoc,
3540 &link_speed_rssi_high,
3541 &link_speed_rssi_mid,
3542 &link_speed_rssi_low,
3543 &link_speed_rssi_report);
Will Huang496b36c2017-07-11 16:38:50 +08003544
Arif Hussaincca60432018-12-03 19:45:12 -08003545 hdd_info("reportMaxLinkSpeed %d", link_speed_rssi_report);
Will Huang496b36c2017-07-11 16:38:50 +08003546 /* convert to 100kbps expected in rate table */
3547 myrate = stats->tx_rate.rate / 100;
3548 rate_flags = stainfo->rate_flags;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003549 if (!(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003550 nss = stainfo->nss;
Arif Hussaincca60432018-12-03 19:45:12 -08003551 if (ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
Will Huang496b36c2017-07-11 16:38:50 +08003552 /* Get current rate flags if report actual */
3553 if (stats->tx_rate.rate_flags)
3554 rate_flags =
3555 stats->tx_rate.rate_flags;
3556 nss = stats->tx_rate.nss;
3557 }
3558
3559 if (stats->tx_rate.mcs == INVALID_MCS_IDX)
Naveen Rawatea1564b2018-05-17 15:56:11 -07003560 rate_flags = TX_RATE_LEGACY;
Will Huang496b36c2017-07-11 16:38:50 +08003561 }
3562
Arif Hussaincca60432018-12-03 19:45:12 -08003563 if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
Will Huang496b36c2017-07-11 16:38:50 +08003564 /* we do not want to necessarily report the current speed */
Arif Hussaincca60432018-12-03 19:45:12 -08003565 if (ucfg_mlme_stats_is_link_speed_report_max(psoc)) {
Will Huang496b36c2017-07-11 16:38:50 +08003566 /* report the max possible speed */
3567 rssidx = 0;
Arif Hussaincca60432018-12-03 19:45:12 -08003568 } else if (ucfg_mlme_stats_is_link_speed_report_max_scaled(
3569 psoc)) {
Will Huang496b36c2017-07-11 16:38:50 +08003570 /* report the max possible speed with RSSI scaling */
Arif Hussaincca60432018-12-03 19:45:12 -08003571 if (stats->rssi >= link_speed_rssi_high) {
Will Huang496b36c2017-07-11 16:38:50 +08003572 /* report the max possible speed */
3573 rssidx = 0;
Arif Hussaincca60432018-12-03 19:45:12 -08003574 } else if (stats->rssi >= link_speed_rssi_mid) {
Will Huang496b36c2017-07-11 16:38:50 +08003575 /* report middle speed */
3576 rssidx = 1;
Arif Hussaincca60432018-12-03 19:45:12 -08003577 } else if (stats->rssi >= link_speed_rssi_low) {
Will Huang496b36c2017-07-11 16:38:50 +08003578 /* report middle speed */
3579 rssidx = 2;
3580 } else {
3581 /* report actual speed */
3582 rssidx = 3;
3583 }
3584 } else {
3585 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
3586 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
Arif Hussaincca60432018-12-03 19:45:12 -08003587 link_speed_rssi_report);
Will Huang496b36c2017-07-11 16:38:50 +08003588 rssidx = 0;
3589 }
3590
3591 maxrate = hdd_get_max_rate_legacy(stainfo, rssidx);
3592
3593 /*
3594 * Get MCS Rate Set --
3595 * Only if we are connected in non legacy mode and not
3596 * reporting actual speed
3597 */
3598 if ((rssidx != 3) &&
Naveen Rawatea1564b2018-05-17 15:56:11 -07003599 !(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003600 hdd_get_max_rate_vht(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;
3611
3612 if (mcsidx == INVALID_MCS_IDX)
3613 hdd_get_max_rate_ht(stainfo,
3614 stats,
3615 rate_flags,
3616 nss,
3617 &tmprate,
3618 &mcsidx,
3619 rssidx == 0);
3620
3621 if (maxrate < tmprate &&
3622 mcsidx != INVALID_MCS_IDX)
3623 maxrate = tmprate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003624 } else if (!(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003625 maxrate = myrate;
3626 mcsidx = stats->tx_rate.mcs;
3627 }
3628
3629 /*
3630 * make sure we report a value at least as big as our
3631 * current rate
3632 */
3633 if ((maxrate < myrate) || (maxrate == 0)) {
3634 maxrate = myrate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003635 if (!(rate_flags & TX_RATE_LEGACY)) {
Will Huang496b36c2017-07-11 16:38:50 +08003636 mcsidx = stats->tx_rate.mcs;
3637 /*
3638 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
3639 * - MCS9 is valid for VHT20 when Nss = 3 or
3640 * Nss = 6
3641 * - MCS9 is not valid for VHT20 when
3642 * Nss = 1,2,4,5,7,8
3643 */
Naveen Rawatea1564b2018-05-17 15:56:11 -07003644 if ((rate_flags & TX_RATE_VHT20) &&
Will Huang496b36c2017-07-11 16:38:50 +08003645 (mcsidx > 8) &&
3646 (nss != 3 && nss != 6))
3647 mcsidx = 8;
3648 }
3649 }
3650 } else {
3651 /* report current rate instead of max rate */
3652 maxrate = myrate;
Naveen Rawatea1564b2018-05-17 15:56:11 -07003653 if (!(rate_flags & TX_RATE_LEGACY))
Will Huang496b36c2017-07-11 16:38:50 +08003654 mcsidx = stats->tx_rate.mcs;
3655 }
3656
3657 hdd_fill_sinfo_rate_info(sinfo,
3658 rate_flags,
3659 mcsidx,
3660 nss,
3661 maxrate);
3662}
3663
3664/**
3665 * wlan_hdd_fill_station_info() - fill station_info struct
Arif Hussaincca60432018-12-03 19:45:12 -08003666 * @psoc: psoc context
Will Huang496b36c2017-07-11 16:38:50 +08003667 * @sinfo: station_info struct pointer
3668 * @stainfo: stainfo pointer
3669 * @stats: fw txrx status pointer
Will Huang496b36c2017-07-11 16:38:50 +08003670 *
3671 * This function will fill station_info struct
3672 *
3673 * Return: None
3674 */
Arif Hussaincca60432018-12-03 19:45:12 -08003675static void wlan_hdd_fill_station_info(struct wlan_objmgr_psoc *psoc,
3676 struct station_info *sinfo,
Jeff Johnson82155922017-09-30 16:54:14 -07003677 struct hdd_station_info *stainfo,
Arif Hussaincca60432018-12-03 19:45:12 -08003678 struct hdd_fw_txrx_stats *stats)
Will Huang496b36c2017-07-11 16:38:50 +08003679{
3680 qdf_time_t curr_time, dur;
3681
3682 curr_time = qdf_system_ticks();
3683 dur = curr_time - stainfo->assoc_ts;
3684 sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000;
3685 dur = curr_time - stainfo->last_tx_rx_ts;
3686 sinfo->inactive_time = qdf_system_ticks_to_msecs(dur);
3687 sinfo->signal = stats->rssi;
3688 sinfo->tx_bytes = stats->tx_bytes;
3689 sinfo->tx_packets = stats->tx_packets;
3690 sinfo->rx_bytes = stats->rx_bytes;
3691 sinfo->rx_packets = stats->rx_packets;
3692 sinfo->tx_failed = stats->tx_failed;
3693 sinfo->tx_retries = stats->tx_retries;
3694
3695 /* tx rate info */
Arif Hussaincca60432018-12-03 19:45:12 -08003696 hdd_fill_rate_info(psoc, sinfo, stainfo, stats);
Will Huang496b36c2017-07-11 16:38:50 +08003697
3698 hdd_fill_station_info_flags(sinfo);
3699
3700 /* dump sta info*/
3701 hdd_info("dump stainfo");
3702 hdd_info("con_time %d inact_time %d tx_pkts %d rx_pkts %d",
3703 sinfo->connected_time, sinfo->inactive_time,
3704 sinfo->tx_packets, sinfo->rx_packets);
3705 hdd_info("failed %d retries %d tx_bytes %lld rx_bytes %lld",
3706 sinfo->tx_failed, sinfo->tx_retries,
3707 sinfo->tx_bytes, sinfo->rx_bytes);
3708 hdd_info("rssi %d mcs %d legacy %d nss %d flags %x",
3709 sinfo->signal, sinfo->txrate.mcs,
3710 sinfo->txrate.legacy, sinfo->txrate.nss,
3711 sinfo->txrate.flags);
3712}
3713
3714/**
3715 * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs
3716 * @rate: Data rate (100 kbps)
3717 * @nss: Number of streams
3718 * @mcs: HT mcs index
3719 *
3720 * This function is used to construct HT rate flag with rate, nss and mcs
3721 *
3722 * Return: rate flags for success, 0 on failure.
3723 */
3724static uint8_t hdd_get_rate_flags_ht(uint32_t rate,
3725 uint8_t nss,
3726 uint8_t mcs)
3727{
3728 struct index_data_rate_type *mcs_rate;
3729 uint8_t flags = 0;
3730
3731 mcs_rate = (struct index_data_rate_type *)
3732 ((nss == 1) ? &supported_mcs_rate_nss1 :
3733 &supported_mcs_rate_nss2);
3734
3735 if (rate == mcs_rate[mcs].supported_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003736 flags |= TX_RATE_HT20;
Will Huang496b36c2017-07-11 16:38:50 +08003737 } else if (rate == mcs_rate[mcs].supported_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003738 flags |= TX_RATE_HT40;
Will Huang496b36c2017-07-11 16:38:50 +08003739 } else if (rate == mcs_rate[mcs].supported_rate[2]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003740 flags |= TX_RATE_HT20;
3741 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003742 } else if (rate == mcs_rate[mcs].supported_rate[3]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003743 flags |= TX_RATE_HT40;
3744 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003745 } else {
3746 hdd_err("invalid params rate %d nss %d mcs %d",
3747 rate, nss, mcs);
3748 }
3749
3750 return flags;
3751}
3752
3753/**
3754 * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs
3755 * @rate: Data rate (100 kbps)
3756 * @nss: Number of streams
3757 * @mcs: VHT mcs index
3758 *
3759 * This function is used to construct VHT rate flag with rate, nss and mcs
3760 *
3761 * Return: rate flags for success, 0 on failure.
3762 */
3763static uint8_t hdd_get_rate_flags_vht(uint32_t rate,
3764 uint8_t nss,
3765 uint8_t mcs)
3766{
3767 struct index_vht_data_rate_type *mcs_rate;
3768 uint8_t flags = 0;
3769
3770 mcs_rate = (struct index_vht_data_rate_type *)
3771 ((nss == 1) ?
3772 &supported_vht_mcs_rate_nss1 :
3773 &supported_vht_mcs_rate_nss2);
3774
3775 if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003776 flags |= TX_RATE_VHT80;
Will Huang496b36c2017-07-11 16:38:50 +08003777 } else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003778 flags |= TX_RATE_VHT80;
3779 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003780 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003781 flags |= TX_RATE_VHT40;
Will Huang496b36c2017-07-11 16:38:50 +08003782 } else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003783 flags |= TX_RATE_VHT40;
3784 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003785 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003786 flags |= TX_RATE_VHT20;
Will Huang496b36c2017-07-11 16:38:50 +08003787 } else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
Naveen Rawatea1564b2018-05-17 15:56:11 -07003788 flags |= TX_RATE_VHT20;
3789 flags |= TX_RATE_SGI;
Will Huang496b36c2017-07-11 16:38:50 +08003790 } else {
3791 hdd_err("invalid params rate %d nss %d mcs %d",
3792 rate, nss, mcs);
3793 }
3794
3795 return flags;
3796}
3797
3798/**
3799 * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs
3800 * @rate: Data rate (100 kbps)
3801 * @mode: Tx/Rx mode
3802 * @nss: Number of streams
3803 * @mcs: Mcs index
3804 *
3805 * This function is used to construct rate flag with rate, nss and mcs
3806 *
3807 * Return: rate flags for success, 0 on failure.
3808 */
3809static uint8_t hdd_get_rate_flags(uint32_t rate,
3810 uint8_t mode,
3811 uint8_t nss,
3812 uint8_t mcs)
3813{
3814 uint8_t flags = 0;
3815
3816 if (mode == SIR_SME_PHY_MODE_HT)
3817 flags = hdd_get_rate_flags_ht(rate, nss, mcs);
3818 else if (mode == SIR_SME_PHY_MODE_VHT)
3819 flags = hdd_get_rate_flags_vht(rate, nss, mcs);
3820 else
3821 hdd_err("invalid mode param %d", mode);
3822
3823 return flags;
3824}
3825
3826/**
3827 * wlan_hdd_fill_rate_info() - fill HDD rate info from SIR peer info
Will Huangb9cb1242019-04-02 14:52:17 +08003828 * @txrx_stats: pointer to txrx stats to be filled with rate info
Will Huang496b36c2017-07-11 16:38:50 +08003829 * @peer_info: SIR peer info pointer
3830 *
3831 * This function is used to fill HDD rate info rom SIR peer info
3832 *
3833 * Return: None
3834 */
Will Huangb9cb1242019-04-02 14:52:17 +08003835static void wlan_hdd_fill_rate_info(struct hdd_fw_txrx_stats *txrx_stats,
Will Huang496b36c2017-07-11 16:38:50 +08003836 struct sir_peer_info_ext *peer_info)
3837{
3838 uint8_t flags;
3839 uint32_t rate_code;
3840
3841 /* tx rate info */
Will Huangb9cb1242019-04-02 14:52:17 +08003842 txrx_stats->tx_rate.rate = peer_info->tx_rate;
Will Huang496b36c2017-07-11 16:38:50 +08003843 rate_code = peer_info->tx_rate_code;
3844
3845 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3846 WMI_RATE_PREAMBLE_HT)
Will Huangb9cb1242019-04-02 14:52:17 +08003847 txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_HT;
Will Huang496b36c2017-07-11 16:38:50 +08003848 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3849 WMI_RATE_PREAMBLE_VHT)
Will Huangb9cb1242019-04-02 14:52:17 +08003850 txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_VHT;
Will Huang496b36c2017-07-11 16:38:50 +08003851 else
Will Huangb9cb1242019-04-02 14:52:17 +08003852 txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
Will Huang496b36c2017-07-11 16:38:50 +08003853
Will Huangb9cb1242019-04-02 14:52:17 +08003854 txrx_stats->tx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3855 txrx_stats->tx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
Will Huang496b36c2017-07-11 16:38:50 +08003856
Will Huangb9cb1242019-04-02 14:52:17 +08003857 flags = hdd_get_rate_flags(txrx_stats->tx_rate.rate / 100,
3858 txrx_stats->tx_rate.mode,
3859 txrx_stats->tx_rate.nss,
3860 txrx_stats->tx_rate.mcs);
Will Huang496b36c2017-07-11 16:38:50 +08003861
Will Huangb9cb1242019-04-02 14:52:17 +08003862 txrx_stats->tx_rate.rate_flags = flags;
Will Huang496b36c2017-07-11 16:38:50 +08003863
3864 hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x",
Will Huangb9cb1242019-04-02 14:52:17 +08003865 txrx_stats->tx_rate.mode,
3866 txrx_stats->tx_rate.nss,
3867 txrx_stats->tx_rate.mcs,
3868 txrx_stats->tx_rate.rate_flags,
Will Huang496b36c2017-07-11 16:38:50 +08003869 flags);
3870
3871 /* rx rate info */
Will Huangb9cb1242019-04-02 14:52:17 +08003872 txrx_stats->rx_rate.rate = peer_info->rx_rate;
Will Huang496b36c2017-07-11 16:38:50 +08003873 rate_code = peer_info->rx_rate_code;
3874
3875 if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3876 WMI_RATE_PREAMBLE_HT)
Will Huangb9cb1242019-04-02 14:52:17 +08003877 txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_HT;
Will Huang496b36c2017-07-11 16:38:50 +08003878 else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
3879 WMI_RATE_PREAMBLE_VHT)
Will Huangb9cb1242019-04-02 14:52:17 +08003880 txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_VHT;
Will Huang496b36c2017-07-11 16:38:50 +08003881 else
Will Huangb9cb1242019-04-02 14:52:17 +08003882 txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
Will Huang496b36c2017-07-11 16:38:50 +08003883
Will Huangb9cb1242019-04-02 14:52:17 +08003884 txrx_stats->rx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
3885 txrx_stats->rx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
Will Huang496b36c2017-07-11 16:38:50 +08003886
Will Huangb9cb1242019-04-02 14:52:17 +08003887 flags = hdd_get_rate_flags(txrx_stats->rx_rate.rate / 100,
3888 txrx_stats->rx_rate.mode,
3889 txrx_stats->rx_rate.nss,
3890 txrx_stats->rx_rate.mcs);
Will Huang496b36c2017-07-11 16:38:50 +08003891
Will Huangb9cb1242019-04-02 14:52:17 +08003892 txrx_stats->rx_rate.rate_flags = flags;
Will Huang496b36c2017-07-11 16:38:50 +08003893
3894 hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x",
Will Huangb9cb1242019-04-02 14:52:17 +08003895 txrx_stats->rx_rate.mode,
3896 txrx_stats->rx_rate.nss,
3897 txrx_stats->rx_rate.mcs,
3898 txrx_stats->rx_rate.rate_flags,
Will Huang496b36c2017-07-11 16:38:50 +08003899 flags);
3900}
3901
Will Huang496b36c2017-07-11 16:38:50 +08003902/**
3903 * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
3904 * @wiphy: pointer to wiphy
3905 * @dev: pointer to net_device structure
3906 * @mac: request peer mac address
3907 * @sinfo: pointer to station_info struct
3908 *
3909 * This function will get remote peer info from fw and fill sinfo struct
3910 *
3911 * Return: 0 on success, otherwise error value
3912 */
Will Huangb9cb1242019-04-02 14:52:17 +08003913static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
3914 struct net_device *dev,
3915 const u8 *mac,
3916 struct station_info *sinfo)
Will Huang496b36c2017-07-11 16:38:50 +08003917{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07003918 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson5eb1e682017-08-28 11:42:15 -07003919 struct hdd_context *hddctx = wiphy_priv(wiphy);
Jeff Johnson82155922017-09-30 16:54:14 -07003920 struct hdd_station_info *stainfo = NULL;
Will Huang496b36c2017-07-11 16:38:50 +08003921 struct qdf_mac_addr macaddr;
3922 struct sir_peer_info_ext peer_info;
Will Huangb9cb1242019-04-02 14:52:17 +08003923 struct hdd_fw_txrx_stats txrx_stats;
Will Huang496b36c2017-07-11 16:38:50 +08003924 int status;
Will Huang496b36c2017-07-11 16:38:50 +08003925
3926 status = wlan_hdd_validate_context(hddctx);
3927 if (status != 0)
3928 return status;
3929
Will Huang496b36c2017-07-11 16:38:50 +08003930 hdd_debug("get peer %pM info", mac);
3931
Sourav Mohapatra43e6dea2019-08-18 11:39:23 +05303932 stainfo = hdd_get_sta_info_by_mac(&adapter->sta_info_list, mac);
Will Huang496b36c2017-07-11 16:38:50 +08003933 if (!stainfo) {
3934 hdd_err("peer %pM not found", mac);
3935 return -EINVAL;
3936 }
3937
3938 qdf_mem_copy(macaddr.bytes, mac, QDF_MAC_ADDR_SIZE);
3939 status = wlan_hdd_get_peer_info(adapter, macaddr, &peer_info);
3940 if (status) {
3941 hdd_err("fail to get peer info from fw");
3942 return -EPERM;
3943 }
3944
Will Huangb9cb1242019-04-02 14:52:17 +08003945 qdf_mem_zero(&txrx_stats, sizeof(txrx_stats));
3946 txrx_stats.tx_packets = peer_info.tx_packets;
3947 txrx_stats.tx_bytes = peer_info.tx_bytes;
3948 txrx_stats.rx_packets = peer_info.rx_packets;
3949 txrx_stats.rx_bytes = peer_info.rx_bytes;
3950 txrx_stats.tx_retries = peer_info.tx_retries;
3951 txrx_stats.tx_failed = peer_info.tx_failed;
3952 txrx_stats.rssi = peer_info.rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM;
3953 wlan_hdd_fill_rate_info(&txrx_stats, &peer_info);
3954 wlan_hdd_fill_station_info(hddctx->psoc, sinfo, stainfo, &txrx_stats);
Will Huang496b36c2017-07-11 16:38:50 +08003955
3956 return status;
3957}
3958
Jingxiang Gef1d81592019-10-20 12:03:22 +08003959#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \
3960 defined(WLAN_FEATURE_11AX)
3961/**
3962 * hdd_map_he_gi_to_os() - map txrate_gi to os guard interval
3963 * @guard_interval: guard interval get from fw rate
3964 *
3965 * Return: os guard interval value
3966 */
3967static inline uint8_t hdd_map_he_gi_to_os(enum txrate_gi guard_interval)
3968{
3969 switch (guard_interval) {
3970 case TXRATE_GI_0_8_US:
3971 return NL80211_RATE_INFO_HE_GI_0_8;
3972 case TXRATE_GI_1_6_US:
3973 return NL80211_RATE_INFO_HE_GI_1_6;
3974 case TXRATE_GI_3_2_US:
3975 return NL80211_RATE_INFO_HE_GI_3_2;
3976 default:
3977 return NL80211_RATE_INFO_HE_GI_0_8;
3978 }
3979}
3980
3981/**
3982 * wlan_hdd_fill_os_he_rateflags() - Fill HE related rate_info
3983 * @os_rate: rate info for os
3984 * @rate_flags: rate flags
3985 * @dcm: dcm from rate
3986 * @guard_interval: guard interval from rate
3987 *
3988 * Return: none
3989 */
3990static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
3991 enum tx_rate_info rate_flags,
3992 uint8_t dcm,
3993 enum txrate_gi guard_interval)
3994{
3995 /* as fw not yet report ofdma to host, so we doesn't
3996 * fill RATE_INFO_BW_HE_RU.
3997 */
3998 if (rate_flags & (TX_RATE_HE80 | TX_RATE_HE40 |
3999 TX_RATE_HE20)) {
4000 if (rate_flags & TX_RATE_HE80)
4001 hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
4002 else if (rate_flags & TX_RATE_HE40)
4003 hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
4004
4005 os_rate->flags |= RATE_INFO_FLAGS_HE_MCS;
4006
4007 os_rate->he_gi = hdd_map_he_gi_to_os(guard_interval);
4008 os_rate->he_dcm = dcm;
4009 }
4010}
4011#else
4012static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
4013 enum tx_rate_info rate_flags,
4014 uint8_t dcm,
4015 enum txrate_gi guard_interval)
4016{}
4017#endif
4018
4019/**
4020 * wlan_hdd_fill_os_rate_info() - Fill os related rate_info
4021 * @rate_flags: rate flags
4022 * @legacy_rate: 802.11abg rate
4023 * @os_rate: rate info for os
4024 * @mcs_index: mcs
4025 * @dcm: dcm from rate
4026 * @guard_interval: guard interval from rate
4027 *
4028 * Return: none
4029 */
4030static void wlan_hdd_fill_os_rate_info(enum tx_rate_info rate_flags,
4031 uint16_t legacy_rate,
4032 struct rate_info *os_rate,
4033 uint8_t mcs_index, uint8_t nss,
4034 uint8_t dcm,
4035 enum txrate_gi guard_interval)
4036{
4037 if (rate_flags & TX_RATE_LEGACY) {
4038 os_rate->legacy = legacy_rate;
4039 hdd_debug("Reporting legacy rate %d", os_rate->legacy);
4040 return;
4041 }
4042
4043 /* assume basic BW. anything else will override this later */
4044 hdd_set_rate_bw(os_rate, HDD_RATE_BW_20);
4045 os_rate->mcs = mcs_index;
4046 os_rate->nss = nss;
4047
4048 wlan_hdd_fill_os_he_rateflags(os_rate, rate_flags, dcm, guard_interval);
4049
4050 if (rate_flags & (TX_RATE_VHT80 | TX_RATE_VHT40 |
4051 TX_RATE_VHT20)) {
4052 if (rate_flags & TX_RATE_VHT80)
4053 hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
4054 else if (rate_flags & TX_RATE_VHT40)
4055 hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
4056 os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
4057 }
4058
4059 if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) {
4060 if (rate_flags & TX_RATE_HT40)
4061 hdd_set_rate_bw(os_rate,
4062 HDD_RATE_BW_40);
4063 os_rate->flags |= RATE_INFO_FLAGS_MCS;
4064 }
4065
4066 if (rate_flags & TX_RATE_SGI)
4067 os_rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
4068}
4069
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304070bool hdd_report_max_rate(mac_handle_t mac_handle,
4071 struct rate_info *rate,
4072 int8_t signal,
Jingxiang Gef1d81592019-10-20 12:03:22 +08004073 enum tx_rate_info rate_flags,
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304074 uint8_t mcs_index,
4075 uint16_t fw_rate, uint8_t nss)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304076{
4077 uint8_t i, j, rssidx;
4078 uint16_t max_rate = 0;
4079 uint32_t vht_mcs_map;
Sourav Mohapatra22ff4c62019-05-16 12:04:59 +05304080 bool is_vht20_mcs9 = false;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304081 uint16_t current_rate = 0;
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05304082 qdf_size_t or_leng = CSR_DOT11_SUPPORTED_RATES_MAX;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304083 uint8_t operational_rates[CSR_DOT11_SUPPORTED_RATES_MAX];
4084 uint8_t extended_rates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05304085 qdf_size_t er_leng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304086 uint8_t mcs_rates[SIZE_OF_BASIC_MCS_SET];
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05304087 qdf_size_t mcs_leng = SIZE_OF_BASIC_MCS_SET;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304088 struct index_data_rate_type *supported_mcs_rate;
4089 enum data_rate_11ac_max_mcs vht_max_mcs;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304090 uint8_t max_mcs_idx = 0;
4091 uint8_t rate_flag = 1;
4092 int mode = 0, max_ht_idx;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05304093 QDF_STATUS stat = QDF_STATUS_E_FAILURE;
4094 struct hdd_context *hdd_ctx;
Arif Hussaincca60432018-12-03 19:45:12 -08004095 int link_speed_rssi_high = 0;
4096 int link_speed_rssi_mid = 0;
4097 int link_speed_rssi_low = 0;
4098 uint32_t link_speed_rssi_report = 0;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05304099
4100 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
4101 if (!hdd_ctx) {
4102 hdd_err("HDD context is NULL");
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304103 return false;
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05304104 }
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304105
Arif Hussaincca60432018-12-03 19:45:12 -08004106 ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
4107 &link_speed_rssi_high,
4108 &link_speed_rssi_mid,
4109 &link_speed_rssi_low,
4110 &link_speed_rssi_report);
4111
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304112 /* we do not want to necessarily report the current speed */
Arif Hussaincca60432018-12-03 19:45:12 -08004113 if (ucfg_mlme_stats_is_link_speed_report_max(hdd_ctx->psoc)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304114 /* report the max possible speed */
4115 rssidx = 0;
Arif Hussaincca60432018-12-03 19:45:12 -08004116 } else if (ucfg_mlme_stats_is_link_speed_report_max_scaled(
4117 hdd_ctx->psoc)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304118 /* report the max possible speed with RSSI scaling */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304119 if (signal >= link_speed_rssi_high) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304120 /* report the max possible speed */
4121 rssidx = 0;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304122 } else if (signal >= link_speed_rssi_mid) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304123 /* report middle speed */
4124 rssidx = 1;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304125 } else if (signal >= link_speed_rssi_low) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304126 /* report middle speed */
4127 rssidx = 2;
4128 } else {
4129 /* report actual speed */
4130 rssidx = 3;
4131 }
4132 } else {
4133 /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
4134 hdd_err("Invalid value for reportMaxLinkSpeed: %u",
Arif Hussaincca60432018-12-03 19:45:12 -08004135 link_speed_rssi_report);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304136 rssidx = 0;
4137 }
4138
4139 max_rate = 0;
4140
4141 /* Get Basic Rate Set */
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05304142 if (0 != ucfg_mlme_get_opr_rate_set(hdd_ctx->psoc,
4143 operational_rates, &or_leng)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304144 hdd_err("cfg get returned failure");
4145 /*To keep GUI happy */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304146 return false;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304147 }
4148
4149 for (i = 0; i < or_leng; i++) {
4150 for (j = 0;
4151 j < ARRAY_SIZE(supported_data_rate); j++) {
4152 /* Validate Rate Set */
4153 if (supported_data_rate[j].beacon_rate_index ==
4154 (operational_rates[i] & 0x7F)) {
4155 current_rate =
4156 supported_data_rate[j].
4157 supported_rate[rssidx];
4158 break;
4159 }
4160 }
4161 /* Update MAX rate */
4162 max_rate = (current_rate > max_rate) ? current_rate : max_rate;
4163 }
4164
4165 /* Get Extended Rate Set */
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05304166 if (0 != ucfg_mlme_get_ext_opr_rate_set(hdd_ctx->psoc,
4167 extended_rates,
4168 &er_leng)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304169 hdd_err("cfg get returned failure");
4170 /*To keep GUI happy */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304171 return false;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304172 }
4173
4174 for (i = 0; i < er_leng; i++) {
4175 for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) {
4176 if (supported_data_rate[j].beacon_rate_index ==
4177 (extended_rates[i] & 0x7F)) {
4178 current_rate = supported_data_rate[j].
4179 supported_rate[rssidx];
4180 break;
4181 }
4182 }
4183 /* Update MAX rate */
4184 max_rate = (current_rate > max_rate) ? current_rate : max_rate;
4185 }
4186 /* Get MCS Rate Set --
4187 * Only if we are connected in non legacy mode and not reporting
4188 * actual speed
4189 */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304190 if ((3 != rssidx) && !(rate_flags & TX_RATE_LEGACY)) {
Karthik Kantamnenie3bbd7f2018-09-19 20:27:32 +05304191 if (0 != ucfg_mlme_get_current_mcs_set(hdd_ctx->psoc,
4192 mcs_rates,
4193 &mcs_leng)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304194 hdd_err("cfg get returned failure");
4195 /*To keep GUI happy */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304196 return false;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304197 }
4198 rate_flag = 0;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304199
Jingxiang Gef1d81592019-10-20 12:03:22 +08004200 if (rate_flags & (TX_RATE_VHT80 | TX_RATE_HE80))
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304201 mode = 2;
Jingxiang Gef1d81592019-10-20 12:03:22 +08004202 else if (rate_flags & (TX_RATE_HT40 |
4203 TX_RATE_VHT40 | TX_RATE_HE40))
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304204 mode = 1;
4205 else
4206 mode = 0;
4207
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304208 if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 |
Jingxiang Gef1d81592019-10-20 12:03:22 +08004209 TX_RATE_VHT80 | TX_RATE_HE20 | TX_RATE_HE40 |
4210 TX_RATE_HE80)) {
Abhinav Kumare057b412018-10-09 17:28:16 +05304211 stat = ucfg_mlme_cfg_get_vht_tx_mcs_map(hdd_ctx->psoc,
4212 &vht_mcs_map);
Abhinav Kumarb074f2f2018-09-15 15:32:11 +05304213 if (QDF_IS_STATUS_ERROR(stat))
4214 hdd_err("failed to get tx_mcs_map");
Sourav Mohapatra22ff4c62019-05-16 12:04:59 +05304215
4216 stat = ucfg_mlme_get_vht20_mcs9(hdd_ctx->psoc,
4217 &is_vht20_mcs9);
4218 if (QDF_IS_STATUS_ERROR(stat))
4219 hdd_err("Failed to get VHT20 MCS9 enable val");
4220
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304221 vht_max_mcs = (enum data_rate_11ac_max_mcs)
4222 (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304223 if (rate_flags & TX_RATE_SGI)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304224 rate_flag |= 1;
4225
4226 if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs) {
4227 max_mcs_idx = 7;
4228 } else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs) {
4229 max_mcs_idx = 8;
4230 } else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs) {
Sourav Mohapatra22ff4c62019-05-16 12:04:59 +05304231 /*
4232 * If the ini enable_vht20_mcs9 is disabled,
4233 * then max mcs index should not be set to 9
4234 * for TX_RATE_VHT20
4235 */
4236 if (!is_vht20_mcs9 &&
4237 (rate_flags & TX_RATE_VHT20))
4238 max_mcs_idx = 8;
4239 else
4240 max_mcs_idx = 9;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304241 }
4242
Jingxiang Gef1d81592019-10-20 12:03:22 +08004243 if (rate_flags & (TX_RATE_HE20 | TX_RATE_HE40 |
4244 TX_RATE_HE80))
4245 max_mcs_idx = 11;
4246
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304247 if (rssidx != 0) {
4248 for (i = 0; i <= max_mcs_idx; i++) {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304249 if (signal <= rssi_mcs_tbl[mode][i]) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304250 max_mcs_idx = i;
4251 break;
4252 }
4253 }
4254 }
4255
Jingxiang Gef1d81592019-10-20 12:03:22 +08004256 max_mcs_idx = (max_mcs_idx > mcs_index) ?
4257 max_mcs_idx : mcs_index;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304258 } else {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304259 if (rate_flags & TX_RATE_HT40)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304260 rate_flag |= 1;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304261 if (rate_flags & TX_RATE_SGI)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304262 rate_flag |= 2;
4263
4264 supported_mcs_rate =
4265 (struct index_data_rate_type *)
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304266 ((nss == 1) ? &supported_mcs_rate_nss1 :
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304267 &supported_mcs_rate_nss2);
4268
4269 max_ht_idx = MAX_HT_MCS_IDX;
4270 if (rssidx != 0) {
4271 for (i = 0; i < MAX_HT_MCS_IDX; i++) {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304272 if (signal <= rssi_mcs_tbl[mode][i]) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304273 max_ht_idx = i + 1;
4274 break;
4275 }
4276 }
4277 }
4278
4279 for (i = 0; i < mcs_leng; i++) {
4280 for (j = 0; j < max_ht_idx; j++) {
4281 if (supported_mcs_rate[j].
4282 beacon_rate_index ==
4283 mcs_rates[i]) {
4284 current_rate =
4285 supported_mcs_rate[j].
4286 supported_rate
4287 [rate_flag];
4288 max_mcs_idx =
4289 supported_mcs_rate[j].
4290 beacon_rate_index;
4291 break;
4292 }
4293 }
4294
4295 if ((j < MAX_HT_MCS_IDX) &&
Jingxiang Gef1d81592019-10-20 12:03:22 +08004296 (current_rate > max_rate))
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304297 max_rate = current_rate;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304298 }
Jingxiang Gef1d81592019-10-20 12:03:22 +08004299
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304300 if (nss == 2)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304301 max_mcs_idx += MAX_HT_MCS_IDX;
Jingxiang Gef1d81592019-10-20 12:03:22 +08004302 max_mcs_idx = (max_mcs_idx > mcs_index) ?
4303 max_mcs_idx : mcs_index;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304304 }
4305 }
4306
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304307 else if (!(rate_flags & TX_RATE_LEGACY)) {
4308 max_rate = fw_rate;
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304309 max_mcs_idx = mcs_index;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304310 }
4311 /* report a value at least as big as current rate */
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304312 if ((max_rate < fw_rate) || (0 == max_rate)) {
4313 max_rate = fw_rate;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304314 }
4315
Jingxiang Gef1d81592019-10-20 12:03:22 +08004316 wlan_hdd_fill_os_rate_info(rate_flags, max_rate, rate,
4317 max_mcs_idx, nss, 0, 0);
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304318
4319 return true;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304320}
4321
4322/**
4323 * hdd_report_actual_rate() - Fill the actual rate stats.
4324 *
4325 * @rate_flags: The rate flags computed from rate
4326 * @my_rate: The rate from fw stats
4327 * @rate: The station_info struct member strust rate_info to be filled
Jingxiang Gef1d81592019-10-20 12:03:22 +08004328 * @mcs_index: The mcs index computed from rate
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304329 * @nss: The NSS from fw stats
Jingxiang Gef1d81592019-10-20 12:03:22 +08004330 * @dcm: the dcm computed from rate
4331 * @guard_interval: the guard interval computed from rate
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304332 *
4333 * Return: None
4334 */
Jingxiang Gef1d81592019-10-20 12:03:22 +08004335static void hdd_report_actual_rate(enum tx_rate_info rate_flags,
4336 uint16_t my_rate,
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304337 struct rate_info *rate, uint8_t mcs_index,
Jingxiang Gef1d81592019-10-20 12:03:22 +08004338 uint8_t nss, uint8_t dcm,
4339 enum txrate_gi guard_interval)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304340{
4341 /* report current rate instead of max rate */
Jingxiang Gef1d81592019-10-20 12:03:22 +08004342 wlan_hdd_fill_os_rate_info(rate_flags, my_rate, rate,
4343 mcs_index, nss, dcm, guard_interval);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304344}
4345
4346/**
4347 * hdd_wlan_fill_per_chain_rssi_stats() - Fill per chain rssi stats
4348 *
4349 * @sinfo: The station_info structure to be filled.
4350 * @adapter: The HDD adapter structure
4351 *
4352 * Return: None
4353 */
4354#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
4355static inline
4356void hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
4357 struct hdd_adapter *adapter)
4358{
4359 bool rssi_stats_valid = false;
4360 uint8_t i;
4361
4362 sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
4363 for (i = 0; i < NUM_CHAINS_MAX; i++) {
4364 sinfo->chain_signal_avg[i] =
4365 adapter->hdd_stats.per_chain_rssi_stats.rssi[i];
4366 sinfo->chains |= 1 << i;
4367 if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
4368 sinfo->chain_signal_avg[i] != 0)
4369 sinfo->signal_avg = sinfo->chain_signal_avg[i];
4370
4371 hdd_debug("RSSI for chain %d, vdev_id %d is %d",
Jeff Johnson1abc5662019-02-04 14:27:02 -08004372 i, adapter->vdev_id, sinfo->chain_signal_avg[i]);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304373
4374 if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
4375 rssi_stats_valid = true;
4376 }
4377
4378 if (rssi_stats_valid) {
4379 sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG;
4380 sinfo->filled |= HDD_INFO_SIGNAL_AVG;
4381 }
4382}
4383
4384#else
4385
4386static inline
4387void hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
4388 struct hdd_adapter *adapter)
4389{
4390}
4391
4392#endif
4393
Ashish Kumar Dhanotiyaed6d0272019-04-15 12:13:24 +05304394#if defined(CFG80211_RX_FCS_ERROR_REPORTING_SUPPORT)
4395static void hdd_fill_fcs_and_mpdu_count(struct hdd_adapter *adapter,
4396 struct station_info *sinfo)
4397{
4398 sinfo->rx_mpdu_count = adapter->hdd_stats.peer_stats.rx_count;
4399 sinfo->fcs_err_count = adapter->hdd_stats.peer_stats.fcs_count;
4400 hdd_debug("RX mpdu count %d fcs_err_count %d",
4401 sinfo->rx_mpdu_count, sinfo->fcs_err_count);
Ashish Kumar Dhanotiya14923e62019-06-19 14:58:18 +05304402 sinfo->filled |= HDD_INFO_FCS_ERROR_COUNT | HDD_INFO_RX_MPDUS;
Ashish Kumar Dhanotiyaed6d0272019-04-15 12:13:24 +05304403}
4404#else
4405static void hdd_fill_fcs_and_mpdu_count(struct hdd_adapter *adapter,
4406 struct station_info *sinfo)
4407{
4408}
4409#endif
4410
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304411/**
Naveen Rawat374d7982018-04-12 10:56:09 -07004412 * wlan_hdd_get_sta_stats() - get aggregate STA stats
4413 * @wiphy: wireless phy
4414 * @adapter: STA adapter to get stats for
4415 * @mac: mac address of sta
4416 * @sinfo: kernel station_info struct to populate
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004417 *
Naveen Rawat374d7982018-04-12 10:56:09 -07004418 * Fetch the vdev-level aggregate stats for the given STA adapter. This is to
4419 * support "station dump" and "station get" for STA vdevs
4420 *
4421 * Return: errno
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004422 */
Naveen Rawat374d7982018-04-12 10:56:09 -07004423static int wlan_hdd_get_sta_stats(struct wiphy *wiphy,
4424 struct hdd_adapter *adapter,
4425 const uint8_t *mac,
4426 struct station_info *sinfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004427{
Jeff Johnsond377dce2017-10-04 10:32:42 -07004428 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jingxiang Gef1d81592019-10-20 12:03:22 +08004429 enum tx_rate_info rate_flags, tx_rate_flags, rx_rate_flags;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304430 uint8_t tx_mcs_index, rx_mcs_index;
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004431 struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
Jeff Johnson003f7392018-06-12 20:45:47 -07004432 mac_handle_t mac_handle;
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304433 int8_t snr = 0;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304434 uint16_t my_tx_rate, my_rx_rate;
Jingxiang Gef1d81592019-10-20 12:03:22 +08004435 uint8_t tx_nss = 1, rx_nss = 1, tx_dcm, rx_dcm;
4436 enum txrate_gi tx_gi, rx_gi;
Rajeev Kumar Sirasanagandlab13b7772017-01-24 15:28:29 +05304437 int32_t rcpi_value;
Arif Hussaincca60432018-12-03 19:45:12 -08004438 int link_speed_rssi_high = 0;
4439 int link_speed_rssi_mid = 0;
4440 int link_speed_rssi_low = 0;
4441 uint32_t link_speed_rssi_report = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004442
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304443 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
4444 TRACE_CODE_HDD_CFG80211_GET_STA,
Jeff Johnson1abc5662019-02-04 14:27:02 -08004445 adapter->vdev_id, 0);
Ashish Kumar Dhanotiyaf10aa5f2018-12-28 21:29:56 +05304446
Jeff Johnsone7951512019-02-27 10:02:51 -08004447 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Paul Zhang9ffb0432018-08-03 10:32:34 +08004448 hdd_debug("Not associated");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004449 /*To keep GUI happy */
4450 return 0;
4451 }
4452
Jeff Johnson690fe952017-10-25 11:48:39 -07004453 if (sta_ctx->hdd_reassoc_scenario) {
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004454 hdd_debug("Roaming is in progress, cannot continue with this request");
Sachin Ahujafeedeba2016-09-13 21:54:16 +05304455 /*
4456 * supplicant reports very low rssi to upper layer
4457 * and handover happens to cellular.
4458 * send the cached rssi when get_station
4459 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004460 sinfo->signal = adapter->rssi;
Naveen Rawat23183d62018-04-12 11:19:01 -07004461 sinfo->filled |= HDD_INFO_SIGNAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004462 return 0;
4463 }
4464
Arif Hussaincca60432018-12-03 19:45:12 -08004465 ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
4466 &link_speed_rssi_high,
4467 &link_speed_rssi_mid,
4468 &link_speed_rssi_low,
4469 &link_speed_rssi_report);
4470
Rajeev Kumar Sirasanagandlab13b7772017-01-24 15:28:29 +05304471 if (hdd_ctx->rcpi_enabled)
4472 wlan_hdd_get_rcpi(adapter, (uint8_t *)mac, &rcpi_value,
4473 RCPI_MEASUREMENT_TYPE_AVG_MGMT);
4474
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004475 wlan_hdd_get_station_stats(adapter);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05304476
Paul Zhangb1f35df2018-04-16 12:19:01 +08004477 adapter->rssi = adapter->hdd_stats.summary_stat.rssi;
4478 snr = adapter->hdd_stats.summary_stat.snr;
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05304479
4480 /* for new connection there might be no valid previous RSSI */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004481 if (!adapter->rssi) {
4482 hdd_get_rssi_snr_by_bssid(adapter,
Jeff Johnsone04b6992019-02-27 14:06:55 -08004483 sta_ctx->conn_info.bssid.bytes,
Paul Zhangb1f35df2018-04-16 12:19:01 +08004484 &adapter->rssi, &snr);
Hanumanth Reddy Pothula90051782017-05-04 22:14:43 +05304485 }
4486
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004487 sinfo->signal = adapter->rssi;
Srinivas Girigowda11daf2a2017-03-06 22:38:06 -08004488 hdd_debug("snr: %d, rssi: %d",
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004489 adapter->hdd_stats.summary_stat.snr,
4490 adapter->hdd_stats.summary_stat.rssi);
Jeff Johnsond377dce2017-10-04 10:32:42 -07004491 sta_ctx->conn_info.signal = sinfo->signal;
4492 sta_ctx->conn_info.noise =
4493 sta_ctx->conn_info.signal - snr;
Ashish Kumar Dhanotiya36d19b02018-02-22 00:59:49 +05304494 sta_ctx->cache_conn_info.signal = sinfo->signal;
4495 sta_ctx->cache_conn_info.noise = sta_ctx->conn_info.noise;
Naveen Rawat23183d62018-04-12 11:19:01 -07004496 sinfo->filled |= HDD_INFO_SIGNAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004497
Jeff Johnson71396692016-09-23 15:41:52 -07004498 /*
4499 * we notify connect to lpass here instead of during actual
4500 * connect processing because rssi info is not accurate during
4501 * actual connection. lpass will ensure the notification is
4502 * only processed once per association.
4503 */
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004504 hdd_lpass_notify_connect(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004505
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304506 rate_flags = adapter->hdd_stats.class_a_stat.tx_rx_rate_flags;
4507 tx_rate_flags = rx_rate_flags = rate_flags;
4508
4509 tx_mcs_index = adapter->hdd_stats.class_a_stat.tx_mcs_index;
4510 rx_mcs_index = adapter->hdd_stats.class_a_stat.rx_mcs_index;
Jeff Johnson003f7392018-06-12 20:45:47 -07004511 mac_handle = hdd_ctx->mac_handle;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004512
4513 /* convert to the UI units of 100kbps */
Sourav Mohapatrad204a812019-01-09 09:45:08 +05304514 my_tx_rate = adapter->hdd_stats.class_a_stat.tx_rate;
4515 my_rx_rate = adapter->hdd_stats.class_a_stat.rx_rate;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304516
Jingxiang Gef1d81592019-10-20 12:03:22 +08004517 tx_dcm = adapter->hdd_stats.class_a_stat.tx_dcm;
4518 rx_dcm = adapter->hdd_stats.class_a_stat.rx_dcm;
4519 tx_gi = adapter->hdd_stats.class_a_stat.tx_gi;
4520 rx_gi = adapter->hdd_stats.class_a_stat.rx_gi;
4521
Naveen Rawatea1564b2018-05-17 15:56:11 -07004522 if (!(rate_flags & TX_RATE_LEGACY)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304523 tx_nss = adapter->hdd_stats.class_a_stat.tx_nss;
4524 rx_nss = adapter->hdd_stats.class_a_stat.rx_nss;
4525
4526 if ((tx_nss > 1) &&
Dustin Brown05d81302018-09-11 16:49:22 -07004527 policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
4528 !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304529 hdd_debug("Hw mode is DBS, Reduce nss(%d) to 1",
4530 tx_nss);
4531 tx_nss--;
4532 }
4533
4534 if ((rx_nss > 1) &&
Dustin Brown05d81302018-09-11 16:49:22 -07004535 policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
4536 !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304537 hdd_debug("Hw mode is DBS, Reduce nss(%d) to 1",
4538 rx_nss);
4539 rx_nss--;
Agrawal Ashish569ad262017-05-01 14:06:36 +05304540 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004541
Arif Hussaincca60432018-12-03 19:45:12 -08004542 if (ucfg_mlme_stats_is_link_speed_report_actual(
4543 hdd_ctx->psoc)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004544 /* Get current rate flags if report actual */
Hanumanth Reddy Pothula063cbe92017-08-08 23:22:01 +05304545 /* WMA fails to find mcs_index for legacy tx rates */
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304546 if (tx_mcs_index == INVALID_MCS_IDX && my_tx_rate)
4547 tx_rate_flags = TX_RATE_LEGACY;
Hanumanth Reddy Pothula063cbe92017-08-08 23:22:01 +05304548 else
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304549 tx_rate_flags =
4550 adapter->hdd_stats.class_a_stat.tx_mcs_rate_flags;
4551
4552 if (rx_mcs_index == INVALID_MCS_IDX && my_rx_rate)
4553 rx_rate_flags = TX_RATE_LEGACY;
4554 else
4555 rx_rate_flags =
4556 adapter->hdd_stats.class_a_stat.rx_mcs_rate_flags;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004557 }
4558
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304559 if (tx_mcs_index == INVALID_MCS_IDX)
4560 tx_mcs_index = 0;
4561 if (rx_mcs_index == INVALID_MCS_IDX)
4562 rx_mcs_index = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004563 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004564
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304565 hdd_debug("RSSI %d, RLMS %u, rssi high %d, rssi mid %d, rssi low %d",
Arif Hussaincca60432018-12-03 19:45:12 -08004566 sinfo->signal, link_speed_rssi_report,
4567 link_speed_rssi_high, link_speed_rssi_mid,
4568 link_speed_rssi_low);
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304569 hdd_debug("Rate info: TX: %d, RX: %d", my_tx_rate, my_rx_rate);
4570 hdd_debug("Rate flags: TX: 0x%x, RX: 0x%x", (int)tx_rate_flags,
4571 (int)rx_rate_flags);
4572 hdd_debug("MCS Index: TX: %d, RX: %d", (int)tx_mcs_index,
4573 (int)rx_mcs_index);
Sourav Mohapatrab22d2692018-09-21 18:11:45 +05304574 hdd_debug("NSS: TX: %d, RX: %d", (int)tx_nss, (int)rx_nss);
Jingxiang Gef1d81592019-10-20 12:03:22 +08004575 hdd_debug("dcm: TX: %d, RX: %d", (int)tx_dcm, (int)rx_dcm);
4576 hdd_debug("guard interval: TX: %d, RX: %d", (int)tx_gi, (int)rx_gi);
Jeff Johnson9cc0ed92016-09-29 12:11:42 -07004577
Arif Hussaincca60432018-12-03 19:45:12 -08004578 if (!ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) {
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304579 bool tx_rate_calc;
4580 bool rx_rate_calc;
4581
4582 tx_rate_calc = hdd_report_max_rate(mac_handle, &sinfo->txrate,
4583 sinfo->signal,
4584 tx_rate_flags,
4585 tx_mcs_index,
4586 my_tx_rate,
Sourav Mohapatra4d1f4cc2019-10-21 16:43:49 +05304587 wlan_vdev_mlme_get_nss(
4588 adapter->vdev));
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304589
4590 rx_rate_calc = hdd_report_max_rate(mac_handle, &sinfo->rxrate,
4591 sinfo->signal,
4592 rx_rate_flags,
4593 rx_mcs_index,
4594 my_rx_rate,
Sourav Mohapatra4d1f4cc2019-10-21 16:43:49 +05304595 wlan_vdev_mlme_get_nss(
4596 adapter->vdev));
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304597
4598 if (!tx_rate_calc || !rx_rate_calc)
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304599 /* Keep GUI happy */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004600 return 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004601 } else {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004602
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304603 /* Fill TX stats */
4604 hdd_report_actual_rate(tx_rate_flags, my_tx_rate,
Jingxiang Gef1d81592019-10-20 12:03:22 +08004605 &sinfo->txrate, tx_mcs_index,
4606 tx_nss, tx_dcm, tx_gi);
4607
Dustin Brown32cb4792017-06-15 15:33:42 -07004608
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304609 /* Fill RX stats */
4610 hdd_report_actual_rate(rx_rate_flags, my_rx_rate,
Jingxiang Gef1d81592019-10-20 12:03:22 +08004611 &sinfo->rxrate, rx_mcs_index,
4612 rx_nss, rx_dcm, rx_gi);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004613 }
Ryan Hsu6139d2d2015-11-04 17:29:00 -08004614
Will Huang136ca8d2019-12-05 13:12:07 +08004615 wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat,
4616 sinfo,
4617 adapter->vdev_id);
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004618 sinfo->tx_bytes = adapter->stats.tx_bytes;
Ashish Kumar Dhanotiyaed6d0272019-04-15 12:13:24 +05304619 sinfo->rx_bytes = adapter->stats.rx_bytes;
4620 sinfo->rx_packets = adapter->stats.rx_packets;
4621
4622 hdd_fill_fcs_and_mpdu_count(adapter, sinfo);
Ryan Hsue7bc3a72016-01-18 12:08:22 -08004623
Jeff Johnsond377dce2017-10-04 10:32:42 -07004624 qdf_mem_copy(&sta_ctx->conn_info.txrate,
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304625 &sinfo->txrate, sizeof(sinfo->txrate));
Ashish Kumar Dhanotiya36d19b02018-02-22 00:59:49 +05304626 qdf_mem_copy(&sta_ctx->cache_conn_info.txrate,
4627 &sinfo->txrate, sizeof(sinfo->txrate));
Anurag Chouhan5de8d172016-07-13 14:44:28 +05304628
Rajeev Kumar Sirasanagandlae709bca2019-04-30 23:36:24 +05304629 qdf_mem_copy(&sta_ctx->conn_info.rxrate,
4630 &sinfo->rxrate, sizeof(sinfo->rxrate));
4631
Naveen Rawat23183d62018-04-12 11:19:01 -07004632 sinfo->filled |= HDD_INFO_TX_BITRATE |
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304633 HDD_INFO_RX_BITRATE |
Naveen Rawat23183d62018-04-12 11:19:01 -07004634 HDD_INFO_TX_BYTES |
4635 HDD_INFO_RX_BYTES |
4636 HDD_INFO_RX_PACKETS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004637
Jingxiang Gef1d81592019-10-20 12:03:22 +08004638 if (tx_rate_flags & TX_RATE_LEGACY) {
4639 hdd_debug("TX: Reporting legacy rate %d pkt cnt %d",
4640 sinfo->txrate.legacy, sinfo->tx_packets);
4641 hdd_debug("RX: Reporting legacy rate %d pkt cnt %d",
4642 sinfo->rxrate.legacy, sinfo->rx_packets);
4643 } else {
4644 hdd_debug("TX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d",
4645 sinfo->txrate.mcs, sinfo->txrate.flags,
4646 sinfo->tx_packets, sinfo->txrate.nss,
4647 sinfo->rxrate.bw);
4648 hdd_debug("RX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d",
4649 sinfo->rxrate.mcs, sinfo->rxrate.flags,
4650 sinfo->rx_packets, sinfo->rxrate.nss,
4651 sinfo->rxrate.bw);
4652 }
Edhar, Mahesh Kumarabfad4f2016-01-27 16:33:05 +05304653
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05304654 hdd_wlan_fill_per_chain_rssi_stats(sinfo, adapter);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304655
Dustin Browne74003f2018-03-14 12:51:58 -07004656 hdd_exit();
Dustin Brown32cb4792017-06-15 15:33:42 -07004657
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004658 return 0;
4659}
4660
4661/**
Naveen Rawat374d7982018-04-12 10:56:09 -07004662 * __wlan_hdd_cfg80211_get_station() - get station statistics
4663 * @wiphy: Pointer to wiphy
4664 * @dev: Pointer to network device
4665 * @mac: Pointer to mac
4666 * @sinfo: Pointer to station info
4667 *
4668 * Return: 0 for success, non-zero for failure
4669 */
4670static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4671 struct net_device *dev,
4672 const uint8_t *mac,
4673 struct station_info *sinfo)
4674{
4675 int status;
4676 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Will Huangb9cb1242019-04-02 14:52:17 +08004677 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
4678 bool get_peer_info_enable;
4679 QDF_STATUS qdf_status;
Naveen Rawat374d7982018-04-12 10:56:09 -07004680
4681 hdd_enter_dev(dev);
4682
4683 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
4684 hdd_err("Command not allowed in FTM mode");
4685 return -EINVAL;
4686 }
4687
4688 status = wlan_hdd_validate_context(hdd_ctx);
4689 if (status)
4690 return status;
4691
Jeff Johnson48363022019-02-24 16:26:51 -08004692 if (wlan_hdd_validate_vdev_id(adapter->vdev_id))
Naveen Rawat374d7982018-04-12 10:56:09 -07004693 return -EINVAL;
Naveen Rawat374d7982018-04-12 10:56:09 -07004694
Will Huangb9cb1242019-04-02 14:52:17 +08004695 if (adapter->device_mode == QDF_SAP_MODE) {
4696 qdf_status = ucfg_mlme_get_sap_get_peer_info(
4697 hdd_ctx->psoc, &get_peer_info_enable);
4698 if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) {
4699 status = wlan_hdd_get_station_remote(wiphy, dev,
4700 mac, sinfo);
4701 if (!status)
4702 return 0;
4703 }
Naveen Rawat374d7982018-04-12 10:56:09 -07004704 return wlan_hdd_get_sap_stats(adapter, sinfo);
Will Huangb9cb1242019-04-02 14:52:17 +08004705 } else {
Naveen Rawat374d7982018-04-12 10:56:09 -07004706 return wlan_hdd_get_sta_stats(wiphy, adapter, mac, sinfo);
Will Huangb9cb1242019-04-02 14:52:17 +08004707 }
Naveen Rawat374d7982018-04-12 10:56:09 -07004708}
4709
4710/**
Yue Ma1c1d0f72019-08-01 19:21:05 -07004711 * _wlan_hdd_cfg80211_get_station() - get station statistics
4712 *
4713 * @wiphy: Pointer to wiphy
4714 * @dev: Pointer to network device
4715 * @mac: Pointer to mac
4716 * @sinfo: Pointer to station info
4717 *
4718 * This API tries runtime PM suspend right away after getting station
4719 * statistics.
4720 *
4721 * Return: 0 for success, non-zero for failure
4722 */
4723static int _wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4724 struct net_device *dev,
4725 const uint8_t *mac,
4726 struct station_info *sinfo)
4727{
Sravan Kumar Kairam10ed0e82019-08-21 20:52:09 +05304728 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Manikandan Mohan1baadae2019-08-23 08:32:56 -07004729 qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
Yue Ma1c1d0f72019-08-01 19:21:05 -07004730 int errno;
4731
Sravan Kumar Kairam10ed0e82019-08-21 20:52:09 +05304732 errno = wlan_hdd_validate_context(hdd_ctx);
4733 if (errno)
4734 return errno;
4735
Manikandan Mohan1f380142019-09-26 18:03:25 -07004736 if (!qdf_ctx)
4737 return -EINVAL;
4738
Manikandan Mohan1baadae2019-08-23 08:32:56 -07004739 errno = pld_qmi_send_get(qdf_ctx->dev);
Yue Ma1c1d0f72019-08-01 19:21:05 -07004740 if (errno)
4741 return errno;
4742
4743 errno = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4744
Manikandan Mohan1baadae2019-08-23 08:32:56 -07004745 pld_qmi_send_put(qdf_ctx->dev);
Yue Ma1c1d0f72019-08-01 19:21:05 -07004746
4747 return errno;
4748}
4749
4750/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004751 * wlan_hdd_cfg80211_get_station() - get station statistics
4752 * @wiphy: Pointer to wiphy
4753 * @dev: Pointer to network device
4754 * @mac: Pointer to mac
4755 * @sinfo: Pointer to station info
4756 *
4757 * Return: 0 for success, non-zero for failure
4758 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004759int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
4760 struct net_device *dev, const uint8_t *mac,
4761 struct station_info *sinfo)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004762{
Dustin Brown1d31b082018-11-22 14:41:20 +05304763 int errno;
4764 struct osif_vdev_sync *vdev_sync;
4765
4766 errno = osif_vdev_sync_op_start(dev, &vdev_sync);
4767 if (errno)
4768 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004769
Yue Ma1c1d0f72019-08-01 19:21:05 -07004770 errno = _wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004771
Dustin Brown1d31b082018-11-22 14:41:20 +05304772 osif_vdev_sync_op_stop(vdev_sync);
4773
4774 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004775}
4776
4777/**
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304778 * __wlan_hdd_cfg80211_dump_station() - dump station statistics
4779 * @wiphy: Pointer to wiphy
4780 * @dev: Pointer to network device
4781 * @idx: variable to determine whether to get stats or not
4782 * @mac: Pointer to mac
4783 * @sinfo: Pointer to station info
4784 *
4785 * Return: 0 for success, non-zero for failure
4786 */
4787static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4788 struct net_device *dev,
4789 int idx, u8 *mac,
4790 struct station_info *sinfo)
4791{
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304792 hdd_debug("%s: idx %d", __func__, idx);
4793 if (idx != 0)
4794 return -ENOENT;
Ashish Kumar Dhanotiyafa55c182019-06-03 19:14:55 +05304795 qdf_mem_copy(mac, dev->dev_addr, QDF_MAC_ADDR_SIZE);
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304796 return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
4797}
4798
4799/**
4800 * wlan_hdd_cfg80211_dump_station() - dump station statistics
4801 * @wiphy: Pointer to wiphy
4802 * @dev: Pointer to network device
4803 * @idx: variable to determine whether to get stats or not
4804 * @mac: Pointer to mac
4805 * @sinfo: Pointer to station info
4806 *
4807 * Return: 0 for success, non-zero for failure
4808 */
4809int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
4810 struct net_device *dev,
4811 int idx, u8 *mac,
4812 struct station_info *sinfo)
4813{
Dustin Brown1d31b082018-11-22 14:41:20 +05304814 int errno;
4815 struct osif_vdev_sync *vdev_sync;
4816
4817 errno = osif_vdev_sync_op_start(dev, &vdev_sync);
4818 if (errno)
4819 return errno;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304820
Dustin Brown1d31b082018-11-22 14:41:20 +05304821 errno = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
Dustin Brown1d31b082018-11-22 14:41:20 +05304822
4823 osif_vdev_sync_op_stop(vdev_sync);
4824
4825 return errno;
Himanshu Agarwal37e42412016-07-21 14:35:09 +05304826}
4827
4828/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004829 * hdd_get_stats() - Function to retrieve interface statistics
4830 * @dev: pointer to network device
4831 *
4832 * This function is the ndo_get_stats method for all netdevs
4833 * registered with the kernel
4834 *
4835 * Return: pointer to net_device_stats structure
4836 */
4837struct net_device_stats *hdd_get_stats(struct net_device *dev)
4838{
Jeff Johnsona11f94b2017-08-29 14:21:35 -07004839 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004840
Dustin Brownfdf17c12018-03-14 12:55:34 -07004841 hdd_enter_dev(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004842 return &adapter->stats;
4843}
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304844
4845
4846/*
4847 * time = cycle_count * cycle
4848 * cycle = 1 / clock_freq
4849 * Since the unit of clock_freq reported from
4850 * FW is MHZ, and we want to calculate time in
4851 * ms level, the result is
4852 * time = cycle / (clock_freq * 1000)
4853 */
4854#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
4855static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4856 struct scan_chan_info *chan_info,
4857 struct ieee80211_channel *channels)
4858{
4859 uint64_t clock_freq = chan_info->clock_freq * 1000;
4860
4861 if (channels->center_freq != (uint16_t)chan_info->freq)
4862 return false;
4863
4864 survey->channel = channels;
4865 survey->noise = chan_info->noise_floor;
4866 survey->filled = SURVEY_INFO_NOISE_DBM;
4867
4868 if (opfreq == chan_info->freq)
4869 survey->filled |= SURVEY_INFO_IN_USE;
4870
4871 if (clock_freq == 0)
4872 return true;
4873
Nirav Shaheb017be2018-02-15 11:20:58 +05304874 survey->time = qdf_do_div(chan_info->cycle_count, clock_freq);
4875
4876 survey->time_busy = qdf_do_div(chan_info->rx_clear_count, clock_freq);
4877
4878 survey->time_tx = qdf_do_div(chan_info->tx_frame_count, clock_freq);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304879
4880 survey->filled |= SURVEY_INFO_TIME |
4881 SURVEY_INFO_TIME_BUSY |
4882 SURVEY_INFO_TIME_TX;
4883 return true;
4884}
4885#else
4886static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
4887 struct scan_chan_info *chan_info,
4888 struct ieee80211_channel *channels)
4889{
4890 uint64_t clock_freq = chan_info->clock_freq * 1000;
4891
4892 if (channels->center_freq != (uint16_t)chan_info->freq)
4893 return false;
4894
4895 survey->channel = channels;
4896 survey->noise = chan_info->noise_floor;
4897 survey->filled = SURVEY_INFO_NOISE_DBM;
4898
4899 if (opfreq == chan_info->freq)
4900 survey->filled |= SURVEY_INFO_IN_USE;
4901
4902 if (clock_freq == 0)
4903 return true;
4904
Nirav Shaheb017be2018-02-15 11:20:58 +05304905 survey->channel_time = qdf_do_div(chan_info->cycle_count, clock_freq);
4906
4907 survey->channel_time_busy = qdf_do_div(chan_info->rx_clear_count,
4908 clock_freq);
4909
4910 survey->channel_time_tx = qdf_do_div(chan_info->tx_frame_count,
4911 clock_freq);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304912
4913 survey->filled |= SURVEY_INFO_CHANNEL_TIME |
4914 SURVEY_INFO_CHANNEL_TIME_BUSY |
4915 SURVEY_INFO_CHANNEL_TIME_TX;
4916 return true;
4917}
4918#endif
4919
4920static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
Jeff Johnson32bd9742018-03-29 13:42:31 -07004921 struct hdd_adapter *adapter,
4922 struct survey_info *survey, int idx)
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304923{
4924 bool filled = false;
4925 int i, j = 0;
Jianmin Zhubc841052019-10-28 17:24:39 +08004926 uint32_t opfreq = 0; /* Initialization Required */
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004927 struct hdd_context *hdd_ctx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304928
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004929 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jianmin Zhubc841052019-10-28 17:24:39 +08004930 sme_get_operation_channel(hdd_ctx->mac_handle, &opfreq,
Jeff Johnson1abc5662019-02-04 14:27:02 -08004931 adapter->vdev_id);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304932
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004933 mutex_lock(&hdd_ctx->chan_info_lock);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304934
Srinivas Girigowda5da651b2017-08-04 11:22:54 -07004935 for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) {
Jeff Johnsond36fa332019-03-18 13:42:25 -07004936 if (!wiphy->bands[i])
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304937 continue;
4938
4939 for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
4940 struct ieee80211_supported_band *band = wiphy->bands[i];
Jeff Johnson4f7f7c62017-10-05 08:53:41 -07004941
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304942 filled = wlan_fill_survey_result(survey, opfreq,
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004943 &hdd_ctx->chan_info[idx],
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304944 &band->channels[j]);
4945 }
4946 }
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004947 mutex_unlock(&hdd_ctx->chan_info_lock);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304948
4949 return filled;
4950}
4951
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004952/**
4953 * __wlan_hdd_cfg80211_dump_survey() - get survey related info
4954 * @wiphy: Pointer to wiphy
4955 * @dev: Pointer to network device
4956 * @idx: Index
4957 * @survey: Pointer to survey info
4958 *
4959 * Return: 0 for success, non-zero for failure
4960 */
4961static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
4962 struct net_device *dev,
4963 int idx, struct survey_info *survey)
4964{
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004965 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004966 struct hdd_context *hdd_ctx;
Jeff Johnsond377dce2017-10-04 10:32:42 -07004967 struct hdd_station_ctx *sta_ctx;
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304968 int status;
4969 bool filled = false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004970
Dustin Brownfdf17c12018-03-14 12:55:34 -07004971 hdd_enter_dev(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004972
Srinivas Girigowda6598eea2017-07-06 19:26:19 -07004973 hdd_debug("dump survey index: %d", idx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304974 if (idx > QDF_MAX_NUM_CHAN - 1)
4975 return -EINVAL;
4976
Jeff Johnsona86e78e2017-10-02 13:23:05 -07004977 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsonf645abf2017-09-03 09:07:46 -07004978 status = wlan_hdd_validate_context(hdd_ctx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304979 if (0 != status)
4980 return status;
4981
Jeff Johnsond36fa332019-03-18 13:42:25 -07004982 if (!hdd_ctx->chan_info) {
Tushnim Bhattacharyya929afa42018-06-01 15:04:44 -07004983 hdd_debug("chan_info is NULL");
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304984 return -EINVAL;
4985 }
4986
4987 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
Jeff Johnson0c1301d2016-05-17 16:16:35 -07004988 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004989 return -EINVAL;
4990 }
4991
Jeff Johnsond377dce2017-10-04 10:32:42 -07004992 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004993
Jeff Johnsona8fef4e2019-03-11 14:38:49 -07004994 if (!hdd_ctx->config->enable_snr_monitoring)
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304995 return -ENONET;
4996
Jeff Johnson690fe952017-10-25 11:48:39 -07004997 if (sta_ctx->hdd_reassoc_scenario) {
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05304998 hdd_info("Roaming in progress, hence return");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004999 return -ENONET;
5000 }
5001
Jeff Johnsona86e78e2017-10-02 13:23:05 -07005002 filled = wlan_hdd_update_survey_info(wiphy, adapter, survey, idx);
Kapil Gupta4f0c0c12017-02-07 15:21:15 +05305003
5004 if (!filled)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005005 return -ENONET;
Dustin Browne74003f2018-03-14 12:51:58 -07005006 hdd_exit();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005007 return 0;
5008}
5009
5010/**
5011 * wlan_hdd_cfg80211_dump_survey() - get survey related info
5012 * @wiphy: Pointer to wiphy
5013 * @dev: Pointer to network device
5014 * @idx: Index
5015 * @survey: Pointer to survey info
5016 *
5017 * Return: 0 for success, non-zero for failure
5018 */
5019int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
5020 struct net_device *dev,
5021 int idx, struct survey_info *survey)
5022{
Dustin Brown1d31b082018-11-22 14:41:20 +05305023 int errno;
5024 struct osif_vdev_sync *vdev_sync;
5025
5026 errno = osif_vdev_sync_op_start(dev, &vdev_sync);
5027 if (errno)
5028 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005029
Dustin Brown1d31b082018-11-22 14:41:20 +05305030 errno = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005031
Dustin Brown1d31b082018-11-22 14:41:20 +05305032 osif_vdev_sync_op_stop(vdev_sync);
5033
5034 return errno;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005035}
Nirav Shahbf1b0332016-05-25 14:27:39 +05305036
5037/**
5038 * hdd_display_hif_stats() - display hif stats
5039 *
5040 * Return: none
5041 *
5042 */
5043void hdd_display_hif_stats(void)
5044{
5045 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
5046
5047 if (!hif_ctx)
5048 return;
Srinivas Girigowda557d2e42017-03-25 14:07:59 -07005049
Nirav Shahbf1b0332016-05-25 14:27:39 +05305050 hif_display_stats(hif_ctx);
5051}
5052
5053/**
5054 * hdd_clear_hif_stats() - clear hif stats
5055 *
5056 * Return: none
5057 */
5058void hdd_clear_hif_stats(void)
5059{
5060 void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
5061
5062 if (!hif_ctx)
5063 return;
5064 hif_clear_stats(hif_ctx);
5065}
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305066
5067/**
5068 * hdd_is_rcpi_applicable() - validates RCPI request
5069 * @adapter: adapter upon which the measurement is requested
5070 * @mac_addr: peer addr for which measurement is requested
5071 * @rcpi_value: pointer to where the RCPI should be returned
5072 * @reassoc: used to return cached RCPI during reassoc
5073 *
5074 * Return: true for success, false for failure
5075 */
5076
5077static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter,
5078 struct qdf_mac_addr *mac_addr,
5079 int32_t *rcpi_value,
5080 bool *reassoc)
5081{
5082 struct hdd_station_ctx *hdd_sta_ctx;
5083
5084 if (adapter->device_mode == QDF_STA_MODE ||
5085 adapter->device_mode == QDF_P2P_CLIENT_MODE) {
5086 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsone7951512019-02-27 10:02:51 -08005087 if (hdd_sta_ctx->conn_info.conn_state !=
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305088 eConnectionState_Associated)
5089 return false;
5090
5091 if (hdd_sta_ctx->hdd_reassoc_scenario) {
5092 /* return the cached rcpi, if mac addr matches */
5093 hdd_debug("Roaming in progress, return cached RCPI");
5094 if (!qdf_mem_cmp(&adapter->rcpi.mac_addr,
5095 mac_addr, sizeof(*mac_addr))) {
5096 *rcpi_value = adapter->rcpi.rcpi;
5097 *reassoc = true;
5098 return true;
5099 }
5100 return false;
5101 }
5102
Jeff Johnsone04b6992019-02-27 14:06:55 -08005103 if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssid,
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305104 sizeof(*mac_addr))) {
5105 hdd_err("mac addr is different from bssid connected");
5106 return false;
5107 }
5108 } else if (adapter->device_mode == QDF_SAP_MODE ||
5109 adapter->device_mode == QDF_P2P_GO_MODE) {
5110 if (!test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) {
5111 hdd_err("Invalid rcpi request, softap not started");
5112 return false;
5113 }
5114
5115 /* check if peer mac addr is associated to softap */
5116 if (!hdd_is_peer_associated(adapter, mac_addr)) {
5117 hdd_err("invalid peer mac-addr: not associated");
5118 return false;
5119 }
5120 } else {
5121 hdd_err("Invalid rcpi request");
5122 return false;
5123 }
5124
5125 *reassoc = false;
5126 return true;
5127}
5128
5129/**
5130 * wlan_hdd_get_rcpi_cb() - callback function for rcpi response
5131 * @context: Pointer to rcpi context
5132 * @rcpi_req: Pointer to rcpi response
5133 *
5134 * Return: None
5135 */
5136static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr,
5137 int32_t rcpi, QDF_STATUS status)
5138{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005139 struct osif_request *request;
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305140 struct rcpi_info *priv;
5141
5142 if (!context) {
5143 hdd_err("No rcpi context");
5144 return;
5145 }
5146
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005147 request = osif_request_get(context);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305148 if (!request) {
5149 hdd_err("Obsolete RCPI request");
5150 return;
5151 }
5152
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005153 priv = osif_request_priv(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305154 priv->mac_addr = mac_addr;
5155
5156 if (!QDF_IS_STATUS_SUCCESS(status)) {
5157 priv->rcpi = 0;
5158 hdd_err("Error in computing RCPI");
5159 } else {
5160 priv->rcpi = rcpi;
5161 }
5162
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005163 osif_request_complete(request);
5164 osif_request_put(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305165}
5166
5167/**
Dustin Brown96b98dd2019-03-06 12:39:37 -08005168 * wlan_hdd_get_rcpi() - local function to get RCPI
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305169 * @adapter: adapter upon which the measurement is requested
5170 * @mac: peer addr for which measurement is requested
5171 * @rcpi_value: pointer to where the RCPI should be returned
5172 * @measurement_type: type of rcpi measurement
5173 *
5174 * Return: 0 for success, non-zero for failure
5175 */
Dustin Brown96b98dd2019-03-06 12:39:37 -08005176int wlan_hdd_get_rcpi(struct hdd_adapter *adapter,
5177 uint8_t *mac,
5178 int32_t *rcpi_value,
5179 enum rcpi_measurement_type measurement_type)
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305180{
5181 struct hdd_context *hdd_ctx;
5182 int status = 0, ret = 0;
5183 struct qdf_mac_addr mac_addr;
5184 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
5185 struct sme_rcpi_req *rcpi_req;
5186 void *cookie;
5187 struct rcpi_info *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005188 struct osif_request *request;
5189 static const struct osif_request_params params = {
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305190 .priv_size = sizeof(*priv),
5191 .timeout_ms = WLAN_WAIT_TIME_RCPI,
5192 };
5193 bool reassoc;
5194
Dustin Brown491d54b2018-03-14 12:39:11 -07005195 hdd_enter();
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305196
5197 /* initialize the rcpi value to zero, useful in error cases */
5198 *rcpi_value = 0;
5199
5200 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
5201 hdd_err("Command not allowed in FTM mode");
5202 return -EINVAL;
5203 }
5204
5205 if (!adapter) {
5206 hdd_warn("adapter context is NULL");
5207 return -EINVAL;
5208 }
5209
5210 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5211 status = wlan_hdd_validate_context(hdd_ctx);
5212 if (status)
5213 return -EINVAL;
5214
5215 if (!hdd_ctx->rcpi_enabled) {
5216 hdd_debug("RCPI not supported");
5217 return -EINVAL;
5218 }
5219
5220 if (!mac) {
5221 hdd_warn("RCPI peer mac-addr is NULL");
5222 return -EINVAL;
5223 }
5224
5225 qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE);
5226
5227 if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc))
5228 return -EINVAL;
5229 if (reassoc)
5230 return 0;
5231
5232 rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
Min Liu74a1a502018-10-10 19:59:07 +08005233 if (!rcpi_req)
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305234 return -EINVAL;
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305235
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005236 request = osif_request_alloc(&params);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305237 if (!request) {
5238 hdd_err("Request allocation failure");
5239 qdf_mem_free(rcpi_req);
5240 return -ENOMEM;
5241 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005242 cookie = osif_request_cookie(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305243
5244 rcpi_req->mac_addr = mac_addr;
Jeff Johnson1abc5662019-02-04 14:27:02 -08005245 rcpi_req->session_id = adapter->vdev_id;
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305246 rcpi_req->measurement_type = measurement_type;
5247 rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb;
5248 rcpi_req->rcpi_context = cookie;
5249
Jeff Johnson003f7392018-06-12 20:45:47 -07005250 qdf_status = sme_get_rcpi(hdd_ctx->mac_handle, rcpi_req);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305251 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
5252 hdd_err("Unable to retrieve RCPI");
5253 status = qdf_status_to_os_return(qdf_status);
5254 goto out;
5255 }
5256
5257 /* request was sent -- wait for the response */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005258 ret = osif_request_wait_for_response(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305259 if (ret) {
5260 hdd_err("SME timed out while retrieving RCPI");
5261 status = -EINVAL;
5262 goto out;
5263 }
5264
5265 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005266 priv = osif_request_priv(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305267 adapter->rcpi.mac_addr = priv->mac_addr;
5268 adapter->rcpi.rcpi = priv->rcpi;
5269 if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) {
5270 hdd_err("mis match of mac addr from call-back");
5271 status = -EINVAL;
5272 goto out;
5273 }
5274
5275 *rcpi_value = adapter->rcpi.rcpi;
5276 hdd_debug("RCPI = %d", *rcpi_value);
5277out:
5278 qdf_mem_free(rcpi_req);
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005279 osif_request_put(request);
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305280
Dustin Browne74003f2018-03-14 12:51:58 -07005281 hdd_exit();
Rajeev Kumar Sirasanagandla996e5292016-11-22 21:20:33 +05305282 return status;
5283}
5284
tinlin9abd17f2019-08-14 13:29:44 +08005285#ifdef WLAN_FEATURE_MIB_STATS
5286QDF_STATUS wlan_hdd_get_mib_stats(struct hdd_adapter *adapter)
5287{
5288 int ret = 0;
5289 struct stats_event *stats;
5290
5291 if (!adapter) {
5292 hdd_err("Invalid context, adapter");
5293 return QDF_STATUS_E_FAULT;
5294 }
5295
5296 stats = wlan_cfg80211_mc_cp_stats_get_mib_stats(
5297 adapter->vdev,
5298 &ret);
5299 if (ret || !stats) {
5300 wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
5301 return ret;
5302 }
5303
5304 hdd_debugfs_process_mib_stats(adapter, stats);
5305
5306 wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
5307 return ret;
5308}
5309#endif
5310
Yu Wangc0b46f82018-03-09 16:04:15 +08005311QDF_STATUS wlan_hdd_get_rssi(struct hdd_adapter *adapter, int8_t *rssi_value)
5312{
Arif Hussain8b54a032018-08-03 14:37:01 -07005313 int ret = 0, i;
Yu Wangc0b46f82018-03-09 16:04:15 +08005314 struct hdd_station_ctx *sta_ctx;
Arif Hussain8b54a032018-08-03 14:37:01 -07005315 struct stats_event *rssi_info;
Yu Wangc0b46f82018-03-09 16:04:15 +08005316
Jeff Johnsond36fa332019-03-18 13:42:25 -07005317 if (!adapter) {
Yu Wangc0b46f82018-03-09 16:04:15 +08005318 hdd_err("Invalid context, adapter");
5319 return QDF_STATUS_E_FAULT;
5320 }
5321 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
5322 hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
5323 cds_get_driver_state());
5324 /* return a cached value */
5325 *rssi_value = adapter->rssi;
5326 return QDF_STATUS_SUCCESS;
5327 }
5328
5329 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5330
Jeff Johnsone7951512019-02-27 10:02:51 -08005331 if (eConnectionState_Associated != sta_ctx->conn_info.conn_state) {
Yu Wangc0b46f82018-03-09 16:04:15 +08005332 hdd_debug("Not associated!, rssi on disconnect %d",
5333 adapter->rssi_on_disconnect);
5334 *rssi_value = adapter->rssi_on_disconnect;
5335 return QDF_STATUS_SUCCESS;
5336 }
5337
5338 if (sta_ctx->hdd_reassoc_scenario) {
5339 hdd_debug("Roaming in progress, return cached RSSI");
5340 *rssi_value = adapter->rssi;
5341 return QDF_STATUS_SUCCESS;
5342 }
5343
Arif Hussain8b54a032018-08-03 14:37:01 -07005344 rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi(
Dustin Brown89fa06e2018-09-07 10:47:27 -07005345 adapter->vdev,
Jeff Johnsone04b6992019-02-27 14:06:55 -08005346 sta_ctx->conn_info.bssid.bytes,
Arif Hussain8b54a032018-08-03 14:37:01 -07005347 &ret);
5348 if (ret || !rssi_info) {
5349 wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
Yu Wangc0b46f82018-03-09 16:04:15 +08005350 return ret;
5351 }
5352
Arif Hussain8b54a032018-08-03 14:37:01 -07005353 for (i = 0; i < rssi_info->num_peer_stats; i++) {
5354 if (!qdf_mem_cmp(rssi_info->peer_stats[i].peer_macaddr,
Jeff Johnsone04b6992019-02-27 14:06:55 -08005355 sta_ctx->conn_info.bssid.bytes,
Srinivas Girigowdaa47b45f2019-02-27 12:29:02 -08005356 QDF_MAC_ADDR_SIZE)) {
Arif Hussain8b54a032018-08-03 14:37:01 -07005357 *rssi_value = rssi_info->peer_stats[i].peer_rssi;
Yu Wangc0b46f82018-03-09 16:04:15 +08005358 hdd_debug("RSSI = %d", *rssi_value);
Arif Hussain8b54a032018-08-03 14:37:01 -07005359 wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
Yu Wangc0b46f82018-03-09 16:04:15 +08005360 return QDF_STATUS_SUCCESS;
5361 }
5362 }
5363
Arif Hussain8b54a032018-08-03 14:37:01 -07005364 wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
Yu Wangc0b46f82018-03-09 16:04:15 +08005365 hdd_err("bss peer not present in returned result");
5366 return QDF_STATUS_E_FAULT;
5367}
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005368
5369struct snr_priv {
5370 int8_t snr;
5371};
5372
5373/**
5374 * hdd_get_snr_cb() - "Get SNR" callback function
5375 * @snr: Current SNR of the station
5376 * @sta_id: ID of the station
5377 * @context: opaque context originally passed to SME. HDD always passes
5378 * a cookie for the request context
5379 *
5380 * Return: None
5381 */
Sourav Mohapatra05a52ed2019-08-06 16:07:05 +05305382static void hdd_get_snr_cb(int8_t snr, void *context)
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005383{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005384 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005385 struct snr_priv *priv;
5386
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005387 request = osif_request_get(context);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005388 if (!request) {
5389 hdd_err("Obsolete request");
5390 return;
5391 }
5392
5393 /* propagate response back to requesting thread */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005394 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005395 priv->snr = snr;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005396 osif_request_complete(request);
5397 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005398}
5399
5400QDF_STATUS wlan_hdd_get_snr(struct hdd_adapter *adapter, int8_t *snr)
5401{
5402 struct hdd_context *hdd_ctx;
5403 struct hdd_station_ctx *sta_ctx;
Jeff Johnson003f7392018-06-12 20:45:47 -07005404 QDF_STATUS status;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005405 int ret;
5406 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005407 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005408 struct snr_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005409 static const struct osif_request_params params = {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005410 .priv_size = sizeof(*priv),
5411 .timeout_ms = WLAN_WAIT_TIME_STATS,
5412 };
5413
5414 hdd_enter();
5415
Jeff Johnsond36fa332019-03-18 13:42:25 -07005416 if (!adapter) {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005417 hdd_err("Invalid context, adapter");
5418 return QDF_STATUS_E_FAULT;
5419 }
5420
5421 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5422
Jeff Johnson003f7392018-06-12 20:45:47 -07005423 ret = wlan_hdd_validate_context(hdd_ctx);
5424 if (ret)
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005425 return QDF_STATUS_E_FAULT;
5426
5427 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5428
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005429 request = osif_request_alloc(&params);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005430 if (!request) {
5431 hdd_err("Request allocation failure");
5432 return QDF_STATUS_E_FAULT;
5433 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005434 cookie = osif_request_cookie(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005435
Jeff Johnson003f7392018-06-12 20:45:47 -07005436 status = sme_get_snr(hdd_ctx->mac_handle, hdd_get_snr_cb,
Jeff Johnsone04b6992019-02-27 14:06:55 -08005437 sta_ctx->conn_info.bssid, cookie);
Jeff Johnson003f7392018-06-12 20:45:47 -07005438 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005439 hdd_err("Unable to retrieve RSSI");
5440 /* we'll returned a cached value below */
5441 } else {
5442 /* request was sent -- wait for the response */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005443 ret = osif_request_wait_for_response(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005444 if (ret) {
5445 hdd_err("SME timed out while retrieving SNR");
5446 /* we'll now returned a cached value below */
5447 } else {
5448 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005449 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005450 adapter->snr = priv->snr;
5451 }
5452 }
5453
5454 /*
5455 * either we never sent a request, we sent a request and
5456 * received a response or we sent a request and timed out.
5457 * regardless we are done with the request.
5458 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005459 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005460
5461 *snr = adapter->snr;
5462 hdd_exit();
5463 return QDF_STATUS_SUCCESS;
5464}
5465
5466struct linkspeed_priv {
Jeff Johnsone943bca2019-02-08 22:45:17 -08005467 struct link_speed_info linkspeed_info;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005468};
5469
5470static void
Jeff Johnsone943bca2019-02-08 22:45:17 -08005471hdd_get_link_speed_cb(struct link_speed_info *linkspeed_info, void *context)
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005472{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005473 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005474 struct linkspeed_priv *priv;
5475
5476 if (!linkspeed_info) {
5477 hdd_err("NULL linkspeed");
5478 return;
5479 }
5480
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005481 request = osif_request_get(context);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005482 if (!request) {
5483 hdd_err("Obsolete request");
5484 return;
5485 }
5486
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005487 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005488 priv->linkspeed_info = *linkspeed_info;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005489 osif_request_complete(request);
5490 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005491}
5492
5493int wlan_hdd_get_linkspeed_for_peermac(struct hdd_adapter *adapter,
5494 struct qdf_mac_addr *mac_address,
5495 uint32_t *linkspeed)
5496{
5497 int ret;
5498 QDF_STATUS status;
5499 void *cookie;
Jeff Johnsone943bca2019-02-08 22:45:17 -08005500 struct link_speed_info *linkspeed_info;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005501 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005502 struct linkspeed_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005503 static const struct osif_request_params params = {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005504 .priv_size = sizeof(*priv),
5505 .timeout_ms = WLAN_WAIT_TIME_STATS,
5506 };
5507
5508 if ((!adapter) || (!linkspeed)) {
5509 hdd_err("NULL argument");
5510 return -EINVAL;
5511 }
5512
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005513 request = osif_request_alloc(&params);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005514 if (!request) {
5515 hdd_err("Request allocation failure");
5516 ret = -ENOMEM;
5517 goto return_cached_value;
5518 }
5519
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005520 cookie = osif_request_cookie(request);
5521 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005522
5523 linkspeed_info = &priv->linkspeed_info;
5524 qdf_copy_macaddr(&linkspeed_info->peer_macaddr, mac_address);
Jeff Johnson003f7392018-06-12 20:45:47 -07005525 status = sme_get_link_speed(adapter->hdd_ctx->mac_handle,
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005526 linkspeed_info,
5527 cookie, hdd_get_link_speed_cb);
5528 if (QDF_IS_STATUS_ERROR(status)) {
5529 hdd_err("Unable to retrieve statistics for link speed");
5530 ret = qdf_status_to_os_return(status);
5531 goto cleanup;
5532 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005533 ret = osif_request_wait_for_response(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005534 if (ret) {
5535 hdd_err("SME timed out while retrieving link speed");
5536 goto cleanup;
5537 }
5538 adapter->estimated_linkspeed = linkspeed_info->estLinkSpeed;
5539
5540cleanup:
5541 /*
5542 * either we never sent a request, we sent a request and
5543 * received a response or we sent a request and timed out.
5544 * regardless we are done with the request.
5545 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005546 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005547
5548return_cached_value:
5549 *linkspeed = adapter->estimated_linkspeed;
5550
5551 return ret;
5552}
5553
5554int wlan_hdd_get_link_speed(struct hdd_adapter *adapter, uint32_t *link_speed)
5555{
5556 struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter);
5557 struct hdd_station_ctx *hdd_stactx =
5558 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5559 int ret;
5560
5561 ret = wlan_hdd_validate_context(hddctx);
5562 if (ret)
5563 return ret;
5564
5565 /* Linkspeed is allowed only for P2P mode */
5566 if (adapter->device_mode != QDF_P2P_CLIENT_MODE) {
5567 hdd_err("Link Speed is not allowed in Device mode %s(%d)",
Dustin Brown458027c2018-10-19 12:26:27 -07005568 qdf_opmode_str(adapter->device_mode),
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005569 adapter->device_mode);
5570 return -ENOTSUPP;
5571 }
5572
Jeff Johnsone7951512019-02-27 10:02:51 -08005573 if (eConnectionState_Associated != hdd_stactx->conn_info.conn_state) {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005574 /* we are not connected so we don't have a classAstats */
5575 *link_speed = 0;
5576 } else {
5577 struct qdf_mac_addr bssid;
5578
Jeff Johnsone04b6992019-02-27 14:06:55 -08005579 qdf_copy_macaddr(&bssid, &hdd_stactx->conn_info.bssid);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005580
5581 ret = wlan_hdd_get_linkspeed_for_peermac(adapter, &bssid,
5582 link_speed);
5583 if (ret) {
5584 hdd_err("Unable to retrieve SME linkspeed");
5585 return ret;
5586 }
5587 /* linkspeed in units of 500 kbps */
5588 *link_speed = (*link_speed) / 500;
5589 }
5590 return 0;
5591}
5592
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005593struct peer_info_priv {
5594 struct sir_peer_sta_ext_info peer_sta_ext_info;
5595};
5596
5597/**
5598 * wlan_hdd_get_peer_info_cb() - get peer info callback
5599 * @sta_info: pointer of peer information
5600 * @context: get peer info callback context
5601 *
5602 * This function will fill stats info to peer info priv
5603 *
5604 */
5605static void wlan_hdd_get_peer_info_cb(struct sir_peer_info_ext_resp *sta_info,
5606 void *context)
5607{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005608 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005609 struct peer_info_priv *priv;
5610 uint8_t sta_num;
5611
5612 if ((!sta_info) || (!context)) {
5613 hdd_err("Bad param, sta_info [%pK] context [%pK]",
5614 sta_info, context);
5615 return;
5616 }
5617
5618 if (!sta_info->count) {
5619 hdd_err("Fail to get remote peer info");
5620 return;
5621 }
5622
5623 if (sta_info->count > MAX_PEER_STA) {
5624 hdd_warn("Exceed max peer number %d", sta_info->count);
5625 sta_num = MAX_PEER_STA;
5626 } else {
5627 sta_num = sta_info->count;
5628 }
5629
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005630 request = osif_request_get(context);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005631 if (!request) {
5632 hdd_err("Obsolete request");
5633 return;
5634 }
5635
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005636 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005637
5638 priv->peer_sta_ext_info.sta_num = sta_num;
5639 qdf_mem_copy(&priv->peer_sta_ext_info.info,
5640 sta_info->info,
5641 sta_num * sizeof(sta_info->info[0]));
5642
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005643 osif_request_complete(request);
5644 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005645}
5646
5647int wlan_hdd_get_peer_info(struct hdd_adapter *adapter,
5648 struct qdf_mac_addr macaddress,
5649 struct sir_peer_info_ext *peer_info_ext)
5650{
5651 QDF_STATUS status;
5652 void *cookie;
5653 int ret;
5654 struct sir_peer_info_ext_req peer_info_req;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005655 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005656 struct peer_info_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005657 static const struct osif_request_params params = {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005658 .priv_size = sizeof(*priv),
5659 .timeout_ms = WLAN_WAIT_TIME_STATS,
5660 };
5661
5662 if (!adapter) {
5663 hdd_err("adapter is NULL");
5664 return -EFAULT;
5665 }
5666
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005667 request = osif_request_alloc(&params);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005668 if (!request) {
5669 hdd_err("Request allocation failure");
5670 return -ENOMEM;
5671 }
5672
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005673 cookie = osif_request_cookie(request);
5674 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005675
5676 qdf_mem_copy(&peer_info_req.peer_macaddr, &macaddress,
5677 QDF_MAC_ADDR_SIZE);
Jeff Johnson1abc5662019-02-04 14:27:02 -08005678 peer_info_req.sessionid = adapter->vdev_id;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005679 peer_info_req.reset_after_request = 0;
Jeff Johnson003f7392018-06-12 20:45:47 -07005680 status = sme_get_peer_info_ext(adapter->hdd_ctx->mac_handle,
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005681 &peer_info_req,
5682 cookie,
5683 wlan_hdd_get_peer_info_cb);
5684 if (status != QDF_STATUS_SUCCESS) {
5685 hdd_err("Unable to retrieve statistics for peer info");
5686 ret = -EFAULT;
5687 } else {
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005688 ret = osif_request_wait_for_response(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005689 if (ret) {
5690 hdd_err("SME timed out while retrieving peer info");
5691 ret = -EFAULT;
5692 } else {
5693 /* only support one peer by now */
5694 *peer_info_ext = priv->peer_sta_ext_info.info[0];
5695 ret = 0;
5696 }
5697 }
5698
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005699 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005700
5701 return ret;
5702}
5703
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005704int wlan_hdd_get_station_stats(struct hdd_adapter *adapter)
5705{
Arif Hussain8b54a032018-08-03 14:37:01 -07005706 int ret = 0;
Arif Hussain8b54a032018-08-03 14:37:01 -07005707 struct stats_event *stats;
Sourav Mohapatra1600c7a2019-11-04 09:06:53 +05305708 struct wlan_mlme_nss_chains *dynamic_cfg;
5709 uint32_t tx_nss, rx_nss;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005710
Dustin Brown89fa06e2018-09-07 10:47:27 -07005711 stats = wlan_cfg80211_mc_cp_stats_get_station_stats(adapter->vdev,
Arif Hussain8b54a032018-08-03 14:37:01 -07005712 &ret);
5713 if (ret || !stats) {
5714 wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
5715 return ret;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005716 }
5717
5718 /* save summary stats to legacy location */
5719 qdf_mem_copy(adapter->hdd_stats.summary_stat.retry_cnt,
Arif Hussain8b54a032018-08-03 14:37:01 -07005720 stats->vdev_summary_stats[0].stats.retry_cnt,
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005721 sizeof(adapter->hdd_stats.summary_stat.retry_cnt));
5722 qdf_mem_copy(adapter->hdd_stats.summary_stat.multiple_retry_cnt,
Arif Hussain8b54a032018-08-03 14:37:01 -07005723 stats->vdev_summary_stats[0].stats.multiple_retry_cnt,
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005724 sizeof(adapter->hdd_stats.summary_stat.multiple_retry_cnt));
5725 qdf_mem_copy(adapter->hdd_stats.summary_stat.tx_frm_cnt,
Arif Hussain8b54a032018-08-03 14:37:01 -07005726 stats->vdev_summary_stats[0].stats.tx_frm_cnt,
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005727 sizeof(adapter->hdd_stats.summary_stat.tx_frm_cnt));
5728 qdf_mem_copy(adapter->hdd_stats.summary_stat.fail_cnt,
Arif Hussain8b54a032018-08-03 14:37:01 -07005729 stats->vdev_summary_stats[0].stats.fail_cnt,
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005730 sizeof(adapter->hdd_stats.summary_stat.fail_cnt));
5731 adapter->hdd_stats.summary_stat.snr =
Arif Hussain8b54a032018-08-03 14:37:01 -07005732 stats->vdev_summary_stats[0].stats.snr;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005733 adapter->hdd_stats.summary_stat.rssi =
Arif Hussain8b54a032018-08-03 14:37:01 -07005734 stats->vdev_summary_stats[0].stats.rssi;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005735 adapter->hdd_stats.summary_stat.rx_frm_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005736 stats->vdev_summary_stats[0].stats.rx_frm_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005737 adapter->hdd_stats.summary_stat.frm_dup_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005738 stats->vdev_summary_stats[0].stats.frm_dup_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005739 adapter->hdd_stats.summary_stat.rts_fail_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005740 stats->vdev_summary_stats[0].stats.rts_fail_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005741 adapter->hdd_stats.summary_stat.ack_fail_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005742 stats->vdev_summary_stats[0].stats.ack_fail_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005743 adapter->hdd_stats.summary_stat.rts_succ_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005744 stats->vdev_summary_stats[0].stats.rts_succ_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005745 adapter->hdd_stats.summary_stat.rx_discard_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005746 stats->vdev_summary_stats[0].stats.rx_discard_cnt;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005747 adapter->hdd_stats.summary_stat.rx_error_cnt =
Arif Hussain8b54a032018-08-03 14:37:01 -07005748 stats->vdev_summary_stats[0].stats.rx_error_cnt;
Sourav Mohapatra9c398f02018-09-03 11:10:37 +05305749 adapter->hdd_stats.peer_stats.rx_count =
5750 stats->peer_adv_stats->rx_count;
5751 adapter->hdd_stats.peer_stats.rx_bytes =
5752 stats->peer_adv_stats->rx_bytes;
5753 adapter->hdd_stats.peer_stats.fcs_count =
5754 stats->peer_adv_stats->fcs_count;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005755
Sourav Mohapatra1600c7a2019-11-04 09:06:53 +05305756 dynamic_cfg = mlme_get_dynamic_vdev_config(adapter->vdev);
5757 if (!dynamic_cfg) {
5758 hdd_err("nss chain dynamic config NULL");
5759 return -EINVAL;
5760 }
5761
5762 switch (hdd_conn_get_connected_band(&adapter->session.station)) {
5763 case BAND_2G:
5764 tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ];
5765 rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ];
5766 break;
5767 case BAND_5G:
5768 tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ];
5769 rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ];
5770 break;
5771 default:
5772 tx_nss = wlan_vdev_mlme_get_nss(adapter->vdev);
5773 rx_nss = wlan_vdev_mlme_get_nss(adapter->vdev);
5774 }
5775
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005776 /* save class a stats to legacy location */
Sourav Mohapatra1600c7a2019-11-04 09:06:53 +05305777 adapter->hdd_stats.class_a_stat.tx_nss = tx_nss;
5778 adapter->hdd_stats.class_a_stat.rx_nss = rx_nss;
Arif Hussain8b54a032018-08-03 14:37:01 -07005779 adapter->hdd_stats.class_a_stat.tx_rate = stats->tx_rate;
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05305780 adapter->hdd_stats.class_a_stat.rx_rate = stats->rx_rate;
5781 adapter->hdd_stats.class_a_stat.tx_rx_rate_flags = stats->tx_rate_flags;
5782 adapter->hdd_stats.class_a_stat.tx_mcs_index =
Sourav Mohapatrad204a812019-01-09 09:45:08 +05305783 sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags,
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05305784 &adapter->hdd_stats.class_a_stat.tx_nss,
Jingxiang Gef1d81592019-10-20 12:03:22 +08005785 &adapter->hdd_stats.class_a_stat.tx_dcm,
5786 &adapter->hdd_stats.class_a_stat.tx_gi,
5787 &adapter->hdd_stats.class_a_stat.
5788 tx_mcs_rate_flags);
5789
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05305790 adapter->hdd_stats.class_a_stat.rx_mcs_index =
Sourav Mohapatrad204a812019-01-09 09:45:08 +05305791 sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags,
Sourav Mohapatra49ce4ce2018-08-07 18:08:51 +05305792 &adapter->hdd_stats.class_a_stat.rx_nss,
Jingxiang Gef1d81592019-10-20 12:03:22 +08005793 &adapter->hdd_stats.class_a_stat.rx_dcm,
5794 &adapter->hdd_stats.class_a_stat.rx_gi,
5795 &adapter->hdd_stats.class_a_stat.
5796 rx_mcs_rate_flags);
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005797
5798 /* save per chain rssi to legacy location */
5799 qdf_mem_copy(adapter->hdd_stats.per_chain_rssi_stats.rssi,
Arif Hussain8b54a032018-08-03 14:37:01 -07005800 stats->vdev_chain_rssi[0].chain_rssi,
5801 sizeof(stats->vdev_chain_rssi[0].chain_rssi));
5802 wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005803
Arif Hussain8b54a032018-08-03 14:37:01 -07005804 return 0;
Naveen Rawatfa2a1002018-05-17 16:06:37 -07005805}
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005806
5807struct temperature_priv {
5808 int temperature;
5809};
5810
5811/**
5812 * hdd_get_temperature_cb() - "Get Temperature" callback function
5813 * @temperature: measured temperature
5814 * @context: callback context
5815 *
5816 * This function is passed to sme_get_temperature() as the callback
5817 * function to be invoked when the temperature measurement is
5818 * available.
5819 *
5820 * Return: None
5821 */
5822static void hdd_get_temperature_cb(int temperature, void *context)
5823{
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005824 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005825 struct temperature_priv *priv;
5826
5827 hdd_enter();
5828
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005829 request = osif_request_get(context);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005830 if (!request) {
5831 hdd_err("Obsolete request");
5832 return;
5833 }
5834
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005835 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005836 priv->temperature = temperature;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005837 osif_request_complete(request);
5838 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005839 hdd_exit();
5840}
5841
5842int wlan_hdd_get_temperature(struct hdd_adapter *adapter, int *temperature)
5843{
5844 QDF_STATUS status;
5845 int ret;
5846 void *cookie;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005847 struct osif_request *request;
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005848 struct temperature_priv *priv;
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005849 static const struct osif_request_params params = {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005850 .priv_size = sizeof(*priv),
5851 .timeout_ms = WLAN_WAIT_TIME_STATS,
5852 };
5853
5854 hdd_enter();
Jeff Johnsond36fa332019-03-18 13:42:25 -07005855 if (!adapter) {
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005856 hdd_err("adapter is NULL");
5857 return -EPERM;
5858 }
5859
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005860 request = osif_request_alloc(&params);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005861 if (!request) {
5862 hdd_err("Request allocation failure");
5863 return -ENOMEM;
5864 }
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005865 cookie = osif_request_cookie(request);
Jeff Johnson003f7392018-06-12 20:45:47 -07005866 status = sme_get_temperature(adapter->hdd_ctx->mac_handle, cookie,
5867 hdd_get_temperature_cb);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005868 if (QDF_STATUS_SUCCESS != status) {
5869 hdd_err("Unable to retrieve temperature");
5870 } else {
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005871 ret = osif_request_wait_for_response(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005872 if (ret) {
5873 hdd_err("SME timed out while retrieving temperature");
5874 } else {
5875 /* update the adapter with the fresh results */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005876 priv = osif_request_priv(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005877 if (priv->temperature)
5878 adapter->temperature = priv->temperature;
5879 }
5880 }
5881
5882 /*
5883 * either we never sent a request, we sent a request and
5884 * received a response or we sent a request and timed out.
5885 * regardless we are done with the request.
5886 */
Jeff Johnsonf1a99ea2018-06-28 13:27:01 -07005887 osif_request_put(request);
Jeff Johnson5fe539b2018-03-23 13:53:30 -07005888
5889 *temperature = adapter->temperature;
5890 hdd_exit();
5891 return 0;
5892}
Mohit Khanna70322002018-05-15 19:21:32 -07005893
Mohit Khanna81418772018-10-30 14:14:46 -07005894void wlan_hdd_display_txrx_stats(struct hdd_context *ctx)
Mohit Khanna70322002018-05-15 19:21:32 -07005895{
5896 struct hdd_adapter *adapter = NULL;
5897 struct hdd_tx_rx_stats *stats;
5898 int i = 0;
5899 uint32_t total_rx_pkt, total_rx_dropped,
5900 total_rx_delv, total_rx_refused;
5901
Mohit Khanna81418772018-10-30 14:14:46 -07005902 hdd_for_each_adapter(ctx, adapter) {
Mohit Khanna70322002018-05-15 19:21:32 -07005903 total_rx_pkt = 0;
5904 total_rx_dropped = 0;
5905 total_rx_delv = 0;
5906 total_rx_refused = 0;
5907 stats = &adapter->hdd_stats.tx_rx_stats;
Mohit Khannaf0620ce2019-07-28 21:31:05 -07005908
5909 if (adapter->vdev_id == INVAL_VDEV_ID)
5910 continue;
5911
Jeff Johnson1abc5662019-02-04 14:27:02 -08005912 hdd_debug("adapter: %u", adapter->vdev_id);
Mohit Khanna70322002018-05-15 19:21:32 -07005913 for (; i < NUM_CPUS; i++) {
5914 total_rx_pkt += stats->rx_packets[i];
5915 total_rx_dropped += stats->rx_dropped[i];
5916 total_rx_delv += stats->rx_delivered[i];
5917 total_rx_refused += stats->rx_refused[i];
5918 }
5919
Mohit Khanna81418772018-10-30 14:14:46 -07005920 hdd_debug("TX - called %u, dropped %u orphan %u",
Mohit Khannab8ccd6e2018-08-31 18:03:39 -07005921 stats->tx_called, stats->tx_dropped,
5922 stats->tx_orphaned);
Mohit Khanna70322002018-05-15 19:21:32 -07005923
5924 for (i = 0; i < NUM_CPUS; i++) {
5925 if (stats->rx_packets[i] == 0)
5926 continue;
Mohit Khannab8ccd6e2018-08-31 18:03:39 -07005927 hdd_debug("Rx CPU[%d]: packets %u, dropped %u, delivered %u, refused %u",
5928 i, stats->rx_packets[i], stats->rx_dropped[i],
5929 stats->rx_delivered[i], stats->rx_refused[i]);
Mohit Khanna70322002018-05-15 19:21:32 -07005930 }
Jinwei Chen0dc383e2019-08-23 00:43:04 +08005931 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 -08005932 total_rx_pkt, total_rx_dropped,
5933 qdf_atomic_read(&stats->rx_usolict_arp_n_mcast_drp),
5934 total_rx_delv,
Mohit Khanna81418772018-10-30 14:14:46 -07005935 total_rx_refused, stats->rx_aggregated,
Manjunathappa Prakash78b6a882019-03-28 19:59:23 -07005936 stats->rx_gro_dropped, stats->rx_non_aggregated,
Jinwei Chenb681a482019-08-14 15:24:06 +08005937 stats->rx_gro_flush_skip,
Jinwei Chen0dc383e2019-08-23 00:43:04 +08005938 stats->rx_gro_low_tput_flush,
Mohit Khanna81418772018-10-30 14:14:46 -07005939 qdf_atomic_read(&ctx->disable_rx_ol_in_concurrency),
5940 qdf_atomic_read(&ctx->disable_rx_ol_in_low_tput));
Mohit Khanna70322002018-05-15 19:21:32 -07005941 }
5942}
Ashish Kumar Dhanotiya017e5022019-07-23 20:58:11 +05305943
Hangtian Zhucf89c862019-08-28 10:48:52 +08005944#ifdef QCA_SUPPORT_CP_STATS
Ashish Kumar Dhanotiya017e5022019-07-23 20:58:11 +05305945/**
5946 * hdd_lost_link_cp_stats_info_cb() - callback function to get lost
5947 * link information
5948 * @stats_ev: Stats event pointer
5949 * FW sends vdev stats on vdev down, this callback is registered
5950 * with cp_stats component to get the last available vdev stats
5951 * From the FW.
5952 *
5953 * Return: None
5954 */
5955
5956static void hdd_lost_link_cp_stats_info_cb(void *stats_ev)
5957{
5958 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
5959 struct hdd_adapter *adapter;
5960 struct stats_event *ev = stats_ev;
5961 uint8_t i;
5962 struct hdd_station_ctx *sta_ctx;
5963
5964 if (wlan_hdd_validate_context(hdd_ctx))
5965 return;
5966
5967 for (i = 0; i < ev->num_summary_stats; i++) {
5968 adapter = hdd_get_adapter_by_vdev(
5969 hdd_ctx,
5970 ev->vdev_summary_stats[i].vdev_id);
5971 if (!adapter) {
5972 hdd_debug("invalid adapter");
5973 continue;
5974 }
5975 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
5976 if ((sta_ctx) &&
5977 (eConnectionState_Associated !=
5978 sta_ctx->conn_info.conn_state)) {
5979 adapter->rssi_on_disconnect =
5980 ev->vdev_summary_stats[i].stats.rssi;
5981 hdd_debug("rssi on disconnect %d for " QDF_MAC_ADDR_STR,
5982 adapter->rssi_on_disconnect,
5983 QDF_MAC_ADDR_ARRAY(adapter->mac_addr.bytes));
5984 }
5985 }
5986}
5987
5988void wlan_hdd_register_cp_stats_cb(struct hdd_context *hdd_ctx)
5989{
5990 ucfg_mc_cp_stats_register_lost_link_info_cb(
5991 hdd_ctx->psoc,
5992 hdd_lost_link_cp_stats_info_cb);
5993}
Hangtian Zhucf89c862019-08-28 10:48:52 +08005994#endif
Ashish Kumar Dhanotiya017e5022019-07-23 20:58:11 +05305995