xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /**
21*5113495bSYour Name  * DOC: wlan_hdd_stats.c
22*5113495bSYour Name  *
23*5113495bSYour Name  * WLAN Host Device Driver statistics related implementation
24*5113495bSYour Name  *
25*5113495bSYour Name  */
26*5113495bSYour Name 
27*5113495bSYour Name #include "wlan_hdd_stats.h"
28*5113495bSYour Name #include "sme_api.h"
29*5113495bSYour Name #include "cds_sched.h"
30*5113495bSYour Name #include "osif_sync.h"
31*5113495bSYour Name #include "wlan_hdd_trace.h"
32*5113495bSYour Name #include "wlan_hdd_lpass.h"
33*5113495bSYour Name #include "hif.h"
34*5113495bSYour Name #include <qca_vendor.h>
35*5113495bSYour Name #include "wma_api.h"
36*5113495bSYour Name #include "wlan_hdd_hostapd.h"
37*5113495bSYour Name #include "wlan_osif_request_manager.h"
38*5113495bSYour Name #include "wlan_hdd_debugfs_llstat.h"
39*5113495bSYour Name #include "wlan_hdd_debugfs_mibstat.h"
40*5113495bSYour Name #include "wlan_reg_services_api.h"
41*5113495bSYour Name #include <wlan_cfg80211_mc_cp_stats.h>
42*5113495bSYour Name #include "wlan_cp_stats_mc_ucfg_api.h"
43*5113495bSYour Name #include "wlan_mlme_ucfg_api.h"
44*5113495bSYour Name #include "wlan_mlme_ucfg_api.h"
45*5113495bSYour Name #include "wlan_hdd_sta_info.h"
46*5113495bSYour Name #include "cdp_txrx_misc.h"
47*5113495bSYour Name #include "cdp_txrx_host_stats.h"
48*5113495bSYour Name #include "wlan_hdd_object_manager.h"
49*5113495bSYour Name #include "wlan_hdd_eht.h"
50*5113495bSYour Name #include "wlan_dp_ucfg_api.h"
51*5113495bSYour Name #include "wlan_cm_roam_ucfg_api.h"
52*5113495bSYour Name #include <wlan_cp_stats_chipset_stats.h>
53*5113495bSYour Name #include <wlan_cp_stats_ucfg_api.h>
54*5113495bSYour Name #ifdef CNSS_GENL
55*5113495bSYour Name #ifdef CONFIG_CNSS_OUT_OF_TREE
56*5113495bSYour Name #include "cnss_nl.h"
57*5113495bSYour Name #else
58*5113495bSYour Name #include <net/cnss_nl.h>
59*5113495bSYour Name #endif
60*5113495bSYour Name #endif
61*5113495bSYour Name #include "wlan_nan_api.h"
62*5113495bSYour Name 
63*5113495bSYour Name #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
64*5113495bSYour Name #define HDD_INFO_SIGNAL                 STATION_INFO_SIGNAL
65*5113495bSYour Name #define HDD_INFO_SIGNAL_AVG             STATION_INFO_SIGNAL_AVG
66*5113495bSYour Name #define HDD_INFO_TX_PACKETS             STATION_INFO_TX_PACKETS
67*5113495bSYour Name #define HDD_INFO_TX_RETRIES             STATION_INFO_TX_RETRIES
68*5113495bSYour Name #define HDD_INFO_TX_FAILED              STATION_INFO_TX_FAILED
69*5113495bSYour Name #define HDD_INFO_TX_BITRATE             STATION_INFO_TX_BITRATE
70*5113495bSYour Name #define HDD_INFO_RX_BITRATE             STATION_INFO_RX_BITRATE
71*5113495bSYour Name #define HDD_INFO_TX_BYTES               STATION_INFO_TX_BYTES
72*5113495bSYour Name #define HDD_INFO_CHAIN_SIGNAL_AVG       STATION_INFO_CHAIN_SIGNAL_AVG
73*5113495bSYour Name #define HDD_INFO_EXPECTED_THROUGHPUT    0
74*5113495bSYour Name #define HDD_INFO_RX_BYTES               STATION_INFO_RX_BYTES
75*5113495bSYour Name #define HDD_INFO_RX_PACKETS             STATION_INFO_RX_PACKETS
76*5113495bSYour Name #define HDD_INFO_TX_BYTES64             0
77*5113495bSYour Name #define HDD_INFO_RX_BYTES64             0
78*5113495bSYour Name #define HDD_INFO_INACTIVE_TIME          0
79*5113495bSYour Name #define HDD_INFO_CONNECTED_TIME         0
80*5113495bSYour Name #define HDD_INFO_STA_FLAGS              0
81*5113495bSYour Name #define HDD_INFO_RX_MPDUS               0
82*5113495bSYour Name #define HDD_INFO_FCS_ERROR_COUNT        0
83*5113495bSYour Name #else
84*5113495bSYour Name #define HDD_INFO_SIGNAL                 BIT(NL80211_STA_INFO_SIGNAL)
85*5113495bSYour Name #define HDD_INFO_SIGNAL_AVG             BIT(NL80211_STA_INFO_SIGNAL_AVG)
86*5113495bSYour Name #define HDD_INFO_TX_PACKETS             BIT(NL80211_STA_INFO_TX_PACKETS)
87*5113495bSYour Name #define HDD_INFO_TX_RETRIES             BIT(NL80211_STA_INFO_TX_RETRIES)
88*5113495bSYour Name #define HDD_INFO_TX_FAILED              BIT(NL80211_STA_INFO_TX_FAILED)
89*5113495bSYour Name #define HDD_INFO_TX_BITRATE             BIT(NL80211_STA_INFO_TX_BITRATE)
90*5113495bSYour Name #define HDD_INFO_RX_BITRATE             BIT(NL80211_STA_INFO_RX_BITRATE)
91*5113495bSYour Name #define HDD_INFO_TX_BYTES               BIT(NL80211_STA_INFO_TX_BYTES)
92*5113495bSYour Name #define HDD_INFO_CHAIN_SIGNAL_AVG       BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)
93*5113495bSYour Name #define HDD_INFO_EXPECTED_THROUGHPUT  BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)
94*5113495bSYour Name #define HDD_INFO_RX_BYTES               BIT(NL80211_STA_INFO_RX_BYTES)
95*5113495bSYour Name #define HDD_INFO_RX_PACKETS             BIT(NL80211_STA_INFO_RX_PACKETS)
96*5113495bSYour Name #define HDD_INFO_TX_BYTES64             BIT(NL80211_STA_INFO_TX_BYTES64)
97*5113495bSYour Name #define HDD_INFO_RX_BYTES64             BIT(NL80211_STA_INFO_RX_BYTES64)
98*5113495bSYour Name #define HDD_INFO_INACTIVE_TIME          BIT(NL80211_STA_INFO_INACTIVE_TIME)
99*5113495bSYour Name #define HDD_INFO_CONNECTED_TIME         BIT(NL80211_STA_INFO_CONNECTED_TIME)
100*5113495bSYour Name #define HDD_INFO_STA_FLAGS              BIT(NL80211_STA_INFO_STA_FLAGS)
101*5113495bSYour Name #define HDD_INFO_RX_MPDUS             BIT_ULL(NL80211_STA_INFO_RX_MPDUS)
102*5113495bSYour Name #define HDD_INFO_FCS_ERROR_COUNT      BIT_ULL(NL80211_STA_INFO_FCS_ERROR_COUNT)
103*5113495bSYour Name #endif /* kernel version less than 4.0.0 && no_backport */
104*5113495bSYour Name 
105*5113495bSYour Name #define HDD_LINK_STATS_MAX		5
106*5113495bSYour Name #define HDD_MAX_ALLOWED_LL_STATS_FAILURE	5
107*5113495bSYour Name 
108*5113495bSYour Name #define INVALID_PREAMBLE 0xFF
109*5113495bSYour Name 
110*5113495bSYour Name #define MAX_RSSI_MCS_INDEX 14
111*5113495bSYour Name 
112*5113495bSYour Name #define MAX_HT_MCS_INDEX 7
113*5113495bSYour Name 
114*5113495bSYour Name /* 11B, 11G Rate table include Basic rate and Extended rate
115*5113495bSYour Name  * The IDX field is the rate index
116*5113495bSYour Name  * The HI field is the rate when RSSI is strong or being ignored
117*5113495bSYour Name  *  (in this case we report actual rate)
118*5113495bSYour Name  * The MID field is the rate when RSSI is moderate
119*5113495bSYour Name  * (in this case we cap 11b rates at 5.5 and 11g rates at 24)
120*5113495bSYour Name  * The LO field is the rate when RSSI is low
121*5113495bSYour Name  *  (in this case we don't report rates, actual current rate used)
122*5113495bSYour Name  */
123*5113495bSYour Name static const struct index_data_rate_type supported_data_rate[] = {
124*5113495bSYour Name 	/* IDX     HI  HM  LM LO (RSSI-based index */
125*5113495bSYour Name 	{2,   { 10,  10, 10, 0} },
126*5113495bSYour Name 	{4,   { 20,  20, 10, 0} },
127*5113495bSYour Name 	{11,  { 55,  20, 10, 0} },
128*5113495bSYour Name 	{12,  { 60,  55, 20, 0} },
129*5113495bSYour Name 	{18,  { 90,  55, 20, 0} },
130*5113495bSYour Name 	{22,  {110,  55, 20, 0} },
131*5113495bSYour Name 	{24,  {120,  90, 60, 0} },
132*5113495bSYour Name 	{36,  {180, 120, 60, 0} },
133*5113495bSYour Name 	{44,  {220, 180, 60, 0} },
134*5113495bSYour Name 	{48,  {240, 180, 90, 0} },
135*5113495bSYour Name 	{66,  {330, 180, 90, 0} },
136*5113495bSYour Name 	{72,  {360, 240, 90, 0} },
137*5113495bSYour Name 	{96,  {480, 240, 120, 0} },
138*5113495bSYour Name 	{108, {540, 240, 120, 0} }
139*5113495bSYour Name };
140*5113495bSYour Name /* MCS Based rate table HT MCS parameters with Nss = 1 */
141*5113495bSYour Name static const struct index_data_rate_type supported_mcs_rate_nss1[] = {
142*5113495bSYour Name /* MCS  L20   L40   S20  S40 */
143*5113495bSYour Name 	{0, {65, 135, 72, 150} },
144*5113495bSYour Name 	{1, {130, 270, 144, 300} },
145*5113495bSYour Name 	{2, {195, 405, 217, 450} },
146*5113495bSYour Name 	{3, {260, 540, 289, 600} },
147*5113495bSYour Name 	{4, {390, 810, 433, 900} },
148*5113495bSYour Name 	{5, {520, 1080, 578, 1200} },
149*5113495bSYour Name 	{6, {585, 1215, 650, 1350} },
150*5113495bSYour Name 	{7, {650, 1350, 722, 1500} }
151*5113495bSYour Name };
152*5113495bSYour Name 
153*5113495bSYour Name /* HT MCS parameters with Nss = 2 */
154*5113495bSYour Name static const struct index_data_rate_type supported_mcs_rate_nss2[] = {
155*5113495bSYour Name /* MCS  L20    L40   S20   S40 */
156*5113495bSYour Name 	{0, {130, 270, 144, 300} },
157*5113495bSYour Name 	{1, {260, 540, 289, 600} },
158*5113495bSYour Name 	{2, {390, 810, 433, 900} },
159*5113495bSYour Name 	{3, {520, 1080, 578, 1200} },
160*5113495bSYour Name 	{4, {780, 1620, 867, 1800} },
161*5113495bSYour Name 	{5, {1040, 2160, 1156, 2400} },
162*5113495bSYour Name 	{6, {1170, 2430, 1300, 2700} },
163*5113495bSYour Name 	{7, {1300, 2700, 1444, 3000} }
164*5113495bSYour Name };
165*5113495bSYour Name 
166*5113495bSYour Name /* MCS Based VHT rate table MCS parameters with Nss = 1*/
167*5113495bSYour Name static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
168*5113495bSYour Name /* MCS  L80    S80     L40   S40    L20   S40*/
169*5113495bSYour Name 	{0, {293, 325}, {135, 150}, {65, 72} },
170*5113495bSYour Name 	{1, {585, 650}, {270, 300}, {130, 144} },
171*5113495bSYour Name 	{2, {878, 975}, {405, 450}, {195, 217} },
172*5113495bSYour Name 	{3, {1170, 1300}, {540, 600}, {260, 289} },
173*5113495bSYour Name 	{4, {1755, 1950}, {810, 900}, {390, 433} },
174*5113495bSYour Name 	{5, {2340, 2600}, {1080, 1200}, {520, 578} },
175*5113495bSYour Name 	{6, {2633, 2925}, {1215, 1350}, {585, 650} },
176*5113495bSYour Name 	{7, {2925, 3250}, {1350, 1500}, {650, 722} },
177*5113495bSYour Name 	{8, {3510, 3900}, {1620, 1800}, {780, 867} },
178*5113495bSYour Name 	{9, {3900, 4333}, {1800, 2000}, {780, 867} },
179*5113495bSYour Name 	{10, {4388, 4875}, {2025, 2250}, {975, 1083} },
180*5113495bSYour Name 	{11, {4875, 5417}, {2250, 2500}, {1083, 1203} }
181*5113495bSYour Name };
182*5113495bSYour Name 
183*5113495bSYour Name /*MCS parameters with Nss = 2*/
184*5113495bSYour Name static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
185*5113495bSYour Name /* MCS  L80    S80     L40   S40    L20   S40*/
186*5113495bSYour Name 	{0, {585, 650}, {270, 300}, {130, 144} },
187*5113495bSYour Name 	{1, {1170, 1300}, {540, 600}, {260, 289} },
188*5113495bSYour Name 	{2, {1755, 1950}, {810, 900}, {390, 433} },
189*5113495bSYour Name 	{3, {2340, 2600}, {1080, 1200}, {520, 578} },
190*5113495bSYour Name 	{4, {3510, 3900}, {1620, 1800}, {780, 867} },
191*5113495bSYour Name 	{5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
192*5113495bSYour Name 	{6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
193*5113495bSYour Name 	{7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
194*5113495bSYour Name 	{8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
195*5113495bSYour Name 	{9, {7800, 8667}, {3600, 4000}, {1730, 1920} },
196*5113495bSYour Name 	{10, {8775, 9750}, {4050, 4500}, {1950, 2167} },
197*5113495bSYour Name 	{11, {9750, 10833}, {4500, 5000}, {2167, 2407} }
198*5113495bSYour Name };
199*5113495bSYour Name 
200*5113495bSYour Name /*array index points to MCS and array value points respective rssi*/
201*5113495bSYour Name static int rssi_mcs_tbl[][MAX_RSSI_MCS_INDEX] = {
202*5113495bSYour Name /*  MCS 0   1    2   3    4    5    6    7    8    9    10   11   12   13*/
203*5113495bSYour Name 	/* 20 */
204*5113495bSYour Name 	{-82, -79, -77, -74, -70, -66, -65, -64, -59, -57, -52, -48, -46, -42},
205*5113495bSYour Name 	/* 40 */
206*5113495bSYour Name 	{-79, -76, -74, -71, -67, -63, -62, -61, -56, -54, -49, -45, -43, -39},
207*5113495bSYour Name 	/* 80 */
208*5113495bSYour Name 	{-76, -73, -71, -68, -64, -60, -59, -58, -53, -51, -46, -42, -46, -36}
209*5113495bSYour Name };
210*5113495bSYour Name 
211*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)212*5113495bSYour Name static bool wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)
213*5113495bSYour Name {
214*5113495bSYour Name 	if (he_mcs_12_13_map)
215*5113495bSYour Name 		return true;
216*5113495bSYour Name 	else
217*5113495bSYour Name 		return false;
218*5113495bSYour Name }
219*5113495bSYour Name #else
wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)220*5113495bSYour Name static bool wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map)
221*5113495bSYour Name {
222*5113495bSYour Name 	return false;
223*5113495bSYour Name }
224*5113495bSYour Name #endif
225*5113495bSYour Name 
226*5113495bSYour Name static bool get_station_fw_request_needed = true;
227*5113495bSYour Name 
228*5113495bSYour Name /*
229*5113495bSYour Name  * copy_station_stats_to_adapter() - Copy station stats to adapter
230*5113495bSYour Name  * @link_info: Pointer to link_info in adapter
231*5113495bSYour Name  * @stats: Pointer to the station stats event
232*5113495bSYour Name  *
233*5113495bSYour Name  * Return: 0 if success, non-zero for failure
234*5113495bSYour Name  */
copy_station_stats_to_adapter(struct wlan_hdd_link_info * link_info,struct stats_event * stats)235*5113495bSYour Name static int copy_station_stats_to_adapter(struct wlan_hdd_link_info *link_info,
236*5113495bSYour Name 					 struct stats_event *stats)
237*5113495bSYour Name {
238*5113495bSYour Name 	int ret = 0;
239*5113495bSYour Name 	struct wlan_mlme_nss_chains *dynamic_cfg;
240*5113495bSYour Name 	uint32_t tx_nss, rx_nss;
241*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
242*5113495bSYour Name 	uint16_t he_mcs_12_13_map;
243*5113495bSYour Name 	bool is_he_mcs_12_13_supported;
244*5113495bSYour Name 	struct hdd_stats *hdd_stats;
245*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
246*5113495bSYour Name 
247*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
248*5113495bSYour Name 	if (!vdev)
249*5113495bSYour Name 		return -EINVAL;
250*5113495bSYour Name 
251*5113495bSYour Name 	hdd_stats = &link_info->hdd_stats;
252*5113495bSYour Name 	/* save summary stats to legacy location */
253*5113495bSYour Name 	qdf_mem_copy(hdd_stats->summary_stat.retry_cnt,
254*5113495bSYour Name 		     stats->vdev_summary_stats[0].stats.retry_cnt,
255*5113495bSYour Name 		     sizeof(hdd_stats->summary_stat.retry_cnt));
256*5113495bSYour Name 	qdf_mem_copy(hdd_stats->summary_stat.multiple_retry_cnt,
257*5113495bSYour Name 		     stats->vdev_summary_stats[0].stats.multiple_retry_cnt,
258*5113495bSYour Name 		     sizeof(hdd_stats->summary_stat.multiple_retry_cnt));
259*5113495bSYour Name 	qdf_mem_copy(hdd_stats->summary_stat.tx_frm_cnt,
260*5113495bSYour Name 		     stats->vdev_summary_stats[0].stats.tx_frm_cnt,
261*5113495bSYour Name 		     sizeof(hdd_stats->summary_stat.tx_frm_cnt));
262*5113495bSYour Name 	qdf_mem_copy(hdd_stats->summary_stat.fail_cnt,
263*5113495bSYour Name 		     stats->vdev_summary_stats[0].stats.fail_cnt,
264*5113495bSYour Name 		     sizeof(hdd_stats->summary_stat.fail_cnt));
265*5113495bSYour Name 	hdd_stats->summary_stat.snr = stats->vdev_summary_stats[0].stats.snr;
266*5113495bSYour Name 	hdd_stats->summary_stat.rssi = stats->vdev_summary_stats[0].stats.rssi;
267*5113495bSYour Name 	hdd_stats->summary_stat.rx_frm_cnt =
268*5113495bSYour Name 			stats->vdev_summary_stats[0].stats.rx_frm_cnt;
269*5113495bSYour Name 	hdd_stats->summary_stat.frm_dup_cnt =
270*5113495bSYour Name 			stats->vdev_summary_stats[0].stats.frm_dup_cnt;
271*5113495bSYour Name 	hdd_stats->summary_stat.rts_fail_cnt =
272*5113495bSYour Name 			stats->vdev_summary_stats[0].stats.rts_fail_cnt;
273*5113495bSYour Name 	hdd_stats->summary_stat.ack_fail_cnt =
274*5113495bSYour Name 			stats->vdev_summary_stats[0].stats.ack_fail_cnt;
275*5113495bSYour Name 	hdd_stats->summary_stat.rts_succ_cnt =
276*5113495bSYour Name 			stats->vdev_summary_stats[0].stats.rts_succ_cnt;
277*5113495bSYour Name 	hdd_stats->summary_stat.rx_discard_cnt =
278*5113495bSYour Name 			stats->vdev_summary_stats[0].stats.rx_discard_cnt;
279*5113495bSYour Name 	hdd_stats->summary_stat.rx_error_cnt =
280*5113495bSYour Name 			stats->vdev_summary_stats[0].stats.rx_error_cnt;
281*5113495bSYour Name 	hdd_stats->peer_stats.rx_count = stats->peer_adv_stats->rx_count;
282*5113495bSYour Name 	hdd_stats->peer_stats.rx_bytes = stats->peer_adv_stats->rx_bytes;
283*5113495bSYour Name 	hdd_stats->peer_stats.fcs_count = stats->peer_adv_stats->fcs_count;
284*5113495bSYour Name 	adapter->tx_power.tx_pwr = stats->pdev_stats->max_pwr;
285*5113495bSYour Name 	adapter->tx_power.tx_pwr_cached_timestamp =
286*5113495bSYour Name 			qdf_system_ticks_to_msecs(qdf_system_ticks());
287*5113495bSYour Name 	/* Copy vdev status info sent by FW */
288*5113495bSYour Name 	if (stats->vdev_extd_stats)
289*5113495bSYour Name 		link_info->is_mlo_vdev_active =
290*5113495bSYour Name 			stats->vdev_extd_stats[0].is_mlo_vdev_active;
291*5113495bSYour Name 
292*5113495bSYour Name 	dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
293*5113495bSYour Name 	if (!dynamic_cfg) {
294*5113495bSYour Name 		hdd_err("nss chain dynamic config NULL");
295*5113495bSYour Name 		ret = -EINVAL;
296*5113495bSYour Name 		goto out;
297*5113495bSYour Name 	}
298*5113495bSYour Name 
299*5113495bSYour Name 	switch (hdd_conn_get_connected_band(link_info)) {
300*5113495bSYour Name 	case BAND_2G:
301*5113495bSYour Name 		tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ];
302*5113495bSYour Name 		rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ];
303*5113495bSYour Name 		break;
304*5113495bSYour Name 	case BAND_5G:
305*5113495bSYour Name 		tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ];
306*5113495bSYour Name 		rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ];
307*5113495bSYour Name 		break;
308*5113495bSYour Name 	default:
309*5113495bSYour Name 		tx_nss = wlan_vdev_mlme_get_nss(vdev);
310*5113495bSYour Name 		rx_nss = wlan_vdev_mlme_get_nss(vdev);
311*5113495bSYour Name 	}
312*5113495bSYour Name 
313*5113495bSYour Name 	/* Intersection of self and AP's NSS capability */
314*5113495bSYour Name 	if (tx_nss > wlan_vdev_mlme_get_nss(vdev))
315*5113495bSYour Name 		tx_nss = wlan_vdev_mlme_get_nss(vdev);
316*5113495bSYour Name 
317*5113495bSYour Name 	if (rx_nss > wlan_vdev_mlme_get_nss(vdev))
318*5113495bSYour Name 		rx_nss = wlan_vdev_mlme_get_nss(vdev);
319*5113495bSYour Name 
320*5113495bSYour Name 	/* save class a stats to legacy location */
321*5113495bSYour Name 	hdd_stats->class_a_stat.tx_nss = tx_nss;
322*5113495bSYour Name 	hdd_stats->class_a_stat.rx_nss = rx_nss;
323*5113495bSYour Name 	hdd_stats->class_a_stat.tx_rate = stats->tx_rate;
324*5113495bSYour Name 	hdd_stats->class_a_stat.rx_rate = stats->rx_rate;
325*5113495bSYour Name 	hdd_stats->class_a_stat.tx_rx_rate_flags = stats->tx_rate_flags;
326*5113495bSYour Name 
327*5113495bSYour Name 	he_mcs_12_13_map = wlan_vdev_mlme_get_he_mcs_12_13_map(vdev);
328*5113495bSYour Name 	is_he_mcs_12_13_supported =
329*5113495bSYour Name 			wlan_hdd_is_he_mcs_12_13_supported(he_mcs_12_13_map);
330*5113495bSYour Name 	hdd_stats->class_a_stat.tx_mcs_index =
331*5113495bSYour Name 		sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags,
332*5113495bSYour Name 				is_he_mcs_12_13_supported,
333*5113495bSYour Name 				&hdd_stats->class_a_stat.tx_nss,
334*5113495bSYour Name 				&hdd_stats->class_a_stat.tx_dcm,
335*5113495bSYour Name 				&hdd_stats->class_a_stat.tx_gi,
336*5113495bSYour Name 				&hdd_stats->class_a_stat.tx_mcs_rate_flags);
337*5113495bSYour Name 	hdd_stats->class_a_stat.rx_mcs_index =
338*5113495bSYour Name 		sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags,
339*5113495bSYour Name 				is_he_mcs_12_13_supported,
340*5113495bSYour Name 				&hdd_stats->class_a_stat.rx_nss,
341*5113495bSYour Name 				&hdd_stats->class_a_stat.rx_dcm,
342*5113495bSYour Name 				&hdd_stats->class_a_stat.rx_gi,
343*5113495bSYour Name 				&hdd_stats->class_a_stat.rx_mcs_rate_flags);
344*5113495bSYour Name 
345*5113495bSYour Name 	/* save per chain rssi to legacy location */
346*5113495bSYour Name 	qdf_mem_copy(hdd_stats->per_chain_rssi_stats.rssi,
347*5113495bSYour Name 		     stats->vdev_chain_rssi[0].chain_rssi,
348*5113495bSYour Name 		     sizeof(stats->vdev_chain_rssi[0].chain_rssi));
349*5113495bSYour Name 	hdd_stats->bcn_protect_stats = stats->bcn_protect_stats;
350*5113495bSYour Name out:
351*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
352*5113495bSYour Name 	return ret;
353*5113495bSYour Name }
354*5113495bSYour Name 
355*5113495bSYour Name #ifdef WLAN_FEATURE_BIG_DATA_STATS
356*5113495bSYour Name /*
357*5113495bSYour Name  * copy_station_big_data_stats_to_adapter() - Copy big data stats to adapter
358*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter.
359*5113495bSYour Name  * @stats: Pointer to the big data stats event
360*5113495bSYour Name  *
361*5113495bSYour Name  * Return: 0 if success, non-zero for failure
362*5113495bSYour Name  */
363*5113495bSYour Name static void
copy_station_big_data_stats_to_adapter(struct wlan_hdd_link_info * link_info,struct big_data_stats_event * stats)364*5113495bSYour Name copy_station_big_data_stats_to_adapter(struct wlan_hdd_link_info *link_info,
365*5113495bSYour Name 				       struct big_data_stats_event *stats)
366*5113495bSYour Name {
367*5113495bSYour Name 	struct big_data_stats_event *big_data_stats =
368*5113495bSYour Name 						&link_info->big_data_stats;
369*5113495bSYour Name 
370*5113495bSYour Name 	big_data_stats->vdev_id = stats->vdev_id;
371*5113495bSYour Name 	big_data_stats->tsf_out_of_sync = stats->tsf_out_of_sync;
372*5113495bSYour Name 	big_data_stats->ani_level = stats->ani_level;
373*5113495bSYour Name 	big_data_stats->last_data_tx_pwr = stats->last_data_tx_pwr;
374*5113495bSYour Name 	big_data_stats->target_power_dsss = stats->target_power_dsss;
375*5113495bSYour Name 	big_data_stats->target_power_ofdm = stats->target_power_ofdm;
376*5113495bSYour Name 	big_data_stats->last_tx_data_rix = stats->last_tx_data_rix;
377*5113495bSYour Name 	big_data_stats->last_tx_data_rate_kbps = stats->last_tx_data_rate_kbps;
378*5113495bSYour Name }
379*5113495bSYour Name #endif
380*5113495bSYour Name 
381*5113495bSYour Name #ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
382*5113495bSYour Name static void
hdd_update_station_stats_cached_timestamp(struct hdd_adapter * adapter)383*5113495bSYour Name hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter)
384*5113495bSYour Name {
385*5113495bSYour Name 	adapter->sta_stats_cached_timestamp =
386*5113495bSYour Name 				qdf_system_ticks_to_msecs(qdf_system_ticks());
387*5113495bSYour Name }
388*5113495bSYour Name #else
389*5113495bSYour Name static void
hdd_update_station_stats_cached_timestamp(struct hdd_adapter * adapter)390*5113495bSYour Name hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter)
391*5113495bSYour Name {
392*5113495bSYour Name }
393*5113495bSYour Name #endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
394*5113495bSYour Name 
395*5113495bSYour Name #ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI
396*5113495bSYour Name /**
397*5113495bSYour Name  * wlan_hdd_qmi_get_sync_resume() - Get operation to trigger RTPM
398*5113495bSYour Name  * sync resume without WoW exit
399*5113495bSYour Name  *
400*5113495bSYour Name  * call qmi_get before sending qmi, and do qmi_put after all the
401*5113495bSYour Name  * qmi response rececived from fw. so this request wlan host to
402*5113495bSYour Name  * wait for the last qmi response, if it doesn't wait, qmi put
403*5113495bSYour Name  * which cause MHI enter M3(suspend) before all the qmi response,
404*5113495bSYour Name  * and MHI will trigger a RTPM resume, this violated design of by
405*5113495bSYour Name  * sending cmd by qmi without wow resume.
406*5113495bSYour Name  *
407*5113495bSYour Name  * Returns: 0 for success, non-zero for failure
408*5113495bSYour Name  */
wlan_hdd_qmi_get_sync_resume(void)409*5113495bSYour Name int wlan_hdd_qmi_get_sync_resume(void)
410*5113495bSYour Name {
411*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
412*5113495bSYour Name 	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
413*5113495bSYour Name 
414*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx))
415*5113495bSYour Name 		return -EINVAL;
416*5113495bSYour Name 
417*5113495bSYour Name 	if (!hdd_ctx->config->is_qmi_stats_enabled) {
418*5113495bSYour Name 		hdd_debug("periodic stats over qmi is disabled");
419*5113495bSYour Name 		return 0;
420*5113495bSYour Name 	}
421*5113495bSYour Name 
422*5113495bSYour Name 	if (!qdf_ctx) {
423*5113495bSYour Name 		hdd_err("qdf_ctx is null");
424*5113495bSYour Name 		return -EINVAL;
425*5113495bSYour Name 	}
426*5113495bSYour Name 
427*5113495bSYour Name 	return pld_qmi_send_get(qdf_ctx->dev);
428*5113495bSYour Name }
429*5113495bSYour Name 
430*5113495bSYour Name /**
431*5113495bSYour Name  * wlan_hdd_qmi_put_suspend() - Put operation to trigger RTPM suspend
432*5113495bSYour Name  * without WoW entry
433*5113495bSYour Name  *
434*5113495bSYour Name  * Returns: 0 for success, non-zero for failure
435*5113495bSYour Name  */
wlan_hdd_qmi_put_suspend(void)436*5113495bSYour Name int wlan_hdd_qmi_put_suspend(void)
437*5113495bSYour Name {
438*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
439*5113495bSYour Name 	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
440*5113495bSYour Name 
441*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx))
442*5113495bSYour Name 		return -EINVAL;
443*5113495bSYour Name 
444*5113495bSYour Name 	if (!hdd_ctx->config->is_qmi_stats_enabled) {
445*5113495bSYour Name 		hdd_debug("periodic stats over qmi is disabled");
446*5113495bSYour Name 		return 0;
447*5113495bSYour Name 	}
448*5113495bSYour Name 
449*5113495bSYour Name 	if (!qdf_ctx) {
450*5113495bSYour Name 		hdd_err("qdf_ctx is null");
451*5113495bSYour Name 		return -EINVAL;
452*5113495bSYour Name 	}
453*5113495bSYour Name 
454*5113495bSYour Name 	return pld_qmi_send_put(qdf_ctx->dev);
455*5113495bSYour Name }
456*5113495bSYour Name #else
wlan_hdd_qmi_get_sync_resume(void)457*5113495bSYour Name int wlan_hdd_qmi_get_sync_resume(void)
458*5113495bSYour Name {
459*5113495bSYour Name 	return 0;
460*5113495bSYour Name }
461*5113495bSYour Name 
wlan_hdd_qmi_put_suspend(void)462*5113495bSYour Name int wlan_hdd_qmi_put_suspend(void)
463*5113495bSYour Name {
464*5113495bSYour Name 	return 0;
465*5113495bSYour Name }
466*5113495bSYour Name #endif /* end if of WLAN_FEATURE_WMI_SEND_RECV_QMI */
467*5113495bSYour Name 
468*5113495bSYour Name /*
469*5113495bSYour Name  * wlan_hdd_is_mlo_connection() - Check if connection is legacy or mlo
470*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
471*5113495bSYour Name  *
472*5113495bSYour Name  * Return: True if MLO connection, else False
473*5113495bSYour Name  */
wlan_hdd_is_mlo_connection(struct wlan_hdd_link_info * link_info)474*5113495bSYour Name static bool wlan_hdd_is_mlo_connection(struct wlan_hdd_link_info *link_info)
475*5113495bSYour Name {
476*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
477*5113495bSYour Name 	bool ret = false;
478*5113495bSYour Name 
479*5113495bSYour Name 	if (!link_info) {
480*5113495bSYour Name 		hdd_err("Invalid link_info");
481*5113495bSYour Name 		return ret;
482*5113495bSYour Name 	}
483*5113495bSYour Name 
484*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
485*5113495bSYour Name 	if (!vdev) {
486*5113495bSYour Name 		hdd_err("invalid vdev");
487*5113495bSYour Name 		return ret;
488*5113495bSYour Name 	}
489*5113495bSYour Name 
490*5113495bSYour Name 	if (wlan_vdev_mlme_is_mlo_vdev(vdev))
491*5113495bSYour Name 		ret = true;
492*5113495bSYour Name 
493*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
494*5113495bSYour Name 	return ret;
495*5113495bSYour Name }
496*5113495bSYour Name 
497*5113495bSYour Name static struct wlan_hdd_link_info *
hdd_get_link_info_by_bssid(struct hdd_context * hdd_ctx,const uint8_t * bssid)498*5113495bSYour Name hdd_get_link_info_by_bssid(struct hdd_context *hdd_ctx, const uint8_t *bssid)
499*5113495bSYour Name {
500*5113495bSYour Name 	struct hdd_adapter *adapter, *next_adapter = NULL;
501*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
502*5113495bSYour Name 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_BSSID;
503*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
504*5113495bSYour Name 
505*5113495bSYour Name 	if (qdf_is_macaddr_zero((struct qdf_mac_addr *)bssid))
506*5113495bSYour Name 		return NULL;
507*5113495bSYour Name 
508*5113495bSYour Name 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
509*5113495bSYour Name 					   dbgid) {
510*5113495bSYour Name 		hdd_adapter_for_each_link_info(adapter, link_info) {
511*5113495bSYour Name 			sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
512*5113495bSYour Name 			if (qdf_is_macaddr_equal((struct qdf_mac_addr *)bssid,
513*5113495bSYour Name 						 &sta_ctx->conn_info.bssid)) {
514*5113495bSYour Name 				hdd_adapter_dev_put_debug(adapter, dbgid);
515*5113495bSYour Name 				if (next_adapter)
516*5113495bSYour Name 					hdd_adapter_dev_put_debug(next_adapter,
517*5113495bSYour Name 								  dbgid);
518*5113495bSYour Name 				return link_info;
519*5113495bSYour Name 			}
520*5113495bSYour Name 		}
521*5113495bSYour Name 		hdd_adapter_dev_put_debug(adapter, dbgid);
522*5113495bSYour Name 	}
523*5113495bSYour Name 	return NULL;
524*5113495bSYour Name }
525*5113495bSYour Name 
526*5113495bSYour Name #define WLAN_INVALID_RSSI_VALUE -128
527*5113495bSYour Name #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
528*5113495bSYour Name /**
529*5113495bSYour Name  * wlan_hdd_is_per_link_stats_supported - Check if FW supports per link stats
530*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
531*5113495bSYour Name  *
532*5113495bSYour Name  * Return: true if FW supports, else False
533*5113495bSYour Name  */
534*5113495bSYour Name static bool
wlan_hdd_is_per_link_stats_supported(struct hdd_context * hdd_ctx)535*5113495bSYour Name wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
536*5113495bSYour Name {
537*5113495bSYour Name 	if (hdd_ctx->is_mlo_per_link_stats_supported)
538*5113495bSYour Name 		return true;
539*5113495bSYour Name 
540*5113495bSYour Name 	hdd_debug("mlo per link stats is not supported by FW");
541*5113495bSYour Name 	return false;
542*5113495bSYour Name }
543*5113495bSYour Name 
544*5113495bSYour Name /**
545*5113495bSYour Name  * wlan_hdd_get_bss_peer_mld_mac() - get bss peer mld mac address
546*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
547*5113495bSYour Name  * @mld_mac: pointer to mld mac address
548*5113495bSYour Name  *
549*5113495bSYour Name  * Return: QDF_STATUS
550*5113495bSYour Name  */
551*5113495bSYour Name static QDF_STATUS
wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info * link_info,struct qdf_mac_addr * mld_mac)552*5113495bSYour Name wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
553*5113495bSYour Name 			      struct qdf_mac_addr *mld_mac)
554*5113495bSYour Name {
555*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
556*5113495bSYour Name 	QDF_STATUS status;
557*5113495bSYour Name 
558*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info,
559*5113495bSYour Name 					   WLAN_OSIF_STATS_ID);
560*5113495bSYour Name 	if (!vdev)
561*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
562*5113495bSYour Name 
563*5113495bSYour Name 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
564*5113495bSYour Name 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
565*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
566*5113495bSYour Name 	}
567*5113495bSYour Name 
568*5113495bSYour Name 	status = wlan_vdev_get_bss_peer_mld_mac(vdev, mld_mac);
569*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
570*5113495bSYour Name 	return status;
571*5113495bSYour Name }
572*5113495bSYour Name 
573*5113495bSYour Name #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
574*5113495bSYour Name static bool
wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info * link_info)575*5113495bSYour Name wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
576*5113495bSYour Name {
577*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
578*5113495bSYour Name 	bool ret = false;
579*5113495bSYour Name 
580*5113495bSYour Name 	if (!link_info) {
581*5113495bSYour Name 		hdd_err_rl("Invalid link info");
582*5113495bSYour Name 		return ret;
583*5113495bSYour Name 	}
584*5113495bSYour Name 
585*5113495bSYour Name 	if (!wlan_hdd_is_mlo_connection(link_info))
586*5113495bSYour Name 		return ret;
587*5113495bSYour Name 
588*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
589*5113495bSYour Name 	if (!vdev) {
590*5113495bSYour Name 		hdd_err("invalid vdev");
591*5113495bSYour Name 		return ret;
592*5113495bSYour Name 	}
593*5113495bSYour Name 
594*5113495bSYour Name 	ret = mlo_mgr_is_link_switch_in_progress(vdev);
595*5113495bSYour Name 
596*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
597*5113495bSYour Name 	return ret;
598*5113495bSYour Name }
599*5113495bSYour Name #else
600*5113495bSYour Name static inline bool
wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info * link_info)601*5113495bSYour Name wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
602*5113495bSYour Name {
603*5113495bSYour Name 	return false;
604*5113495bSYour Name }
605*5113495bSYour Name #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
606*5113495bSYour Name 
607*5113495bSYour Name /**
608*5113495bSYour Name  * wlan_hdd_copy_sinfo_to_link_info() - Copy sinfo to link_info
609*5113495bSYour Name  * @link_info: Pointer to the hdd link info
610*5113495bSYour Name  * @sinfo: Pointer to kernel station info struct
611*5113495bSYour Name  *
612*5113495bSYour Name  * Return: none
613*5113495bSYour Name  */
614*5113495bSYour Name static void
wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)615*5113495bSYour Name wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info,
616*5113495bSYour Name 				 struct station_info *sinfo)
617*5113495bSYour Name {
618*5113495bSYour Name 	struct wlan_hdd_station_stats_info *hdd_sinfo;
619*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
620*5113495bSYour Name 	uint8_t i, *link_mac;
621*5113495bSYour Name 
622*5113495bSYour Name 	if (!wlan_hdd_is_mlo_connection(link_info))
623*5113495bSYour Name 		return;
624*5113495bSYour Name 
625*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
626*5113495bSYour Name 
627*5113495bSYour Name 	hdd_sinfo = &link_info->hdd_sinfo;
628*5113495bSYour Name 
629*5113495bSYour Name 	hdd_sinfo->signal = sinfo->signal;
630*5113495bSYour Name 	hdd_sinfo->signal_avg = sinfo->signal_avg;
631*5113495bSYour Name 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
632*5113495bSYour Name 		hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i];
633*5113495bSYour Name 
634*5113495bSYour Name 	qdf_mem_copy(&hdd_sinfo->txrate,
635*5113495bSYour Name 		     &sinfo->txrate, sizeof(sinfo->txrate));
636*5113495bSYour Name 
637*5113495bSYour Name 	qdf_mem_copy(&hdd_sinfo->rxrate,
638*5113495bSYour Name 		     &sinfo->rxrate, sizeof(sinfo->rxrate));
639*5113495bSYour Name 	hdd_sinfo->rx_bytes = sinfo->rx_bytes;
640*5113495bSYour Name 	hdd_sinfo->tx_bytes = sinfo->tx_bytes;
641*5113495bSYour Name 	hdd_sinfo->rx_packets = sinfo->rx_packets;
642*5113495bSYour Name 	hdd_sinfo->tx_packets = sinfo->tx_packets;
643*5113495bSYour Name 	hdd_sinfo->tx_retries = sinfo->tx_retries;
644*5113495bSYour Name 	hdd_sinfo->tx_failed = sinfo->tx_failed;
645*5113495bSYour Name 	hdd_sinfo->rx_mpdu_count = sinfo->rx_mpdu_count;
646*5113495bSYour Name 	hdd_sinfo->fcs_err_count = sinfo->fcs_err_count;
647*5113495bSYour Name 
648*5113495bSYour Name 	link_mac = sta_ctx->conn_info.bssid.bytes;
649*5113495bSYour Name 	hdd_nofl_debug("copied sinfo for " QDF_MAC_ADDR_FMT " into link_info",
650*5113495bSYour Name 		       QDF_MAC_ADDR_REF(link_mac));
651*5113495bSYour Name }
652*5113495bSYour Name 
653*5113495bSYour Name /**
654*5113495bSYour Name  * wlan_hdd_copy_hdd_stats_to_sinfo() - Copy hdd station stats info to sinfo
655*5113495bSYour Name  * @sinfo: Pointer to kernel station info struct
656*5113495bSYour Name  * @hdd_sinfo: Pointer to the hdd station stats info struct
657*5113495bSYour Name  *
658*5113495bSYour Name  * Return: none
659*5113495bSYour Name  */
660*5113495bSYour Name static void
wlan_hdd_copy_hdd_stats_to_sinfo(struct station_info * sinfo,struct wlan_hdd_station_stats_info * hdd_sinfo)661*5113495bSYour Name wlan_hdd_copy_hdd_stats_to_sinfo(struct station_info *sinfo,
662*5113495bSYour Name 				 struct wlan_hdd_station_stats_info *hdd_sinfo)
663*5113495bSYour Name {
664*5113495bSYour Name 	uint8_t i;
665*5113495bSYour Name 
666*5113495bSYour Name 	sinfo->signal = hdd_sinfo->signal;
667*5113495bSYour Name 	sinfo->signal_avg = hdd_sinfo->signal_avg;
668*5113495bSYour Name 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
669*5113495bSYour Name 		sinfo->chain_signal_avg[i] = hdd_sinfo->chain_signal_avg[i];
670*5113495bSYour Name 
671*5113495bSYour Name 	if (!hdd_sinfo->signal) {
672*5113495bSYour Name 		sinfo->signal = WLAN_INVALID_RSSI_VALUE;
673*5113495bSYour Name 		sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
674*5113495bSYour Name 		for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
675*5113495bSYour Name 			sinfo->chain_signal_avg[i] = WLAN_INVALID_RSSI_VALUE;
676*5113495bSYour Name 	}
677*5113495bSYour Name 
678*5113495bSYour Name 	qdf_mem_copy(&sinfo->txrate,
679*5113495bSYour Name 		     &hdd_sinfo->txrate, sizeof(sinfo->txrate));
680*5113495bSYour Name 
681*5113495bSYour Name 	qdf_mem_copy(&sinfo->rxrate,
682*5113495bSYour Name 		     &hdd_sinfo->rxrate, sizeof(sinfo->rxrate));
683*5113495bSYour Name 	sinfo->rx_bytes = hdd_sinfo->rx_bytes;
684*5113495bSYour Name 	sinfo->tx_bytes = hdd_sinfo->tx_bytes;
685*5113495bSYour Name 	sinfo->rx_packets = hdd_sinfo->rx_packets;
686*5113495bSYour Name 	sinfo->tx_packets = hdd_sinfo->tx_packets;
687*5113495bSYour Name 	sinfo->tx_retries = hdd_sinfo->tx_retries;
688*5113495bSYour Name 	sinfo->tx_failed = hdd_sinfo->tx_failed;
689*5113495bSYour Name 	sinfo->rx_mpdu_count = hdd_sinfo->rx_mpdu_count;
690*5113495bSYour Name 	sinfo->fcs_err_count = hdd_sinfo->fcs_err_count;
691*5113495bSYour Name }
692*5113495bSYour Name 
693*5113495bSYour Name /**
694*5113495bSYour Name  * wlan_hdd_update_sinfo() - Function to update station info structure
695*5113495bSYour Name  * @sinfo: kernel station_info to populate
696*5113495bSYour Name  * @link_info: Pointer to the hdd link info
697*5113495bSYour Name  *
698*5113495bSYour Name  * Return: None
699*5113495bSYour Name  */
wlan_hdd_update_sinfo(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)700*5113495bSYour Name static void wlan_hdd_update_sinfo(struct station_info *sinfo,
701*5113495bSYour Name 				  struct wlan_hdd_link_info *link_info)
702*5113495bSYour Name {
703*5113495bSYour Name 	uint8_t i;
704*5113495bSYour Name 
705*5113495bSYour Name 	if (!link_info) {
706*5113495bSYour Name 		hdd_err("Invalid link_info");
707*5113495bSYour Name 		return;
708*5113495bSYour Name 	}
709*5113495bSYour Name 
710*5113495bSYour Name 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &link_info->hdd_sinfo);
711*5113495bSYour Name 
712*5113495bSYour Name 	if (link_info->vdev_id == WLAN_INVALID_VDEV_ID) {
713*5113495bSYour Name 		sinfo->signal = WLAN_INVALID_RSSI_VALUE;
714*5113495bSYour Name 		sinfo->signal_avg = WLAN_INVALID_RSSI_VALUE;
715*5113495bSYour Name 		for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
716*5113495bSYour Name 			sinfo->chain_signal_avg[i] = WLAN_INVALID_RSSI_VALUE;
717*5113495bSYour Name 	}
718*5113495bSYour Name 
719*5113495bSYour Name 	sinfo->filled |= HDD_INFO_SIGNAL | HDD_INFO_SIGNAL_AVG |
720*5113495bSYour Name 			HDD_INFO_CHAIN_SIGNAL_AVG | HDD_INFO_TX_PACKETS |
721*5113495bSYour Name 			HDD_INFO_TX_RETRIES | HDD_INFO_TX_FAILED |
722*5113495bSYour Name 			HDD_INFO_TX_BITRATE | HDD_INFO_RX_BITRATE |
723*5113495bSYour Name 			HDD_INFO_TX_BYTES | HDD_INFO_RX_BYTES |
724*5113495bSYour Name 			HDD_INFO_RX_PACKETS | HDD_INFO_FCS_ERROR_COUNT |
725*5113495bSYour Name 			HDD_INFO_RX_MPDUS;
726*5113495bSYour Name }
727*5113495bSYour Name 
728*5113495bSYour Name static void
wlan_hdd_get_mlo_links_count(struct hdd_adapter * adapter,uint32_t * count)729*5113495bSYour Name wlan_hdd_get_mlo_links_count(struct hdd_adapter *adapter, uint32_t *count)
730*5113495bSYour Name {
731*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
732*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx = NULL;
733*5113495bSYour Name 	u32 num_links = 0;
734*5113495bSYour Name 
735*5113495bSYour Name 	hdd_adapter_for_each_link_info(adapter, link_info) {
736*5113495bSYour Name 		if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE ||
737*5113495bSYour Name 		    link_info->adapter->device_mode == QDF_STA_MODE) {
738*5113495bSYour Name 			sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
739*5113495bSYour Name 			if (sta_ctx->conn_info.ieee_link_id !=
740*5113495bSYour Name 			    WLAN_INVALID_LINK_ID) {
741*5113495bSYour Name 				num_links++;
742*5113495bSYour Name 			}
743*5113495bSYour Name 		} else if (link_info->adapter->device_mode == QDF_SAP_MODE ||
744*5113495bSYour Name 			   link_info->adapter->device_mode == QDF_P2P_GO_MODE) {
745*5113495bSYour Name 			if (test_bit(SOFTAP_BSS_STARTED,
746*5113495bSYour Name 				     &link_info->link_flags)) {
747*5113495bSYour Name 				num_links++;
748*5113495bSYour Name 			}
749*5113495bSYour Name 		}
750*5113495bSYour Name 	}
751*5113495bSYour Name 
752*5113495bSYour Name 	*count = num_links;
753*5113495bSYour Name }
754*5113495bSYour Name 
755*5113495bSYour Name #else
756*5113495bSYour Name static inline bool
wlan_hdd_is_per_link_stats_supported(struct hdd_context * hdd_ctx)757*5113495bSYour Name wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx)
758*5113495bSYour Name {
759*5113495bSYour Name 	return false;
760*5113495bSYour Name }
761*5113495bSYour Name 
762*5113495bSYour Name static inline QDF_STATUS
wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info * link_info,struct qdf_mac_addr * mld_mac)763*5113495bSYour Name wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info,
764*5113495bSYour Name 			      struct qdf_mac_addr *mld_mac)
765*5113495bSYour Name {
766*5113495bSYour Name 	return QDF_STATUS_E_FAILURE;
767*5113495bSYour Name }
768*5113495bSYour Name 
769*5113495bSYour Name static inline bool
wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info * link_info)770*5113495bSYour Name wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info)
771*5113495bSYour Name {
772*5113495bSYour Name 	return false;
773*5113495bSYour Name }
774*5113495bSYour Name 
775*5113495bSYour Name static inline void
wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)776*5113495bSYour Name wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info,
777*5113495bSYour Name 				 struct station_info *sinfo)
778*5113495bSYour Name {
779*5113495bSYour Name }
780*5113495bSYour Name 
781*5113495bSYour Name static inline void
wlan_hdd_update_sinfo(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)782*5113495bSYour Name wlan_hdd_update_sinfo(struct station_info *sinfo,
783*5113495bSYour Name 		      struct wlan_hdd_link_info *link_info)
784*5113495bSYour Name {
785*5113495bSYour Name }
786*5113495bSYour Name 
787*5113495bSYour Name static inline void
wlan_hdd_get_mlo_links_count(struct hdd_adapter * adapter,uint32_t * count)788*5113495bSYour Name wlan_hdd_get_mlo_links_count(struct hdd_adapter *adapter, uint32_t *count)
789*5113495bSYour Name {
790*5113495bSYour Name }
791*5113495bSYour Name #endif
792*5113495bSYour Name 
793*5113495bSYour Name #ifdef WLAN_FEATURE_LINK_LAYER_STATS
794*5113495bSYour Name 
795*5113495bSYour Name /**
796*5113495bSYour Name  * struct hdd_ll_stats - buffered hdd link layer stats
797*5113495bSYour Name  * @ll_stats_node: pointer to next stats buffered in scheduler thread context
798*5113495bSYour Name  * @result_param_id: Received link layer stats ID
799*5113495bSYour Name  * @result: received stats from FW
800*5113495bSYour Name  * @more_data: if more stats are pending
801*5113495bSYour Name  * @stats_nradio_npeer: union of counts
802*5113495bSYour Name  * @stats_nradio_npeer.no_of_radios: no of radios
803*5113495bSYour Name  * @stats_nradio_npeer.no_of_peers: no of peers
804*5113495bSYour Name  */
805*5113495bSYour Name struct hdd_ll_stats {
806*5113495bSYour Name 	qdf_list_node_t ll_stats_node;
807*5113495bSYour Name 	u32 result_param_id;
808*5113495bSYour Name 	void *result;
809*5113495bSYour Name 	u32 more_data;
810*5113495bSYour Name 	union {
811*5113495bSYour Name 		u32 no_of_radios;
812*5113495bSYour Name 		u32 no_of_peers;
813*5113495bSYour Name 	} stats_nradio_npeer;
814*5113495bSYour Name };
815*5113495bSYour Name 
816*5113495bSYour Name /**
817*5113495bSYour Name  * struct hdd_ll_stats_priv - hdd link layer stats private
818*5113495bSYour Name  * @ll_stats_q: head to different link layer stats received in scheduler
819*5113495bSYour Name  *            thread context
820*5113495bSYour Name  * @request_id: userspace-assigned link layer stats request id
821*5113495bSYour Name  * @request_bitmap: userspace-assigned link layer stats request bitmap
822*5113495bSYour Name  * @ll_stats_lock: Lock to serially access request_bitmap
823*5113495bSYour Name  * @vdev_id: id of vdev handle
824*5113495bSYour Name  * @is_mlo_req: is the request for mlo link layer stats
825*5113495bSYour Name  * @mlo_vdev_id_bitmap: bitmap of all ml vdevs
826*5113495bSYour Name  */
827*5113495bSYour Name struct hdd_ll_stats_priv {
828*5113495bSYour Name 	qdf_list_t ll_stats_q;
829*5113495bSYour Name 	uint32_t request_id;
830*5113495bSYour Name 	uint32_t request_bitmap;
831*5113495bSYour Name 	qdf_spinlock_t ll_stats_lock;
832*5113495bSYour Name 	uint8_t vdev_id;
833*5113495bSYour Name 	bool is_mlo_req;
834*5113495bSYour Name 	uint32_t mlo_vdev_id_bitmap;
835*5113495bSYour Name };
836*5113495bSYour Name 
837*5113495bSYour Name /*
838*5113495bSYour Name  * Used to allocate the size of 4096 for the link layer stats.
839*5113495bSYour Name  * The size of 4096 is considered assuming that all data per
840*5113495bSYour Name  * respective event fit with in the limit.Please take a call
841*5113495bSYour Name  * on the limit based on the data requirements on link layer
842*5113495bSYour Name  * statistics.
843*5113495bSYour Name  */
844*5113495bSYour Name #define LL_STATS_EVENT_BUF_SIZE 4096
845*5113495bSYour Name 
846*5113495bSYour Name /**
847*5113495bSYour Name  * put_wifi_rate_stat() - put wifi rate stats
848*5113495bSYour Name  * @stats: Pointer to stats context
849*5113495bSYour Name  * @vendor_event: Pointer to vendor event
850*5113495bSYour Name  *
851*5113495bSYour Name  * Return: bool
852*5113495bSYour Name  */
put_wifi_rate_stat(struct wifi_rate_stat * stats,struct sk_buff * vendor_event)853*5113495bSYour Name static bool put_wifi_rate_stat(struct wifi_rate_stat *stats,
854*5113495bSYour Name 			       struct sk_buff *vendor_event)
855*5113495bSYour Name {
856*5113495bSYour Name 	if (nla_put_u8(vendor_event,
857*5113495bSYour Name 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE,
858*5113495bSYour Name 		       stats->rate.preamble) ||
859*5113495bSYour Name 	    nla_put_u8(vendor_event,
860*5113495bSYour Name 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS,
861*5113495bSYour Name 		       stats->rate.nss) ||
862*5113495bSYour Name 	    nla_put_u8(vendor_event,
863*5113495bSYour Name 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW,
864*5113495bSYour Name 		       stats->rate.bw) ||
865*5113495bSYour Name 	    nla_put_u8(vendor_event,
866*5113495bSYour Name 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX,
867*5113495bSYour Name 		       stats->rate.rate_or_mcs_index) ||
868*5113495bSYour Name 	    nla_put_u32(vendor_event,
869*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE,
870*5113495bSYour Name 			stats->rate.bitrate) ||
871*5113495bSYour Name 	    nla_put_u32(vendor_event,
872*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU,
873*5113495bSYour Name 			stats->tx_mpdu) ||
874*5113495bSYour Name 	    nla_put_u32(vendor_event,
875*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU,
876*5113495bSYour Name 			stats->rx_mpdu) ||
877*5113495bSYour Name 	    nla_put_u32(vendor_event,
878*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST,
879*5113495bSYour Name 			stats->mpdu_lost) ||
880*5113495bSYour Name 	    nla_put_u32(vendor_event,
881*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES,
882*5113495bSYour Name 			stats->retries) ||
883*5113495bSYour Name 	    nla_put_u32(vendor_event,
884*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT,
885*5113495bSYour Name 			stats->retries_short) ||
886*5113495bSYour Name 	    nla_put_u32(vendor_event,
887*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG,
888*5113495bSYour Name 			stats->retries_long)) {
889*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
890*5113495bSYour Name 		return false;
891*5113495bSYour Name 	}
892*5113495bSYour Name 
893*5113495bSYour Name 	return true;
894*5113495bSYour Name }
895*5113495bSYour Name 
896*5113495bSYour Name /**
897*5113495bSYour Name  * put_wifi_peer_rates() - put wifi peer rate info
898*5113495bSYour Name  * @stats: Pointer to stats context
899*5113495bSYour Name  * @vendor_event: Pointer to vendor event
900*5113495bSYour Name  *
901*5113495bSYour Name  * Return: bool
902*5113495bSYour Name  */
put_wifi_peer_rates(struct wifi_peer_info * stats,struct sk_buff * vendor_event)903*5113495bSYour Name static bool put_wifi_peer_rates(struct wifi_peer_info *stats,
904*5113495bSYour Name 				struct sk_buff *vendor_event)
905*5113495bSYour Name {
906*5113495bSYour Name 	uint32_t i;
907*5113495bSYour Name 	struct wifi_rate_stat *rate_stat;
908*5113495bSYour Name 	int nest_id;
909*5113495bSYour Name 	struct nlattr *info;
910*5113495bSYour Name 	struct nlattr *rates;
911*5113495bSYour Name 
912*5113495bSYour Name 	/* no rates is ok */
913*5113495bSYour Name 	if (!stats->num_rate)
914*5113495bSYour Name 		return true;
915*5113495bSYour Name 
916*5113495bSYour Name 	nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO;
917*5113495bSYour Name 	info = nla_nest_start(vendor_event, nest_id);
918*5113495bSYour Name 	if (!info)
919*5113495bSYour Name 		return false;
920*5113495bSYour Name 
921*5113495bSYour Name 	for (i = 0; i < stats->num_rate; i++) {
922*5113495bSYour Name 		rates = nla_nest_start(vendor_event, i);
923*5113495bSYour Name 		if (!rates)
924*5113495bSYour Name 			return false;
925*5113495bSYour Name 		rate_stat = &stats->rate_stats[i];
926*5113495bSYour Name 		if (!put_wifi_rate_stat(rate_stat, vendor_event)) {
927*5113495bSYour Name 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
928*5113495bSYour Name 			return false;
929*5113495bSYour Name 		}
930*5113495bSYour Name 		nla_nest_end(vendor_event, rates);
931*5113495bSYour Name 	}
932*5113495bSYour Name 	nla_nest_end(vendor_event, info);
933*5113495bSYour Name 
934*5113495bSYour Name 	return true;
935*5113495bSYour Name }
936*5113495bSYour Name 
937*5113495bSYour Name #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
938*5113495bSYour Name /**
939*5113495bSYour Name  * wlan_hdd_put_mlo_link_iface_info() - Send per mlo link info to framework
940*5113495bSYour Name  * @info: Pointer to wlan_hdd_mlo_iface_stats_info struct
941*5113495bSYour Name  * @skb: Pointer to data buffer
942*5113495bSYour Name  *
943*5113495bSYour Name  * Return: True on success, False on failure
944*5113495bSYour Name  */
945*5113495bSYour Name static bool
wlan_hdd_put_mlo_link_iface_info(struct wlan_hdd_mlo_iface_stats_info * info,struct sk_buff * skb)946*5113495bSYour Name wlan_hdd_put_mlo_link_iface_info(struct wlan_hdd_mlo_iface_stats_info *info,
947*5113495bSYour Name 				 struct sk_buff *skb)
948*5113495bSYour Name {
949*5113495bSYour Name 	if (nla_put_u8(skb,
950*5113495bSYour Name 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID,
951*5113495bSYour Name 		       info->link_id) ||
952*5113495bSYour Name 	    nla_put_u32(skb,
953*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
954*5113495bSYour Name 			info->radio_id) ||
955*5113495bSYour Name 	    nla_put_u32(skb,
956*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
957*5113495bSYour Name 			info->freq)) {
958*5113495bSYour Name 		hdd_err("wlan_hdd_put_mlo_link_iface_info failed");
959*5113495bSYour Name 		return false;
960*5113495bSYour Name 	}
961*5113495bSYour Name 
962*5113495bSYour Name 	return true;
963*5113495bSYour Name }
964*5113495bSYour Name 
965*5113495bSYour Name /**
966*5113495bSYour Name  * wlan_hdd_get_connected_link_info() - Get connected links' id and frequency
967*5113495bSYour Name  * @link_info: Link info pointerin adapter
968*5113495bSYour Name  * @info: Pointer to wlan_hdd_mlo_iface_stats_info struct
969*5113495bSYour Name  *
970*5113495bSYour Name  * Return: void
971*5113495bSYour Name  */
972*5113495bSYour Name static void
wlan_hdd_get_connected_link_info(struct wlan_hdd_link_info * link_info,struct wlan_hdd_mlo_iface_stats_info * info)973*5113495bSYour Name wlan_hdd_get_connected_link_info(struct wlan_hdd_link_info *link_info,
974*5113495bSYour Name 				 struct wlan_hdd_mlo_iface_stats_info *info)
975*5113495bSYour Name {
976*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx = NULL;
977*5113495bSYour Name 	struct hdd_ap_ctx *ap_ctx = NULL;
978*5113495bSYour Name 
979*5113495bSYour Name 	info->link_id = WLAN_INVALID_LINK_ID;
980*5113495bSYour Name 
981*5113495bSYour Name 	if (!link_info) {
982*5113495bSYour Name 		hdd_err("Invalid link_info");
983*5113495bSYour Name 		return;
984*5113495bSYour Name 	}
985*5113495bSYour Name 
986*5113495bSYour Name 	if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE ||
987*5113495bSYour Name 	    link_info->adapter->device_mode == QDF_STA_MODE) {
988*5113495bSYour Name 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
989*5113495bSYour Name 		info->link_id = sta_ctx->conn_info.ieee_link_id;
990*5113495bSYour Name 		info->freq = sta_ctx->conn_info.chan_freq;
991*5113495bSYour Name 	} else if ((link_info->adapter->device_mode == QDF_SAP_MODE ||
992*5113495bSYour Name 		    link_info->adapter->device_mode == QDF_P2P_GO_MODE) &&
993*5113495bSYour Name 		   test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) {
994*5113495bSYour Name 		ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info);
995*5113495bSYour Name 		info->link_id = ap_ctx->sap_config.link_id;
996*5113495bSYour Name 		info->freq = ap_ctx->sap_config.chan_freq;
997*5113495bSYour Name 	}
998*5113495bSYour Name }
999*5113495bSYour Name #endif
1000*5113495bSYour Name 
1001*5113495bSYour Name /**
1002*5113495bSYour Name  * put_wifi_peer_info() - put wifi peer info
1003*5113495bSYour Name  * @stats: Pointer to stats context
1004*5113495bSYour Name  * @vendor_event: Pointer to vendor event
1005*5113495bSYour Name  *
1006*5113495bSYour Name  * Return: bool
1007*5113495bSYour Name  */
put_wifi_peer_info(struct wifi_peer_info * stats,struct sk_buff * vendor_event)1008*5113495bSYour Name static bool put_wifi_peer_info(struct wifi_peer_info *stats,
1009*5113495bSYour Name 			       struct sk_buff *vendor_event)
1010*5113495bSYour Name {
1011*5113495bSYour Name 	if (nla_put_u32(vendor_event,
1012*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
1013*5113495bSYour Name 			wmi_to_sir_peer_type(stats->type)) ||
1014*5113495bSYour Name 	    nla_put(vendor_event,
1015*5113495bSYour Name 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
1016*5113495bSYour Name 		       QDF_MAC_ADDR_SIZE, &stats->peer_macaddr.bytes[0]) ||
1017*5113495bSYour Name 	    nla_put_u32(vendor_event,
1018*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
1019*5113495bSYour Name 			stats->capabilities) ||
1020*5113495bSYour Name 	    nla_put_u32(vendor_event,
1021*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
1022*5113495bSYour Name 			stats->num_rate)) {
1023*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1024*5113495bSYour Name 		return false;
1025*5113495bSYour Name 	}
1026*5113495bSYour Name 
1027*5113495bSYour Name 	return put_wifi_peer_rates(stats, vendor_event);
1028*5113495bSYour Name }
1029*5113495bSYour Name 
1030*5113495bSYour Name /**
1031*5113495bSYour Name  * put_wifi_wmm_ac_stat() - put wifi wmm ac stats
1032*5113495bSYour Name  * @stats: Pointer to stats context
1033*5113495bSYour Name  * @vendor_event: Pointer to vendor event
1034*5113495bSYour Name  *
1035*5113495bSYour Name  * Return: bool
1036*5113495bSYour Name  */
put_wifi_wmm_ac_stat(wmi_wmm_ac_stats * stats,struct sk_buff * vendor_event)1037*5113495bSYour Name static bool put_wifi_wmm_ac_stat(wmi_wmm_ac_stats *stats,
1038*5113495bSYour Name 				 struct sk_buff *vendor_event)
1039*5113495bSYour Name {
1040*5113495bSYour Name 	if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
1041*5113495bSYour Name 			stats->ac_type) ||
1042*5113495bSYour Name 	    nla_put_u32(vendor_event,
1043*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
1044*5113495bSYour Name 			stats->tx_mpdu) ||
1045*5113495bSYour Name 	    nla_put_u32(vendor_event,
1046*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
1047*5113495bSYour Name 			stats->rx_mpdu) ||
1048*5113495bSYour Name 	    nla_put_u32(vendor_event,
1049*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
1050*5113495bSYour Name 			stats->tx_mcast) ||
1051*5113495bSYour Name 	    nla_put_u32(vendor_event,
1052*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
1053*5113495bSYour Name 			stats->rx_mcast) ||
1054*5113495bSYour Name 	    nla_put_u32(vendor_event,
1055*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
1056*5113495bSYour Name 			stats->rx_ampdu) ||
1057*5113495bSYour Name 	    nla_put_u32(vendor_event,
1058*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
1059*5113495bSYour Name 			stats->tx_ampdu) ||
1060*5113495bSYour Name 	    nla_put_u32(vendor_event,
1061*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
1062*5113495bSYour Name 			stats->mpdu_lost) ||
1063*5113495bSYour Name 	    nla_put_u32(vendor_event,
1064*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
1065*5113495bSYour Name 			stats->retries) ||
1066*5113495bSYour Name 	    nla_put_u32(vendor_event,
1067*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
1068*5113495bSYour Name 			stats->retries_short) ||
1069*5113495bSYour Name 	    nla_put_u32(vendor_event,
1070*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
1071*5113495bSYour Name 			stats->retries_long) ||
1072*5113495bSYour Name 	    nla_put_u32(vendor_event,
1073*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
1074*5113495bSYour Name 			stats->contention_time_min) ||
1075*5113495bSYour Name 	    nla_put_u32(vendor_event,
1076*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
1077*5113495bSYour Name 			stats->contention_time_max) ||
1078*5113495bSYour Name 	    nla_put_u32(vendor_event,
1079*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
1080*5113495bSYour Name 			stats->contention_time_avg) ||
1081*5113495bSYour Name 	    nla_put_u32(vendor_event,
1082*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
1083*5113495bSYour Name 			stats->contention_num_samples)) {
1084*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1085*5113495bSYour Name 		return false;
1086*5113495bSYour Name 	}
1087*5113495bSYour Name 
1088*5113495bSYour Name 	return true;
1089*5113495bSYour Name }
1090*5113495bSYour Name 
1091*5113495bSYour Name /**
1092*5113495bSYour Name  * put_wifi_interface_info() - put wifi interface info
1093*5113495bSYour Name  * @stats: Pointer to stats context
1094*5113495bSYour Name  * @vendor_event: Pointer to vendor event
1095*5113495bSYour Name  * @link_info: Pointer to link_info
1096*5113495bSYour Name  *
1097*5113495bSYour Name  * Return: bool
1098*5113495bSYour Name  */
put_wifi_interface_info(struct wifi_interface_info * stats,struct sk_buff * vendor_event,struct wlan_hdd_link_info * link_info)1099*5113495bSYour Name static bool put_wifi_interface_info(struct wifi_interface_info *stats,
1100*5113495bSYour Name 				    struct sk_buff *vendor_event,
1101*5113495bSYour Name 				    struct wlan_hdd_link_info *link_info)
1102*5113495bSYour Name {
1103*5113495bSYour Name 	if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE ||
1104*5113495bSYour Name 	    link_info->adapter->device_mode == QDF_STA_MODE) {
1105*5113495bSYour Name 		if (nla_put_u32(vendor_event,
1106*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE,
1107*5113495bSYour Name 				stats->state)) {
1108*5113495bSYour Name 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1109*5113495bSYour Name 			return false;
1110*5113495bSYour Name 		}
1111*5113495bSYour Name 	}
1112*5113495bSYour Name 
1113*5113495bSYour Name 	if (nla_put_u32(vendor_event,
1114*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE,
1115*5113495bSYour Name 			stats->mode) ||
1116*5113495bSYour Name 	    nla_put(vendor_event,
1117*5113495bSYour Name 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR,
1118*5113495bSYour Name 		    QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) ||
1119*5113495bSYour Name 	    nla_put_u32(vendor_event,
1120*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING,
1121*5113495bSYour Name 			stats->roaming) ||
1122*5113495bSYour Name 	    nla_put_u32(vendor_event,
1123*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES,
1124*5113495bSYour Name 			stats->capabilities) ||
1125*5113495bSYour Name 	    nla_put(vendor_event,
1126*5113495bSYour Name 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID,
1127*5113495bSYour Name 		    strlen(stats->ssid), stats->ssid) ||
1128*5113495bSYour Name 	    nla_put(vendor_event,
1129*5113495bSYour Name 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID,
1130*5113495bSYour Name 		    QDF_MAC_ADDR_SIZE, stats->bssid.bytes) ||
1131*5113495bSYour Name 	    nla_put(vendor_event,
1132*5113495bSYour Name 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR,
1133*5113495bSYour Name 		    REG_ALPHA2_LEN + 1, stats->apCountryStr) ||
1134*5113495bSYour Name 	    nla_put(vendor_event,
1135*5113495bSYour Name 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR,
1136*5113495bSYour Name 		    REG_ALPHA2_LEN + 1, stats->countryStr) ||
1137*5113495bSYour Name 	    nla_put_u8(vendor_event,
1138*5113495bSYour Name 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_TS_DUTY_CYCLE,
1139*5113495bSYour Name 		       stats->time_slice_duty_cycle)) {
1140*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1141*5113495bSYour Name 		return false;
1142*5113495bSYour Name 	}
1143*5113495bSYour Name 
1144*5113495bSYour Name 	return true;
1145*5113495bSYour Name }
1146*5113495bSYour Name 
1147*5113495bSYour Name /**
1148*5113495bSYour Name  * put_wifi_iface_stats() - put wifi interface stats
1149*5113495bSYour Name  * @if_stat: Pointer to interface stats context
1150*5113495bSYour Name  * @num_peers: Number of peers
1151*5113495bSYour Name  * @vendor_event: Pointer to vendor event
1152*5113495bSYour Name  * @link_info: Pointer to link_info
1153*5113495bSYour Name  *
1154*5113495bSYour Name  * Return: bool
1155*5113495bSYour Name  */
put_wifi_iface_stats(struct wifi_interface_stats * if_stat,u32 num_peers,struct sk_buff * vendor_event,struct wlan_hdd_link_info * link_info)1156*5113495bSYour Name static bool put_wifi_iface_stats(struct wifi_interface_stats *if_stat,
1157*5113495bSYour Name 				 u32 num_peers, struct sk_buff *vendor_event,
1158*5113495bSYour Name 				 struct wlan_hdd_link_info *link_info)
1159*5113495bSYour Name {
1160*5113495bSYour Name 	int i = 0;
1161*5113495bSYour Name 	struct nlattr *wmm_info;
1162*5113495bSYour Name 	struct nlattr *wmm_stats;
1163*5113495bSYour Name 	u64 average_tsf_offset;
1164*5113495bSYour Name 	wmi_iface_link_stats *link_stats = &if_stat->link_stats;
1165*5113495bSYour Name 
1166*5113495bSYour Name 	if (!put_wifi_interface_info(&if_stat->info, vendor_event, link_info)) {
1167*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1168*5113495bSYour Name 		return false;
1169*5113495bSYour Name 
1170*5113495bSYour Name 	}
1171*5113495bSYour Name 
1172*5113495bSYour Name 	average_tsf_offset =  link_stats->avg_bcn_spread_offset_high;
1173*5113495bSYour Name 	average_tsf_offset =  (average_tsf_offset << 32) |
1174*5113495bSYour Name 		link_stats->avg_bcn_spread_offset_low;
1175*5113495bSYour Name 
1176*5113495bSYour Name 	if (nla_put_u32(vendor_event,
1177*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
1178*5113495bSYour Name 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_IFACE) ||
1179*5113495bSYour Name 	    nla_put_u32(vendor_event,
1180*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
1181*5113495bSYour Name 			num_peers) ||
1182*5113495bSYour Name 	    nla_put_u32(vendor_event,
1183*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
1184*5113495bSYour Name 			link_stats->beacon_rx) ||
1185*5113495bSYour Name 	    nla_put_u32(vendor_event,
1186*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
1187*5113495bSYour Name 			link_stats->mgmt_rx) ||
1188*5113495bSYour Name 	    nla_put_u32(vendor_event,
1189*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
1190*5113495bSYour Name 			link_stats->mgmt_action_rx) ||
1191*5113495bSYour Name 	    nla_put_u32(vendor_event,
1192*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
1193*5113495bSYour Name 			link_stats->mgmt_action_tx) ||
1194*5113495bSYour Name 	    nla_put_u32(vendor_event,
1195*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
1196*5113495bSYour Name 			link_stats->rssi_mgmt) ||
1197*5113495bSYour Name 	    nla_put_u32(vendor_event,
1198*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
1199*5113495bSYour Name 			link_stats->rssi_data) ||
1200*5113495bSYour Name 	    nla_put_u32(vendor_event,
1201*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
1202*5113495bSYour Name 			link_stats->rssi_ack) ||
1203*5113495bSYour Name 	    nla_put_u32(vendor_event,
1204*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
1205*5113495bSYour Name 			link_stats->is_leaky_ap) ||
1206*5113495bSYour Name 	    nla_put_u32(vendor_event,
1207*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
1208*5113495bSYour Name 			link_stats->avg_rx_frms_leaked) ||
1209*5113495bSYour Name 	    nla_put_u32(vendor_event,
1210*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
1211*5113495bSYour Name 			link_stats->rx_leak_window) ||
1212*5113495bSYour Name 	    nla_put_s32(vendor_event,
1213*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NF_CAL_VAL,
1214*5113495bSYour Name 			link_stats->nf_cal_val) ||
1215*5113495bSYour Name 	    hdd_wlan_nla_put_u64(vendor_event,
1216*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
1217*5113495bSYour Name 			average_tsf_offset) ||
1218*5113495bSYour Name 	    nla_put_u32(vendor_event,
1219*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT,
1220*5113495bSYour Name 			if_stat->rts_succ_cnt) ||
1221*5113495bSYour Name 	    nla_put_u32(vendor_event,
1222*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT,
1223*5113495bSYour Name 			if_stat->rts_fail_cnt) ||
1224*5113495bSYour Name 	    nla_put_u32(vendor_event,
1225*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT,
1226*5113495bSYour Name 			if_stat->ppdu_succ_cnt) ||
1227*5113495bSYour Name 	    nla_put_u32(vendor_event,
1228*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT,
1229*5113495bSYour Name 			if_stat->ppdu_fail_cnt)) {
1230*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1231*5113495bSYour Name 		return false;
1232*5113495bSYour Name 	}
1233*5113495bSYour Name 
1234*5113495bSYour Name 	wmm_info = nla_nest_start(vendor_event,
1235*5113495bSYour Name 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO);
1236*5113495bSYour Name 	if (!wmm_info)
1237*5113495bSYour Name 		return false;
1238*5113495bSYour Name 
1239*5113495bSYour Name 	for (i = 0; i < WIFI_AC_MAX; i++) {
1240*5113495bSYour Name 		wmm_stats = nla_nest_start(vendor_event, i);
1241*5113495bSYour Name 		if (!wmm_stats)
1242*5113495bSYour Name 			return false;
1243*5113495bSYour Name 
1244*5113495bSYour Name 		if (!put_wifi_wmm_ac_stat(&if_stat->ac_stats[i],
1245*5113495bSYour Name 					  vendor_event)) {
1246*5113495bSYour Name 			hdd_err("put_wifi_wmm_ac_stat Fail");
1247*5113495bSYour Name 			return false;
1248*5113495bSYour Name 		}
1249*5113495bSYour Name 
1250*5113495bSYour Name 		nla_nest_end(vendor_event, wmm_stats);
1251*5113495bSYour Name 	}
1252*5113495bSYour Name 	nla_nest_end(vendor_event, wmm_info);
1253*5113495bSYour Name 
1254*5113495bSYour Name 	if (nla_put_u32(vendor_event,
1255*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON,
1256*5113495bSYour Name 			if_stat->powersave_stats.tot_tim_bcn) ||
1257*5113495bSYour Name 	    nla_put_u32(vendor_event,
1258*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON_ERR,
1259*5113495bSYour Name 			if_stat->powersave_stats.tot_err_tim_bcn)) {
1260*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put powersave_stat fail");
1261*5113495bSYour Name 		return false;
1262*5113495bSYour Name 	}
1263*5113495bSYour Name 
1264*5113495bSYour Name 	return true;
1265*5113495bSYour Name }
1266*5113495bSYour Name 
1267*5113495bSYour Name /**
1268*5113495bSYour Name  * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode
1269*5113495bSYour Name  * @device_mode: Device mode
1270*5113495bSYour Name  *
1271*5113495bSYour Name  * Return: interface mode
1272*5113495bSYour Name  */
hdd_map_device_to_ll_iface_mode(int device_mode)1273*5113495bSYour Name static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int device_mode)
1274*5113495bSYour Name {
1275*5113495bSYour Name 	switch (device_mode) {
1276*5113495bSYour Name 	case QDF_STA_MODE:
1277*5113495bSYour Name 		return WIFI_INTERFACE_STA;
1278*5113495bSYour Name 	case QDF_SAP_MODE:
1279*5113495bSYour Name 		return WIFI_INTERFACE_SOFTAP;
1280*5113495bSYour Name 	case QDF_P2P_CLIENT_MODE:
1281*5113495bSYour Name 		return WIFI_INTERFACE_P2P_CLIENT;
1282*5113495bSYour Name 	case QDF_P2P_GO_MODE:
1283*5113495bSYour Name 		return WIFI_INTERFACE_P2P_GO;
1284*5113495bSYour Name 	default:
1285*5113495bSYour Name 		/* Return Interface Mode as STA for all the unsupported modes */
1286*5113495bSYour Name 		return WIFI_INTERFACE_STA;
1287*5113495bSYour Name 	}
1288*5113495bSYour Name }
1289*5113495bSYour Name 
hdd_get_interface_info(struct wlan_hdd_link_info * link_info,struct wifi_interface_info * info)1290*5113495bSYour Name bool hdd_get_interface_info(struct wlan_hdd_link_info *link_info,
1291*5113495bSYour Name 			    struct wifi_interface_info *info)
1292*5113495bSYour Name {
1293*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
1294*5113495bSYour Name 	struct sap_config *config;
1295*5113495bSYour Name 	struct qdf_mac_addr *mac;
1296*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
1297*5113495bSYour Name 
1298*5113495bSYour Name 	info->mode = hdd_map_device_to_ll_iface_mode(adapter->device_mode);
1299*5113495bSYour Name 
1300*5113495bSYour Name 	mac = hdd_adapter_get_link_mac_addr(link_info);
1301*5113495bSYour Name 	if (!mac) {
1302*5113495bSYour Name 		hdd_debug("Invalid HDD link info");
1303*5113495bSYour Name 		return false;
1304*5113495bSYour Name 	}
1305*5113495bSYour Name 
1306*5113495bSYour Name 	qdf_copy_macaddr(&info->macAddr, mac);
1307*5113495bSYour Name 
1308*5113495bSYour Name 	if (((QDF_STA_MODE == adapter->device_mode) ||
1309*5113495bSYour Name 	     (QDF_P2P_CLIENT_MODE == adapter->device_mode) ||
1310*5113495bSYour Name 	     (QDF_P2P_DEVICE_MODE == adapter->device_mode))) {
1311*5113495bSYour Name 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1312*5113495bSYour Name 		if (hdd_cm_is_disconnected(link_info))
1313*5113495bSYour Name 			info->state = WIFI_DISCONNECTED;
1314*5113495bSYour Name 
1315*5113495bSYour Name 		if (hdd_cm_is_connecting(link_info)) {
1316*5113495bSYour Name 			hdd_debug("Session ID %d, Connection is in progress",
1317*5113495bSYour Name 				  link_info->vdev_id);
1318*5113495bSYour Name 			info->state = WIFI_ASSOCIATING;
1319*5113495bSYour Name 		}
1320*5113495bSYour Name 		if (hdd_cm_is_vdev_associated(link_info) &&
1321*5113495bSYour Name 		    !sta_ctx->conn_info.is_authenticated) {
1322*5113495bSYour Name 			hdd_err("client " QDF_MAC_ADDR_FMT
1323*5113495bSYour Name 				" is in the middle of WPS/EAPOL exchange.",
1324*5113495bSYour Name 				QDF_MAC_ADDR_REF(mac->bytes));
1325*5113495bSYour Name 			info->state = WIFI_AUTHENTICATING;
1326*5113495bSYour Name 		}
1327*5113495bSYour Name 		if (hdd_cm_is_vdev_associated(link_info) ||
1328*5113495bSYour Name 		    link_info->vdev_id == WLAN_INVALID_VDEV_ID) {
1329*5113495bSYour Name 			info->state = WIFI_ASSOCIATED;
1330*5113495bSYour Name 			qdf_copy_macaddr(&info->bssid,
1331*5113495bSYour Name 					 &sta_ctx->conn_info.bssid);
1332*5113495bSYour Name 			qdf_mem_copy(info->ssid,
1333*5113495bSYour Name 				     sta_ctx->conn_info.ssid.SSID.ssId,
1334*5113495bSYour Name 				     sta_ctx->conn_info.ssid.SSID.length);
1335*5113495bSYour Name 			/*
1336*5113495bSYour Name 			 * NULL Terminate the string
1337*5113495bSYour Name 			 */
1338*5113495bSYour Name 			info->ssid[sta_ctx->conn_info.ssid.SSID.length] = 0;
1339*5113495bSYour Name 		}
1340*5113495bSYour Name 	}
1341*5113495bSYour Name 
1342*5113495bSYour Name 	if ((adapter->device_mode == QDF_SAP_MODE ||
1343*5113495bSYour Name 	     adapter->device_mode == QDF_P2P_GO_MODE) &&
1344*5113495bSYour Name 	    test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) {
1345*5113495bSYour Name 		config = &link_info->session.ap.sap_config;
1346*5113495bSYour Name 		qdf_copy_macaddr(&info->bssid, &config->self_macaddr);
1347*5113495bSYour Name 	}
1348*5113495bSYour Name 	wlan_reg_get_cc_and_src(adapter->hdd_ctx->psoc, info->countryStr);
1349*5113495bSYour Name 	wlan_reg_get_cc_and_src(adapter->hdd_ctx->psoc, info->apCountryStr);
1350*5113495bSYour Name 
1351*5113495bSYour Name 	return true;
1352*5113495bSYour Name }
1353*5113495bSYour Name 
1354*5113495bSYour Name #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
1355*5113495bSYour Name /**
1356*5113495bSYour Name  * hdd_cache_ll_iface_stats() - Caches ll_stats received from fw
1357*5113495bSYour Name  * @hdd_ctx: Pointer to hdd_context
1358*5113495bSYour Name  * @if_stat: Pointer to stats data
1359*5113495bSYour Name  *
1360*5113495bSYour Name  * After receiving Link Layer Interface statistics from FW.
1361*5113495bSYour Name  * This function caches them into wlan_hdd_link_info.
1362*5113495bSYour Name  *
1363*5113495bSYour Name  * Return: None
1364*5113495bSYour Name  */
1365*5113495bSYour Name static void
hdd_cache_ll_iface_stats(struct hdd_context * hdd_ctx,struct wifi_interface_stats * if_stat)1366*5113495bSYour Name hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx,
1367*5113495bSYour Name 			 struct wifi_interface_stats *if_stat)
1368*5113495bSYour Name {
1369*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
1370*5113495bSYour Name 
1371*5113495bSYour Name 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, if_stat->vdev_id);
1372*5113495bSYour Name 	if (!link_info) {
1373*5113495bSYour Name 		hdd_err("Invalid link_info. Unable to cache mlo iface stats");
1374*5113495bSYour Name 		return;
1375*5113495bSYour Name 	}
1376*5113495bSYour Name 	/*
1377*5113495bSYour Name 	 * There is no need for wlan_hdd_validate_context here. This is a NB
1378*5113495bSYour Name 	 * operation that will come with DSC synchronization. This ensures that
1379*5113495bSYour Name 	 * no driver transition will take place as long as this operation is
1380*5113495bSYour Name 	 * not complete. Thus the need to check validity of hdd_context is not
1381*5113495bSYour Name 	 * required.
1382*5113495bSYour Name 	 */
1383*5113495bSYour Name 	hdd_nofl_debug("Copying iface stats for vdev_id[%u] into link_info",
1384*5113495bSYour Name 		       link_info->vdev_id);
1385*5113495bSYour Name 	link_info->ll_iface_stats = *if_stat;
1386*5113495bSYour Name }
1387*5113495bSYour Name 
1388*5113495bSYour Name /**
1389*5113495bSYour Name  * wlan_hdd_update_wmm_ac_stats() - Populate ll_iface ac stats
1390*5113495bSYour Name  * @link_info: Link info pointer of STA adapter
1391*5113495bSYour Name  * @if_stat: Pointer to wifi_interface_stats structure
1392*5113495bSYour Name  * @update_contention_stats: whether to update contention stats or not
1393*5113495bSYour Name  *
1394*5113495bSYour Name  * Return: none
1395*5113495bSYour Name  */
1396*5113495bSYour Name static void
wlan_hdd_update_wmm_ac_stats(struct wlan_hdd_link_info * link_info,struct wifi_interface_stats * if_stat,bool update_contention_stats)1397*5113495bSYour Name wlan_hdd_update_wmm_ac_stats(struct wlan_hdd_link_info *link_info,
1398*5113495bSYour Name 			     struct wifi_interface_stats *if_stat,
1399*5113495bSYour Name 			     bool update_contention_stats)
1400*5113495bSYour Name {
1401*5113495bSYour Name 	int i;
1402*5113495bSYour Name 	wmi_wmm_ac_stats *hdd_ac_stats, *stats;
1403*5113495bSYour Name 
1404*5113495bSYour Name 	for (i = 0; i < WIFI_AC_MAX; i++) {
1405*5113495bSYour Name 		hdd_ac_stats = &link_info->ll_iface_stats.ac_stats[i];
1406*5113495bSYour Name 		stats = &if_stat->ac_stats[i];
1407*5113495bSYour Name 		stats->ac_type = hdd_ac_stats->ac_type;
1408*5113495bSYour Name 		stats->tx_mpdu += hdd_ac_stats->tx_mpdu;
1409*5113495bSYour Name 		stats->rx_mpdu += hdd_ac_stats->rx_mpdu;
1410*5113495bSYour Name 		stats->tx_mcast += hdd_ac_stats->tx_mcast;
1411*5113495bSYour Name 		stats->rx_mcast += hdd_ac_stats->rx_mcast;
1412*5113495bSYour Name 		stats->rx_ampdu += hdd_ac_stats->rx_ampdu;
1413*5113495bSYour Name 		stats->tx_ampdu += hdd_ac_stats->tx_ampdu;
1414*5113495bSYour Name 		stats->mpdu_lost += hdd_ac_stats->mpdu_lost;
1415*5113495bSYour Name 		stats->retries += hdd_ac_stats->retries;
1416*5113495bSYour Name 		stats->retries_short += hdd_ac_stats->retries_short;
1417*5113495bSYour Name 		stats->retries_long += hdd_ac_stats->retries_long;
1418*5113495bSYour Name 		if (!update_contention_stats)
1419*5113495bSYour Name 			continue;
1420*5113495bSYour Name 		stats->contention_time_min = hdd_ac_stats->contention_time_min;
1421*5113495bSYour Name 		stats->contention_time_max = hdd_ac_stats->contention_time_max;
1422*5113495bSYour Name 		stats->contention_time_avg = hdd_ac_stats->contention_time_avg;
1423*5113495bSYour Name 		stats->contention_num_samples =
1424*5113495bSYour Name 					hdd_ac_stats->contention_num_samples;
1425*5113495bSYour Name 	}
1426*5113495bSYour Name }
1427*5113495bSYour Name 
1428*5113495bSYour Name /**
1429*5113495bSYour Name  * wlan_hdd_update_iface_stats_info() - Populate ll_iface stats info
1430*5113495bSYour Name  * @link_info: Link info pointer of STA adapter
1431*5113495bSYour Name  * @if_stat: Pointer to wifi_interface_stats structure
1432*5113495bSYour Name  * @update_stats: whether to update iface stats
1433*5113495bSYour Name  *
1434*5113495bSYour Name  * Return: none
1435*5113495bSYour Name  */
1436*5113495bSYour Name static void
wlan_hdd_update_iface_stats_info(struct wlan_hdd_link_info * link_info,struct wifi_interface_stats * if_stat,bool update_stats)1437*5113495bSYour Name wlan_hdd_update_iface_stats_info(struct wlan_hdd_link_info *link_info,
1438*5113495bSYour Name 				 struct wifi_interface_stats *if_stat,
1439*5113495bSYour Name 				 bool update_stats)
1440*5113495bSYour Name {
1441*5113495bSYour Name 	wmi_iface_link_stats *hdd_stats, *stats;
1442*5113495bSYour Name 
1443*5113495bSYour Name 	hdd_stats = &link_info->ll_iface_stats.link_stats;
1444*5113495bSYour Name 	stats = &if_stat->link_stats;
1445*5113495bSYour Name 
1446*5113495bSYour Name 	if (!update_stats) {
1447*5113495bSYour Name 		wlan_hdd_update_wmm_ac_stats(link_info, if_stat, update_stats);
1448*5113495bSYour Name 		return;
1449*5113495bSYour Name 	}
1450*5113495bSYour Name 
1451*5113495bSYour Name 	stats->beacon_rx = hdd_stats->beacon_rx;
1452*5113495bSYour Name 	stats->mgmt_rx = hdd_stats->mgmt_rx;
1453*5113495bSYour Name 	stats->mgmt_action_rx = hdd_stats->mgmt_action_rx;
1454*5113495bSYour Name 	stats->mgmt_action_tx = hdd_stats->mgmt_action_tx;
1455*5113495bSYour Name 	stats->rssi_mgmt = hdd_stats->rssi_mgmt;
1456*5113495bSYour Name 	stats->rssi_data = hdd_stats->rssi_data;
1457*5113495bSYour Name 	stats->rssi_ack = hdd_stats->rssi_ack;
1458*5113495bSYour Name 	stats->avg_bcn_spread_offset_low =
1459*5113495bSYour Name 			hdd_stats->avg_bcn_spread_offset_low;
1460*5113495bSYour Name 	stats->avg_bcn_spread_offset_high =
1461*5113495bSYour Name 			hdd_stats->avg_bcn_spread_offset_high;
1462*5113495bSYour Name 	stats->is_leaky_ap = hdd_stats->is_leaky_ap;
1463*5113495bSYour Name 	stats->avg_rx_frms_leaked = hdd_stats->avg_rx_frms_leaked;
1464*5113495bSYour Name 	stats->rx_leak_window = hdd_stats->rx_leak_window;
1465*5113495bSYour Name 	stats->nf_cal_val = hdd_stats->nf_cal_val;
1466*5113495bSYour Name 	stats->num_peers = hdd_stats->num_peers;
1467*5113495bSYour Name 	stats->num_ac = hdd_stats->num_ac;
1468*5113495bSYour Name 
1469*5113495bSYour Name 	if_stat->rts_succ_cnt = link_info->ll_iface_stats.rts_succ_cnt;
1470*5113495bSYour Name 	if_stat->rts_fail_cnt = link_info->ll_iface_stats.rts_fail_cnt;
1471*5113495bSYour Name 	if_stat->ppdu_succ_cnt = link_info->ll_iface_stats.ppdu_succ_cnt;
1472*5113495bSYour Name 	if_stat->ppdu_fail_cnt = link_info->ll_iface_stats.ppdu_fail_cnt;
1473*5113495bSYour Name 
1474*5113495bSYour Name 	if_stat->powersave_stats.tot_tim_bcn =
1475*5113495bSYour Name 		link_info->ll_iface_stats.powersave_stats.tot_tim_bcn;
1476*5113495bSYour Name 	if_stat->powersave_stats.tot_err_tim_bcn =
1477*5113495bSYour Name 		link_info->ll_iface_stats.powersave_stats.tot_err_tim_bcn;
1478*5113495bSYour Name 
1479*5113495bSYour Name 	wlan_hdd_update_wmm_ac_stats(link_info, if_stat, update_stats);
1480*5113495bSYour Name }
1481*5113495bSYour Name 
1482*5113495bSYour Name /**
1483*5113495bSYour Name  * wlan_hdd_copy_mlo_peer_stats() - copy mlo peer stats to link_info
1484*5113495bSYour Name  * @adapter: Pointer to HDD adapter
1485*5113495bSYour Name  * @peer_stat: Pointer to wifi_peer_stat
1486*5113495bSYour Name  *
1487*5113495bSYour Name  * Return: none
1488*5113495bSYour Name  */
1489*5113495bSYour Name static void
wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter * adapter,struct wifi_peer_stat * peer_stat)1490*5113495bSYour Name wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter *adapter,
1491*5113495bSYour Name 			     struct wifi_peer_stat *peer_stat)
1492*5113495bSYour Name {
1493*5113495bSYour Name 	uint8_t i, j, num_rate;
1494*5113495bSYour Name 	struct wifi_peer_info *peer_info = NULL;
1495*5113495bSYour Name 	struct wifi_rate_stat *rate_stat;
1496*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
1497*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
1498*5113495bSYour Name 
1499*5113495bSYour Name 	if (!peer_stat) {
1500*5113495bSYour Name 		hdd_err("Invalid mlo peer stats");
1501*5113495bSYour Name 		return;
1502*5113495bSYour Name 	}
1503*5113495bSYour Name 
1504*5113495bSYour Name 	if (!peer_stat->num_peers) {
1505*5113495bSYour Name 		hdd_err("No mlo peers");
1506*5113495bSYour Name 		return;
1507*5113495bSYour Name 	}
1508*5113495bSYour Name 
1509*5113495bSYour Name 	/* Firmware doesn't send peer stats for stanby link, but we need to
1510*5113495bSYour Name 	 * send peer stats for stanby link as well to userspace. So, in that
1511*5113495bSYour Name 	 * case we fill partial values for stanby link and full stats received
1512*5113495bSYour Name 	 * from firmware for active links and set the flag stats_cached in
1513*5113495bSYour Name 	 * the link_info->mlo_peer_info structure.
1514*5113495bSYour Name 	 */
1515*5113495bSYour Name 
1516*5113495bSYour Name 	peer_info = (struct wifi_peer_info *)peer_stat->peer_info;
1517*5113495bSYour Name 
1518*5113495bSYour Name 	hdd_adapter_for_each_link_info(adapter, link_info) {
1519*5113495bSYour Name 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1520*5113495bSYour Name 		link_info->mlo_peer_info.link_id =
1521*5113495bSYour Name 						sta_ctx->conn_info.ieee_link_id;
1522*5113495bSYour Name 
1523*5113495bSYour Name 		if (link_info->mlo_peer_info.stats_cached)
1524*5113495bSYour Name 			continue;
1525*5113495bSYour Name 
1526*5113495bSYour Name 		/* since for stanby link we don't have valid values from
1527*5113495bSYour Name 		 * firmware, we just fill peer mac and link id.
1528*5113495bSYour Name 		 */
1529*5113495bSYour Name 		qdf_mem_copy(&link_info->mlo_peer_info.peer_mac,
1530*5113495bSYour Name 			     &sta_ctx->conn_info.bssid, QDF_MAC_ADDR_SIZE);
1531*5113495bSYour Name 		link_info->mlo_peer_info.type = peer_info->type;
1532*5113495bSYour Name 		link_info->mlo_peer_info.num_rate = HDD_MAX_PER_PEER_RATES;
1533*5113495bSYour Name 		for (j = 0; j < HDD_MAX_PER_PEER_RATES; j++)
1534*5113495bSYour Name 			qdf_mem_zero(&link_info->mlo_peer_info.rate_stats[j],
1535*5113495bSYour Name 				     sizeof(struct wifi_rate_stat));
1536*5113495bSYour Name 		hdd_debug("Default values for standby link " QDF_MAC_ADDR_FMT,
1537*5113495bSYour Name 			  QDF_MAC_ADDR_REF(sta_ctx->conn_info.bssid.bytes));
1538*5113495bSYour Name 	}
1539*5113495bSYour Name 
1540*5113495bSYour Name 	for (i = 1; i <= peer_stat->num_peers; i++) {
1541*5113495bSYour Name 		link_info = hdd_get_link_info_by_bssid(adapter->hdd_ctx,
1542*5113495bSYour Name 						peer_info->peer_macaddr.bytes);
1543*5113495bSYour Name 		if (!link_info) {
1544*5113495bSYour Name 			hdd_err("invalid link_info");
1545*5113495bSYour Name 			continue;
1546*5113495bSYour Name 		}
1547*5113495bSYour Name 
1548*5113495bSYour Name 		num_rate = peer_info->num_rate;
1549*5113495bSYour Name 		if (num_rate > HDD_MAX_PER_PEER_RATES) {
1550*5113495bSYour Name 			hdd_err("For peer " QDF_MAC_ADDR_FMT " got %u rate stats, expected %d",
1551*5113495bSYour Name 				QDF_MAC_ADDR_REF(peer_info->peer_macaddr.bytes),
1552*5113495bSYour Name 				num_rate, HDD_MAX_PER_PEER_RATES);
1553*5113495bSYour Name 			return;
1554*5113495bSYour Name 		}
1555*5113495bSYour Name 
1556*5113495bSYour Name 		link_info->mlo_peer_info.type = peer_info->type;
1557*5113495bSYour Name 		qdf_mem_copy(&link_info->mlo_peer_info.peer_mac,
1558*5113495bSYour Name 			     &peer_info->peer_macaddr, QDF_MAC_ADDR_SIZE);
1559*5113495bSYour Name 		link_info->mlo_peer_info.capabilities = peer_info->capabilities;
1560*5113495bSYour Name 		link_info->mlo_peer_info.num_rate = peer_info->num_rate;
1561*5113495bSYour Name 		link_info->mlo_peer_info.power_saving = peer_info->power_saving;
1562*5113495bSYour Name 
1563*5113495bSYour Name 		for (j = 0; j < num_rate; j++) {
1564*5113495bSYour Name 			rate_stat = &peer_info->rate_stats[j];
1565*5113495bSYour Name 			qdf_mem_copy(&link_info->mlo_peer_info.rate_stats[j],
1566*5113495bSYour Name 				     rate_stat, sizeof(struct wifi_rate_stat));
1567*5113495bSYour Name 		}
1568*5113495bSYour Name 
1569*5113495bSYour Name 		/* peer stats for active link are cached in link_info
1570*5113495bSYour Name 		 * so set the flag stats_cahed to true.
1571*5113495bSYour Name 		 */
1572*5113495bSYour Name 		link_info->mlo_peer_info.stats_cached = true;
1573*5113495bSYour Name 
1574*5113495bSYour Name 		peer_info = (struct wifi_peer_info *)
1575*5113495bSYour Name 				((uint8_t *)peer_stat->peer_info +
1576*5113495bSYour Name 				(i * sizeof(struct wifi_peer_info)) +
1577*5113495bSYour Name 				(num_rate * sizeof(struct wifi_rate_stat)));
1578*5113495bSYour Name 	}
1579*5113495bSYour Name 	hdd_debug_rl("Copied MLO Peer stats into link_info");
1580*5113495bSYour Name }
1581*5113495bSYour Name 
1582*5113495bSYour Name /**
1583*5113495bSYour Name  * wlan_hdd_put_mlo_peer_info() - send mlo peer info to userspace
1584*5113495bSYour Name  * @link_info: Link info pointer of STA adapter
1585*5113495bSYour Name  * @skb: Pointer to vendor event
1586*5113495bSYour Name  *
1587*5113495bSYour Name  * Return: none
1588*5113495bSYour Name  */
wlan_hdd_put_mlo_peer_info(struct wlan_hdd_link_info * link_info,struct sk_buff * skb)1589*5113495bSYour Name static bool wlan_hdd_put_mlo_peer_info(struct wlan_hdd_link_info *link_info,
1590*5113495bSYour Name 				       struct sk_buff *skb)
1591*5113495bSYour Name {
1592*5113495bSYour Name 	struct wifi_rate_stat *rate_stat;
1593*5113495bSYour Name 	struct nlattr *rate_nest, *rates;
1594*5113495bSYour Name 	int rate_nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO;
1595*5113495bSYour Name 	uint8_t i;
1596*5113495bSYour Name 
1597*5113495bSYour Name 	if (!link_info) {
1598*5113495bSYour Name 		hdd_err("Invalid link_info");
1599*5113495bSYour Name 		return false;
1600*5113495bSYour Name 	}
1601*5113495bSYour Name 
1602*5113495bSYour Name 	if (nla_put_u32(skb,
1603*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE,
1604*5113495bSYour Name 			wmi_to_sir_peer_type(link_info->mlo_peer_info.type)) ||
1605*5113495bSYour Name 	    nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS,
1606*5113495bSYour Name 		    QDF_MAC_ADDR_SIZE,
1607*5113495bSYour Name 		    &link_info->mlo_peer_info.peer_mac.bytes[0]) ||
1608*5113495bSYour Name 	    nla_put_u32(skb,
1609*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES,
1610*5113495bSYour Name 			link_info->mlo_peer_info.capabilities) ||
1611*5113495bSYour Name 	    nla_put_u32(skb,
1612*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES,
1613*5113495bSYour Name 			link_info->mlo_peer_info.num_rate) ||
1614*5113495bSYour Name 	    nla_put_u8(skb,
1615*5113495bSYour Name 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID,
1616*5113495bSYour Name 		       link_info->mlo_peer_info.link_id)) {
1617*5113495bSYour Name 		hdd_err("put mlo peer info fail");
1618*5113495bSYour Name 		return false;
1619*5113495bSYour Name 	}
1620*5113495bSYour Name 
1621*5113495bSYour Name 	/* no rates is ok */
1622*5113495bSYour Name 	if (!link_info->mlo_peer_info.num_rate)
1623*5113495bSYour Name 		return true;
1624*5113495bSYour Name 
1625*5113495bSYour Name 	rate_nest = nla_nest_start(skb, rate_nest_id);
1626*5113495bSYour Name 	if (!rate_nest)
1627*5113495bSYour Name 		return false;
1628*5113495bSYour Name 
1629*5113495bSYour Name 	for (i = 0; i < link_info->mlo_peer_info.num_rate; i++) {
1630*5113495bSYour Name 		rates = nla_nest_start(skb, i);
1631*5113495bSYour Name 		if (!rates)
1632*5113495bSYour Name 			return false;
1633*5113495bSYour Name 		rate_stat = &link_info->mlo_peer_info.rate_stats[i];
1634*5113495bSYour Name 		if (!put_wifi_rate_stat(rate_stat, skb)) {
1635*5113495bSYour Name 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1636*5113495bSYour Name 			return false;
1637*5113495bSYour Name 		}
1638*5113495bSYour Name 		nla_nest_end(skb, rates);
1639*5113495bSYour Name 	}
1640*5113495bSYour Name 	nla_nest_end(skb, rate_nest);
1641*5113495bSYour Name 
1642*5113495bSYour Name 	return true;
1643*5113495bSYour Name }
1644*5113495bSYour Name 
1645*5113495bSYour Name /**
1646*5113495bSYour Name  * wlan_hdd_send_mlo_ll_peer_stats_to_user() - send mlo ll peer stats to userspace
1647*5113495bSYour Name  * @adapter: Pointer to HDD adapter
1648*5113495bSYour Name  *
1649*5113495bSYour Name  * Return: none
1650*5113495bSYour Name  */
1651*5113495bSYour Name static void
wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter * adapter)1652*5113495bSYour Name wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter *adapter)
1653*5113495bSYour Name {
1654*5113495bSYour Name 	struct sk_buff *skb;
1655*5113495bSYour Name 	struct nlattr *peers, *peer_nest;
1656*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
1657*5113495bSYour Name 	struct wlan_hdd_mlo_iface_stats_info info = {0};
1658*5113495bSYour Name 	int peer_nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO;
1659*5113495bSYour Name 	u32 num_peers;
1660*5113495bSYour Name 	uint8_t i = 0;
1661*5113495bSYour Name 
1662*5113495bSYour Name 	wlan_hdd_get_mlo_links_count(adapter, &num_peers);
1663*5113495bSYour Name 
1664*5113495bSYour Name 	hdd_debug_rl("WMI_MLO_LINK_STATS_PEER. Num Peers: %u", num_peers);
1665*5113495bSYour Name 
1666*5113495bSYour Name 	if (!num_peers) {
1667*5113495bSYour Name 		hdd_err("No mlo peers");
1668*5113495bSYour Name 		return;
1669*5113495bSYour Name 	}
1670*5113495bSYour Name 
1671*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(adapter->hdd_ctx->wiphy,
1672*5113495bSYour Name 						       LL_STATS_EVENT_BUF_SIZE);
1673*5113495bSYour Name 	if (!skb) {
1674*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1675*5113495bSYour Name 		return;
1676*5113495bSYour Name 	}
1677*5113495bSYour Name 
1678*5113495bSYour Name 	if (nla_put_u32(skb,
1679*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
1680*5113495bSYour Name 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS) ||
1681*5113495bSYour Name 	    nla_put_u32(skb,
1682*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
1683*5113495bSYour Name 			adapter->hdd_ctx->more_peer_data) ||
1684*5113495bSYour Name 	    nla_put_u32(skb,
1685*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
1686*5113495bSYour Name 			num_peers)) {
1687*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
1688*5113495bSYour Name 
1689*5113495bSYour Name 		goto exit;
1690*5113495bSYour Name 	}
1691*5113495bSYour Name 
1692*5113495bSYour Name 	peer_nest = nla_nest_start(skb, peer_nest_id);
1693*5113495bSYour Name 	if (!peer_nest) {
1694*5113495bSYour Name 		hdd_err("nla_nest_start failed");
1695*5113495bSYour Name 		goto exit;
1696*5113495bSYour Name 	}
1697*5113495bSYour Name 
1698*5113495bSYour Name 	hdd_adapter_for_each_link_info(adapter, link_info) {
1699*5113495bSYour Name 		wlan_hdd_get_connected_link_info(link_info, &info);
1700*5113495bSYour Name 		if (info.link_id == WLAN_INVALID_LINK_ID)
1701*5113495bSYour Name 			continue;
1702*5113495bSYour Name 
1703*5113495bSYour Name 		peers = nla_nest_start(skb, i);
1704*5113495bSYour Name 		if (!peers) {
1705*5113495bSYour Name 			hdd_err("nla_nest_start failed");
1706*5113495bSYour Name 			goto exit;
1707*5113495bSYour Name 		}
1708*5113495bSYour Name 
1709*5113495bSYour Name 		if (!wlan_hdd_put_mlo_peer_info(link_info, skb)) {
1710*5113495bSYour Name 			hdd_err("put_wifi_peer_info fail");
1711*5113495bSYour Name 			goto exit;
1712*5113495bSYour Name 		}
1713*5113495bSYour Name 		nla_nest_end(skb, peers);
1714*5113495bSYour Name 		i++;
1715*5113495bSYour Name 	}
1716*5113495bSYour Name 	nla_nest_end(skb, peer_nest);
1717*5113495bSYour Name 
1718*5113495bSYour Name 	wlan_cfg80211_vendor_cmd_reply(skb);
1719*5113495bSYour Name 
1720*5113495bSYour Name 	hdd_debug_rl("Sent %u MLO Peer stats to User Space", i);
1721*5113495bSYour Name 	return;
1722*5113495bSYour Name exit:
1723*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(skb);
1724*5113495bSYour Name }
1725*5113495bSYour Name 
1726*5113495bSYour Name #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
1727*5113495bSYour Name /**
1728*5113495bSYour Name  * wlan_hdd_get_iface_stats() - Get ll_iface stats info from link_info
1729*5113495bSYour Name  * @link_info: Link info pointer of STA adapter
1730*5113495bSYour Name  * @if_stat: Pointer to wifi_interface_stats structure
1731*5113495bSYour Name  *
1732*5113495bSYour Name  * Return: 0 on success, error on failure
1733*5113495bSYour Name  */
wlan_hdd_get_iface_stats(struct wlan_hdd_link_info * link_info,struct wifi_interface_stats * if_stat)1734*5113495bSYour Name static int wlan_hdd_get_iface_stats(struct wlan_hdd_link_info *link_info,
1735*5113495bSYour Name 				    struct wifi_interface_stats *if_stat)
1736*5113495bSYour Name {
1737*5113495bSYour Name 	if (!link_info || !if_stat) {
1738*5113495bSYour Name 		hdd_err("Invalid link_info or interface stats");
1739*5113495bSYour Name 		return -EINVAL;
1740*5113495bSYour Name 	}
1741*5113495bSYour Name 
1742*5113495bSYour Name 	qdf_mem_copy(if_stat, &link_info->ll_iface_stats,
1743*5113495bSYour Name 		     sizeof(link_info->ll_iface_stats));
1744*5113495bSYour Name 
1745*5113495bSYour Name 	if (!hdd_get_interface_info(link_info, &if_stat->info)) {
1746*5113495bSYour Name 		hdd_err("Unable to get iface info for vdev[%u]",
1747*5113495bSYour Name 			if_stat->vdev_id);
1748*5113495bSYour Name 		return -EINVAL;
1749*5113495bSYour Name 	}
1750*5113495bSYour Name 
1751*5113495bSYour Name 	return 0;
1752*5113495bSYour Name }
1753*5113495bSYour Name 
1754*5113495bSYour Name static bool
wlan_hdd_get_mlo_iface_info(struct hdd_context * hdd_ctx,struct wifi_interface_stats * stats,struct wlan_hdd_mlo_iface_stats_info * info)1755*5113495bSYour Name wlan_hdd_get_mlo_iface_info(struct hdd_context *hdd_ctx,
1756*5113495bSYour Name 			    struct wifi_interface_stats *stats,
1757*5113495bSYour Name 			    struct wlan_hdd_mlo_iface_stats_info *info)
1758*5113495bSYour Name {
1759*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
1760*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
1761*5113495bSYour Name 
1762*5113495bSYour Name 	if (!stats) {
1763*5113495bSYour Name 		hdd_err("invalid wifi interface stats");
1764*5113495bSYour Name 		return false;
1765*5113495bSYour Name 	}
1766*5113495bSYour Name 
1767*5113495bSYour Name 	link_info = hdd_get_link_info_by_bssid(hdd_ctx,
1768*5113495bSYour Name 				(const uint8_t *)stats->info.bssid.bytes);
1769*5113495bSYour Name 
1770*5113495bSYour Name 	if (!link_info) {
1771*5113495bSYour Name 		hdd_err("invalid link_info");
1772*5113495bSYour Name 		return false;
1773*5113495bSYour Name 	}
1774*5113495bSYour Name 
1775*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1776*5113495bSYour Name 	info->link_id = sta_ctx->conn_info.ieee_link_id;
1777*5113495bSYour Name 	info->freq = sta_ctx->conn_info.chan_freq;
1778*5113495bSYour Name 
1779*5113495bSYour Name 	return true;
1780*5113495bSYour Name }
1781*5113495bSYour Name 
1782*5113495bSYour Name /**
1783*5113495bSYour Name  * wlan_hdd_send_mlo_ll_iface_stats_to_user() - send mlo ll stats to userspace
1784*5113495bSYour Name  * @adapter: Pointer to adapter
1785*5113495bSYour Name  *
1786*5113495bSYour Name  * Return: none
1787*5113495bSYour Name  */
1788*5113495bSYour Name static void
wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter * adapter)1789*5113495bSYour Name wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter)
1790*5113495bSYour Name {
1791*5113495bSYour Name 	struct hdd_mlo_adapter_info *mlo_adapter_info;
1792*5113495bSYour Name 	struct hdd_adapter *link_adapter, *ml_adapter;
1793*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1794*5113495bSYour Name 	u32 num_links, per_link_peers;
1795*5113495bSYour Name 	uint8_t i, j = 0;
1796*5113495bSYour Name 	int8_t rssi;
1797*5113495bSYour Name 	struct wifi_interface_stats cumulative_if_stat = {0};
1798*5113495bSYour Name 	struct wlan_hdd_mlo_iface_stats_info info = {0};
1799*5113495bSYour Name 	struct wifi_interface_stats *link_if_stat;
1800*5113495bSYour Name 	bool update_stats = false;
1801*5113495bSYour Name 	QDF_STATUS status;
1802*5113495bSYour Name 	struct nlattr *ml_iface_nest, *ml_iface_links;
1803*5113495bSYour Name 	struct sk_buff *skb;
1804*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
1805*5113495bSYour Name 	struct qdf_mac_addr *netdev_addr;
1806*5113495bSYour Name 
1807*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx)) {
1808*5113495bSYour Name 		hdd_err("Invalid hdd context");
1809*5113495bSYour Name 		return;
1810*5113495bSYour Name 	}
1811*5113495bSYour Name 
1812*5113495bSYour Name 	ml_adapter = adapter;
1813*5113495bSYour Name 	if (hdd_adapter_is_link_adapter(adapter))
1814*5113495bSYour Name 		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
1815*5113495bSYour Name 
1816*5113495bSYour Name 	link_info = ml_adapter->deflink;
1817*5113495bSYour Name 	rssi = link_info->rssi;
1818*5113495bSYour Name 	wlan_hdd_get_mlo_links_count(adapter, &num_links);
1819*5113495bSYour Name 
1820*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
1821*5113495bSYour Name 						       LL_STATS_EVENT_BUF_SIZE);
1822*5113495bSYour Name 
1823*5113495bSYour Name 	if (!skb) {
1824*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1825*5113495bSYour Name 		return;
1826*5113495bSYour Name 	}
1827*5113495bSYour Name 
1828*5113495bSYour Name 	link_if_stat = qdf_mem_malloc(sizeof(*link_if_stat) * num_links);
1829*5113495bSYour Name 	if (!link_if_stat) {
1830*5113495bSYour Name 		hdd_err("failed to allocate memory for link iface stat");
1831*5113495bSYour Name 		goto err;
1832*5113495bSYour Name 	}
1833*5113495bSYour Name 
1834*5113495bSYour Name 	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_links = %u", num_links);
1835*5113495bSYour Name 
1836*5113495bSYour Name 	if (!hdd_get_interface_info(link_info, &cumulative_if_stat.info)) {
1837*5113495bSYour Name 		hdd_err("hdd_get_interface_info get fail for ml_adapter");
1838*5113495bSYour Name 		goto err;
1839*5113495bSYour Name 	}
1840*5113495bSYour Name 
1841*5113495bSYour Name 	wlan_hdd_update_iface_stats_info(link_info, &cumulative_if_stat,
1842*5113495bSYour Name 					 true);
1843*5113495bSYour Name 
1844*5113495bSYour Name 	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
1845*5113495bSYour Name 	for (i = 0; i < WLAN_MAX_MLD; i++) {
1846*5113495bSYour Name 		link_adapter = mlo_adapter_info->link_adapter[i];
1847*5113495bSYour Name 
1848*5113495bSYour Name 		if (!link_adapter)
1849*5113495bSYour Name 			continue;
1850*5113495bSYour Name 
1851*5113495bSYour Name 		link_info = link_adapter->deflink;
1852*5113495bSYour Name 		if (!hdd_cm_is_vdev_associated(link_info)) {
1853*5113495bSYour Name 			hdd_debug_rl("vdev_id[%u] is not associated\n",
1854*5113495bSYour Name 				     link_info->vdev_id);
1855*5113495bSYour Name 			continue;
1856*5113495bSYour Name 		}
1857*5113495bSYour Name 
1858*5113495bSYour Name 		if (hdd_adapter_is_associated_with_ml_adapter(link_adapter)) {
1859*5113495bSYour Name 			if (wlan_hdd_get_iface_stats(ml_adapter->deflink,
1860*5113495bSYour Name 						     &link_if_stat[j]))
1861*5113495bSYour Name 				goto err;
1862*5113495bSYour Name 			j++;
1863*5113495bSYour Name 			if (j == num_links)
1864*5113495bSYour Name 				break;
1865*5113495bSYour Name 			continue;
1866*5113495bSYour Name 		}
1867*5113495bSYour Name 
1868*5113495bSYour Name 		if (wlan_hdd_get_iface_stats(link_info, &link_if_stat[j]))
1869*5113495bSYour Name 			goto err;
1870*5113495bSYour Name 		j++;
1871*5113495bSYour Name 		if (j == num_links)
1872*5113495bSYour Name 			break;
1873*5113495bSYour Name 
1874*5113495bSYour Name 		if (rssi <= link_info->rssi) {
1875*5113495bSYour Name 			rssi = link_info->rssi;
1876*5113495bSYour Name 			update_stats = true;
1877*5113495bSYour Name 		}
1878*5113495bSYour Name 
1879*5113495bSYour Name 		wlan_hdd_update_iface_stats_info(link_info,
1880*5113495bSYour Name 						 &cumulative_if_stat,
1881*5113495bSYour Name 						 update_stats);
1882*5113495bSYour Name 	}
1883*5113495bSYour Name 
1884*5113495bSYour Name 	netdev_addr = hdd_adapter_get_netdev_mac_addr(ml_adapter);
1885*5113495bSYour Name 	qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr);
1886*5113495bSYour Name 
1887*5113495bSYour Name 	status = wlan_hdd_get_bss_peer_mld_mac(ml_adapter->deflink,
1888*5113495bSYour Name 					       &cumulative_if_stat.info.bssid);
1889*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
1890*5113495bSYour Name 		hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac");
1891*5113495bSYour Name 
1892*5113495bSYour Name 	if (!put_wifi_iface_stats(&cumulative_if_stat, num_links, skb,
1893*5113495bSYour Name 				  ml_adapter->deflink)) {
1894*5113495bSYour Name 		hdd_err("put_wifi_iface_stats fail");
1895*5113495bSYour Name 		goto err;
1896*5113495bSYour Name 	}
1897*5113495bSYour Name 
1898*5113495bSYour Name 	ml_iface_nest = nla_nest_start(skb,
1899*5113495bSYour Name 				       QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK);
1900*5113495bSYour Name 	if (!ml_iface_nest) {
1901*5113495bSYour Name 		hdd_err("Nesting mlo iface stats info failed");
1902*5113495bSYour Name 		goto err;
1903*5113495bSYour Name 	}
1904*5113495bSYour Name 
1905*5113495bSYour Name 	for (i = 0; i < num_links; i++) {
1906*5113495bSYour Name 		ml_iface_links = nla_nest_start(skb, i);
1907*5113495bSYour Name 		if (!ml_iface_links) {
1908*5113495bSYour Name 			hdd_err("per link mlo iface stats failed");
1909*5113495bSYour Name 			goto err;
1910*5113495bSYour Name 		}
1911*5113495bSYour Name 
1912*5113495bSYour Name 		per_link_peers =
1913*5113495bSYour Name 			link_info->ll_iface_stats.link_stats.num_peers;
1914*5113495bSYour Name 
1915*5113495bSYour Name 		if (!wlan_hdd_get_mlo_iface_info(hdd_ctx,
1916*5113495bSYour Name 						 &link_if_stat[i], &info))
1917*5113495bSYour Name 			goto err;
1918*5113495bSYour Name 
1919*5113495bSYour Name 		if (!wlan_hdd_put_mlo_link_iface_info(&info, skb))
1920*5113495bSYour Name 			goto err;
1921*5113495bSYour Name 
1922*5113495bSYour Name 		if (!put_wifi_iface_stats(&link_if_stat[i],
1923*5113495bSYour Name 					  per_link_peers, skb, link_info)) {
1924*5113495bSYour Name 			hdd_err("put_wifi_iface_stats failed for link[%u]", i);
1925*5113495bSYour Name 			goto err;
1926*5113495bSYour Name 		}
1927*5113495bSYour Name 
1928*5113495bSYour Name 		nla_nest_end(skb, ml_iface_links);
1929*5113495bSYour Name 	}
1930*5113495bSYour Name 	nla_nest_end(skb, ml_iface_nest);
1931*5113495bSYour Name 
1932*5113495bSYour Name 	wlan_cfg80211_vendor_cmd_reply(skb);
1933*5113495bSYour Name 	qdf_mem_free(link_if_stat);
1934*5113495bSYour Name 	hdd_nofl_debug("Sent mlo interface stats to userspace");
1935*5113495bSYour Name 	return;
1936*5113495bSYour Name err:
1937*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(skb);
1938*5113495bSYour Name 	qdf_mem_free(link_if_stat);
1939*5113495bSYour Name }
1940*5113495bSYour Name #else
1941*5113495bSYour Name static void
wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter * adapter)1942*5113495bSYour Name wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter)
1943*5113495bSYour Name {
1944*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1945*5113495bSYour Name 	u32 num_links, per_link_peers;
1946*5113495bSYour Name 	uint8_t i = 0;
1947*5113495bSYour Name 	int8_t rssi = WLAN_INVALID_RSSI_VALUE;
1948*5113495bSYour Name 	struct wifi_interface_stats cumulative_if_stat = {0};
1949*5113495bSYour Name 	struct wlan_hdd_mlo_iface_stats_info info = {0};
1950*5113495bSYour Name 	struct wifi_interface_stats *stats;
1951*5113495bSYour Name 	struct wifi_interface_info *iface_info;
1952*5113495bSYour Name 	bool update_stats;
1953*5113495bSYour Name 	QDF_STATUS status;
1954*5113495bSYour Name 	struct nlattr *ml_iface_nest, *ml_iface_links;
1955*5113495bSYour Name 	struct sk_buff *skb;
1956*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
1957*5113495bSYour Name 	struct qdf_mac_addr *netdev_addr;
1958*5113495bSYour Name 	int8_t rssi_data;
1959*5113495bSYour Name 
1960*5113495bSYour Name 	if (!wlan_hdd_is_mlo_connection(adapter->deflink))
1961*5113495bSYour Name 		return;
1962*5113495bSYour Name 
1963*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx)) {
1964*5113495bSYour Name 		hdd_err("Invalid hdd context");
1965*5113495bSYour Name 		return;
1966*5113495bSYour Name 	}
1967*5113495bSYour Name 
1968*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
1969*5113495bSYour Name 						       LL_STATS_EVENT_BUF_SIZE);
1970*5113495bSYour Name 
1971*5113495bSYour Name 	if (!skb) {
1972*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1973*5113495bSYour Name 		return;
1974*5113495bSYour Name 	}
1975*5113495bSYour Name 
1976*5113495bSYour Name 	wlan_hdd_get_mlo_links_count(adapter, &num_links);
1977*5113495bSYour Name 
1978*5113495bSYour Name 	hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_links = %u", num_links);
1979*5113495bSYour Name 
1980*5113495bSYour Name 	hdd_adapter_for_each_link_info(adapter, link_info) {
1981*5113495bSYour Name 		wlan_hdd_get_connected_link_info(link_info, &info);
1982*5113495bSYour Name 
1983*5113495bSYour Name 		if (info.link_id == WLAN_INVALID_LINK_ID)
1984*5113495bSYour Name 			continue;
1985*5113495bSYour Name 
1986*5113495bSYour Name 		rssi_data = link_info->ll_iface_stats.link_stats.rssi_data;
1987*5113495bSYour Name 
1988*5113495bSYour Name 		if ((link_info->adapter->device_mode == QDF_P2P_GO_MODE ||
1989*5113495bSYour Name 		     link_info->adapter->device_mode == QDF_SAP_MODE) &&
1990*5113495bSYour Name 		    rssi <= rssi_data) {
1991*5113495bSYour Name 			rssi = rssi_data;
1992*5113495bSYour Name 			update_stats = true;
1993*5113495bSYour Name 			if (!hdd_get_interface_info(link_info,
1994*5113495bSYour Name 						    &cumulative_if_stat.info)) {
1995*5113495bSYour Name 				hdd_err("failed to get iface info for link %u",
1996*5113495bSYour Name 					info.link_id);
1997*5113495bSYour Name 				goto err;
1998*5113495bSYour Name 			}
1999*5113495bSYour Name 		} else if (rssi_data != 0 && (rssi <= rssi_data)) {
2000*5113495bSYour Name 			rssi = rssi_data;
2001*5113495bSYour Name 			update_stats = true;
2002*5113495bSYour Name 			if (!hdd_get_interface_info(link_info,
2003*5113495bSYour Name 						    &cumulative_if_stat.info)) {
2004*5113495bSYour Name 				hdd_err("failed to get iface info for link %u",
2005*5113495bSYour Name 					info.link_id);
2006*5113495bSYour Name 				goto err;
2007*5113495bSYour Name 			}
2008*5113495bSYour Name 		} else {
2009*5113495bSYour Name 			update_stats = false;
2010*5113495bSYour Name 		}
2011*5113495bSYour Name 
2012*5113495bSYour Name 		iface_info = &link_info->ll_iface_stats.info;
2013*5113495bSYour Name 		if (!hdd_get_interface_info(link_info, iface_info)) {
2014*5113495bSYour Name 			hdd_err("get iface info failed for link %u", info.link_id);
2015*5113495bSYour Name 			goto err;
2016*5113495bSYour Name 		}
2017*5113495bSYour Name 
2018*5113495bSYour Name 		wlan_hdd_update_iface_stats_info(link_info, &cumulative_if_stat,
2019*5113495bSYour Name 						 update_stats);
2020*5113495bSYour Name 	}
2021*5113495bSYour Name 
2022*5113495bSYour Name 	netdev_addr = hdd_adapter_get_netdev_mac_addr(adapter);
2023*5113495bSYour Name 	qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr);
2024*5113495bSYour Name 
2025*5113495bSYour Name 	status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink,
2026*5113495bSYour Name 					       &cumulative_if_stat.info.bssid);
2027*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
2028*5113495bSYour Name 		hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac");
2029*5113495bSYour Name 
2030*5113495bSYour Name 	if (!put_wifi_iface_stats(&cumulative_if_stat, num_links, skb,
2031*5113495bSYour Name 				  adapter->deflink)) {
2032*5113495bSYour Name 		hdd_err("put_wifi_iface_stats fail");
2033*5113495bSYour Name 		goto err;
2034*5113495bSYour Name 	}
2035*5113495bSYour Name 
2036*5113495bSYour Name 	ml_iface_nest =
2037*5113495bSYour Name 		nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK);
2038*5113495bSYour Name 
2039*5113495bSYour Name 	if (!ml_iface_nest) {
2040*5113495bSYour Name 		hdd_err("Nesting mlo iface stats info failed");
2041*5113495bSYour Name 		goto err;
2042*5113495bSYour Name 	}
2043*5113495bSYour Name 
2044*5113495bSYour Name 	hdd_adapter_for_each_link_info(adapter, link_info) {
2045*5113495bSYour Name 		wlan_hdd_get_connected_link_info(link_info, &info);
2046*5113495bSYour Name 
2047*5113495bSYour Name 		if (info.link_id == WLAN_INVALID_LINK_ID)
2048*5113495bSYour Name 			continue;
2049*5113495bSYour Name 
2050*5113495bSYour Name 		ml_iface_links = nla_nest_start(skb, i);
2051*5113495bSYour Name 		if (!ml_iface_links) {
2052*5113495bSYour Name 			hdd_err("per link mlo iface stats failed");
2053*5113495bSYour Name 			goto err;
2054*5113495bSYour Name 		}
2055*5113495bSYour Name 
2056*5113495bSYour Name 		stats = &link_info->ll_iface_stats;
2057*5113495bSYour Name 		per_link_peers = stats->link_stats.num_peers;
2058*5113495bSYour Name 
2059*5113495bSYour Name 		if (!wlan_hdd_put_mlo_link_iface_info(&info, skb))
2060*5113495bSYour Name 			goto err;
2061*5113495bSYour Name 
2062*5113495bSYour Name 		if (!put_wifi_iface_stats(stats, per_link_peers, skb,
2063*5113495bSYour Name 					  link_info)) {
2064*5113495bSYour Name 			hdd_err("put iface stats failed for link[%u]", info.link_id);
2065*5113495bSYour Name 			goto err;
2066*5113495bSYour Name 		}
2067*5113495bSYour Name 
2068*5113495bSYour Name 		nla_nest_end(skb, ml_iface_links);
2069*5113495bSYour Name 		i++;
2070*5113495bSYour Name 	}
2071*5113495bSYour Name 	nla_nest_end(skb, ml_iface_nest);
2072*5113495bSYour Name 
2073*5113495bSYour Name 	wlan_cfg80211_vendor_cmd_reply(skb);
2074*5113495bSYour Name 	hdd_nofl_debug("Sent mlo interface stats to userspace");
2075*5113495bSYour Name 	return;
2076*5113495bSYour Name err:
2077*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(skb);
2078*5113495bSYour Name }
2079*5113495bSYour Name #endif
2080*5113495bSYour Name #else
2081*5113495bSYour Name static void
hdd_cache_ll_iface_stats(struct hdd_context * hdd_ctx,struct wifi_interface_stats * if_stat)2082*5113495bSYour Name hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx,
2083*5113495bSYour Name 			 struct wifi_interface_stats *if_stat)
2084*5113495bSYour Name {
2085*5113495bSYour Name }
2086*5113495bSYour Name 
2087*5113495bSYour Name static inline void
wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter * adapter)2088*5113495bSYour Name wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter)
2089*5113495bSYour Name {
2090*5113495bSYour Name }
2091*5113495bSYour Name 
2092*5113495bSYour Name static inline void
wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter * adapter)2093*5113495bSYour Name wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter *adapter)
2094*5113495bSYour Name {
2095*5113495bSYour Name }
2096*5113495bSYour Name 
2097*5113495bSYour Name static inline bool
wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter * adapter,struct wifi_peer_stat * peer_stat)2098*5113495bSYour Name wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter *adapter,
2099*5113495bSYour Name 			     struct wifi_peer_stat *peer_stat)
2100*5113495bSYour Name {
2101*5113495bSYour Name 	return true;
2102*5113495bSYour Name }
2103*5113495bSYour Name #endif
2104*5113495bSYour Name 
2105*5113495bSYour Name /**
2106*5113495bSYour Name  * hdd_link_layer_process_peer_stats() - This function is called after
2107*5113495bSYour Name  * @adapter: Pointer to device adapter
2108*5113495bSYour Name  * @more_data: More data
2109*5113495bSYour Name  * @peer_stat: Pointer to stats data
2110*5113495bSYour Name  *
2111*5113495bSYour Name  * Receiving Link Layer Peer statistics from FW.This function converts
2112*5113495bSYour Name  * the firmware data to the NL data and sends the same to the kernel/upper
2113*5113495bSYour Name  * layers.
2114*5113495bSYour Name  *
2115*5113495bSYour Name  * Return: None
2116*5113495bSYour Name  */
hdd_link_layer_process_peer_stats(struct hdd_adapter * adapter,u32 more_data,struct wifi_peer_stat * peer_stat)2117*5113495bSYour Name static void hdd_link_layer_process_peer_stats(struct hdd_adapter *adapter,
2118*5113495bSYour Name 					      u32 more_data,
2119*5113495bSYour Name 					      struct wifi_peer_stat *peer_stat)
2120*5113495bSYour Name {
2121*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2122*5113495bSYour Name 	struct wifi_peer_info *peer_info;
2123*5113495bSYour Name 	struct sk_buff *skb;
2124*5113495bSYour Name 	int i, nestid;
2125*5113495bSYour Name 	struct nlattr *peers;
2126*5113495bSYour Name 	int num_rate;
2127*5113495bSYour Name 
2128*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx))
2129*5113495bSYour Name 		return;
2130*5113495bSYour Name 
2131*5113495bSYour Name 	if ((adapter->device_mode == QDF_STA_MODE ||
2132*5113495bSYour Name 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) &&
2133*5113495bSYour Name 	    wlan_hdd_is_mlo_connection(adapter->deflink)) {
2134*5113495bSYour Name 		wlan_hdd_copy_mlo_peer_stats(adapter, peer_stat);
2135*5113495bSYour Name 		return;
2136*5113495bSYour Name 	}
2137*5113495bSYour Name 
2138*5113495bSYour Name 	hdd_nofl_debug("LL_STATS_PEER_ALL : num_peers %u, more data = %u",
2139*5113495bSYour Name 		       peer_stat->num_peers, more_data);
2140*5113495bSYour Name 
2141*5113495bSYour Name 	/*
2142*5113495bSYour Name 	 * Allocate a size of 4096 for the peer stats comprising
2143*5113495bSYour Name 	 * each of size = sizeof (struct wifi_peer_info) + num_rate *
2144*5113495bSYour Name 	 * sizeof (struct wifi_rate_stat).Each field is put with an
2145*5113495bSYour Name 	 * NL attribute.The size of 4096 is considered assuming
2146*5113495bSYour Name 	 * that number of rates shall not exceed beyond 50 with
2147*5113495bSYour Name 	 * the sizeof (struct wifi_rate_stat) being 32.
2148*5113495bSYour Name 	 */
2149*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
2150*5113495bSYour Name 						       LL_STATS_EVENT_BUF_SIZE);
2151*5113495bSYour Name 
2152*5113495bSYour Name 	if (!skb) {
2153*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
2154*5113495bSYour Name 		return;
2155*5113495bSYour Name 	}
2156*5113495bSYour Name 
2157*5113495bSYour Name 	if (nla_put_u32(skb,
2158*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
2159*5113495bSYour Name 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS) ||
2160*5113495bSYour Name 	    nla_put_u32(skb,
2161*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
2162*5113495bSYour Name 			more_data) ||
2163*5113495bSYour Name 	    nla_put_u32(skb,
2164*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
2165*5113495bSYour Name 			peer_stat->num_peers)) {
2166*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2167*5113495bSYour Name 
2168*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(skb);
2169*5113495bSYour Name 		return;
2170*5113495bSYour Name 	}
2171*5113495bSYour Name 
2172*5113495bSYour Name 	peer_info = (struct wifi_peer_info *) ((uint8_t *)
2173*5113495bSYour Name 					     peer_stat->peer_info);
2174*5113495bSYour Name 
2175*5113495bSYour Name 	if (peer_stat->num_peers) {
2176*5113495bSYour Name 		struct nlattr *peer_nest;
2177*5113495bSYour Name 
2178*5113495bSYour Name 		nestid = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO;
2179*5113495bSYour Name 		peer_nest = nla_nest_start(skb, nestid);
2180*5113495bSYour Name 		if (!peer_nest) {
2181*5113495bSYour Name 			hdd_err("nla_nest_start failed");
2182*5113495bSYour Name 			wlan_cfg80211_vendor_free_skb(skb);
2183*5113495bSYour Name 			return;
2184*5113495bSYour Name 		}
2185*5113495bSYour Name 
2186*5113495bSYour Name 		for (i = 1; i <= peer_stat->num_peers; i++) {
2187*5113495bSYour Name 			peers = nla_nest_start(skb, i);
2188*5113495bSYour Name 			if (!peers) {
2189*5113495bSYour Name 				hdd_err("nla_nest_start failed");
2190*5113495bSYour Name 				wlan_cfg80211_vendor_free_skb(skb);
2191*5113495bSYour Name 				return;
2192*5113495bSYour Name 			}
2193*5113495bSYour Name 
2194*5113495bSYour Name 			num_rate = peer_info->num_rate;
2195*5113495bSYour Name 
2196*5113495bSYour Name 			if (!put_wifi_peer_info(peer_info, skb)) {
2197*5113495bSYour Name 				hdd_err("put_wifi_peer_info fail");
2198*5113495bSYour Name 				wlan_cfg80211_vendor_free_skb(skb);
2199*5113495bSYour Name 				return;
2200*5113495bSYour Name 			}
2201*5113495bSYour Name 
2202*5113495bSYour Name 			peer_info = (struct wifi_peer_info *)
2203*5113495bSYour Name 				((uint8_t *)peer_stat->peer_info +
2204*5113495bSYour Name 				 (i * sizeof(struct wifi_peer_info)) +
2205*5113495bSYour Name 				 (num_rate * sizeof(struct wifi_rate_stat)));
2206*5113495bSYour Name 			nla_nest_end(skb, peers);
2207*5113495bSYour Name 		}
2208*5113495bSYour Name 		nla_nest_end(skb, peer_nest);
2209*5113495bSYour Name 	}
2210*5113495bSYour Name 
2211*5113495bSYour Name 	wlan_cfg80211_vendor_cmd_reply(skb);
2212*5113495bSYour Name }
2213*5113495bSYour Name 
2214*5113495bSYour Name /**
2215*5113495bSYour Name  * hdd_link_layer_process_iface_stats() - This function is called after
2216*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
2217*5113495bSYour Name  * @if_stat: Pointer to stats data
2218*5113495bSYour Name  * @num_peers: Number of peers
2219*5113495bSYour Name  *
2220*5113495bSYour Name  * Receiving Link Layer Interface statistics from FW.This function converts
2221*5113495bSYour Name  * the firmware data to the NL data and sends the same to the kernel/upper
2222*5113495bSYour Name  * layers.
2223*5113495bSYour Name  *
2224*5113495bSYour Name  * Return: None
2225*5113495bSYour Name  */
2226*5113495bSYour Name static void
hdd_link_layer_process_iface_stats(struct wlan_hdd_link_info * link_info,struct wifi_interface_stats * if_stat,u32 num_peers)2227*5113495bSYour Name hdd_link_layer_process_iface_stats(struct wlan_hdd_link_info *link_info,
2228*5113495bSYour Name 				   struct wifi_interface_stats *if_stat,
2229*5113495bSYour Name 				   u32 num_peers)
2230*5113495bSYour Name {
2231*5113495bSYour Name 	struct sk_buff *skb;
2232*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2233*5113495bSYour Name 
2234*5113495bSYour Name 	if (wlan_hdd_is_mlo_connection(link_info)) {
2235*5113495bSYour Name 		hdd_cache_ll_iface_stats(hdd_ctx, if_stat);
2236*5113495bSYour Name 		return;
2237*5113495bSYour Name 	}
2238*5113495bSYour Name 
2239*5113495bSYour Name 	/*
2240*5113495bSYour Name 	 * There is no need for wlan_hdd_validate_context here. This is a NB
2241*5113495bSYour Name 	 * operation that will come with DSC synchronization. This ensures that
2242*5113495bSYour Name 	 * no driver transition will take place as long as this operation is
2243*5113495bSYour Name 	 * not complete. Thus the need to check validity of hdd_context is not
2244*5113495bSYour Name 	 * required.
2245*5113495bSYour Name 	 */
2246*5113495bSYour Name 
2247*5113495bSYour Name 	/*
2248*5113495bSYour Name 	 * Allocate a size of 4096 for the interface stats comprising
2249*5113495bSYour Name 	 * sizeof (struct wifi_interface_stats *).The size of 4096 is considered
2250*5113495bSYour Name 	 * assuming that all these fit with in the limit.Please take
2251*5113495bSYour Name 	 * a call on the limit based on the data requirements on
2252*5113495bSYour Name 	 * interface statistics.
2253*5113495bSYour Name 	 */
2254*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
2255*5113495bSYour Name 						       LL_STATS_EVENT_BUF_SIZE);
2256*5113495bSYour Name 
2257*5113495bSYour Name 	if (!skb) {
2258*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
2259*5113495bSYour Name 		return;
2260*5113495bSYour Name 	}
2261*5113495bSYour Name 
2262*5113495bSYour Name 	hdd_debug("WMI_LINK_STATS_IFACE Data");
2263*5113495bSYour Name 
2264*5113495bSYour Name 	if (!hdd_get_interface_info(link_info, &if_stat->info)) {
2265*5113495bSYour Name 		hdd_err("hdd_get_interface_info get fail");
2266*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(skb);
2267*5113495bSYour Name 		return;
2268*5113495bSYour Name 	}
2269*5113495bSYour Name 
2270*5113495bSYour Name 	if (!put_wifi_iface_stats(if_stat, num_peers, skb, link_info)) {
2271*5113495bSYour Name 		hdd_err("put_wifi_iface_stats fail");
2272*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(skb);
2273*5113495bSYour Name 		return;
2274*5113495bSYour Name 	}
2275*5113495bSYour Name 
2276*5113495bSYour Name 	wlan_cfg80211_vendor_cmd_reply(skb);
2277*5113495bSYour Name }
2278*5113495bSYour Name 
2279*5113495bSYour Name /**
2280*5113495bSYour Name  * put_channel_stats_chload - put chload of channel stats
2281*5113495bSYour Name  * @vendor_event: vendor event
2282*5113495bSYour Name  * @channel_stats: Pointer to channel stats
2283*5113495bSYour Name  *
2284*5113495bSYour Name  * Return: bool
2285*5113495bSYour Name  */
put_channel_stats_chload(struct sk_buff * vendor_event,struct wifi_channel_stats * channel_stats)2286*5113495bSYour Name static bool put_channel_stats_chload(struct sk_buff *vendor_event,
2287*5113495bSYour Name 				     struct wifi_channel_stats *channel_stats)
2288*5113495bSYour Name {
2289*5113495bSYour Name 	uint64_t txrx_time;
2290*5113495bSYour Name 	uint32_t chload;
2291*5113495bSYour Name 
2292*5113495bSYour Name 	if (!channel_stats->on_time)
2293*5113495bSYour Name 		return true;
2294*5113495bSYour Name 
2295*5113495bSYour Name 	txrx_time = (channel_stats->tx_time + channel_stats->rx_time) * 100;
2296*5113495bSYour Name 	chload = qdf_do_div(txrx_time, channel_stats->on_time);
2297*5113495bSYour Name 
2298*5113495bSYour Name 	if (nla_put_u8(vendor_event,
2299*5113495bSYour Name 		       QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE,
2300*5113495bSYour Name 		       chload))
2301*5113495bSYour Name 		return false;
2302*5113495bSYour Name 
2303*5113495bSYour Name 	return true;
2304*5113495bSYour Name }
2305*5113495bSYour Name 
2306*5113495bSYour Name /**
2307*5113495bSYour Name  * hdd_llstats_radio_fill_channels() - radio stats fill channels
2308*5113495bSYour Name  * @adapter: Pointer to device adapter
2309*5113495bSYour Name  * @radiostat: Pointer to stats data
2310*5113495bSYour Name  * @vendor_event: vendor event
2311*5113495bSYour Name  *
2312*5113495bSYour Name  * Return: 0 on success; errno on failure
2313*5113495bSYour Name  */
hdd_llstats_radio_fill_channels(struct hdd_adapter * adapter,struct wifi_radio_stats * radiostat,struct sk_buff * vendor_event)2314*5113495bSYour Name static int hdd_llstats_radio_fill_channels(struct hdd_adapter *adapter,
2315*5113495bSYour Name 					   struct wifi_radio_stats *radiostat,
2316*5113495bSYour Name 					   struct sk_buff *vendor_event)
2317*5113495bSYour Name {
2318*5113495bSYour Name 	struct wifi_channel_stats *channel_stats;
2319*5113495bSYour Name 	struct nlattr *chlist;
2320*5113495bSYour Name 	struct nlattr *chinfo;
2321*5113495bSYour Name 	int i;
2322*5113495bSYour Name 
2323*5113495bSYour Name 	chlist = nla_nest_start(vendor_event,
2324*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO);
2325*5113495bSYour Name 	if (!chlist) {
2326*5113495bSYour Name 		hdd_err("nla_nest_start failed, %u", radiostat->num_channels);
2327*5113495bSYour Name 		return -EINVAL;
2328*5113495bSYour Name 	}
2329*5113495bSYour Name 
2330*5113495bSYour Name 	for (i = 0; i < radiostat->num_channels; i++) {
2331*5113495bSYour Name 		channel_stats = (struct wifi_channel_stats *) ((uint8_t *)
2332*5113495bSYour Name 				     radiostat->channels +
2333*5113495bSYour Name 				     (i * sizeof(struct wifi_channel_stats)));
2334*5113495bSYour Name 
2335*5113495bSYour Name 		chinfo = nla_nest_start(vendor_event, i);
2336*5113495bSYour Name 		if (!chinfo) {
2337*5113495bSYour Name 			hdd_err("nla_nest_start failed, chan number %u",
2338*5113495bSYour Name 				radiostat->num_channels);
2339*5113495bSYour Name 			return -EINVAL;
2340*5113495bSYour Name 		}
2341*5113495bSYour Name 
2342*5113495bSYour Name 		if (nla_put_u32(vendor_event,
2343*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH,
2344*5113495bSYour Name 				channel_stats->channel.width) ||
2345*5113495bSYour Name 		    nla_put_u32(vendor_event,
2346*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ,
2347*5113495bSYour Name 				channel_stats->channel.center_freq) ||
2348*5113495bSYour Name 		    nla_put_u32(vendor_event,
2349*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0,
2350*5113495bSYour Name 				channel_stats->channel.center_freq0) ||
2351*5113495bSYour Name 		    nla_put_u32(vendor_event,
2352*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1,
2353*5113495bSYour Name 				channel_stats->channel.center_freq1) ||
2354*5113495bSYour Name 		    nla_put_u32(vendor_event,
2355*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME,
2356*5113495bSYour Name 				channel_stats->on_time) ||
2357*5113495bSYour Name 		    nla_put_u32(vendor_event,
2358*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME,
2359*5113495bSYour Name 				channel_stats->cca_busy_time)) {
2360*5113495bSYour Name 			hdd_err("nla_put failed for channel info (%u, %d, %u)",
2361*5113495bSYour Name 				radiostat->num_channels, i,
2362*5113495bSYour Name 				channel_stats->channel.center_freq);
2363*5113495bSYour Name 			return -EINVAL;
2364*5113495bSYour Name 		}
2365*5113495bSYour Name 
2366*5113495bSYour Name 		if (adapter->hdd_ctx &&
2367*5113495bSYour Name 		    adapter->hdd_ctx->ll_stats_per_chan_rx_tx_time) {
2368*5113495bSYour Name 			if (nla_put_u32(
2369*5113495bSYour Name 				vendor_event,
2370*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_TX_TIME,
2371*5113495bSYour Name 				channel_stats->tx_time) ||
2372*5113495bSYour Name 			    nla_put_u32(
2373*5113495bSYour Name 				vendor_event,
2374*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME,
2375*5113495bSYour Name 				channel_stats->rx_time)) {
2376*5113495bSYour Name 				hdd_err("nla_put failed for tx time (%u, %d)",
2377*5113495bSYour Name 					radiostat->num_channels, i);
2378*5113495bSYour Name 				return -EINVAL;
2379*5113495bSYour Name 			}
2380*5113495bSYour Name 
2381*5113495bSYour Name 			if (!put_channel_stats_chload(vendor_event,
2382*5113495bSYour Name 						      channel_stats)) {
2383*5113495bSYour Name 				hdd_err("nla_put failed for chload (%u, %d)",
2384*5113495bSYour Name 					radiostat->num_channels, i);
2385*5113495bSYour Name 				return -EINVAL;
2386*5113495bSYour Name 			}
2387*5113495bSYour Name 		}
2388*5113495bSYour Name 
2389*5113495bSYour Name 		nla_nest_end(vendor_event, chinfo);
2390*5113495bSYour Name 	}
2391*5113495bSYour Name 	nla_nest_end(vendor_event, chlist);
2392*5113495bSYour Name 
2393*5113495bSYour Name 	return 0;
2394*5113495bSYour Name }
2395*5113495bSYour Name 
2396*5113495bSYour Name /**
2397*5113495bSYour Name  * hdd_llstats_free_radio_stats() - free wifi_radio_stats member pointers
2398*5113495bSYour Name  * @radiostat: Pointer to stats data
2399*5113495bSYour Name  *
2400*5113495bSYour Name  * Return: void
2401*5113495bSYour Name  */
hdd_llstats_free_radio_stats(struct wifi_radio_stats * radiostat)2402*5113495bSYour Name static void hdd_llstats_free_radio_stats(struct wifi_radio_stats *radiostat)
2403*5113495bSYour Name {
2404*5113495bSYour Name 	if (radiostat->total_num_tx_power_levels &&
2405*5113495bSYour Name 	    radiostat->tx_time_per_power_level) {
2406*5113495bSYour Name 		qdf_mem_free(radiostat->tx_time_per_power_level);
2407*5113495bSYour Name 		radiostat->tx_time_per_power_level = NULL;
2408*5113495bSYour Name 	}
2409*5113495bSYour Name 	if (radiostat->num_channels && radiostat->channels) {
2410*5113495bSYour Name 		qdf_mem_free(radiostat->channels);
2411*5113495bSYour Name 		radiostat->channels = NULL;
2412*5113495bSYour Name 	}
2413*5113495bSYour Name }
2414*5113495bSYour Name 
2415*5113495bSYour Name /**
2416*5113495bSYour Name  * hdd_llstats_post_radio_stats() - post radio stats
2417*5113495bSYour Name  * @adapter: Pointer to device adapter
2418*5113495bSYour Name  * @more_data: More data
2419*5113495bSYour Name  * @radiostat: Pointer to stats data
2420*5113495bSYour Name  * @num_radio: Number of radios
2421*5113495bSYour Name  *
2422*5113495bSYour Name  * Return: void
2423*5113495bSYour Name  */
hdd_llstats_post_radio_stats(struct hdd_adapter * adapter,u32 more_data,struct wifi_radio_stats * radiostat,u32 num_radio)2424*5113495bSYour Name static void hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
2425*5113495bSYour Name 					 u32 more_data,
2426*5113495bSYour Name 					 struct wifi_radio_stats *radiostat,
2427*5113495bSYour Name 					 u32 num_radio)
2428*5113495bSYour Name {
2429*5113495bSYour Name 	struct sk_buff *vendor_event;
2430*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2431*5113495bSYour Name 	int ret;
2432*5113495bSYour Name 
2433*5113495bSYour Name 	/*
2434*5113495bSYour Name 	 * Allocate a size of 4096 for the Radio stats comprising
2435*5113495bSYour Name 	 * sizeof (struct wifi_radio_stats) + num_channels * sizeof
2436*5113495bSYour Name 	 * (struct wifi_channel_stats).Each channel data is put with an
2437*5113495bSYour Name 	 * NL attribute.The size of 4096 is considered assuming that
2438*5113495bSYour Name 	 * number of channels shall not exceed beyond  60 with the
2439*5113495bSYour Name 	 * sizeof (struct wifi_channel_stats) being 24 bytes.
2440*5113495bSYour Name 	 */
2441*5113495bSYour Name 
2442*5113495bSYour Name 	vendor_event = wlan_cfg80211_vendor_cmd_alloc_reply_skb(
2443*5113495bSYour Name 					hdd_ctx->wiphy,
2444*5113495bSYour Name 					LL_STATS_EVENT_BUF_SIZE);
2445*5113495bSYour Name 
2446*5113495bSYour Name 	if (!vendor_event) {
2447*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
2448*5113495bSYour Name 		hdd_llstats_free_radio_stats(radiostat);
2449*5113495bSYour Name 		return;
2450*5113495bSYour Name 	}
2451*5113495bSYour Name 
2452*5113495bSYour Name 	if (nla_put_u32(vendor_event,
2453*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
2454*5113495bSYour Name 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_RADIO) ||
2455*5113495bSYour Name 	    nla_put_u32(vendor_event,
2456*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA,
2457*5113495bSYour Name 			more_data) ||
2458*5113495bSYour Name 	    nla_put_u32(vendor_event,
2459*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS,
2460*5113495bSYour Name 			num_radio) ||
2461*5113495bSYour Name 	    nla_put_u32(vendor_event,
2462*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
2463*5113495bSYour Name 			radiostat->radio) ||
2464*5113495bSYour Name 	    nla_put_u32(vendor_event,
2465*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME,
2466*5113495bSYour Name 			radiostat->on_time) ||
2467*5113495bSYour Name 	    nla_put_u32(vendor_event,
2468*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME,
2469*5113495bSYour Name 			radiostat->tx_time) ||
2470*5113495bSYour Name 	    nla_put_u32(vendor_event,
2471*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME,
2472*5113495bSYour Name 			radiostat->rx_time) ||
2473*5113495bSYour Name 	    nla_put_u32(vendor_event,
2474*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN,
2475*5113495bSYour Name 			radiostat->on_time_scan) ||
2476*5113495bSYour Name 	    nla_put_u32(vendor_event,
2477*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD,
2478*5113495bSYour Name 			radiostat->on_time_nbd) ||
2479*5113495bSYour Name 	    nla_put_u32(vendor_event,
2480*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN,
2481*5113495bSYour Name 			radiostat->on_time_gscan) ||
2482*5113495bSYour Name 	    nla_put_u32(vendor_event,
2483*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN,
2484*5113495bSYour Name 			radiostat->on_time_roam_scan) ||
2485*5113495bSYour Name 	    nla_put_u32(vendor_event,
2486*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN,
2487*5113495bSYour Name 			radiostat->on_time_pno_scan) ||
2488*5113495bSYour Name 	    nla_put_u32(vendor_event,
2489*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20,
2490*5113495bSYour Name 			radiostat->on_time_hs20) ||
2491*5113495bSYour Name 	    nla_put_u32(vendor_event,
2492*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS,
2493*5113495bSYour Name 			radiostat->total_num_tx_power_levels)    ||
2494*5113495bSYour Name 	    nla_put_u32(vendor_event,
2495*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
2496*5113495bSYour Name 			radiostat->num_channels)) {
2497*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
2498*5113495bSYour Name 		hdd_llstats_free_radio_stats(radiostat);
2499*5113495bSYour Name 
2500*5113495bSYour Name 		goto failure;
2501*5113495bSYour Name 	}
2502*5113495bSYour Name 
2503*5113495bSYour Name 	if (radiostat->total_num_tx_power_levels) {
2504*5113495bSYour Name 		ret =
2505*5113495bSYour Name 		    nla_put(vendor_event,
2506*5113495bSYour Name 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
2507*5113495bSYour Name 			    sizeof(u32) *
2508*5113495bSYour Name 			    radiostat->total_num_tx_power_levels,
2509*5113495bSYour Name 			    radiostat->tx_time_per_power_level);
2510*5113495bSYour Name 		if (ret) {
2511*5113495bSYour Name 			hdd_err("nla_put fail");
2512*5113495bSYour Name 			goto failure;
2513*5113495bSYour Name 		}
2514*5113495bSYour Name 	}
2515*5113495bSYour Name 
2516*5113495bSYour Name 	if (radiostat->num_channels) {
2517*5113495bSYour Name 		ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
2518*5113495bSYour Name 						      vendor_event);
2519*5113495bSYour Name 		if (ret)
2520*5113495bSYour Name 			goto failure;
2521*5113495bSYour Name 	}
2522*5113495bSYour Name 
2523*5113495bSYour Name 	wlan_cfg80211_vendor_cmd_reply(vendor_event);
2524*5113495bSYour Name 	hdd_llstats_free_radio_stats(radiostat);
2525*5113495bSYour Name 	return;
2526*5113495bSYour Name 
2527*5113495bSYour Name failure:
2528*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(vendor_event);
2529*5113495bSYour Name 	hdd_llstats_free_radio_stats(radiostat);
2530*5113495bSYour Name }
2531*5113495bSYour Name 
2532*5113495bSYour Name /**
2533*5113495bSYour Name  * hdd_link_layer_process_radio_stats() - This function is called after
2534*5113495bSYour Name  * @adapter: Pointer to device adapter
2535*5113495bSYour Name  * @more_data: More data
2536*5113495bSYour Name  * @radio_stat: Pointer to stats data
2537*5113495bSYour Name  * @num_radio: Number of radios
2538*5113495bSYour Name  *
2539*5113495bSYour Name  * Receiving Link Layer Radio statistics from FW.This function converts
2540*5113495bSYour Name  * the firmware data to the NL data and sends the same to the kernel/upper
2541*5113495bSYour Name  * layers.
2542*5113495bSYour Name  *
2543*5113495bSYour Name  * Return: None
2544*5113495bSYour Name  */
2545*5113495bSYour Name static void
hdd_link_layer_process_radio_stats(struct hdd_adapter * adapter,u32 more_data,struct wifi_radio_stats * radio_stat,u32 num_radio)2546*5113495bSYour Name hdd_link_layer_process_radio_stats(struct hdd_adapter *adapter,
2547*5113495bSYour Name 				   u32 more_data,
2548*5113495bSYour Name 				   struct wifi_radio_stats *radio_stat,
2549*5113495bSYour Name 				   u32 num_radio)
2550*5113495bSYour Name {
2551*5113495bSYour Name 	int i, nr;
2552*5113495bSYour Name 	struct wifi_radio_stats *radio_stat_save = radio_stat;
2553*5113495bSYour Name 
2554*5113495bSYour Name 	/*
2555*5113495bSYour Name 	 * There is no need for wlan_hdd_validate_context here. This is a NB
2556*5113495bSYour Name 	 * operation that will come with DSC synchronization. This ensures that
2557*5113495bSYour Name 	 * no driver transition will take place as long as this operation is
2558*5113495bSYour Name 	 * not complete. Thus the need to check validity of hdd_context is not
2559*5113495bSYour Name 	 * required.
2560*5113495bSYour Name 	 */
2561*5113495bSYour Name 
2562*5113495bSYour Name 	for (i = 0; i < num_radio; i++) {
2563*5113495bSYour Name 		hdd_nofl_debug("LL_STATS_RADIO"
2564*5113495bSYour Name 		       " radio: %u on_time: %u tx_time: %u rx_time: %u"
2565*5113495bSYour Name 		       " on_time_scan: %u on_time_nbd: %u"
2566*5113495bSYour Name 		       " on_time_gscan: %u on_time_roam_scan: %u"
2567*5113495bSYour Name 		       " on_time_pno_scan: %u  on_time_hs20: %u"
2568*5113495bSYour Name 		       " num_channels: %u total_num_tx_pwr_levels: %u"
2569*5113495bSYour Name 		       " on_time_host_scan: %u, on_time_lpi_scan: %u",
2570*5113495bSYour Name 		       radio_stat->radio, radio_stat->on_time,
2571*5113495bSYour Name 		       radio_stat->tx_time, radio_stat->rx_time,
2572*5113495bSYour Name 		       radio_stat->on_time_scan, radio_stat->on_time_nbd,
2573*5113495bSYour Name 		       radio_stat->on_time_gscan,
2574*5113495bSYour Name 		       radio_stat->on_time_roam_scan,
2575*5113495bSYour Name 		       radio_stat->on_time_pno_scan,
2576*5113495bSYour Name 		       radio_stat->on_time_hs20,
2577*5113495bSYour Name 		       radio_stat->num_channels,
2578*5113495bSYour Name 		       radio_stat->total_num_tx_power_levels,
2579*5113495bSYour Name 		       radio_stat->on_time_host_scan,
2580*5113495bSYour Name 		       radio_stat->on_time_lpi_scan);
2581*5113495bSYour Name 		radio_stat++;
2582*5113495bSYour Name 	}
2583*5113495bSYour Name 
2584*5113495bSYour Name 	radio_stat = radio_stat_save;
2585*5113495bSYour Name 	for (nr = 0; nr < num_radio; nr++) {
2586*5113495bSYour Name 		hdd_llstats_post_radio_stats(adapter, more_data,
2587*5113495bSYour Name 					     radio_stat, num_radio);
2588*5113495bSYour Name 		radio_stat++;
2589*5113495bSYour Name 	}
2590*5113495bSYour Name 
2591*5113495bSYour Name 	hdd_exit();
2592*5113495bSYour Name }
2593*5113495bSYour Name 
hdd_process_ll_stats(tSirLLStatsResults * results,struct osif_request * request)2594*5113495bSYour Name static void hdd_process_ll_stats(tSirLLStatsResults *results,
2595*5113495bSYour Name 				 struct osif_request *request)
2596*5113495bSYour Name {
2597*5113495bSYour Name 	struct hdd_ll_stats_priv *priv = osif_request_priv(request);
2598*5113495bSYour Name 	struct hdd_ll_stats *stats = NULL;
2599*5113495bSYour Name 	size_t stat_size = 0;
2600*5113495bSYour Name 
2601*5113495bSYour Name 	qdf_spin_lock(&priv->ll_stats_lock);
2602*5113495bSYour Name 
2603*5113495bSYour Name 	if (!(priv->request_bitmap & results->paramId)) {
2604*5113495bSYour Name 		qdf_spin_unlock(&priv->ll_stats_lock);
2605*5113495bSYour Name 		return;
2606*5113495bSYour Name 	}
2607*5113495bSYour Name 
2608*5113495bSYour Name 	if (results->paramId & WMI_LINK_STATS_RADIO) {
2609*5113495bSYour Name 		struct wifi_radio_stats *rs_results, *stat_result;
2610*5113495bSYour Name 		u64 channel_size = 0, pwr_lvl_size = 0;
2611*5113495bSYour Name 		int i;
2612*5113495bSYour Name 
2613*5113495bSYour Name 		if (!results->num_radio)
2614*5113495bSYour Name 			goto exit;
2615*5113495bSYour Name 
2616*5113495bSYour Name 		stats = qdf_mem_malloc(sizeof(*stats));
2617*5113495bSYour Name 		if (!stats)
2618*5113495bSYour Name 			goto exit;
2619*5113495bSYour Name 
2620*5113495bSYour Name 		stat_size = sizeof(struct wifi_radio_stats) *
2621*5113495bSYour Name 			    results->num_radio;
2622*5113495bSYour Name 		stats->result_param_id = WMI_LINK_STATS_RADIO;
2623*5113495bSYour Name 		stat_result = qdf_mem_malloc(stat_size);
2624*5113495bSYour Name 		if (!stat_result) {
2625*5113495bSYour Name 			qdf_mem_free(stats);
2626*5113495bSYour Name 			goto exit;
2627*5113495bSYour Name 		}
2628*5113495bSYour Name 		stats->result = stat_result;
2629*5113495bSYour Name 		rs_results = (struct wifi_radio_stats *)results->results;
2630*5113495bSYour Name 		qdf_mem_copy(stats->result, results->results, stat_size);
2631*5113495bSYour Name 		for (i = 0; i < results->num_radio; i++) {
2632*5113495bSYour Name 			channel_size = rs_results->num_channels *
2633*5113495bSYour Name 				       sizeof(struct wifi_channel_stats);
2634*5113495bSYour Name 			pwr_lvl_size = sizeof(uint32_t) *
2635*5113495bSYour Name 				       rs_results->total_num_tx_power_levels;
2636*5113495bSYour Name 
2637*5113495bSYour Name 			if (rs_results->total_num_tx_power_levels &&
2638*5113495bSYour Name 			    rs_results->tx_time_per_power_level) {
2639*5113495bSYour Name 				stat_result->tx_time_per_power_level =
2640*5113495bSYour Name 						qdf_mem_malloc(pwr_lvl_size);
2641*5113495bSYour Name 				if (!stat_result->tx_time_per_power_level) {
2642*5113495bSYour Name 					while (i-- > 0) {
2643*5113495bSYour Name 						stat_result--;
2644*5113495bSYour Name 						qdf_mem_free(stat_result->
2645*5113495bSYour Name 						    tx_time_per_power_level);
2646*5113495bSYour Name 						qdf_mem_free(stat_result->
2647*5113495bSYour Name 							     channels);
2648*5113495bSYour Name 					}
2649*5113495bSYour Name 					qdf_mem_free(stat_result);
2650*5113495bSYour Name 					qdf_mem_free(stats);
2651*5113495bSYour Name 					goto exit;
2652*5113495bSYour Name 				}
2653*5113495bSYour Name 			      qdf_mem_copy(stat_result->tx_time_per_power_level,
2654*5113495bSYour Name 					   rs_results->tx_time_per_power_level,
2655*5113495bSYour Name 					   pwr_lvl_size);
2656*5113495bSYour Name 			}
2657*5113495bSYour Name 			if (channel_size) {
2658*5113495bSYour Name 				stat_result->channels =
2659*5113495bSYour Name 						qdf_mem_malloc(channel_size);
2660*5113495bSYour Name 				if (!stat_result->channels) {
2661*5113495bSYour Name 					qdf_mem_free(stat_result->
2662*5113495bSYour Name 						     tx_time_per_power_level);
2663*5113495bSYour Name 					while (i-- > 0) {
2664*5113495bSYour Name 						stat_result--;
2665*5113495bSYour Name 						qdf_mem_free(stat_result->
2666*5113495bSYour Name 						    tx_time_per_power_level);
2667*5113495bSYour Name 						qdf_mem_free(stat_result->
2668*5113495bSYour Name 							     channels);
2669*5113495bSYour Name 					}
2670*5113495bSYour Name 					qdf_mem_free(stats->result);
2671*5113495bSYour Name 					qdf_mem_free(stats);
2672*5113495bSYour Name 					goto exit;
2673*5113495bSYour Name 				}
2674*5113495bSYour Name 				qdf_mem_copy(stat_result->channels,
2675*5113495bSYour Name 					     rs_results->channels,
2676*5113495bSYour Name 					     channel_size);
2677*5113495bSYour Name 			}
2678*5113495bSYour Name 			rs_results++;
2679*5113495bSYour Name 			stat_result++;
2680*5113495bSYour Name 		}
2681*5113495bSYour Name 		stats->stats_nradio_npeer.no_of_radios = results->num_radio;
2682*5113495bSYour Name 		stats->more_data = results->moreResultToFollow;
2683*5113495bSYour Name 		if (!results->moreResultToFollow)
2684*5113495bSYour Name 			priv->request_bitmap &= ~stats->result_param_id;
2685*5113495bSYour Name 	} else if (results->paramId & WMI_LINK_STATS_IFACE) {
2686*5113495bSYour Name 		stats = qdf_mem_malloc(sizeof(*stats));
2687*5113495bSYour Name 		if (!stats)
2688*5113495bSYour Name 			goto exit;
2689*5113495bSYour Name 
2690*5113495bSYour Name 		stats->result_param_id = WMI_LINK_STATS_IFACE;
2691*5113495bSYour Name 		stats->stats_nradio_npeer.no_of_peers = results->num_peers;
2692*5113495bSYour Name 		stats->result = qdf_mem_malloc(sizeof(struct
2693*5113495bSYour Name 					       wifi_interface_stats));
2694*5113495bSYour Name 		if (!stats->result) {
2695*5113495bSYour Name 			qdf_mem_free(stats);
2696*5113495bSYour Name 			goto exit;
2697*5113495bSYour Name 		}
2698*5113495bSYour Name 		qdf_mem_copy(stats->result, results->results,
2699*5113495bSYour Name 			     sizeof(struct wifi_interface_stats));
2700*5113495bSYour Name 
2701*5113495bSYour Name 		/* Firmware doesn't send peerstats event if no peers are
2702*5113495bSYour Name 		 * connected. HDD should not wait for any peerstats in
2703*5113495bSYour Name 		 * this case and return the status to middleware after
2704*5113495bSYour Name 		 * receiving iface stats
2705*5113495bSYour Name 		 */
2706*5113495bSYour Name 		if (!results->num_peers)
2707*5113495bSYour Name 			priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
2708*5113495bSYour Name 		priv->request_bitmap &= ~stats->result_param_id;
2709*5113495bSYour Name 
2710*5113495bSYour Name 		/* Firmware sends interface stats based on vdev_id_bitmap
2711*5113495bSYour Name 		 * So, clear the mlo_vdev_id_bitmap in the host accordingly
2712*5113495bSYour Name 		 */
2713*5113495bSYour Name 		if (priv->is_mlo_req)
2714*5113495bSYour Name 			priv->mlo_vdev_id_bitmap &= ~(1 << results->ifaceId);
2715*5113495bSYour Name 	} else if (results->paramId & WMI_LINK_STATS_ALL_PEER) {
2716*5113495bSYour Name 		struct wifi_peer_stat *peer_stat = (struct wifi_peer_stat *)
2717*5113495bSYour Name 						   results->results;
2718*5113495bSYour Name 		struct wifi_peer_info *peer_info = NULL;
2719*5113495bSYour Name 		u64 num_rate = 0, peers, rates;
2720*5113495bSYour Name 		int i;
2721*5113495bSYour Name 		stats = qdf_mem_malloc(sizeof(*stats));
2722*5113495bSYour Name 		if (!stats)
2723*5113495bSYour Name 			goto exit;
2724*5113495bSYour Name 
2725*5113495bSYour Name 		peer_info = (struct wifi_peer_info *)peer_stat->peer_info;
2726*5113495bSYour Name 		for (i = 1; i <= peer_stat->num_peers; i++) {
2727*5113495bSYour Name 			num_rate += peer_info->num_rate;
2728*5113495bSYour Name 			peer_info = (struct wifi_peer_info *)((uint8_t *)
2729*5113495bSYour Name 				    peer_info + sizeof(struct wifi_peer_info) +
2730*5113495bSYour Name 				    (peer_info->num_rate *
2731*5113495bSYour Name 				    sizeof(struct wifi_rate_stat)));
2732*5113495bSYour Name 		}
2733*5113495bSYour Name 
2734*5113495bSYour Name 		peers = sizeof(struct wifi_peer_info) * peer_stat->num_peers;
2735*5113495bSYour Name 		rates = sizeof(struct wifi_rate_stat) * num_rate;
2736*5113495bSYour Name 		stat_size = sizeof(struct wifi_peer_stat) + peers + rates;
2737*5113495bSYour Name 		stats->result_param_id = WMI_LINK_STATS_ALL_PEER;
2738*5113495bSYour Name 
2739*5113495bSYour Name 		stats->result = qdf_mem_malloc(stat_size);
2740*5113495bSYour Name 		if (!stats->result) {
2741*5113495bSYour Name 			qdf_mem_free(stats);
2742*5113495bSYour Name 			goto exit;
2743*5113495bSYour Name 		}
2744*5113495bSYour Name 
2745*5113495bSYour Name 		qdf_mem_copy(stats->result, results->results, stat_size);
2746*5113495bSYour Name 		stats->more_data = results->moreResultToFollow;
2747*5113495bSYour Name 		if (!results->moreResultToFollow)
2748*5113495bSYour Name 			priv->request_bitmap &= ~stats->result_param_id;
2749*5113495bSYour Name 	} else {
2750*5113495bSYour Name 		hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
2751*5113495bSYour Name 	}
2752*5113495bSYour Name 	/* send indication to caller thread */
2753*5113495bSYour Name 	if (stats)
2754*5113495bSYour Name 		qdf_list_insert_back(&priv->ll_stats_q, &stats->ll_stats_node);
2755*5113495bSYour Name 
2756*5113495bSYour Name 	if (!priv->request_bitmap) {
2757*5113495bSYour Name 		if (priv->is_mlo_req && priv->mlo_vdev_id_bitmap)
2758*5113495bSYour Name 			goto out;
2759*5113495bSYour Name exit:
2760*5113495bSYour Name 		qdf_spin_unlock(&priv->ll_stats_lock);
2761*5113495bSYour Name 
2762*5113495bSYour Name 		/* Thread which invokes this function has allocated memory in
2763*5113495bSYour Name 		 * WMA for radio stats, that memory should be freed from the
2764*5113495bSYour Name 		 * same thread to avoid any race conditions between two threads
2765*5113495bSYour Name 		 */
2766*5113495bSYour Name 		sme_radio_tx_mem_free();
2767*5113495bSYour Name 		osif_request_complete(request);
2768*5113495bSYour Name 		return;
2769*5113495bSYour Name 	}
2770*5113495bSYour Name out:
2771*5113495bSYour Name 	qdf_spin_unlock(&priv->ll_stats_lock);
2772*5113495bSYour Name }
2773*5113495bSYour Name 
hdd_debugfs_process_ll_stats(struct wlan_hdd_link_info * link_info,tSirLLStatsResults * results,struct osif_request * request)2774*5113495bSYour Name static void hdd_debugfs_process_ll_stats(struct wlan_hdd_link_info *link_info,
2775*5113495bSYour Name 					 tSirLLStatsResults *results,
2776*5113495bSYour Name 					 struct osif_request *request)
2777*5113495bSYour Name {
2778*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
2779*5113495bSYour Name 	struct hdd_ll_stats_priv *priv = osif_request_priv(request);
2780*5113495bSYour Name 
2781*5113495bSYour Name 	if (results->paramId & WMI_LINK_STATS_RADIO) {
2782*5113495bSYour Name 		hdd_debugfs_process_radio_stats(adapter,
2783*5113495bSYour Name 						results->moreResultToFollow,
2784*5113495bSYour Name 						results->results,
2785*5113495bSYour Name 						results->num_radio);
2786*5113495bSYour Name 		if (!results->moreResultToFollow)
2787*5113495bSYour Name 			priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
2788*5113495bSYour Name 	} else if (results->paramId & WMI_LINK_STATS_IFACE) {
2789*5113495bSYour Name 		hdd_debugfs_process_iface_stats(link_info, results->results,
2790*5113495bSYour Name 						results->num_peers);
2791*5113495bSYour Name 
2792*5113495bSYour Name 		/* Firmware doesn't send peerstats event if no peers are
2793*5113495bSYour Name 		 * connected. HDD should not wait for any peerstats in
2794*5113495bSYour Name 		 * this case and return the status to middleware after
2795*5113495bSYour Name 		 * receiving iface stats
2796*5113495bSYour Name 		 */
2797*5113495bSYour Name 
2798*5113495bSYour Name 		if (!results->num_peers)
2799*5113495bSYour Name 			priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
2800*5113495bSYour Name 
2801*5113495bSYour Name 		priv->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
2802*5113495bSYour Name 
2803*5113495bSYour Name 		/* Firmware sends interface stats based on vdev_id_bitmap
2804*5113495bSYour Name 		 * So, clear the mlo_vdev_id_bitmap in the host accordingly
2805*5113495bSYour Name 		 */
2806*5113495bSYour Name 		if (priv->is_mlo_req)
2807*5113495bSYour Name 			priv->mlo_vdev_id_bitmap &= ~(1 << results->ifaceId);
2808*5113495bSYour Name 	} else if (results->paramId & WMI_LINK_STATS_ALL_PEER) {
2809*5113495bSYour Name 		hdd_debugfs_process_peer_stats(adapter, results->results);
2810*5113495bSYour Name 		if (!results->moreResultToFollow)
2811*5113495bSYour Name 			priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
2812*5113495bSYour Name 	} else {
2813*5113495bSYour Name 		hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
2814*5113495bSYour Name 	}
2815*5113495bSYour Name 
2816*5113495bSYour Name 	if (!priv->request_bitmap) {
2817*5113495bSYour Name 		if (priv->is_mlo_req && priv->mlo_vdev_id_bitmap)
2818*5113495bSYour Name 			return;
2819*5113495bSYour Name 		/* Thread which invokes this function has allocated memory in
2820*5113495bSYour Name 		 * WMA for radio stats, that memory should be freed from the
2821*5113495bSYour Name 		 * same thread to avoid any race conditions between two threads
2822*5113495bSYour Name 		 */
2823*5113495bSYour Name 		sme_radio_tx_mem_free();
2824*5113495bSYour Name 		osif_request_complete(request);
2825*5113495bSYour Name 	}
2826*5113495bSYour Name 
2827*5113495bSYour Name }
2828*5113495bSYour Name 
2829*5113495bSYour Name static void
wlan_hdd_update_ll_stats_request_bitmap(struct hdd_context * hdd_ctx,struct osif_request * request,tSirLLStatsResults * results)2830*5113495bSYour Name wlan_hdd_update_ll_stats_request_bitmap(struct hdd_context *hdd_ctx,
2831*5113495bSYour Name 					struct osif_request *request,
2832*5113495bSYour Name 					tSirLLStatsResults *results)
2833*5113495bSYour Name {
2834*5113495bSYour Name 	struct hdd_ll_stats_priv *priv = osif_request_priv(request);
2835*5113495bSYour Name 	bool is_mlo_link;
2836*5113495bSYour Name 
2837*5113495bSYour Name 	if (!wlan_vdev_mlme_get_is_mlo_vdev(hdd_ctx->psoc, priv->vdev_id)) {
2838*5113495bSYour Name 		hdd_nofl_debug("Can't update req_bitmap for non MLO case");
2839*5113495bSYour Name 		return;
2840*5113495bSYour Name 	}
2841*5113495bSYour Name 
2842*5113495bSYour Name 	is_mlo_link = wlan_vdev_mlme_get_is_mlo_link(hdd_ctx->psoc,
2843*5113495bSYour Name 						     results->ifaceId);
2844*5113495bSYour Name 	/* In case of MLO Connection, set the request_bitmap */
2845*5113495bSYour Name 	if (is_mlo_link && results->paramId == WMI_LINK_STATS_IFACE) {
2846*5113495bSYour Name 		/* Set the request_bitmap for MLO link vdev iface stats */
2847*5113495bSYour Name 		if (!(priv->request_bitmap & results->paramId))
2848*5113495bSYour Name 			priv->request_bitmap |= results->paramId;
2849*5113495bSYour Name 
2850*5113495bSYour Name 		hdd_nofl_debug("MLO_LL_STATS set request_bitmap = 0x%x",
2851*5113495bSYour Name 			       priv->request_bitmap);
2852*5113495bSYour Name 	}
2853*5113495bSYour Name }
2854*5113495bSYour Name 
wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,int indication_type,tSirLLStatsResults * results,void * cookie)2855*5113495bSYour Name void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
2856*5113495bSYour Name 						 int indication_type,
2857*5113495bSYour Name 						 tSirLLStatsResults *results,
2858*5113495bSYour Name 						 void *cookie)
2859*5113495bSYour Name {
2860*5113495bSYour Name 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
2861*5113495bSYour Name 	struct hdd_ll_stats_priv *priv;
2862*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
2863*5113495bSYour Name 	int status;
2864*5113495bSYour Name 	struct osif_request *request;
2865*5113495bSYour Name 
2866*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
2867*5113495bSYour Name 	if (status)
2868*5113495bSYour Name 		return;
2869*5113495bSYour Name 
2870*5113495bSYour Name 	switch (indication_type) {
2871*5113495bSYour Name 	case SIR_HAL_LL_STATS_RESULTS_RSP:
2872*5113495bSYour Name 	{
2873*5113495bSYour Name 		hdd_nofl_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %pK",
2874*5113495bSYour Name 			       results->paramId, results->ifaceId,
2875*5113495bSYour Name 			       results->rspId, results->moreResultToFollow,
2876*5113495bSYour Name 			       results->num_radio, results->results);
2877*5113495bSYour Name 
2878*5113495bSYour Name 		request = osif_request_get(cookie);
2879*5113495bSYour Name 		if (!request) {
2880*5113495bSYour Name 			hdd_err("Obsolete request");
2881*5113495bSYour Name 			return;
2882*5113495bSYour Name 		}
2883*5113495bSYour Name 
2884*5113495bSYour Name 		priv = osif_request_priv(request);
2885*5113495bSYour Name 
2886*5113495bSYour Name 		/* validate response received from target */
2887*5113495bSYour Name 		if (priv->request_id != results->rspId) {
2888*5113495bSYour Name 			hdd_err("Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
2889*5113495bSYour Name 				priv->request_id, results->rspId,
2890*5113495bSYour Name 				priv->request_bitmap, results->paramId);
2891*5113495bSYour Name 			osif_request_put(request);
2892*5113495bSYour Name 			return;
2893*5113495bSYour Name 		}
2894*5113495bSYour Name 
2895*5113495bSYour Name 		link_info =
2896*5113495bSYour Name 			hdd_get_link_info_by_vdev(hdd_ctx, results->ifaceId);
2897*5113495bSYour Name 		if (!link_info) {
2898*5113495bSYour Name 			hdd_debug_rl("invalid vdev_id %d sent by FW",
2899*5113495bSYour Name 				     results->ifaceId);
2900*5113495bSYour Name 			/* for peer stats FW doesn't update the vdev_id info*/
2901*5113495bSYour Name 			link_info = hdd_get_link_info_by_vdev(hdd_ctx,
2902*5113495bSYour Name 							      priv->vdev_id);
2903*5113495bSYour Name 			if (!link_info) {
2904*5113495bSYour Name 				hdd_err("invalid vdev %d", priv->vdev_id);
2905*5113495bSYour Name 				osif_request_put(request);
2906*5113495bSYour Name 				return;
2907*5113495bSYour Name 			}
2908*5113495bSYour Name 		}
2909*5113495bSYour Name 		wlan_hdd_update_ll_stats_request_bitmap(hdd_ctx, request,
2910*5113495bSYour Name 							results);
2911*5113495bSYour Name 		if (results->rspId == DEBUGFS_LLSTATS_REQID) {
2912*5113495bSYour Name 			hdd_debugfs_process_ll_stats(link_info,
2913*5113495bSYour Name 						     results, request);
2914*5113495bSYour Name 		 } else {
2915*5113495bSYour Name 			hdd_process_ll_stats(results, request);
2916*5113495bSYour Name 		}
2917*5113495bSYour Name 
2918*5113495bSYour Name 		osif_request_put(request);
2919*5113495bSYour Name 		break;
2920*5113495bSYour Name 	}
2921*5113495bSYour Name 	default:
2922*5113495bSYour Name 		hdd_warn("invalid event type %d", indication_type);
2923*5113495bSYour Name 		break;
2924*5113495bSYour Name 	}
2925*5113495bSYour Name }
2926*5113495bSYour Name 
hdd_lost_link_info_cb(hdd_handle_t hdd_handle,struct sir_lost_link_info * lost_link_info)2927*5113495bSYour Name void hdd_lost_link_info_cb(hdd_handle_t hdd_handle,
2928*5113495bSYour Name 			   struct sir_lost_link_info *lost_link_info)
2929*5113495bSYour Name {
2930*5113495bSYour Name 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
2931*5113495bSYour Name 	int status;
2932*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
2933*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
2934*5113495bSYour Name 
2935*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
2936*5113495bSYour Name 	if (status)
2937*5113495bSYour Name 		return;
2938*5113495bSYour Name 
2939*5113495bSYour Name 	if (!lost_link_info) {
2940*5113495bSYour Name 		hdd_err("lost_link_info is NULL");
2941*5113495bSYour Name 		return;
2942*5113495bSYour Name 	}
2943*5113495bSYour Name 
2944*5113495bSYour Name 	if (lost_link_info->rssi == 0) {
2945*5113495bSYour Name 		hdd_debug_rl("Invalid rssi on disconnect sent by FW");
2946*5113495bSYour Name 		return;
2947*5113495bSYour Name 	}
2948*5113495bSYour Name 
2949*5113495bSYour Name 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, lost_link_info->vdev_id);
2950*5113495bSYour Name 	if (!link_info) {
2951*5113495bSYour Name 		hdd_err("invalid vdev");
2952*5113495bSYour Name 		return;
2953*5113495bSYour Name 	}
2954*5113495bSYour Name 
2955*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
2956*5113495bSYour Name 
2957*5113495bSYour Name 	link_info->rssi_on_disconnect = lost_link_info->rssi;
2958*5113495bSYour Name 	hdd_debug("rssi on disconnect %d", link_info->rssi_on_disconnect);
2959*5113495bSYour Name 
2960*5113495bSYour Name 	sta_ctx->cache_conn_info.signal = lost_link_info->rssi;
2961*5113495bSYour Name }
2962*5113495bSYour Name 
2963*5113495bSYour Name const struct nla_policy qca_wlan_vendor_ll_set_policy[
2964*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = {
2965*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]
2966*5113495bSYour Name 						= { .type = NLA_U32 },
2967*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]
2968*5113495bSYour Name 						= { .type = NLA_U32 },
2969*5113495bSYour Name };
2970*5113495bSYour Name 
2971*5113495bSYour Name /**
2972*5113495bSYour Name  * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats
2973*5113495bSYour Name  * @wiphy: Pointer to wiphy
2974*5113495bSYour Name  * @wdev: Pointer to wdev
2975*5113495bSYour Name  * @data: Pointer to data
2976*5113495bSYour Name  * @data_len: Data length
2977*5113495bSYour Name  *
2978*5113495bSYour Name  * Return: int
2979*5113495bSYour Name  */
2980*5113495bSYour Name static int
__wlan_hdd_cfg80211_ll_stats_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2981*5113495bSYour Name __wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
2982*5113495bSYour Name 				   struct wireless_dev *wdev,
2983*5113495bSYour Name 				   const void *data,
2984*5113495bSYour Name 				   int data_len)
2985*5113495bSYour Name {
2986*5113495bSYour Name 	int status;
2987*5113495bSYour Name 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1];
2988*5113495bSYour Name 	tSirLLStatsSetReq req;
2989*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
2990*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2991*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2992*5113495bSYour Name 
2993*5113495bSYour Name 	hdd_enter_dev(dev);
2994*5113495bSYour Name 
2995*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2996*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
2997*5113495bSYour Name 		return -EPERM;
2998*5113495bSYour Name 	}
2999*5113495bSYour Name 
3000*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
3001*5113495bSYour Name 	if (0 != status)
3002*5113495bSYour Name 		return -EINVAL;
3003*5113495bSYour Name 
3004*5113495bSYour Name 	if (hdd_validate_adapter(adapter))
3005*5113495bSYour Name 		return -EINVAL;
3006*5113495bSYour Name 
3007*5113495bSYour Name 	if (adapter->device_mode != QDF_STA_MODE &&
3008*5113495bSYour Name 	    adapter->device_mode != QDF_SAP_MODE &&
3009*5113495bSYour Name 	    adapter->device_mode != QDF_P2P_CLIENT_MODE &&
3010*5113495bSYour Name 	    adapter->device_mode != QDF_P2P_GO_MODE) {
3011*5113495bSYour Name 		hdd_debug("Cannot set LL_STATS for device mode %d",
3012*5113495bSYour Name 			  adapter->device_mode);
3013*5113495bSYour Name 		return -EINVAL;
3014*5113495bSYour Name 	}
3015*5113495bSYour Name 
3016*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb_vendor,
3017*5113495bSYour Name 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX,
3018*5113495bSYour Name 				    (struct nlattr *)data, data_len,
3019*5113495bSYour Name 				    qca_wlan_vendor_ll_set_policy)) {
3020*5113495bSYour Name 		hdd_err("maximum attribute not present");
3021*5113495bSYour Name 		return -EINVAL;
3022*5113495bSYour Name 	}
3023*5113495bSYour Name 
3024*5113495bSYour Name 	if (!tb_vendor
3025*5113495bSYour Name 	    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) {
3026*5113495bSYour Name 		hdd_err("MPDU size Not present");
3027*5113495bSYour Name 		return -EINVAL;
3028*5113495bSYour Name 	}
3029*5113495bSYour Name 
3030*5113495bSYour Name 	if (!tb_vendor
3031*5113495bSYour Name 	    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) {
3032*5113495bSYour Name 		hdd_err("Stats Gathering Not Present");
3033*5113495bSYour Name 		return -EINVAL;
3034*5113495bSYour Name 	}
3035*5113495bSYour Name 
3036*5113495bSYour Name 	/* Shall take the request Id if the Upper layers pass. 1 For now. */
3037*5113495bSYour Name 	req.reqId = 1;
3038*5113495bSYour Name 
3039*5113495bSYour Name 	req.mpduSizeThreshold =
3040*5113495bSYour Name 		nla_get_u32(tb_vendor
3041*5113495bSYour Name 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]);
3042*5113495bSYour Name 
3043*5113495bSYour Name 	req.aggressiveStatisticsGathering =
3044*5113495bSYour Name 		nla_get_u32(tb_vendor
3045*5113495bSYour Name 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]);
3046*5113495bSYour Name 
3047*5113495bSYour Name 	req.staId = adapter->deflink->vdev_id;
3048*5113495bSYour Name 
3049*5113495bSYour Name 	hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d",
3050*5113495bSYour Name 		req.reqId, req.staId,
3051*5113495bSYour Name 		req.mpduSizeThreshold,
3052*5113495bSYour Name 		req.aggressiveStatisticsGathering);
3053*5113495bSYour Name 
3054*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(hdd_ctx->mac_handle,
3055*5113495bSYour Name 						       &req)) {
3056*5113495bSYour Name 		hdd_err("sme_ll_stats_set_req Failed");
3057*5113495bSYour Name 		return -EINVAL;
3058*5113495bSYour Name 	}
3059*5113495bSYour Name 
3060*5113495bSYour Name 	adapter->is_link_layer_stats_set = true;
3061*5113495bSYour Name 	hdd_exit();
3062*5113495bSYour Name 	return 0;
3063*5113495bSYour Name }
3064*5113495bSYour Name 
3065*5113495bSYour Name /**
3066*5113495bSYour Name  * wlan_hdd_cfg80211_ll_stats_set() - set ll stats
3067*5113495bSYour Name  * @wiphy: Pointer to wiphy
3068*5113495bSYour Name  * @wdev: Pointer to wdev
3069*5113495bSYour Name  * @data: Pointer to data
3070*5113495bSYour Name  * @data_len: Data length
3071*5113495bSYour Name  *
3072*5113495bSYour Name  * Return: 0 if success, non-zero for failure
3073*5113495bSYour Name  */
wlan_hdd_cfg80211_ll_stats_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3074*5113495bSYour Name int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy,
3075*5113495bSYour Name 					struct wireless_dev *wdev,
3076*5113495bSYour Name 					const void *data,
3077*5113495bSYour Name 					int data_len)
3078*5113495bSYour Name {
3079*5113495bSYour Name 	int errno;
3080*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
3081*5113495bSYour Name 
3082*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3083*5113495bSYour Name 	if (errno)
3084*5113495bSYour Name 		return errno;
3085*5113495bSYour Name 
3086*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len);
3087*5113495bSYour Name 
3088*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
3089*5113495bSYour Name 
3090*5113495bSYour Name 	return errno;
3091*5113495bSYour Name }
3092*5113495bSYour Name 
3093*5113495bSYour Name const struct nla_policy qca_wlan_vendor_ll_get_policy[
3094*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = {
3095*5113495bSYour Name 	/* Unsigned 32bit value provided by the caller issuing the GET stats
3096*5113495bSYour Name 	 * command. When reporting
3097*5113495bSYour Name 	 * the stats results, the driver uses the same value to indicate
3098*5113495bSYour Name 	 * which GET request the results
3099*5113495bSYour Name 	 * correspond to.
3100*5113495bSYour Name 	 */
3101*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32},
3102*5113495bSYour Name 
3103*5113495bSYour Name 	/* Unsigned 32bit value . bit mask to identify what statistics are
3104*5113495bSYour Name 	 * requested for retrieval
3105*5113495bSYour Name 	 */
3106*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
3107*5113495bSYour Name };
3108*5113495bSYour Name 
wlan_hdd_handle_ll_stats(struct wlan_hdd_link_info * link_info,struct hdd_ll_stats * stats,int ret)3109*5113495bSYour Name static void wlan_hdd_handle_ll_stats(struct wlan_hdd_link_info *link_info,
3110*5113495bSYour Name 				     struct hdd_ll_stats *stats, int ret)
3111*5113495bSYour Name {
3112*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
3113*5113495bSYour Name 
3114*5113495bSYour Name 	switch (stats->result_param_id) {
3115*5113495bSYour Name 	case WMI_LINK_STATS_RADIO:
3116*5113495bSYour Name 	{
3117*5113495bSYour Name 		struct wifi_radio_stats *radio_stat = stats->result;
3118*5113495bSYour Name 		int i, num_radio = stats->stats_nradio_npeer.no_of_radios;
3119*5113495bSYour Name 
3120*5113495bSYour Name 		if (ret == -ETIMEDOUT) {
3121*5113495bSYour Name 			for (i = 0; i < num_radio; i++) {
3122*5113495bSYour Name 				if (radio_stat->num_channels)
3123*5113495bSYour Name 					qdf_mem_free(radio_stat->channels);
3124*5113495bSYour Name 				if (radio_stat->total_num_tx_power_levels)
3125*5113495bSYour Name 					qdf_mem_free(radio_stat->
3126*5113495bSYour Name 						     tx_time_per_power_level);
3127*5113495bSYour Name 				radio_stat++;
3128*5113495bSYour Name 			}
3129*5113495bSYour Name 			return;
3130*5113495bSYour Name 		}
3131*5113495bSYour Name 		hdd_link_layer_process_radio_stats(adapter, stats->more_data,
3132*5113495bSYour Name 						   radio_stat, num_radio);
3133*5113495bSYour Name 	}
3134*5113495bSYour Name 		break;
3135*5113495bSYour Name 	case WMI_LINK_STATS_IFACE:
3136*5113495bSYour Name 		hdd_link_layer_process_iface_stats(link_info,
3137*5113495bSYour Name 						   stats->result,
3138*5113495bSYour Name 						   stats->stats_nradio_npeer.
3139*5113495bSYour Name 						   no_of_peers);
3140*5113495bSYour Name 		break;
3141*5113495bSYour Name 	case WMI_LINK_STATS_ALL_PEER:
3142*5113495bSYour Name 		hdd_link_layer_process_peer_stats(adapter,
3143*5113495bSYour Name 						  stats->more_data,
3144*5113495bSYour Name 						  stats->result);
3145*5113495bSYour Name 		break;
3146*5113495bSYour Name 	default:
3147*5113495bSYour Name 		hdd_err("not requested event");
3148*5113495bSYour Name 	}
3149*5113495bSYour Name }
3150*5113495bSYour Name 
wlan_hdd_dealloc_ll_stats(void * priv)3151*5113495bSYour Name static void wlan_hdd_dealloc_ll_stats(void *priv)
3152*5113495bSYour Name {
3153*5113495bSYour Name 	struct hdd_ll_stats_priv *ll_stats_priv = priv;
3154*5113495bSYour Name 	struct hdd_ll_stats *stats = NULL;
3155*5113495bSYour Name 	QDF_STATUS status;
3156*5113495bSYour Name 	qdf_list_node_t *ll_node;
3157*5113495bSYour Name 
3158*5113495bSYour Name 	if (!ll_stats_priv)
3159*5113495bSYour Name 		return;
3160*5113495bSYour Name 
3161*5113495bSYour Name 	qdf_spin_lock(&ll_stats_priv->ll_stats_lock);
3162*5113495bSYour Name 	status = qdf_list_remove_front(&ll_stats_priv->ll_stats_q, &ll_node);
3163*5113495bSYour Name 	qdf_spin_unlock(&ll_stats_priv->ll_stats_lock);
3164*5113495bSYour Name 	while (QDF_IS_STATUS_SUCCESS(status)) {
3165*5113495bSYour Name 		stats =  qdf_container_of(ll_node, struct hdd_ll_stats,
3166*5113495bSYour Name 					  ll_stats_node);
3167*5113495bSYour Name 
3168*5113495bSYour Name 		if (stats->result_param_id == WMI_LINK_STATS_RADIO) {
3169*5113495bSYour Name 			struct wifi_radio_stats *radio_stat = stats->result;
3170*5113495bSYour Name 			int i;
3171*5113495bSYour Name 			int num_radio = stats->stats_nradio_npeer.no_of_radios;
3172*5113495bSYour Name 
3173*5113495bSYour Name 			for (i = 0; i < num_radio; i++) {
3174*5113495bSYour Name 				if (radio_stat->num_channels)
3175*5113495bSYour Name 					qdf_mem_free(radio_stat->channels);
3176*5113495bSYour Name 				if (radio_stat->total_num_tx_power_levels)
3177*5113495bSYour Name 					qdf_mem_free(radio_stat->
3178*5113495bSYour Name 						tx_time_per_power_level);
3179*5113495bSYour Name 				radio_stat++;
3180*5113495bSYour Name 			}
3181*5113495bSYour Name 		}
3182*5113495bSYour Name 
3183*5113495bSYour Name 		qdf_mem_free(stats->result);
3184*5113495bSYour Name 		qdf_mem_free(stats);
3185*5113495bSYour Name 		qdf_spin_lock(&ll_stats_priv->ll_stats_lock);
3186*5113495bSYour Name 		status = qdf_list_remove_front(&ll_stats_priv->ll_stats_q,
3187*5113495bSYour Name 					       &ll_node);
3188*5113495bSYour Name 		qdf_spin_unlock(&ll_stats_priv->ll_stats_lock);
3189*5113495bSYour Name 	}
3190*5113495bSYour Name 	qdf_list_destroy(&ll_stats_priv->ll_stats_q);
3191*5113495bSYour Name }
3192*5113495bSYour Name 
3193*5113495bSYour Name static QDF_STATUS
wlan_hdd_set_ll_stats_request_pending(struct hdd_adapter * adapter)3194*5113495bSYour Name wlan_hdd_set_ll_stats_request_pending(struct hdd_adapter *adapter)
3195*5113495bSYour Name {
3196*5113495bSYour Name 	if (qdf_atomic_read(&adapter->is_ll_stats_req_pending)) {
3197*5113495bSYour Name 		hdd_nofl_debug("Previous ll_stats request is in progress");
3198*5113495bSYour Name 		return QDF_STATUS_E_ALREADY;
3199*5113495bSYour Name 	}
3200*5113495bSYour Name 
3201*5113495bSYour Name 	qdf_atomic_set(&adapter->is_ll_stats_req_pending, 1);
3202*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
3203*5113495bSYour Name }
3204*5113495bSYour Name 
3205*5113495bSYour Name #ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
3206*5113495bSYour Name /**
3207*5113495bSYour Name  * cache_station_stats_cb() - cache_station_stats_cb callback function
3208*5113495bSYour Name  * @ev: station stats buffer
3209*5113495bSYour Name  * @cookie: cookie that contains the address of the adapter corresponding to
3210*5113495bSYour Name  *          the request
3211*5113495bSYour Name  *
3212*5113495bSYour Name  * Return: None
3213*5113495bSYour Name  */
cache_station_stats_cb(struct stats_event * ev,void * cookie)3214*5113495bSYour Name static void cache_station_stats_cb(struct stats_event *ev, void *cookie)
3215*5113495bSYour Name {
3216*5113495bSYour Name 	struct hdd_adapter *adapter = cookie, *next_adapter = NULL;
3217*5113495bSYour Name 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
3218*5113495bSYour Name 	uint8_t vdev_id;
3219*5113495bSYour Name 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_DISPLAY_TXRX_STATS;
3220*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
3221*5113495bSYour Name 
3222*5113495bSYour Name 	if (!ev->vdev_summary_stats || !ev->vdev_chain_rssi ||
3223*5113495bSYour Name 	    !ev->peer_adv_stats || !ev->pdev_stats) {
3224*5113495bSYour Name 		hdd_debug("Invalid stats");
3225*5113495bSYour Name 		return;
3226*5113495bSYour Name 	}
3227*5113495bSYour Name 
3228*5113495bSYour Name 	vdev_id = ev->vdev_summary_stats->vdev_id;
3229*5113495bSYour Name 
3230*5113495bSYour Name 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
3231*5113495bSYour Name 					   dbgid) {
3232*5113495bSYour Name 		hdd_adapter_for_each_active_link_info(adapter, link_info) {
3233*5113495bSYour Name 			if (link_info->vdev_id != vdev_id)
3234*5113495bSYour Name 				continue;
3235*5113495bSYour Name 
3236*5113495bSYour Name 			copy_station_stats_to_adapter(link_info, ev);
3237*5113495bSYour Name 			wlan_hdd_get_peer_rx_rate_stats(link_info);
3238*5113495bSYour Name 
3239*5113495bSYour Name 			/* dev_put has to be done here */
3240*5113495bSYour Name 			hdd_adapter_dev_put_debug(adapter, dbgid);
3241*5113495bSYour Name 			if (next_adapter)
3242*5113495bSYour Name 				hdd_adapter_dev_put_debug(next_adapter, dbgid);
3243*5113495bSYour Name 			return;
3244*5113495bSYour Name 		}
3245*5113495bSYour Name 		hdd_adapter_dev_put_debug(adapter, dbgid);
3246*5113495bSYour Name 	}
3247*5113495bSYour Name }
3248*5113495bSYour Name 
3249*5113495bSYour Name #ifdef WLAN_FEATURE_11BE_MLO
3250*5113495bSYour Name static QDF_STATUS
wlan_hdd_get_mlo_vdev_params(struct hdd_adapter * adapter,struct request_info * req_info,tSirLLStatsGetReq * req)3251*5113495bSYour Name wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter,
3252*5113495bSYour Name 			     struct request_info *req_info,
3253*5113495bSYour Name 			     tSirLLStatsGetReq *req)
3254*5113495bSYour Name {
3255*5113495bSYour Name 	struct wlan_objmgr_peer *peer;
3256*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
3257*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
3258*5113495bSYour Name 	struct mlo_stats_vdev_params *info = &req_info->ml_vdev_info;
3259*5113495bSYour Name 	int i;
3260*5113495bSYour Name 	uint32_t bmap = 0;
3261*5113495bSYour Name 	QDF_STATUS status;
3262*5113495bSYour Name 
3263*5113495bSYour Name 	req->is_mlo_req = wlan_vdev_mlme_get_is_mlo_vdev(
3264*5113495bSYour Name 					psoc, adapter->deflink->vdev_id);
3265*5113495bSYour Name 	status = mlo_get_mlstats_vdev_params(psoc, info,
3266*5113495bSYour Name 					     adapter->deflink->vdev_id);
3267*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
3268*5113495bSYour Name 		return status;
3269*5113495bSYour Name 	for (i = 0; i < info->ml_vdev_count; i++) {
3270*5113495bSYour Name 		bmap |= (1 << info->ml_vdev_id[i]);
3271*5113495bSYour Name 
3272*5113495bSYour Name 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
3273*5113495bSYour Name 							    info->ml_vdev_id[i],
3274*5113495bSYour Name 							    WLAN_OSIF_STATS_ID);
3275*5113495bSYour Name 		if (!vdev) {
3276*5113495bSYour Name 			hdd_err("vdev object is NULL for vdev %d",
3277*5113495bSYour Name 				info->ml_vdev_id[i]);
3278*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3279*5113495bSYour Name 		}
3280*5113495bSYour Name 
3281*5113495bSYour Name 		peer = wlan_objmgr_vdev_try_get_bsspeer(vdev,
3282*5113495bSYour Name 							WLAN_OSIF_STATS_ID);
3283*5113495bSYour Name 		if (!peer) {
3284*5113495bSYour Name 			hdd_err("peer is null");
3285*5113495bSYour Name 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3286*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3287*5113495bSYour Name 		}
3288*5113495bSYour Name 
3289*5113495bSYour Name 		qdf_mem_copy(&(req_info->ml_peer_mac_addr[i][0]), peer->macaddr,
3290*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
3291*5113495bSYour Name 
3292*5113495bSYour Name 		wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_STATS_ID);
3293*5113495bSYour Name 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3294*5113495bSYour Name 	}
3295*5113495bSYour Name 	req->mlo_vdev_id_bitmap = bmap;
3296*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
3297*5113495bSYour Name }
3298*5113495bSYour Name #else
3299*5113495bSYour Name static QDF_STATUS
wlan_hdd_get_mlo_vdev_params(struct hdd_adapter * adapter,struct request_info * req_info,tSirLLStatsGetReq * req)3300*5113495bSYour Name wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter,
3301*5113495bSYour Name 			     struct request_info *req_info,
3302*5113495bSYour Name 			     tSirLLStatsGetReq *req)
3303*5113495bSYour Name {
3304*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
3305*5113495bSYour Name }
3306*5113495bSYour Name #endif
3307*5113495bSYour Name 
3308*5113495bSYour Name static QDF_STATUS
wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info * link_info,tSirLLStatsGetReq * req)3309*5113495bSYour Name wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info *link_info,
3310*5113495bSYour Name 					   tSirLLStatsGetReq *req)
3311*5113495bSYour Name {
3312*5113495bSYour Name 	struct wlan_objmgr_peer *peer;
3313*5113495bSYour Name 	struct request_info info = {0};
3314*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
3315*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
3316*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
3317*5113495bSYour Name 	bool is_mlo_vdev = false;
3318*5113495bSYour Name 	QDF_STATUS status;
3319*5113495bSYour Name 
3320*5113495bSYour Name 	if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req)
3321*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
3322*5113495bSYour Name 
3323*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
3324*5113495bSYour Name 	if (!vdev)
3325*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
3326*5113495bSYour Name 
3327*5113495bSYour Name 	info.cookie = adapter;
3328*5113495bSYour Name 	info.u.get_station_stats_cb = cache_station_stats_cb;
3329*5113495bSYour Name 	info.vdev_id = link_info->vdev_id;
3330*5113495bSYour Name 	is_mlo_vdev = wlan_vdev_mlme_get_is_mlo_vdev(psoc, link_info->vdev_id);
3331*5113495bSYour Name 	if (is_mlo_vdev) {
3332*5113495bSYour Name 		status = wlan_hdd_get_mlo_vdev_params(adapter, &info, req);
3333*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
3334*5113495bSYour Name 			hdd_err("unable to get vdev params for mlo stats");
3335*5113495bSYour Name 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3336*5113495bSYour Name 			return status;
3337*5113495bSYour Name 		}
3338*5113495bSYour Name 	}
3339*5113495bSYour Name 
3340*5113495bSYour Name 	info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
3341*5113495bSYour Name 
3342*5113495bSYour Name 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_STATS_ID);
3343*5113495bSYour Name 	if (!peer) {
3344*5113495bSYour Name 		osif_err("peer is null");
3345*5113495bSYour Name 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3346*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
3347*5113495bSYour Name 	}
3348*5113495bSYour Name 
3349*5113495bSYour Name 	qdf_mem_copy(info.peer_mac_addr, peer->macaddr, QDF_MAC_ADDR_SIZE);
3350*5113495bSYour Name 
3351*5113495bSYour Name 	wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_STATS_ID);
3352*5113495bSYour Name 
3353*5113495bSYour Name 	ucfg_mc_cp_stats_set_pending_req(psoc, TYPE_STATION_STATS, &info);
3354*5113495bSYour Name 
3355*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
3356*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
3357*5113495bSYour Name }
3358*5113495bSYour Name 
3359*5113495bSYour Name static void
wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc * psoc,struct hdd_adapter * adapter)3360*5113495bSYour Name wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc,
3361*5113495bSYour Name 					     struct hdd_adapter *adapter)
3362*5113495bSYour Name {
3363*5113495bSYour Name 	QDF_STATUS status;
3364*5113495bSYour Name 	struct request_info last_req = {0};
3365*5113495bSYour Name 	bool pending = false;
3366*5113495bSYour Name 
3367*5113495bSYour Name 	if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req)
3368*5113495bSYour Name 		return;
3369*5113495bSYour Name 
3370*5113495bSYour Name 	status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS,
3371*5113495bSYour Name 						  &last_req);
3372*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3373*5113495bSYour Name 		hdd_err("ucfg_mc_cp_stats_get_pending_req failed");
3374*5113495bSYour Name 		return;
3375*5113495bSYour Name 	}
3376*5113495bSYour Name 
3377*5113495bSYour Name 	ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_STATION_STATS,
3378*5113495bSYour Name 					   &last_req, &pending);
3379*5113495bSYour Name }
3380*5113495bSYour Name 
wlan_hdd_stats_request_needed(struct hdd_adapter * adapter)3381*5113495bSYour Name static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
3382*5113495bSYour Name {
3383*5113495bSYour Name 	if (adapter->device_mode != QDF_STA_MODE)
3384*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
3385*5113495bSYour Name 
3386*5113495bSYour Name 	if (!adapter->hdd_ctx->config) {
3387*5113495bSYour Name 		hdd_err("Invalid hdd config");
3388*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
3389*5113495bSYour Name 	}
3390*5113495bSYour Name 
3391*5113495bSYour Name 	if (adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req) {
3392*5113495bSYour Name 		uint32_t stats_cached_duration;
3393*5113495bSYour Name 
3394*5113495bSYour Name 		stats_cached_duration =
3395*5113495bSYour Name 				qdf_system_ticks_to_msecs(qdf_system_ticks()) -
3396*5113495bSYour Name 				adapter->sta_stats_cached_timestamp;
3397*5113495bSYour Name 		if (qdf_atomic_read(&adapter->is_ll_stats_req_pending) ||
3398*5113495bSYour Name 		    (stats_cached_duration <=
3399*5113495bSYour Name 			adapter->hdd_ctx->config->sta_stats_cache_expiry_time))
3400*5113495bSYour Name 			return QDF_STATUS_E_ALREADY;
3401*5113495bSYour Name 	}
3402*5113495bSYour Name 
3403*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
3404*5113495bSYour Name }
3405*5113495bSYour Name 
3406*5113495bSYour Name #else
3407*5113495bSYour Name static inline QDF_STATUS
wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info * link_info,tSirLLStatsGetReq * req)3408*5113495bSYour Name wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info *link_info,
3409*5113495bSYour Name 					   tSirLLStatsGetReq *req)
3410*5113495bSYour Name {
3411*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
3412*5113495bSYour Name }
3413*5113495bSYour Name 
3414*5113495bSYour Name static void
wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc * psoc,struct hdd_adapter * adapter)3415*5113495bSYour Name wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc,
3416*5113495bSYour Name 					     struct hdd_adapter *adapter)
3417*5113495bSYour Name {
3418*5113495bSYour Name }
3419*5113495bSYour Name 
wlan_hdd_stats_request_needed(struct hdd_adapter * adapter)3420*5113495bSYour Name static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
3421*5113495bSYour Name {
3422*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
3423*5113495bSYour Name }
3424*5113495bSYour Name #endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
3425*5113495bSYour Name 
wlan_hdd_send_mlo_ll_stats_to_user(struct hdd_adapter * adapter)3426*5113495bSYour Name static void wlan_hdd_send_mlo_ll_stats_to_user(struct hdd_adapter *adapter)
3427*5113495bSYour Name {
3428*5113495bSYour Name 	if (!wlan_hdd_is_mlo_connection(adapter->deflink))
3429*5113495bSYour Name 		return;
3430*5113495bSYour Name 
3431*5113495bSYour Name 	wlan_hdd_send_mlo_ll_iface_stats_to_user(adapter);
3432*5113495bSYour Name 	wlan_hdd_send_mlo_ll_peer_stats_to_user(adapter);
3433*5113495bSYour Name }
3434*5113495bSYour Name 
wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info * link_info,tSirLLStatsGetReq * req)3435*5113495bSYour Name static int wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info *link_info,
3436*5113495bSYour Name 				      tSirLLStatsGetReq *req)
3437*5113495bSYour Name {
3438*5113495bSYour Name 	int ret = 0;
3439*5113495bSYour Name 	struct hdd_ll_stats_priv *priv;
3440*5113495bSYour Name 	struct hdd_ll_stats *stats = NULL;
3441*5113495bSYour Name 	struct osif_request *request;
3442*5113495bSYour Name 	qdf_list_node_t *ll_node;
3443*5113495bSYour Name 	QDF_STATUS status, vdev_req_status;
3444*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
3445*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3446*5113495bSYour Name 	void *cookie;
3447*5113495bSYour Name 	static const struct osif_request_params params = {
3448*5113495bSYour Name 		.priv_size = sizeof(*priv),
3449*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_LL_STATS,
3450*5113495bSYour Name 		.dealloc = wlan_hdd_dealloc_ll_stats,
3451*5113495bSYour Name 	};
3452*5113495bSYour Name 
3453*5113495bSYour Name 	hdd_enter_dev(adapter->dev);
3454*5113495bSYour Name 
3455*5113495bSYour Name 	status = wlan_hdd_set_ll_stats_request_pending(adapter);
3456*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
3457*5113495bSYour Name 		return qdf_status_to_os_return(status);
3458*5113495bSYour Name 
3459*5113495bSYour Name 	vdev_req_status = wlan_hdd_set_station_stats_request_pending(link_info,
3460*5113495bSYour Name 								     req);
3461*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(vdev_req_status))
3462*5113495bSYour Name 		hdd_nofl_debug("Requesting LL_STATS only");
3463*5113495bSYour Name 
3464*5113495bSYour Name 	/*
3465*5113495bSYour Name 	 * FW can send radio stats with multiple events and for the first event
3466*5113495bSYour Name 	 * host allocates memory in wma and processes the events, there is a
3467*5113495bSYour Name 	 * possibility that host receives first event and gets timed out, on
3468*5113495bSYour Name 	 * time out host frees the allocated memory. now if host receives
3469*5113495bSYour Name 	 * remaining events it will again allocate memory and processes the
3470*5113495bSYour Name 	 * stats, since this is not an allocation for new command, this will
3471*5113495bSYour Name 	 * lead to out of order processing of the next event and this memory
3472*5113495bSYour Name 	 * might not be freed, so free the already allocated memory from WMA
3473*5113495bSYour Name 	 * before issuing any new ll stats request free memory allocated for
3474*5113495bSYour Name 	 * previous command
3475*5113495bSYour Name 	 */
3476*5113495bSYour Name 	sme_radio_tx_mem_free();
3477*5113495bSYour Name 
3478*5113495bSYour Name 	request = osif_request_alloc(&params);
3479*5113495bSYour Name 	if (!request) {
3480*5113495bSYour Name 		hdd_err("Request Allocation Failure");
3481*5113495bSYour Name 		wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc,
3482*5113495bSYour Name 							     adapter);
3483*5113495bSYour Name 		return -ENOMEM;
3484*5113495bSYour Name 	}
3485*5113495bSYour Name 
3486*5113495bSYour Name 	cookie = osif_request_cookie(request);
3487*5113495bSYour Name 
3488*5113495bSYour Name 	priv = osif_request_priv(request);
3489*5113495bSYour Name 
3490*5113495bSYour Name 	priv->request_id = req->reqId;
3491*5113495bSYour Name 	priv->request_bitmap = req->paramIdMask;
3492*5113495bSYour Name 	priv->vdev_id = link_info->vdev_id;
3493*5113495bSYour Name 	priv->is_mlo_req = wlan_vdev_mlme_get_is_mlo_vdev(hdd_ctx->psoc,
3494*5113495bSYour Name 							  link_info->vdev_id);
3495*5113495bSYour Name 	if (priv->is_mlo_req)
3496*5113495bSYour Name 		priv->mlo_vdev_id_bitmap = req->mlo_vdev_id_bitmap;
3497*5113495bSYour Name 
3498*5113495bSYour Name 	qdf_spinlock_create(&priv->ll_stats_lock);
3499*5113495bSYour Name 	qdf_list_create(&priv->ll_stats_q, HDD_LINK_STATS_MAX);
3500*5113495bSYour Name 
3501*5113495bSYour Name 	status = sme_ll_stats_get_req(hdd_ctx->mac_handle, req, cookie);
3502*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3503*5113495bSYour Name 		hdd_err("sme_ll_stats_get_req Failed");
3504*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
3505*5113495bSYour Name 		goto exit;
3506*5113495bSYour Name 	}
3507*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
3508*5113495bSYour Name 	if (ret) {
3509*5113495bSYour Name 		adapter->ll_stats_failure_count++;
3510*5113495bSYour Name 		hdd_err("Target response timed out request id %d request bitmap 0x%x ll_stats failure count %d",
3511*5113495bSYour Name 			priv->request_id, priv->request_bitmap,
3512*5113495bSYour Name 			adapter->ll_stats_failure_count);
3513*5113495bSYour Name 		qdf_spin_lock(&priv->ll_stats_lock);
3514*5113495bSYour Name 		priv->request_bitmap = 0;
3515*5113495bSYour Name 		qdf_spin_unlock(&priv->ll_stats_lock);
3516*5113495bSYour Name 		sme_radio_tx_mem_free();
3517*5113495bSYour Name 		ret = -ETIMEDOUT;
3518*5113495bSYour Name 	} else {
3519*5113495bSYour Name 		if (QDF_IS_STATUS_SUCCESS(vdev_req_status)) {
3520*5113495bSYour Name 			hdd_update_station_stats_cached_timestamp(adapter);
3521*5113495bSYour Name 			hdd_update_link_state_cached_timestamp(adapter);
3522*5113495bSYour Name 		}
3523*5113495bSYour Name 
3524*5113495bSYour Name 		adapter->ll_stats_failure_count = 0;
3525*5113495bSYour Name 	}
3526*5113495bSYour Name 
3527*5113495bSYour Name 	qdf_spin_lock(&priv->ll_stats_lock);
3528*5113495bSYour Name 	status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node);
3529*5113495bSYour Name 	qdf_spin_unlock(&priv->ll_stats_lock);
3530*5113495bSYour Name 	while (QDF_IS_STATUS_SUCCESS(status)) {
3531*5113495bSYour Name 		stats =  qdf_container_of(ll_node, struct hdd_ll_stats,
3532*5113495bSYour Name 					  ll_stats_node);
3533*5113495bSYour Name 		wlan_hdd_handle_ll_stats(link_info, stats, ret);
3534*5113495bSYour Name 		qdf_mem_free(stats->result);
3535*5113495bSYour Name 		qdf_mem_free(stats);
3536*5113495bSYour Name 		qdf_spin_lock(&priv->ll_stats_lock);
3537*5113495bSYour Name 		status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node);
3538*5113495bSYour Name 		qdf_spin_unlock(&priv->ll_stats_lock);
3539*5113495bSYour Name 	}
3540*5113495bSYour Name 	qdf_list_destroy(&priv->ll_stats_q);
3541*5113495bSYour Name 
3542*5113495bSYour Name 	if (!ret && req->reqId != DEBUGFS_LLSTATS_REQID)
3543*5113495bSYour Name 		wlan_hdd_send_mlo_ll_stats_to_user(adapter);
3544*5113495bSYour Name 
3545*5113495bSYour Name exit:
3546*5113495bSYour Name 	qdf_atomic_set(&adapter->is_ll_stats_req_pending, 0);
3547*5113495bSYour Name 	wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc, adapter);
3548*5113495bSYour Name 	hdd_exit();
3549*5113495bSYour Name 	osif_request_put(request);
3550*5113495bSYour Name 
3551*5113495bSYour Name 	if (adapter->ll_stats_failure_count >=
3552*5113495bSYour Name 					HDD_MAX_ALLOWED_LL_STATS_FAILURE) {
3553*5113495bSYour Name 		cds_trigger_recovery(QDF_STATS_REQ_TIMEDOUT);
3554*5113495bSYour Name 		adapter->ll_stats_failure_count = 0;
3555*5113495bSYour Name 	}
3556*5113495bSYour Name 
3557*5113495bSYour Name 	return ret;
3558*5113495bSYour Name }
3559*5113495bSYour Name 
wlan_hdd_ll_stats_get(struct wlan_hdd_link_info * link_info,uint32_t req_id,uint32_t req_mask)3560*5113495bSYour Name int wlan_hdd_ll_stats_get(struct wlan_hdd_link_info *link_info,
3561*5113495bSYour Name 			  uint32_t req_id, uint32_t req_mask)
3562*5113495bSYour Name {
3563*5113495bSYour Name 	int errno;
3564*5113495bSYour Name 	tSirLLStatsGetReq get_req;
3565*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
3566*5113495bSYour Name 
3567*5113495bSYour Name 	hdd_enter_dev(adapter->dev);
3568*5113495bSYour Name 
3569*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3570*5113495bSYour Name 		hdd_warn("Command not allowed in FTM mode");
3571*5113495bSYour Name 		return -EPERM;
3572*5113495bSYour Name 	}
3573*5113495bSYour Name 
3574*5113495bSYour Name 	if (hdd_cm_is_vdev_roaming(link_info)) {
3575*5113495bSYour Name 		hdd_debug("Roaming in progress, cannot process the request");
3576*5113495bSYour Name 		return -EBUSY;
3577*5113495bSYour Name 	}
3578*5113495bSYour Name 
3579*5113495bSYour Name 	if (!adapter->is_link_layer_stats_set) {
3580*5113495bSYour Name 		hdd_info("LL_STATs not set");
3581*5113495bSYour Name 		return -EINVAL;
3582*5113495bSYour Name 	}
3583*5113495bSYour Name 
3584*5113495bSYour Name 	get_req.reqId = req_id;
3585*5113495bSYour Name 	get_req.paramIdMask = req_mask;
3586*5113495bSYour Name 	get_req.staId = link_info->vdev_id;
3587*5113495bSYour Name 
3588*5113495bSYour Name 	rtnl_lock();
3589*5113495bSYour Name 	errno = wlan_hdd_send_ll_stats_req(link_info, &get_req);
3590*5113495bSYour Name 	rtnl_unlock();
3591*5113495bSYour Name 	if (errno)
3592*5113495bSYour Name 		hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
3593*5113495bSYour Name 			req_id, req_mask, link_info->vdev_id);
3594*5113495bSYour Name 
3595*5113495bSYour Name 	hdd_exit();
3596*5113495bSYour Name 
3597*5113495bSYour Name 	return errno;
3598*5113495bSYour Name }
3599*5113495bSYour Name 
3600*5113495bSYour Name /**
3601*5113495bSYour Name  * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats
3602*5113495bSYour Name  * @wiphy: Pointer to wiphy
3603*5113495bSYour Name  * @wdev: Pointer to wdev
3604*5113495bSYour Name  * @data: Pointer to data
3605*5113495bSYour Name  * @data_len: Data length
3606*5113495bSYour Name  *
3607*5113495bSYour Name  * Return: int
3608*5113495bSYour Name  */
3609*5113495bSYour Name static int
__wlan_hdd_cfg80211_ll_stats_get(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3610*5113495bSYour Name __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
3611*5113495bSYour Name 				   struct wireless_dev *wdev,
3612*5113495bSYour Name 				   const void *data,
3613*5113495bSYour Name 				   int data_len)
3614*5113495bSYour Name {
3615*5113495bSYour Name 	int ret;
3616*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3617*5113495bSYour Name 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
3618*5113495bSYour Name 	tSirLLStatsGetReq LinkLayerStatsGetReq;
3619*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
3620*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3621*5113495bSYour Name 	struct wlan_hdd_link_info *link_info = adapter->deflink;
3622*5113495bSYour Name 
3623*5113495bSYour Name 	hdd_enter_dev(dev);
3624*5113495bSYour Name 
3625*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3626*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
3627*5113495bSYour Name 		return -EPERM;
3628*5113495bSYour Name 	}
3629*5113495bSYour Name 
3630*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
3631*5113495bSYour Name 	if (0 != ret)
3632*5113495bSYour Name 		return -EINVAL;
3633*5113495bSYour Name 
3634*5113495bSYour Name 	if (!adapter->is_link_layer_stats_set) {
3635*5113495bSYour Name 		hdd_nofl_debug("is_link_layer_stats_set: %d",
3636*5113495bSYour Name 			       adapter->is_link_layer_stats_set);
3637*5113495bSYour Name 		return -EINVAL;
3638*5113495bSYour Name 	}
3639*5113495bSYour Name 
3640*5113495bSYour Name 	if (hdd_cm_is_vdev_roaming(link_info)) {
3641*5113495bSYour Name 		hdd_debug("Roaming in progress, cannot process the request");
3642*5113495bSYour Name 		return -EBUSY;
3643*5113495bSYour Name 	}
3644*5113495bSYour Name 
3645*5113495bSYour Name 	if (wlan_hdd_is_link_switch_in_progress(link_info)) {
3646*5113495bSYour Name 		hdd_debug("Link Switch in progress, can't process the request");
3647*5113495bSYour Name 		return -EBUSY;
3648*5113495bSYour Name 	}
3649*5113495bSYour Name 
3650*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb_vendor,
3651*5113495bSYour Name 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX,
3652*5113495bSYour Name 				    (struct nlattr *)data, data_len,
3653*5113495bSYour Name 				    qca_wlan_vendor_ll_get_policy)) {
3654*5113495bSYour Name 		hdd_err("max attribute not present");
3655*5113495bSYour Name 		return -EINVAL;
3656*5113495bSYour Name 	}
3657*5113495bSYour Name 
3658*5113495bSYour Name 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) {
3659*5113495bSYour Name 		hdd_err("Request Id Not present");
3660*5113495bSYour Name 		return -EINVAL;
3661*5113495bSYour Name 	}
3662*5113495bSYour Name 
3663*5113495bSYour Name 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) {
3664*5113495bSYour Name 		hdd_err("Req Mask Not present");
3665*5113495bSYour Name 		return -EINVAL;
3666*5113495bSYour Name 	}
3667*5113495bSYour Name 
3668*5113495bSYour Name 	LinkLayerStatsGetReq.reqId =
3669*5113495bSYour Name 		nla_get_u32(tb_vendor
3670*5113495bSYour Name 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]);
3671*5113495bSYour Name 	LinkLayerStatsGetReq.paramIdMask =
3672*5113495bSYour Name 		nla_get_u32(tb_vendor
3673*5113495bSYour Name 			    [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]);
3674*5113495bSYour Name 
3675*5113495bSYour Name 	LinkLayerStatsGetReq.staId = link_info->vdev_id;
3676*5113495bSYour Name 
3677*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
3678*5113495bSYour Name 		return -EINVAL;
3679*5113495bSYour Name 
3680*5113495bSYour Name 	ret = wlan_hdd_send_ll_stats_req(link_info, &LinkLayerStatsGetReq);
3681*5113495bSYour Name 	if (0 != ret) {
3682*5113495bSYour Name 		hdd_err("Failed to send LL stats request (id:%u)",
3683*5113495bSYour Name 			LinkLayerStatsGetReq.reqId);
3684*5113495bSYour Name 		return ret;
3685*5113495bSYour Name 	}
3686*5113495bSYour Name 
3687*5113495bSYour Name 	hdd_exit();
3688*5113495bSYour Name 	return 0;
3689*5113495bSYour Name }
3690*5113495bSYour Name 
3691*5113495bSYour Name /**
3692*5113495bSYour Name  * wlan_hdd_cfg80211_ll_stats_get() - get ll stats
3693*5113495bSYour Name  * @wiphy: Pointer to wiphy
3694*5113495bSYour Name  * @wdev: Pointer to wdev
3695*5113495bSYour Name  * @data: Pointer to data
3696*5113495bSYour Name  * @data_len: Data length
3697*5113495bSYour Name  *
3698*5113495bSYour Name  * Return: 0 if success, non-zero for failure
3699*5113495bSYour Name  */
wlan_hdd_cfg80211_ll_stats_get(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3700*5113495bSYour Name int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
3701*5113495bSYour Name 				   struct wireless_dev *wdev,
3702*5113495bSYour Name 				   const void *data,
3703*5113495bSYour Name 				   int data_len)
3704*5113495bSYour Name {
3705*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3706*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
3707*5113495bSYour Name 	int errno;
3708*5113495bSYour Name 
3709*5113495bSYour Name 	errno = wlan_hdd_validate_context(hdd_ctx);
3710*5113495bSYour Name 	if (0 != errno)
3711*5113495bSYour Name 		return -EINVAL;
3712*5113495bSYour Name 
3713*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3714*5113495bSYour Name 	if (errno)
3715*5113495bSYour Name 		return errno;
3716*5113495bSYour Name 
3717*5113495bSYour Name 	errno = wlan_hdd_qmi_get_sync_resume();
3718*5113495bSYour Name 	if (errno) {
3719*5113495bSYour Name 		hdd_err("qmi sync resume failed: %d", errno);
3720*5113495bSYour Name 		goto end;
3721*5113495bSYour Name 	}
3722*5113495bSYour Name 
3723*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len);
3724*5113495bSYour Name 
3725*5113495bSYour Name 	wlan_hdd_qmi_put_suspend();
3726*5113495bSYour Name 
3727*5113495bSYour Name end:
3728*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
3729*5113495bSYour Name 
3730*5113495bSYour Name 	return errno;
3731*5113495bSYour Name }
3732*5113495bSYour Name 
3733*5113495bSYour Name const struct
3734*5113495bSYour Name nla_policy
3735*5113495bSYour Name 	qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = {
3736*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32},
3737*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8},
3738*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32},
3739*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8},
3740*5113495bSYour Name };
3741*5113495bSYour Name 
3742*5113495bSYour Name /**
3743*5113495bSYour Name  * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats
3744*5113495bSYour Name  * @wiphy: Pointer to wiphy
3745*5113495bSYour Name  * @wdev: Pointer to wdev
3746*5113495bSYour Name  * @data: Pointer to data
3747*5113495bSYour Name  * @data_len: Data length
3748*5113495bSYour Name  *
3749*5113495bSYour Name  * Return: int
3750*5113495bSYour Name  */
3751*5113495bSYour Name static int
__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3752*5113495bSYour Name __wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
3753*5113495bSYour Name 				    struct wireless_dev *wdev,
3754*5113495bSYour Name 				    const void *data,
3755*5113495bSYour Name 				    int data_len)
3756*5113495bSYour Name {
3757*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3758*5113495bSYour Name 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1];
3759*5113495bSYour Name 	tSirLLStatsClearReq LinkLayerStatsClearReq;
3760*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
3761*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3762*5113495bSYour Name 	u32 statsClearReqMask;
3763*5113495bSYour Name 	u8 stopReq;
3764*5113495bSYour Name 	int errno;
3765*5113495bSYour Name 	QDF_STATUS status;
3766*5113495bSYour Name 	struct sk_buff *skb;
3767*5113495bSYour Name 
3768*5113495bSYour Name 	hdd_enter_dev(dev);
3769*5113495bSYour Name 
3770*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3771*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
3772*5113495bSYour Name 		return -EPERM;
3773*5113495bSYour Name 	}
3774*5113495bSYour Name 
3775*5113495bSYour Name 	errno = wlan_hdd_validate_context(hdd_ctx);
3776*5113495bSYour Name 	if (errno)
3777*5113495bSYour Name 		return -EINVAL;
3778*5113495bSYour Name 
3779*5113495bSYour Name 	if (!adapter->is_link_layer_stats_set) {
3780*5113495bSYour Name 		hdd_warn("is_link_layer_stats_set : %d",
3781*5113495bSYour Name 			  adapter->is_link_layer_stats_set);
3782*5113495bSYour Name 		return -EINVAL;
3783*5113495bSYour Name 	}
3784*5113495bSYour Name 
3785*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb_vendor,
3786*5113495bSYour Name 				    QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX,
3787*5113495bSYour Name 				    (struct nlattr *)data, data_len,
3788*5113495bSYour Name 				    qca_wlan_vendor_ll_clr_policy)) {
3789*5113495bSYour Name 		hdd_err("STATS_CLR_MAX is not present");
3790*5113495bSYour Name 		return -EINVAL;
3791*5113495bSYour Name 	}
3792*5113495bSYour Name 
3793*5113495bSYour Name 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] ||
3794*5113495bSYour Name 	    !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) {
3795*5113495bSYour Name 		hdd_err("Error in LL_STATS CLR CONFIG PARA");
3796*5113495bSYour Name 		return -EINVAL;
3797*5113495bSYour Name 	}
3798*5113495bSYour Name 
3799*5113495bSYour Name 	statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask =
3800*5113495bSYour Name 				    nla_get_u32(tb_vendor
3801*5113495bSYour Name 						[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]);
3802*5113495bSYour Name 
3803*5113495bSYour Name 	stopReq = LinkLayerStatsClearReq.stopReq =
3804*5113495bSYour Name 			  nla_get_u8(tb_vendor
3805*5113495bSYour Name 				     [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]);
3806*5113495bSYour Name 
3807*5113495bSYour Name 	/*
3808*5113495bSYour Name 	 * Shall take the request Id if the Upper layers pass. 1 For now.
3809*5113495bSYour Name 	 */
3810*5113495bSYour Name 	LinkLayerStatsClearReq.reqId = 1;
3811*5113495bSYour Name 
3812*5113495bSYour Name 	LinkLayerStatsClearReq.staId = adapter->deflink->vdev_id;
3813*5113495bSYour Name 
3814*5113495bSYour Name 	hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d",
3815*5113495bSYour Name 		LinkLayerStatsClearReq.reqId,
3816*5113495bSYour Name 		LinkLayerStatsClearReq.staId,
3817*5113495bSYour Name 		LinkLayerStatsClearReq.statsClearReqMask,
3818*5113495bSYour Name 		LinkLayerStatsClearReq.stopReq);
3819*5113495bSYour Name 
3820*5113495bSYour Name 	status = sme_ll_stats_clear_req(hdd_ctx->mac_handle,
3821*5113495bSYour Name 					&LinkLayerStatsClearReq);
3822*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3823*5113495bSYour Name 		hdd_err("stats clear request failed, %d", status);
3824*5113495bSYour Name 		return -EINVAL;
3825*5113495bSYour Name 	}
3826*5113495bSYour Name 
3827*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
3828*5113495bSYour Name 						       2 * sizeof(u32) +
3829*5113495bSYour Name 						       2 * NLMSG_HDRLEN);
3830*5113495bSYour Name 	if (!skb) {
3831*5113495bSYour Name 		hdd_err("skb allocation failed");
3832*5113495bSYour Name 		return -ENOMEM;
3833*5113495bSYour Name 	}
3834*5113495bSYour Name 
3835*5113495bSYour Name 	if (nla_put_u32(skb,
3836*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK,
3837*5113495bSYour Name 			statsClearReqMask) ||
3838*5113495bSYour Name 	    nla_put_u32(skb,
3839*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP,
3840*5113495bSYour Name 			stopReq)) {
3841*5113495bSYour Name 		hdd_err("LL_STATS_CLR put fail");
3842*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(skb);
3843*5113495bSYour Name 		return -EINVAL;
3844*5113495bSYour Name 	}
3845*5113495bSYour Name 
3846*5113495bSYour Name 	/* If the ask is to stop the stats collection
3847*5113495bSYour Name 	 * as part of clear (stopReq = 1), ensure
3848*5113495bSYour Name 	 * that no further requests of get go to the
3849*5113495bSYour Name 	 * firmware by having is_link_layer_stats_set set
3850*5113495bSYour Name 	 * to 0.  However it the stopReq as part of
3851*5113495bSYour Name 	 * the clear request is 0, the request to get
3852*5113495bSYour Name 	 * the statistics are honoured as in this case
3853*5113495bSYour Name 	 * the firmware is just asked to clear the
3854*5113495bSYour Name 	 * statistics.
3855*5113495bSYour Name 	 */
3856*5113495bSYour Name 	if (stopReq == 1)
3857*5113495bSYour Name 		adapter->is_link_layer_stats_set = false;
3858*5113495bSYour Name 
3859*5113495bSYour Name 	hdd_exit();
3860*5113495bSYour Name 
3861*5113495bSYour Name 	return wlan_cfg80211_vendor_cmd_reply(skb);
3862*5113495bSYour Name }
3863*5113495bSYour Name 
3864*5113495bSYour Name /**
3865*5113495bSYour Name  * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats
3866*5113495bSYour Name  * @wiphy: Pointer to wiphy
3867*5113495bSYour Name  * @wdev: Pointer to wdev
3868*5113495bSYour Name  * @data: Pointer to data
3869*5113495bSYour Name  * @data_len: Data length
3870*5113495bSYour Name  *
3871*5113495bSYour Name  * Return: 0 if success, non-zero for failure
3872*5113495bSYour Name  */
wlan_hdd_cfg80211_ll_stats_clear(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3873*5113495bSYour Name int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
3874*5113495bSYour Name 					struct wireless_dev *wdev,
3875*5113495bSYour Name 					const void *data,
3876*5113495bSYour Name 					int data_len)
3877*5113495bSYour Name {
3878*5113495bSYour Name 	int errno;
3879*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
3880*5113495bSYour Name 
3881*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3882*5113495bSYour Name 	if (errno)
3883*5113495bSYour Name 		return errno;
3884*5113495bSYour Name 
3885*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len);
3886*5113495bSYour Name 
3887*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
3888*5113495bSYour Name 
3889*5113495bSYour Name 	return errno;
3890*5113495bSYour Name }
3891*5113495bSYour Name 
3892*5113495bSYour Name /**
3893*5113495bSYour Name  * wlan_hdd_clear_link_layer_stats() - clear link layer stats
3894*5113495bSYour Name  * @adapter: pointer to adapter
3895*5113495bSYour Name  *
3896*5113495bSYour Name  * Wrapper function to clear link layer stats.
3897*5113495bSYour Name  * return - void
3898*5113495bSYour Name  */
wlan_hdd_clear_link_layer_stats(struct hdd_adapter * adapter)3899*5113495bSYour Name void wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter)
3900*5113495bSYour Name {
3901*5113495bSYour Name 	tSirLLStatsClearReq link_layer_stats_clear_req;
3902*5113495bSYour Name 	mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle;
3903*5113495bSYour Name 
3904*5113495bSYour Name 	link_layer_stats_clear_req.statsClearReqMask = WIFI_STATS_IFACE_AC |
3905*5113495bSYour Name 		WIFI_STATS_IFACE_ALL_PEER | WIFI_STATS_IFACE_CONTENTION;
3906*5113495bSYour Name 	link_layer_stats_clear_req.stopReq = 0;
3907*5113495bSYour Name 	link_layer_stats_clear_req.reqId = 1;
3908*5113495bSYour Name 	link_layer_stats_clear_req.staId = adapter->deflink->vdev_id;
3909*5113495bSYour Name 	sme_ll_stats_clear_req(mac_handle, &link_layer_stats_clear_req);
3910*5113495bSYour Name }
3911*5113495bSYour Name 
3912*5113495bSYour Name /**
3913*5113495bSYour Name  * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
3914*5113495bSYour Name  * @wifi_peer_info: peer information
3915*5113495bSYour Name  * @vendor_event: buffer for vendor event
3916*5113495bSYour Name  *
3917*5113495bSYour Name  * Return: 0 success
3918*5113495bSYour Name  */
3919*5113495bSYour Name static inline int
hdd_populate_per_peer_ps_info(struct wifi_peer_info * wifi_peer_info,struct sk_buff * vendor_event)3920*5113495bSYour Name hdd_populate_per_peer_ps_info(struct wifi_peer_info *wifi_peer_info,
3921*5113495bSYour Name 			      struct sk_buff *vendor_event)
3922*5113495bSYour Name {
3923*5113495bSYour Name 	if (!wifi_peer_info) {
3924*5113495bSYour Name 		hdd_err("Invalid pointer to peer info.");
3925*5113495bSYour Name 		return -EINVAL;
3926*5113495bSYour Name 	}
3927*5113495bSYour Name 
3928*5113495bSYour Name 	if (nla_put_u32(vendor_event,
3929*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
3930*5113495bSYour Name 			wifi_peer_info->power_saving) ||
3931*5113495bSYour Name 	    nla_put(vendor_event,
3932*5113495bSYour Name 		    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
3933*5113495bSYour Name 		    QDF_MAC_ADDR_SIZE, &wifi_peer_info->peer_macaddr)) {
3934*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
3935*5113495bSYour Name 		return -EINVAL;
3936*5113495bSYour Name 	}
3937*5113495bSYour Name 	return 0;
3938*5113495bSYour Name }
3939*5113495bSYour Name 
3940*5113495bSYour Name /**
3941*5113495bSYour Name  * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
3942*5113495bSYour Name  * @data: stats for peer STA
3943*5113495bSYour Name  * @vendor_event: buffer for vendor event
3944*5113495bSYour Name  *
3945*5113495bSYour Name  * Return: 0 success
3946*5113495bSYour Name  */
hdd_populate_wifi_peer_ps_info(struct wifi_peer_stat * data,struct sk_buff * vendor_event)3947*5113495bSYour Name static int hdd_populate_wifi_peer_ps_info(struct wifi_peer_stat *data,
3948*5113495bSYour Name 					  struct sk_buff *vendor_event)
3949*5113495bSYour Name {
3950*5113495bSYour Name 	uint32_t peer_num, i;
3951*5113495bSYour Name 	struct wifi_peer_info *wifi_peer_info;
3952*5113495bSYour Name 	struct nlattr *peer_info, *peers;
3953*5113495bSYour Name 
3954*5113495bSYour Name 	if (!data) {
3955*5113495bSYour Name 		hdd_err("Invalid pointer to Wifi peer stat.");
3956*5113495bSYour Name 		return -EINVAL;
3957*5113495bSYour Name 	}
3958*5113495bSYour Name 
3959*5113495bSYour Name 	peer_num = data->num_peers;
3960*5113495bSYour Name 	if (peer_num == 0) {
3961*5113495bSYour Name 		hdd_err("Peer number is zero.");
3962*5113495bSYour Name 		return -EINVAL;
3963*5113495bSYour Name 	}
3964*5113495bSYour Name 
3965*5113495bSYour Name 	if (nla_put_u32(vendor_event,
3966*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
3967*5113495bSYour Name 			peer_num)) {
3968*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
3969*5113495bSYour Name 		return -EINVAL;
3970*5113495bSYour Name 	}
3971*5113495bSYour Name 
3972*5113495bSYour Name 	peer_info = nla_nest_start(vendor_event,
3973*5113495bSYour Name 			       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
3974*5113495bSYour Name 	if (!peer_info) {
3975*5113495bSYour Name 		hdd_err("nla_nest_start failed");
3976*5113495bSYour Name 		return -EINVAL;
3977*5113495bSYour Name 	}
3978*5113495bSYour Name 
3979*5113495bSYour Name 	for (i = 0; i < peer_num; i++) {
3980*5113495bSYour Name 		wifi_peer_info = &data->peer_info[i];
3981*5113495bSYour Name 		peers = nla_nest_start(vendor_event, i);
3982*5113495bSYour Name 
3983*5113495bSYour Name 		if (!peers) {
3984*5113495bSYour Name 			hdd_err("nla_nest_start failed");
3985*5113495bSYour Name 			return -EINVAL;
3986*5113495bSYour Name 		}
3987*5113495bSYour Name 
3988*5113495bSYour Name 		if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
3989*5113495bSYour Name 			return -EINVAL;
3990*5113495bSYour Name 
3991*5113495bSYour Name 		nla_nest_end(vendor_event, peers);
3992*5113495bSYour Name 	}
3993*5113495bSYour Name 	nla_nest_end(vendor_event, peer_info);
3994*5113495bSYour Name 
3995*5113495bSYour Name 	return 0;
3996*5113495bSYour Name }
3997*5113495bSYour Name 
3998*5113495bSYour Name /**
3999*5113495bSYour Name  * hdd_populate_tx_failure_info() - populate TX failure info
4000*5113495bSYour Name  * @tx_fail: TX failure info
4001*5113495bSYour Name  * @skb: buffer for vendor event
4002*5113495bSYour Name  *
4003*5113495bSYour Name  * Return: 0 Success
4004*5113495bSYour Name  */
4005*5113495bSYour Name static inline int
hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail * tx_fail,struct sk_buff * skb)4006*5113495bSYour Name hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
4007*5113495bSYour Name 			     struct sk_buff *skb)
4008*5113495bSYour Name {
4009*5113495bSYour Name 	int status = 0;
4010*5113495bSYour Name 
4011*5113495bSYour Name 	if (!tx_fail || !skb)
4012*5113495bSYour Name 		return -EINVAL;
4013*5113495bSYour Name 
4014*5113495bSYour Name 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
4015*5113495bSYour Name 			tx_fail->tid) ||
4016*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
4017*5113495bSYour Name 			tx_fail->msdu_num) ||
4018*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
4019*5113495bSYour Name 			tx_fail->status)) {
4020*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4021*5113495bSYour Name 		status = -EINVAL;
4022*5113495bSYour Name 	}
4023*5113495bSYour Name 
4024*5113495bSYour Name 	return status;
4025*5113495bSYour Name }
4026*5113495bSYour Name 
4027*5113495bSYour Name /**
4028*5113495bSYour Name  * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event
4029*5113495bSYour Name  * @cca: cca info array for all channels
4030*5113495bSYour Name  * @vendor_event: vendor event buffer
4031*5113495bSYour Name  *
4032*5113495bSYour Name  * Return: 0 Success, EINVAL failure
4033*5113495bSYour Name  */
4034*5113495bSYour Name static int
hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats * cca,struct sk_buff * vendor_event)4035*5113495bSYour Name hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca,
4036*5113495bSYour Name 				   struct sk_buff *vendor_event)
4037*5113495bSYour Name {
4038*5113495bSYour Name 	/* There might be no CCA info for a channel */
4039*5113495bSYour Name 	if (!cca)
4040*5113495bSYour Name 		return 0;
4041*5113495bSYour Name 
4042*5113495bSYour Name 	if (nla_put_u32(vendor_event,
4043*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
4044*5113495bSYour Name 			cca->idle_time) ||
4045*5113495bSYour Name 	    nla_put_u32(vendor_event,
4046*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
4047*5113495bSYour Name 			cca->tx_time) ||
4048*5113495bSYour Name 	    nla_put_u32(vendor_event,
4049*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
4050*5113495bSYour Name 			cca->rx_in_bss_time) ||
4051*5113495bSYour Name 	    nla_put_u32(vendor_event,
4052*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
4053*5113495bSYour Name 			cca->rx_out_bss_time) ||
4054*5113495bSYour Name 	    nla_put_u32(vendor_event,
4055*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
4056*5113495bSYour Name 			cca->rx_busy_time) ||
4057*5113495bSYour Name 	    nla_put_u32(vendor_event,
4058*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
4059*5113495bSYour Name 			cca->rx_in_bad_cond_time) ||
4060*5113495bSYour Name 	    nla_put_u32(vendor_event,
4061*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
4062*5113495bSYour Name 			cca->tx_in_bad_cond_time) ||
4063*5113495bSYour Name 	    nla_put_u32(vendor_event,
4064*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
4065*5113495bSYour Name 			cca->wlan_not_avail_time) ||
4066*5113495bSYour Name 	    nla_put_u32(vendor_event,
4067*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
4068*5113495bSYour Name 			cca->vdev_id)) {
4069*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4070*5113495bSYour Name 		return -EINVAL;
4071*5113495bSYour Name 	}
4072*5113495bSYour Name 	return 0;
4073*5113495bSYour Name }
4074*5113495bSYour Name 
4075*5113495bSYour Name /**
4076*5113495bSYour Name  * hdd_populate_wifi_signal_info - put chain signal info
4077*5113495bSYour Name  * @peer_signal: RF chain signal info
4078*5113495bSYour Name  * @skb: vendor event buffer
4079*5113495bSYour Name  *
4080*5113495bSYour Name  * Return: 0 Success, EINVAL failure
4081*5113495bSYour Name  */
4082*5113495bSYour Name static int
hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats * peer_signal,struct sk_buff * skb)4083*5113495bSYour Name hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal,
4084*5113495bSYour Name 			      struct sk_buff *skb)
4085*5113495bSYour Name {
4086*5113495bSYour Name 	uint32_t i, chain_count;
4087*5113495bSYour Name 	struct nlattr *chains, *att;
4088*5113495bSYour Name 
4089*5113495bSYour Name 	/* There might be no signal info for a peer */
4090*5113495bSYour Name 	if (!peer_signal)
4091*5113495bSYour Name 		return 0;
4092*5113495bSYour Name 
4093*5113495bSYour Name 	chain_count = peer_signal->num_chain < WIFI_MAX_CHAINS ?
4094*5113495bSYour Name 		      peer_signal->num_chain : WIFI_MAX_CHAINS;
4095*5113495bSYour Name 	if (nla_put_u32(skb,
4096*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
4097*5113495bSYour Name 			chain_count)) {
4098*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4099*5113495bSYour Name 		return -EINVAL;
4100*5113495bSYour Name 	}
4101*5113495bSYour Name 
4102*5113495bSYour Name 	att = nla_nest_start(skb,
4103*5113495bSYour Name 			     QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL);
4104*5113495bSYour Name 	if (!att) {
4105*5113495bSYour Name 		hdd_err("nla_nest_start failed");
4106*5113495bSYour Name 		return -EINVAL;
4107*5113495bSYour Name 	}
4108*5113495bSYour Name 
4109*5113495bSYour Name 	for (i = 0; i < chain_count; i++) {
4110*5113495bSYour Name 		chains = nla_nest_start(skb, i);
4111*5113495bSYour Name 
4112*5113495bSYour Name 		if (!chains) {
4113*5113495bSYour Name 			hdd_err("nla_nest_start failed");
4114*5113495bSYour Name 			return -EINVAL;
4115*5113495bSYour Name 		}
4116*5113495bSYour Name 
4117*5113495bSYour Name 		hdd_debug("SNR=%d, NF=%d, Rx=%d, Tx=%d",
4118*5113495bSYour Name 			  peer_signal->per_ant_snr[i],
4119*5113495bSYour Name 			  peer_signal->nf[i],
4120*5113495bSYour Name 			  peer_signal->per_ant_rx_mpdus[i],
4121*5113495bSYour Name 			  peer_signal->per_ant_tx_mpdus[i]);
4122*5113495bSYour Name 		if (nla_put_u32(skb,
4123*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
4124*5113495bSYour Name 				peer_signal->per_ant_snr[i]) ||
4125*5113495bSYour Name 		    nla_put_u32(skb,
4126*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
4127*5113495bSYour Name 				peer_signal->nf[i]) ||
4128*5113495bSYour Name 		    nla_put_u32(skb,
4129*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
4130*5113495bSYour Name 				peer_signal->per_ant_rx_mpdus[i]) ||
4131*5113495bSYour Name 		    nla_put_u32(skb,
4132*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
4133*5113495bSYour Name 				peer_signal->per_ant_tx_mpdus[i])) {
4134*5113495bSYour Name 			hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4135*5113495bSYour Name 			return -EINVAL;
4136*5113495bSYour Name 		}
4137*5113495bSYour Name 		nla_nest_end(skb, chains);
4138*5113495bSYour Name 	}
4139*5113495bSYour Name 	nla_nest_end(skb, att);
4140*5113495bSYour Name 
4141*5113495bSYour Name 	return 0;
4142*5113495bSYour Name }
4143*5113495bSYour Name 
4144*5113495bSYour Name /**
4145*5113495bSYour Name  * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info
4146*5113495bSYour Name  * @tx_stats: tx info
4147*5113495bSYour Name  * @skb: vendor event buffer
4148*5113495bSYour Name  *
4149*5113495bSYour Name  * Return: 0 Success, EINVAL failure
4150*5113495bSYour Name  */
4151*5113495bSYour Name static int
hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx * tx_stats,struct sk_buff * skb)4152*5113495bSYour Name hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats,
4153*5113495bSYour Name 				 struct sk_buff *skb)
4154*5113495bSYour Name {
4155*5113495bSYour Name 	uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay;
4156*5113495bSYour Name 
4157*5113495bSYour Name 	/* There might be no TX info for a peer */
4158*5113495bSYour Name 	if (!tx_stats)
4159*5113495bSYour Name 		return 0;
4160*5113495bSYour Name 
4161*5113495bSYour Name 	agg_size = tx_stats->mpdu_aggr_size;
4162*5113495bSYour Name 	succ_mcs = tx_stats->success_mcs;
4163*5113495bSYour Name 	fail_mcs = tx_stats->fail_mcs;
4164*5113495bSYour Name 	delay = tx_stats->delay;
4165*5113495bSYour Name 
4166*5113495bSYour Name 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
4167*5113495bSYour Name 			tx_stats->msdus) ||
4168*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
4169*5113495bSYour Name 			tx_stats->mpdus) ||
4170*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
4171*5113495bSYour Name 			tx_stats->ppdus) ||
4172*5113495bSYour Name 	    nla_put_u32(skb,
4173*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
4174*5113495bSYour Name 			tx_stats->bytes) ||
4175*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
4176*5113495bSYour Name 			tx_stats->drops) ||
4177*5113495bSYour Name 	    nla_put_u32(skb,
4178*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
4179*5113495bSYour Name 			tx_stats->drop_bytes) ||
4180*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
4181*5113495bSYour Name 			tx_stats->retries) ||
4182*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
4183*5113495bSYour Name 			tx_stats->failed) ||
4184*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
4185*5113495bSYour Name 			tx_stats->aggr_len) ||
4186*5113495bSYour Name 	    nla_put_u32(skb,
4187*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
4188*5113495bSYour Name 			tx_stats->success_mcs_len) ||
4189*5113495bSYour Name 	    nla_put_u32(skb,
4190*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
4191*5113495bSYour Name 			tx_stats->fail_mcs_len) ||
4192*5113495bSYour Name 	    nla_put_u32(skb,
4193*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
4194*5113495bSYour Name 			tx_stats->delay_len))
4195*5113495bSYour Name 		goto put_attr_fail;
4196*5113495bSYour Name 
4197*5113495bSYour Name 	if (agg_size) {
4198*5113495bSYour Name 		if (nla_put(skb,
4199*5113495bSYour Name 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
4200*5113495bSYour Name 			    tx_stats->aggr_len, agg_size))
4201*5113495bSYour Name 			goto put_attr_fail;
4202*5113495bSYour Name 	}
4203*5113495bSYour Name 
4204*5113495bSYour Name 	if (succ_mcs) {
4205*5113495bSYour Name 		if (nla_put(skb,
4206*5113495bSYour Name 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
4207*5113495bSYour Name 			    tx_stats->success_mcs_len, succ_mcs))
4208*5113495bSYour Name 			goto put_attr_fail;
4209*5113495bSYour Name 	}
4210*5113495bSYour Name 
4211*5113495bSYour Name 	if (fail_mcs) {
4212*5113495bSYour Name 		if (nla_put(skb,
4213*5113495bSYour Name 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
4214*5113495bSYour Name 			    tx_stats->fail_mcs_len, fail_mcs))
4215*5113495bSYour Name 			goto put_attr_fail;
4216*5113495bSYour Name 	}
4217*5113495bSYour Name 
4218*5113495bSYour Name 	if (delay) {
4219*5113495bSYour Name 		if (nla_put(skb,
4220*5113495bSYour Name 			    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
4221*5113495bSYour Name 			    tx_stats->delay_len, delay))
4222*5113495bSYour Name 			goto put_attr_fail;
4223*5113495bSYour Name 	}
4224*5113495bSYour Name 	return 0;
4225*5113495bSYour Name 
4226*5113495bSYour Name put_attr_fail:
4227*5113495bSYour Name 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4228*5113495bSYour Name 	return -EINVAL;
4229*5113495bSYour Name }
4230*5113495bSYour Name 
4231*5113495bSYour Name /**
4232*5113495bSYour Name  * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info
4233*5113495bSYour Name  * @rx_stats: rx info
4234*5113495bSYour Name  * @skb: vendor event buffer
4235*5113495bSYour Name  *
4236*5113495bSYour Name  * Return: 0 Success, EINVAL failure
4237*5113495bSYour Name  */
4238*5113495bSYour Name static int
hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx * rx_stats,struct sk_buff * skb)4239*5113495bSYour Name hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats,
4240*5113495bSYour Name 				 struct sk_buff *skb)
4241*5113495bSYour Name {
4242*5113495bSYour Name 	uint32_t *mcs, *aggr;
4243*5113495bSYour Name 
4244*5113495bSYour Name 	/* There might be no RX info for a peer */
4245*5113495bSYour Name 	if (!rx_stats)
4246*5113495bSYour Name 		return 0;
4247*5113495bSYour Name 
4248*5113495bSYour Name 	aggr = rx_stats->mpdu_aggr;
4249*5113495bSYour Name 	mcs = rx_stats->mcs;
4250*5113495bSYour Name 
4251*5113495bSYour Name 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
4252*5113495bSYour Name 			rx_stats->mpdus) ||
4253*5113495bSYour Name 	    nla_put_u32(skb,
4254*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
4255*5113495bSYour Name 			rx_stats->bytes) ||
4256*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
4257*5113495bSYour Name 			rx_stats->ppdus) ||
4258*5113495bSYour Name 	    nla_put_u32(skb,
4259*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
4260*5113495bSYour Name 			rx_stats->ppdu_bytes) ||
4261*5113495bSYour Name 	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
4262*5113495bSYour Name 			rx_stats->mpdu_lost) ||
4263*5113495bSYour Name 	    nla_put_u32(skb,
4264*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
4265*5113495bSYour Name 			rx_stats->mpdu_retry) ||
4266*5113495bSYour Name 	    nla_put_u32(skb,
4267*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
4268*5113495bSYour Name 			rx_stats->mpdu_dup) ||
4269*5113495bSYour Name 	    nla_put_u32(skb,
4270*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
4271*5113495bSYour Name 			rx_stats->mpdu_discard) ||
4272*5113495bSYour Name 	    nla_put_u32(skb,
4273*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
4274*5113495bSYour Name 			rx_stats->aggr_len) ||
4275*5113495bSYour Name 	    nla_put_u32(skb,
4276*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
4277*5113495bSYour Name 			rx_stats->mcs_len))
4278*5113495bSYour Name 		goto put_attr_fail;
4279*5113495bSYour Name 
4280*5113495bSYour Name 	if (aggr) {
4281*5113495bSYour Name 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
4282*5113495bSYour Name 			    rx_stats->aggr_len, aggr))
4283*5113495bSYour Name 			goto put_attr_fail;
4284*5113495bSYour Name 	}
4285*5113495bSYour Name 
4286*5113495bSYour Name 	if (mcs) {
4287*5113495bSYour Name 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
4288*5113495bSYour Name 			    rx_stats->mcs_len, mcs))
4289*5113495bSYour Name 			goto put_attr_fail;
4290*5113495bSYour Name 	}
4291*5113495bSYour Name 
4292*5113495bSYour Name 	return 0;
4293*5113495bSYour Name 
4294*5113495bSYour Name put_attr_fail:
4295*5113495bSYour Name 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4296*5113495bSYour Name 	return -EINVAL;
4297*5113495bSYour Name }
4298*5113495bSYour Name 
4299*5113495bSYour Name /**
4300*5113495bSYour Name  * hdd_populate_wifi_wmm_ac_info() - put WMM AC info
4301*5113495bSYour Name  * @ac_stats: per AC stats
4302*5113495bSYour Name  * @skb: vendor event buffer
4303*5113495bSYour Name  *
4304*5113495bSYour Name  * Return: 0 Success, EINVAL failure
4305*5113495bSYour Name  */
4306*5113495bSYour Name static int
hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats * ac_stats,struct sk_buff * skb)4307*5113495bSYour Name hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats,
4308*5113495bSYour Name 			      struct sk_buff *skb)
4309*5113495bSYour Name {
4310*5113495bSYour Name 	struct nlattr *wmm;
4311*5113495bSYour Name 
4312*5113495bSYour Name 	wmm = nla_nest_start(skb, ac_stats->type);
4313*5113495bSYour Name 	if (!wmm)
4314*5113495bSYour Name 		goto nest_start_fail;
4315*5113495bSYour Name 
4316*5113495bSYour Name 	if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) ||
4317*5113495bSYour Name 	    hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb))
4318*5113495bSYour Name 		goto put_attr_fail;
4319*5113495bSYour Name 
4320*5113495bSYour Name 	nla_nest_end(skb, wmm);
4321*5113495bSYour Name 	return 0;
4322*5113495bSYour Name 
4323*5113495bSYour Name nest_start_fail:
4324*5113495bSYour Name 	hdd_err("nla_nest_start failed");
4325*5113495bSYour Name 	return -EINVAL;
4326*5113495bSYour Name 
4327*5113495bSYour Name put_attr_fail:
4328*5113495bSYour Name 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4329*5113495bSYour Name 	return -EINVAL;
4330*5113495bSYour Name }
4331*5113495bSYour Name 
4332*5113495bSYour Name /**
4333*5113495bSYour Name  * hdd_populate_wifi_ll_ext_peer_info() - put per peer info
4334*5113495bSYour Name  * @peers: peer stats
4335*5113495bSYour Name  * @skb: vendor event buffer
4336*5113495bSYour Name  *
4337*5113495bSYour Name  * Return: 0 Success, EINVAL failure
4338*5113495bSYour Name  */
4339*5113495bSYour Name static int
hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats * peers,struct sk_buff * skb)4340*5113495bSYour Name hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers,
4341*5113495bSYour Name 				   struct sk_buff *skb)
4342*5113495bSYour Name {
4343*5113495bSYour Name 	uint32_t i;
4344*5113495bSYour Name 	struct nlattr *wmm_ac;
4345*5113495bSYour Name 
4346*5113495bSYour Name 	if (nla_put_u32(skb,
4347*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
4348*5113495bSYour Name 			peers->peer_id) ||
4349*5113495bSYour Name 	    nla_put_u32(skb,
4350*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
4351*5113495bSYour Name 			peers->vdev_id) ||
4352*5113495bSYour Name 	    nla_put_u32(skb,
4353*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
4354*5113495bSYour Name 			peers->sta_ps_inds) ||
4355*5113495bSYour Name 	    nla_put_u32(skb,
4356*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
4357*5113495bSYour Name 			peers->sta_ps_durs) ||
4358*5113495bSYour Name 	    nla_put_u32(skb,
4359*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
4360*5113495bSYour Name 			peers->rx_probe_reqs) ||
4361*5113495bSYour Name 	    nla_put_u32(skb,
4362*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
4363*5113495bSYour Name 			peers->rx_oth_mgmts) ||
4364*5113495bSYour Name 	    nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
4365*5113495bSYour Name 		    QDF_MAC_ADDR_SIZE, peers->mac_address) ||
4366*5113495bSYour Name 	    hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) {
4367*5113495bSYour Name 		hdd_err("put peer signal attr failed");
4368*5113495bSYour Name 		return -EINVAL;
4369*5113495bSYour Name 	}
4370*5113495bSYour Name 
4371*5113495bSYour Name 	wmm_ac = nla_nest_start(skb,
4372*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS);
4373*5113495bSYour Name 	if (!wmm_ac) {
4374*5113495bSYour Name 		hdd_err("nla_nest_start failed");
4375*5113495bSYour Name 		return -EINVAL;
4376*5113495bSYour Name 	}
4377*5113495bSYour Name 
4378*5113495bSYour Name 	for (i = 0; i < WLAN_MAX_AC; i++) {
4379*5113495bSYour Name 		if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) {
4380*5113495bSYour Name 			hdd_err("put WMM AC attr failed");
4381*5113495bSYour Name 			return -EINVAL;
4382*5113495bSYour Name 		}
4383*5113495bSYour Name 	}
4384*5113495bSYour Name 
4385*5113495bSYour Name 	nla_nest_end(skb, wmm_ac);
4386*5113495bSYour Name 	return 0;
4387*5113495bSYour Name }
4388*5113495bSYour Name 
4389*5113495bSYour Name /**
4390*5113495bSYour Name  * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats
4391*5113495bSYour Name  * @stats: link layer stats
4392*5113495bSYour Name  * @skb: vendor event buffer
4393*5113495bSYour Name  *
4394*5113495bSYour Name  * Return: 0 Success, EINVAL failure
4395*5113495bSYour Name  */
4396*5113495bSYour Name static int
hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats * stats,struct sk_buff * skb)4397*5113495bSYour Name hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats,
4398*5113495bSYour Name 			       struct sk_buff *skb)
4399*5113495bSYour Name {
4400*5113495bSYour Name 	uint32_t i;
4401*5113495bSYour Name 	struct nlattr *peer, *peer_info, *channels, *channel_info;
4402*5113495bSYour Name 
4403*5113495bSYour Name 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
4404*5113495bSYour Name 			stats->trigger_cond_id) ||
4405*5113495bSYour Name 	    nla_put_u32(skb,
4406*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
4407*5113495bSYour Name 			stats->cca_chgd_bitmap) ||
4408*5113495bSYour Name 	    nla_put_u32(skb,
4409*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
4410*5113495bSYour Name 			stats->sig_chgd_bitmap) ||
4411*5113495bSYour Name 	    nla_put_u32(skb,
4412*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
4413*5113495bSYour Name 			stats->tx_chgd_bitmap) ||
4414*5113495bSYour Name 	    nla_put_u32(skb,
4415*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
4416*5113495bSYour Name 			stats->rx_chgd_bitmap) ||
4417*5113495bSYour Name 	    nla_put_u32(skb,
4418*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
4419*5113495bSYour Name 			stats->channel_num) ||
4420*5113495bSYour Name 	    nla_put_u32(skb,
4421*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
4422*5113495bSYour Name 			stats->peer_num)) {
4423*5113495bSYour Name 		goto put_attr_fail;
4424*5113495bSYour Name 	}
4425*5113495bSYour Name 
4426*5113495bSYour Name 	channels = nla_nest_start(skb,
4427*5113495bSYour Name 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS);
4428*5113495bSYour Name 	if (!channels) {
4429*5113495bSYour Name 		hdd_err("nla_nest_start failed");
4430*5113495bSYour Name 		return -EINVAL;
4431*5113495bSYour Name 	}
4432*5113495bSYour Name 
4433*5113495bSYour Name 	for (i = 0; i < stats->channel_num; i++) {
4434*5113495bSYour Name 		channel_info = nla_nest_start(skb, i);
4435*5113495bSYour Name 		if (!channel_info) {
4436*5113495bSYour Name 			hdd_err("nla_nest_start failed");
4437*5113495bSYour Name 			return -EINVAL;
4438*5113495bSYour Name 		}
4439*5113495bSYour Name 
4440*5113495bSYour Name 		if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb))
4441*5113495bSYour Name 			goto put_attr_fail;
4442*5113495bSYour Name 		nla_nest_end(skb, channel_info);
4443*5113495bSYour Name 	}
4444*5113495bSYour Name 	nla_nest_end(skb, channels);
4445*5113495bSYour Name 
4446*5113495bSYour Name 	peer_info = nla_nest_start(skb,
4447*5113495bSYour Name 				   QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER);
4448*5113495bSYour Name 	if (!peer_info) {
4449*5113495bSYour Name 		hdd_err("nla_nest_start failed");
4450*5113495bSYour Name 		return -EINVAL;
4451*5113495bSYour Name 	}
4452*5113495bSYour Name 
4453*5113495bSYour Name 	for (i = 0; i < stats->peer_num; i++) {
4454*5113495bSYour Name 		peer = nla_nest_start(skb, i);
4455*5113495bSYour Name 		if (!peer) {
4456*5113495bSYour Name 			hdd_err("nla_nest_start failed");
4457*5113495bSYour Name 			return -EINVAL;
4458*5113495bSYour Name 		}
4459*5113495bSYour Name 
4460*5113495bSYour Name 		if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i],
4461*5113495bSYour Name 						       skb))
4462*5113495bSYour Name 			goto put_attr_fail;
4463*5113495bSYour Name 		nla_nest_end(skb, peer);
4464*5113495bSYour Name 	}
4465*5113495bSYour Name 
4466*5113495bSYour Name 	nla_nest_end(skb, peer_info);
4467*5113495bSYour Name 	return 0;
4468*5113495bSYour Name 
4469*5113495bSYour Name put_attr_fail:
4470*5113495bSYour Name 	hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
4471*5113495bSYour Name 	return -EINVAL;
4472*5113495bSYour Name }
4473*5113495bSYour Name 
4474*5113495bSYour Name /**
4475*5113495bSYour Name  * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
4476*5113495bSYour Name  * @ctx: HDD context
4477*5113495bSYour Name  * @rsp: msg from FW
4478*5113495bSYour Name  *
4479*5113495bSYour Name  * This function is an extension of
4480*5113495bSYour Name  * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
4481*5113495bSYour Name  * monitoring parameters offloaded to NL data and send the same to the
4482*5113495bSYour Name  * kernel/upper layers.
4483*5113495bSYour Name  *
4484*5113495bSYour Name  * Return: None
4485*5113495bSYour Name  */
wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx,tSirLLStatsResults * rsp)4486*5113495bSYour Name void wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx,
4487*5113495bSYour Name 						     tSirLLStatsResults *rsp)
4488*5113495bSYour Name {
4489*5113495bSYour Name 	struct hdd_context *hdd_ctx;
4490*5113495bSYour Name 	struct sk_buff *skb;
4491*5113495bSYour Name 	uint32_t param_id, index;
4492*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
4493*5113495bSYour Name 	struct wifi_peer_stat *peer_stats;
4494*5113495bSYour Name 	uint8_t *results;
4495*5113495bSYour Name 	int status;
4496*5113495bSYour Name 
4497*5113495bSYour Name 	hdd_enter();
4498*5113495bSYour Name 
4499*5113495bSYour Name 	if (!rsp) {
4500*5113495bSYour Name 		hdd_err("Invalid result.");
4501*5113495bSYour Name 		return;
4502*5113495bSYour Name 	}
4503*5113495bSYour Name 
4504*5113495bSYour Name 	hdd_ctx = hdd_handle_to_context(ctx);
4505*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
4506*5113495bSYour Name 	if (0 != status)
4507*5113495bSYour Name 		return;
4508*5113495bSYour Name 
4509*5113495bSYour Name 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, rsp->ifaceId);
4510*5113495bSYour Name 	if (!link_info) {
4511*5113495bSYour Name 		hdd_err("vdev_id %d does not exist with host.", rsp->ifaceId);
4512*5113495bSYour Name 		return;
4513*5113495bSYour Name 	}
4514*5113495bSYour Name 
4515*5113495bSYour Name 	index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
4516*5113495bSYour Name 	skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
4517*5113495bSYour Name 					       LL_STATS_EVENT_BUF_SIZE +
4518*5113495bSYour Name 					       NLMSG_HDRLEN,
4519*5113495bSYour Name 					       index, GFP_KERNEL);
4520*5113495bSYour Name 	if (!skb) {
4521*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_event_alloc failed.");
4522*5113495bSYour Name 		return;
4523*5113495bSYour Name 	}
4524*5113495bSYour Name 
4525*5113495bSYour Name 	results = rsp->results;
4526*5113495bSYour Name 	param_id = rsp->paramId;
4527*5113495bSYour Name 	hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %pK",
4528*5113495bSYour Name 		 rsp->paramId, rsp->ifaceId, rsp->results);
4529*5113495bSYour Name 	if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
4530*5113495bSYour Name 		peer_stats = (struct wifi_peer_stat *)results;
4531*5113495bSYour Name 		status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
4532*5113495bSYour Name 	} else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
4533*5113495bSYour Name 		struct sir_wifi_iface_tx_fail *tx_fail;
4534*5113495bSYour Name 
4535*5113495bSYour Name 		tx_fail = (struct sir_wifi_iface_tx_fail *)results;
4536*5113495bSYour Name 		status = hdd_populate_tx_failure_info(tx_fail, skb);
4537*5113495bSYour Name 	} else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
4538*5113495bSYour Name 		hdd_info("MAC counters stats");
4539*5113495bSYour Name 		status = hdd_populate_wifi_ll_ext_stats(
4540*5113495bSYour Name 				(struct sir_wifi_ll_ext_stats *)
4541*5113495bSYour Name 				rsp->results, skb);
4542*5113495bSYour Name 	} else {
4543*5113495bSYour Name 		hdd_info("Unknown link layer stats");
4544*5113495bSYour Name 		status = -EINVAL;
4545*5113495bSYour Name 	}
4546*5113495bSYour Name 
4547*5113495bSYour Name 	if (status == 0)
4548*5113495bSYour Name 		wlan_cfg80211_vendor_event(skb, GFP_KERNEL);
4549*5113495bSYour Name 	else
4550*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(skb);
4551*5113495bSYour Name 	hdd_exit();
4552*5113495bSYour Name }
4553*5113495bSYour Name 
4554*5113495bSYour Name const struct nla_policy
4555*5113495bSYour Name qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = {
4556*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = {
4557*5113495bSYour Name 		.type = NLA_U32
4558*5113495bSYour Name 	},
4559*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = {
4560*5113495bSYour Name 		.type = NLA_U32
4561*5113495bSYour Name 	},
4562*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG] = {
4563*5113495bSYour Name 		.type = NLA_U32
4564*5113495bSYour Name 	},
4565*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID] = {
4566*5113495bSYour Name 		.type = NLA_U32
4567*5113495bSYour Name 	},
4568*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU] = {
4569*5113495bSYour Name 		.type = NLA_U32
4570*5113495bSYour Name 	},
4571*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS] = {
4572*5113495bSYour Name 		.type = NLA_U32
4573*5113495bSYour Name 	},
4574*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE] = {
4575*5113495bSYour Name 		.type = NLA_U32
4576*5113495bSYour Name 	},
4577*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS] = {
4578*5113495bSYour Name 		.type = NLA_U32
4579*5113495bSYour Name 	},
4580*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = {
4581*5113495bSYour Name 		.type = NLA_U32
4582*5113495bSYour Name 	},
4583*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE] = {
4584*5113495bSYour Name 		.type = NLA_U32
4585*5113495bSYour Name 	},
4586*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID] = {
4587*5113495bSYour Name 		.type = NLA_U32
4588*5113495bSYour Name 	},
4589*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID] = {
4590*5113495bSYour Name 		.type = NLA_U32
4591*5113495bSYour Name 	},
4592*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = {
4593*5113495bSYour Name 		.type = NLA_U32
4594*5113495bSYour Name 	},
4595*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = {
4596*5113495bSYour Name 		.type = NLA_U32
4597*5113495bSYour Name 	},
4598*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = {
4599*5113495bSYour Name 		.type = NLA_U32
4600*5113495bSYour Name 	},
4601*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = {
4602*5113495bSYour Name 		.type = NLA_U32
4603*5113495bSYour Name 	},
4604*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM] = {
4605*5113495bSYour Name 		.type = NLA_U32
4606*5113495bSYour Name 	},
4607*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM] = {
4608*5113495bSYour Name 		.type = NLA_U32
4609*5113495bSYour Name 	},
4610*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS] = {
4611*5113495bSYour Name 		.type = NLA_U32
4612*5113495bSYour Name 	},
4613*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER] = {
4614*5113495bSYour Name 		.type = NLA_U32
4615*5113495bSYour Name 	},
4616*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = {
4617*5113495bSYour Name 		.type = NLA_U32
4618*5113495bSYour Name 	},
4619*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = {
4620*5113495bSYour Name 		.type = NLA_U32
4621*5113495bSYour Name 	},
4622*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = {
4623*5113495bSYour Name 		.type = NLA_U32
4624*5113495bSYour Name 	},
4625*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = {
4626*5113495bSYour Name 		.type = NLA_U32
4627*5113495bSYour Name 	},
4628*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = {
4629*5113495bSYour Name 		.type = NLA_U32
4630*5113495bSYour Name 	},
4631*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = {
4632*5113495bSYour Name 		.type = NLA_U32
4633*5113495bSYour Name 	},
4634*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = {
4635*5113495bSYour Name 		.type = NLA_U32
4636*5113495bSYour Name 	},
4637*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = {
4638*5113495bSYour Name 		.type = NLA_U32
4639*5113495bSYour Name 	},
4640*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = {
4641*5113495bSYour Name 		.type = NLA_U32
4642*5113495bSYour Name 	},
4643*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM] = {
4644*5113495bSYour Name 		.type = NLA_U32
4645*5113495bSYour Name 	},
4646*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM] = {
4647*5113495bSYour Name 		.type = NLA_U32
4648*5113495bSYour Name 	},
4649*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM] = {
4650*5113495bSYour Name 		.type = NLA_U32
4651*5113495bSYour Name 	},
4652*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = {
4653*5113495bSYour Name 		.type = NLA_U32
4654*5113495bSYour Name 	},
4655*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = {
4656*5113495bSYour Name 		.type = NLA_U32
4657*5113495bSYour Name 	},
4658*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = {
4659*5113495bSYour Name 		.type = NLA_U32
4660*5113495bSYour Name 	},
4661*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE] = {
4662*5113495bSYour Name 		.type = NLA_U32
4663*5113495bSYour Name 	},
4664*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = {
4665*5113495bSYour Name 		.type = NLA_U32
4666*5113495bSYour Name 	},
4667*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = {
4668*5113495bSYour Name 		.type = NLA_U32
4669*5113495bSYour Name 	},
4670*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = {
4671*5113495bSYour Name 		.type = NLA_U32
4672*5113495bSYour Name 	},
4673*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = {
4674*5113495bSYour Name 		.type = NLA_U32
4675*5113495bSYour Name 	},
4676*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = {
4677*5113495bSYour Name 		.type = NLA_U32
4678*5113495bSYour Name 	},
4679*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = {
4680*5113495bSYour Name 		.type = NLA_U32
4681*5113495bSYour Name 	},
4682*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = {
4683*5113495bSYour Name 		.type = NLA_U32
4684*5113495bSYour Name 	},
4685*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = {
4686*5113495bSYour Name 		.type = NLA_U32
4687*5113495bSYour Name 	},
4688*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = {
4689*5113495bSYour Name 		.type = NLA_U32
4690*5113495bSYour Name 	},
4691*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM] = {
4692*5113495bSYour Name 		.type = NLA_U32
4693*5113495bSYour Name 	},
4694*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM] = {
4695*5113495bSYour Name 		.type = NLA_U32
4696*5113495bSYour Name 	},
4697*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = {
4698*5113495bSYour Name 		.type = NLA_U32
4699*5113495bSYour Name 	},
4700*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = {
4701*5113495bSYour Name 		.type = NLA_U32
4702*5113495bSYour Name 	},
4703*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = {
4704*5113495bSYour Name 		.type = NLA_U32
4705*5113495bSYour Name 	},
4706*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = {
4707*5113495bSYour Name 		.type = NLA_U32
4708*5113495bSYour Name 	},
4709*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = {
4710*5113495bSYour Name 		.type = NLA_U32
4711*5113495bSYour Name 	},
4712*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = {
4713*5113495bSYour Name 		.type = NLA_U32
4714*5113495bSYour Name 	},
4715*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = {
4716*5113495bSYour Name 		.type = NLA_U32
4717*5113495bSYour Name 	},
4718*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = {
4719*5113495bSYour Name 		.type = NLA_U32
4720*5113495bSYour Name 	},
4721*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME] = {
4722*5113495bSYour Name 		.type = NLA_U32
4723*5113495bSYour Name 	},
4724*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = {
4725*5113495bSYour Name 		.type = NLA_U32
4726*5113495bSYour Name 	},
4727*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = {
4728*5113495bSYour Name 		.type = NLA_U32
4729*5113495bSYour Name 	},
4730*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = {
4731*5113495bSYour Name 		.type = NLA_U32
4732*5113495bSYour Name 	},
4733*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = {
4734*5113495bSYour Name 		.type = NLA_U32
4735*5113495bSYour Name 	},
4736*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = {
4737*5113495bSYour Name 		.type = NLA_U32
4738*5113495bSYour Name 	},
4739*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = {
4740*5113495bSYour Name 		.type = NLA_U32
4741*5113495bSYour Name 	},
4742*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM] = {
4743*5113495bSYour Name 		.type = NLA_U32
4744*5113495bSYour Name 	},
4745*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL] = {
4746*5113495bSYour Name 		.type = NLA_U32
4747*5113495bSYour Name 	},
4748*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = {
4749*5113495bSYour Name 		.type = NLA_U32
4750*5113495bSYour Name 	},
4751*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = {
4752*5113495bSYour Name 		.type = NLA_U32
4753*5113495bSYour Name 	},
4754*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON] = {
4755*5113495bSYour Name 		.type = NLA_U32
4756*5113495bSYour Name 	},
4757*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON] = {
4758*5113495bSYour Name 		.type = NLA_U32
4759*5113495bSYour Name 	},
4760*5113495bSYour Name };
4761*5113495bSYour Name 
4762*5113495bSYour Name /**
4763*5113495bSYour Name  * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
4764*5113495bSYour Name  * @wiphy: wiphy handle
4765*5113495bSYour Name  * @wdev: wdev handle
4766*5113495bSYour Name  * @data: user layer input
4767*5113495bSYour Name  * @data_len: length of user layer input
4768*5113495bSYour Name  *
4769*5113495bSYour Name  * this function is called in ssr protected environment.
4770*5113495bSYour Name  *
4771*5113495bSYour Name  * return: 0 success, none zero for failure
4772*5113495bSYour Name  */
__wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)4773*5113495bSYour Name static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
4774*5113495bSYour Name 						      struct wireless_dev *wdev,
4775*5113495bSYour Name 						      const void *data,
4776*5113495bSYour Name 						      int data_len)
4777*5113495bSYour Name {
4778*5113495bSYour Name 	QDF_STATUS status;
4779*5113495bSYour Name 	int errno;
4780*5113495bSYour Name 	uint32_t period;
4781*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
4782*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4783*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
4784*5113495bSYour Name 	struct sir_ll_ext_stats_threshold thresh = {0,};
4785*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1];
4786*5113495bSYour Name 
4787*5113495bSYour Name 	hdd_enter_dev(dev);
4788*5113495bSYour Name 
4789*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
4790*5113495bSYour Name 		hdd_warn("command not allowed in ftm mode");
4791*5113495bSYour Name 		return -EPERM;
4792*5113495bSYour Name 	}
4793*5113495bSYour Name 
4794*5113495bSYour Name 	errno = wlan_hdd_validate_context(hdd_ctx);
4795*5113495bSYour Name 	if (errno)
4796*5113495bSYour Name 		return -EPERM;
4797*5113495bSYour Name 
4798*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX,
4799*5113495bSYour Name 				    (struct nlattr *)data, data_len,
4800*5113495bSYour Name 				    qca_wlan_vendor_ll_ext_policy)) {
4801*5113495bSYour Name 		hdd_err("maximum attribute not present");
4802*5113495bSYour Name 		return -EPERM;
4803*5113495bSYour Name 	}
4804*5113495bSYour Name 
4805*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) {
4806*5113495bSYour Name 		period = nla_get_u32(tb[
4807*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]);
4808*5113495bSYour Name 
4809*5113495bSYour Name 		if (period != 0 && period < LL_STATS_MIN_PERIOD)
4810*5113495bSYour Name 			period = LL_STATS_MIN_PERIOD;
4811*5113495bSYour Name 
4812*5113495bSYour Name 		/*
4813*5113495bSYour Name 		 * Only enable/disable counters.
4814*5113495bSYour Name 		 * Keep the last threshold settings.
4815*5113495bSYour Name 		 */
4816*5113495bSYour Name 		goto set_period;
4817*5113495bSYour Name 	}
4818*5113495bSYour Name 
4819*5113495bSYour Name 	/* global thresh is not enabled */
4820*5113495bSYour Name 	if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) {
4821*5113495bSYour Name 		thresh.global = false;
4822*5113495bSYour Name 		hdd_warn("global thresh is not set");
4823*5113495bSYour Name 	} else {
4824*5113495bSYour Name 		thresh.global_threshold = nla_get_u32(tb[
4825*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]);
4826*5113495bSYour Name 		thresh.global = true;
4827*5113495bSYour Name 		hdd_debug("globle thresh is %d", thresh.global_threshold);
4828*5113495bSYour Name 	}
4829*5113495bSYour Name 
4830*5113495bSYour Name 	if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) {
4831*5113495bSYour Name 		thresh.global = false;
4832*5113495bSYour Name 		hdd_warn("global thresh is not enabled");
4833*5113495bSYour Name 	} else {
4834*5113495bSYour Name 		thresh.global = nla_get_u32(tb[
4835*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]);
4836*5113495bSYour Name 		hdd_debug("global is %d", thresh.global);
4837*5113495bSYour Name 	}
4838*5113495bSYour Name 
4839*5113495bSYour Name 	thresh.enable_bitmap = false;
4840*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) {
4841*5113495bSYour Name 		thresh.tx_bitmap = nla_get_u32(tb[
4842*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]);
4843*5113495bSYour Name 		thresh.enable_bitmap = true;
4844*5113495bSYour Name 	}
4845*5113495bSYour Name 
4846*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) {
4847*5113495bSYour Name 		thresh.rx_bitmap = nla_get_u32(tb[
4848*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]);
4849*5113495bSYour Name 		thresh.enable_bitmap = true;
4850*5113495bSYour Name 	}
4851*5113495bSYour Name 
4852*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) {
4853*5113495bSYour Name 		thresh.cca_bitmap = nla_get_u32(tb[
4854*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]);
4855*5113495bSYour Name 		thresh.enable_bitmap = true;
4856*5113495bSYour Name 	}
4857*5113495bSYour Name 
4858*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) {
4859*5113495bSYour Name 		thresh.signal_bitmap = nla_get_u32(tb[
4860*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]);
4861*5113495bSYour Name 		thresh.enable_bitmap = true;
4862*5113495bSYour Name 	}
4863*5113495bSYour Name 
4864*5113495bSYour Name 	if (!thresh.global && !thresh.enable_bitmap) {
4865*5113495bSYour Name 		hdd_warn("threshold will be disabled.");
4866*5113495bSYour Name 		thresh.enable = false;
4867*5113495bSYour Name 
4868*5113495bSYour Name 		/* Just disable threshold */
4869*5113495bSYour Name 		goto set_thresh;
4870*5113495bSYour Name 	} else {
4871*5113495bSYour Name 		thresh.enable = true;
4872*5113495bSYour Name 	}
4873*5113495bSYour Name 
4874*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) {
4875*5113495bSYour Name 		thresh.tx.msdu = nla_get_u32(tb[
4876*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]);
4877*5113495bSYour Name 	}
4878*5113495bSYour Name 
4879*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) {
4880*5113495bSYour Name 		thresh.tx.mpdu = nla_get_u32(tb[
4881*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]);
4882*5113495bSYour Name 	}
4883*5113495bSYour Name 
4884*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) {
4885*5113495bSYour Name 		thresh.tx.ppdu = nla_get_u32(tb[
4886*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]);
4887*5113495bSYour Name 	}
4888*5113495bSYour Name 
4889*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) {
4890*5113495bSYour Name 		thresh.tx.bytes = nla_get_u32(tb[
4891*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]);
4892*5113495bSYour Name 	}
4893*5113495bSYour Name 
4894*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) {
4895*5113495bSYour Name 		thresh.tx.msdu_drop = nla_get_u32(
4896*5113495bSYour Name 			tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]);
4897*5113495bSYour Name 	}
4898*5113495bSYour Name 
4899*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) {
4900*5113495bSYour Name 		thresh.tx.byte_drop = nla_get_u32(tb[
4901*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]);
4902*5113495bSYour Name 	}
4903*5113495bSYour Name 
4904*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) {
4905*5113495bSYour Name 		thresh.tx.mpdu_retry = nla_get_u32(tb[
4906*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]);
4907*5113495bSYour Name 	}
4908*5113495bSYour Name 
4909*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) {
4910*5113495bSYour Name 		thresh.tx.mpdu_fail = nla_get_u32(tb[
4911*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]);
4912*5113495bSYour Name 	}
4913*5113495bSYour Name 
4914*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) {
4915*5113495bSYour Name 		thresh.tx.ppdu_fail = nla_get_u32(tb[
4916*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]);
4917*5113495bSYour Name 	}
4918*5113495bSYour Name 
4919*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) {
4920*5113495bSYour Name 		thresh.tx.aggregation = nla_get_u32(tb[
4921*5113495bSYour Name 				  QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]);
4922*5113495bSYour Name 	}
4923*5113495bSYour Name 
4924*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) {
4925*5113495bSYour Name 		thresh.tx.succ_mcs = nla_get_u32(tb[
4926*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]);
4927*5113495bSYour Name 	}
4928*5113495bSYour Name 
4929*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) {
4930*5113495bSYour Name 		thresh.tx.fail_mcs = nla_get_u32(tb[
4931*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]);
4932*5113495bSYour Name 	}
4933*5113495bSYour Name 
4934*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) {
4935*5113495bSYour Name 		thresh.tx.delay = nla_get_u32(tb[
4936*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]);
4937*5113495bSYour Name 	}
4938*5113495bSYour Name 
4939*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) {
4940*5113495bSYour Name 		thresh.rx.mpdu = nla_get_u32(tb[
4941*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]);
4942*5113495bSYour Name 	}
4943*5113495bSYour Name 
4944*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) {
4945*5113495bSYour Name 		thresh.rx.bytes = nla_get_u32(tb[
4946*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]);
4947*5113495bSYour Name 	}
4948*5113495bSYour Name 
4949*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) {
4950*5113495bSYour Name 		thresh.rx.ppdu = nla_get_u32(tb[
4951*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]);
4952*5113495bSYour Name 	}
4953*5113495bSYour Name 
4954*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) {
4955*5113495bSYour Name 		thresh.rx.ppdu_bytes = nla_get_u32(tb[
4956*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]);
4957*5113495bSYour Name 	}
4958*5113495bSYour Name 
4959*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) {
4960*5113495bSYour Name 		thresh.rx.mpdu_lost = nla_get_u32(tb[
4961*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]);
4962*5113495bSYour Name 	}
4963*5113495bSYour Name 
4964*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) {
4965*5113495bSYour Name 		thresh.rx.mpdu_retry = nla_get_u32(tb[
4966*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]);
4967*5113495bSYour Name 	}
4968*5113495bSYour Name 
4969*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) {
4970*5113495bSYour Name 		thresh.rx.mpdu_dup = nla_get_u32(tb[
4971*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]);
4972*5113495bSYour Name 	}
4973*5113495bSYour Name 
4974*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) {
4975*5113495bSYour Name 		thresh.rx.mpdu_discard = nla_get_u32(tb[
4976*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]);
4977*5113495bSYour Name 	}
4978*5113495bSYour Name 
4979*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) {
4980*5113495bSYour Name 		thresh.rx.aggregation = nla_get_u32(tb[
4981*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]);
4982*5113495bSYour Name 	}
4983*5113495bSYour Name 
4984*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) {
4985*5113495bSYour Name 		thresh.rx.mcs = nla_get_u32(tb[
4986*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]);
4987*5113495bSYour Name 	}
4988*5113495bSYour Name 
4989*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) {
4990*5113495bSYour Name 		thresh.rx.ps_inds = nla_get_u32(tb[
4991*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]);
4992*5113495bSYour Name 	}
4993*5113495bSYour Name 
4994*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) {
4995*5113495bSYour Name 		thresh.rx.ps_durs = nla_get_u32(tb[
4996*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]);
4997*5113495bSYour Name 	}
4998*5113495bSYour Name 
4999*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) {
5000*5113495bSYour Name 		thresh.rx.probe_reqs = nla_get_u32(tb[
5001*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]);
5002*5113495bSYour Name 	}
5003*5113495bSYour Name 
5004*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) {
5005*5113495bSYour Name 		thresh.rx.other_mgmt = nla_get_u32(tb[
5006*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]);
5007*5113495bSYour Name 	}
5008*5113495bSYour Name 
5009*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) {
5010*5113495bSYour Name 		thresh.cca.idle_time = nla_get_u32(tb[
5011*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]);
5012*5113495bSYour Name 	}
5013*5113495bSYour Name 
5014*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) {
5015*5113495bSYour Name 		thresh.cca.tx_time = nla_get_u32(tb[
5016*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]);
5017*5113495bSYour Name 	}
5018*5113495bSYour Name 
5019*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) {
5020*5113495bSYour Name 		thresh.cca.rx_in_bss_time = nla_get_u32(tb[
5021*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]);
5022*5113495bSYour Name 	}
5023*5113495bSYour Name 
5024*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) {
5025*5113495bSYour Name 		thresh.cca.rx_out_bss_time = nla_get_u32(tb[
5026*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]);
5027*5113495bSYour Name 	}
5028*5113495bSYour Name 
5029*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) {
5030*5113495bSYour Name 		thresh.cca.rx_busy_time = nla_get_u32(tb[
5031*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]);
5032*5113495bSYour Name 	}
5033*5113495bSYour Name 
5034*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) {
5035*5113495bSYour Name 		thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[
5036*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]);
5037*5113495bSYour Name 	}
5038*5113495bSYour Name 
5039*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) {
5040*5113495bSYour Name 		thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[
5041*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]);
5042*5113495bSYour Name 	}
5043*5113495bSYour Name 
5044*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) {
5045*5113495bSYour Name 		thresh.cca.wlan_not_avail_time = nla_get_u32(tb[
5046*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]);
5047*5113495bSYour Name 	}
5048*5113495bSYour Name 
5049*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) {
5050*5113495bSYour Name 		thresh.signal.snr = nla_get_u32(tb[
5051*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]);
5052*5113495bSYour Name 	}
5053*5113495bSYour Name 
5054*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) {
5055*5113495bSYour Name 		thresh.signal.nf = nla_get_u32(tb[
5056*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]);
5057*5113495bSYour Name 	}
5058*5113495bSYour Name 
5059*5113495bSYour Name set_thresh:
5060*5113495bSYour Name 	hdd_info("send thresh settings to target");
5061*5113495bSYour Name 	status = sme_ll_stats_set_thresh(hdd_ctx->mac_handle, &thresh);
5062*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
5063*5113495bSYour Name 		hdd_err("sme_ll_stats_set_thresh failed.");
5064*5113495bSYour Name 		return -EINVAL;
5065*5113495bSYour Name 	}
5066*5113495bSYour Name 	return 0;
5067*5113495bSYour Name 
5068*5113495bSYour Name set_period:
5069*5113495bSYour Name 	hdd_info("send period to target");
5070*5113495bSYour Name 	errno = wma_cli_set_command(adapter->deflink->vdev_id,
5071*5113495bSYour Name 				    wmi_pdev_param_stats_observation_period,
5072*5113495bSYour Name 				    period, PDEV_CMD);
5073*5113495bSYour Name 	if (errno) {
5074*5113495bSYour Name 		hdd_err("wma_cli_set_command set_period failed.");
5075*5113495bSYour Name 		return -EINVAL;
5076*5113495bSYour Name 	}
5077*5113495bSYour Name 	return 0;
5078*5113495bSYour Name }
5079*5113495bSYour Name 
5080*5113495bSYour Name /**
5081*5113495bSYour Name  * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters
5082*5113495bSYour Name  * @wiphy: wiphy handle
5083*5113495bSYour Name  * @wdev: wdev handle
5084*5113495bSYour Name  * @data: user layer input
5085*5113495bSYour Name  * @data_len: length of user layer input
5086*5113495bSYour Name  *
5087*5113495bSYour Name  * return: 0 success, einval failure
5088*5113495bSYour Name  */
wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5089*5113495bSYour Name int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
5090*5113495bSYour Name 					     struct wireless_dev *wdev,
5091*5113495bSYour Name 					     const void *data,
5092*5113495bSYour Name 					     int data_len)
5093*5113495bSYour Name {
5094*5113495bSYour Name 	int errno;
5095*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
5096*5113495bSYour Name 
5097*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5098*5113495bSYour Name 	if (errno)
5099*5113495bSYour Name 		return errno;
5100*5113495bSYour Name 
5101*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev,
5102*5113495bSYour Name 							   data, data_len);
5103*5113495bSYour Name 
5104*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
5105*5113495bSYour Name 
5106*5113495bSYour Name 	return errno;
5107*5113495bSYour Name }
5108*5113495bSYour Name 
5109*5113495bSYour Name #else
wlan_hdd_stats_request_needed(struct hdd_adapter * adapter)5110*5113495bSYour Name static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
5111*5113495bSYour Name {
5112*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
5113*5113495bSYour Name }
5114*5113495bSYour Name #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
5115*5113495bSYour Name 
5116*5113495bSYour Name /**
5117*5113495bSYour Name  * __wlan_hdd_cfg80211_connected_chan_stats_request() - stats request for
5118*5113495bSYour Name  * currently connected channel
5119*5113495bSYour Name  * @wiphy: Pointer to wiphy
5120*5113495bSYour Name  * @wdev: Pointer to wdev
5121*5113495bSYour Name  * @data: Pointer to data
5122*5113495bSYour Name  * @data_len: Data length
5123*5113495bSYour Name  *
5124*5113495bSYour Name  * Return: int
5125*5113495bSYour Name  */
5126*5113495bSYour Name static int
__wlan_hdd_cfg80211_connected_chan_stats_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5127*5113495bSYour Name __wlan_hdd_cfg80211_connected_chan_stats_request(struct wiphy *wiphy,
5128*5113495bSYour Name 						 struct wireless_dev *wdev,
5129*5113495bSYour Name 						 const void *data,
5130*5113495bSYour Name 						 int data_len)
5131*5113495bSYour Name {
5132*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
5133*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
5134*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
5135*5113495bSYour Name 	bool is_vdev_connected;
5136*5113495bSYour Name 	enum QDF_OPMODE mode;
5137*5113495bSYour Name 	QDF_STATUS status;
5138*5113495bSYour Name 
5139*5113495bSYour Name 	is_vdev_connected = hdd_cm_is_vdev_connected(adapter->deflink);
5140*5113495bSYour Name 	mode = adapter->device_mode;
5141*5113495bSYour Name 
5142*5113495bSYour Name 	if (mode != QDF_STA_MODE || !is_vdev_connected) {
5143*5113495bSYour Name 		hdd_debug("vdev %d: reject chan stats req, mode:%d, conn:%d",
5144*5113495bSYour Name 			  adapter->deflink->vdev_id, mode, is_vdev_connected);
5145*5113495bSYour Name 		return -EPERM;
5146*5113495bSYour Name 	}
5147*5113495bSYour Name 
5148*5113495bSYour Name 	status = ucfg_mlme_connected_chan_stats_request(hdd_ctx->psoc,
5149*5113495bSYour Name 					adapter->deflink->vdev_id);
5150*5113495bSYour Name 	return qdf_status_to_os_return(status);
5151*5113495bSYour Name }
5152*5113495bSYour Name 
wlan_hdd_cfg80211_connected_chan_stats_req(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5153*5113495bSYour Name int wlan_hdd_cfg80211_connected_chan_stats_req(struct wiphy *wiphy,
5154*5113495bSYour Name 					       struct wireless_dev *wdev,
5155*5113495bSYour Name 					       const void *data,
5156*5113495bSYour Name 					       int data_len)
5157*5113495bSYour Name {
5158*5113495bSYour Name 	int errno;
5159*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
5160*5113495bSYour Name 
5161*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5162*5113495bSYour Name 	if (errno)
5163*5113495bSYour Name 		return errno;
5164*5113495bSYour Name 
5165*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_connected_chan_stats_request(wiphy, wdev,
5166*5113495bSYour Name 								 data,
5167*5113495bSYour Name 								 data_len);
5168*5113495bSYour Name 
5169*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
5170*5113495bSYour Name 
5171*5113495bSYour Name 	return errno;
5172*5113495bSYour Name }
5173*5113495bSYour Name 
5174*5113495bSYour Name #ifdef WLAN_FEATURE_STATS_EXT
5175*5113495bSYour Name /**
5176*5113495bSYour Name  * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request
5177*5113495bSYour Name  * @wiphy: Pointer to wiphy
5178*5113495bSYour Name  * @wdev: Pointer to wdev
5179*5113495bSYour Name  * @data: Pointer to data
5180*5113495bSYour Name  * @data_len: Data length
5181*5113495bSYour Name  *
5182*5113495bSYour Name  * Return: int
5183*5113495bSYour Name  */
__wlan_hdd_cfg80211_stats_ext_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5184*5113495bSYour Name static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
5185*5113495bSYour Name 						 struct wireless_dev *wdev,
5186*5113495bSYour Name 						 const void *data,
5187*5113495bSYour Name 						 int data_len)
5188*5113495bSYour Name {
5189*5113495bSYour Name 	tStatsExtRequestReq stats_ext_req;
5190*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
5191*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
5192*5113495bSYour Name 	int ret_val;
5193*5113495bSYour Name 	QDF_STATUS status;
5194*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
5195*5113495bSYour Name 	ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC);
5196*5113495bSYour Name 	struct cdp_txrx_stats_req txrx_req = {0};
5197*5113495bSYour Name 
5198*5113495bSYour Name 	hdd_enter_dev(dev);
5199*5113495bSYour Name 
5200*5113495bSYour Name 	ret_val = wlan_hdd_validate_context(hdd_ctx);
5201*5113495bSYour Name 	if (ret_val)
5202*5113495bSYour Name 		return ret_val;
5203*5113495bSYour Name 
5204*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
5205*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
5206*5113495bSYour Name 		return -EPERM;
5207*5113495bSYour Name 	}
5208*5113495bSYour Name 
5209*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
5210*5113495bSYour Name 		return -EINVAL;
5211*5113495bSYour Name 	/**
5212*5113495bSYour Name 	 * HTT_DBG_EXT_STATS_PDEV_RX
5213*5113495bSYour Name 	 */
5214*5113495bSYour Name 	txrx_req.stats = 2;
5215*5113495bSYour Name 	/* default value of secondary parameter is 0(mac_id) */
5216*5113495bSYour Name 	txrx_req.mac_id = 0;
5217*5113495bSYour Name 	status = cdp_txrx_stats_request(soc, adapter->deflink->vdev_id,
5218*5113495bSYour Name 					&txrx_req);
5219*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
5220*5113495bSYour Name 		hdd_err_rl("Failed to get hw stats: %u", status);
5221*5113495bSYour Name 		ret_val = -EINVAL;
5222*5113495bSYour Name 	}
5223*5113495bSYour Name 
5224*5113495bSYour Name 	stats_ext_req.request_data_len = data_len;
5225*5113495bSYour Name 	stats_ext_req.request_data = (void *)data;
5226*5113495bSYour Name 
5227*5113495bSYour Name 	status = cdp_request_rx_hw_stats(soc, adapter->deflink->vdev_id);
5228*5113495bSYour Name 
5229*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
5230*5113495bSYour Name 		hdd_err_rl("Failed to get hw stats: %u", status);
5231*5113495bSYour Name 		ret_val = -EINVAL;
5232*5113495bSYour Name 	}
5233*5113495bSYour Name 
5234*5113495bSYour Name 	status = sme_stats_ext_request(adapter->deflink->vdev_id,
5235*5113495bSYour Name 				       &stats_ext_req);
5236*5113495bSYour Name 
5237*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
5238*5113495bSYour Name 		hdd_err_rl("Failed to get fw stats: %u", status);
5239*5113495bSYour Name 		ret_val = -EINVAL;
5240*5113495bSYour Name 	}
5241*5113495bSYour Name 
5242*5113495bSYour Name 	return ret_val;
5243*5113495bSYour Name }
5244*5113495bSYour Name 
5245*5113495bSYour Name /**
5246*5113495bSYour Name  * wlan_hdd_cfg80211_stats_ext_request() - ext stats request
5247*5113495bSYour Name  * @wiphy: Pointer to wiphy
5248*5113495bSYour Name  * @wdev: Pointer to wdev
5249*5113495bSYour Name  * @data: Pointer to data
5250*5113495bSYour Name  * @data_len: Data length
5251*5113495bSYour Name  *
5252*5113495bSYour Name  * Return: int
5253*5113495bSYour Name  */
wlan_hdd_cfg80211_stats_ext_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5254*5113495bSYour Name int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy,
5255*5113495bSYour Name 					struct wireless_dev *wdev,
5256*5113495bSYour Name 					const void *data,
5257*5113495bSYour Name 					int data_len)
5258*5113495bSYour Name {
5259*5113495bSYour Name 	int errno;
5260*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
5261*5113495bSYour Name 
5262*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5263*5113495bSYour Name 	if (errno)
5264*5113495bSYour Name 		return errno;
5265*5113495bSYour Name 
5266*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev,
5267*5113495bSYour Name 						      data, data_len);
5268*5113495bSYour Name 
5269*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
5270*5113495bSYour Name 
5271*5113495bSYour Name 	return errno;
5272*5113495bSYour Name }
5273*5113495bSYour Name 
wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,struct stats_ext_event * data)5274*5113495bSYour Name void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,
5275*5113495bSYour Name 					  struct stats_ext_event *data)
5276*5113495bSYour Name {
5277*5113495bSYour Name 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
5278*5113495bSYour Name 	struct sk_buff *vendor_event;
5279*5113495bSYour Name 	int status;
5280*5113495bSYour Name 	int ret_val;
5281*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
5282*5113495bSYour Name 	enum qca_nl80211_vendor_subcmds_index index =
5283*5113495bSYour Name 		QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX;
5284*5113495bSYour Name 
5285*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
5286*5113495bSYour Name 	if (status)
5287*5113495bSYour Name 		return;
5288*5113495bSYour Name 
5289*5113495bSYour Name 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, data->vdev_id);
5290*5113495bSYour Name 	if (!link_info) {
5291*5113495bSYour Name 		hdd_err("vdev_id %d does not exist with host", data->vdev_id);
5292*5113495bSYour Name 		return;
5293*5113495bSYour Name 	}
5294*5113495bSYour Name 
5295*5113495bSYour Name 	vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
5296*5113495bSYour Name 							data->event_data_len +
5297*5113495bSYour Name 							sizeof(uint32_t) +
5298*5113495bSYour Name 							NLMSG_HDRLEN +
5299*5113495bSYour Name 							NLMSG_HDRLEN,
5300*5113495bSYour Name 							index, GFP_KERNEL);
5301*5113495bSYour Name 	if (!vendor_event) {
5302*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_event_alloc failed");
5303*5113495bSYour Name 		return;
5304*5113495bSYour Name 	}
5305*5113495bSYour Name 
5306*5113495bSYour Name 	ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX,
5307*5113495bSYour Name 			      link_info->adapter->dev->ifindex);
5308*5113495bSYour Name 	if (ret_val) {
5309*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail");
5310*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(vendor_event);
5311*5113495bSYour Name 
5312*5113495bSYour Name 		return;
5313*5113495bSYour Name 	}
5314*5113495bSYour Name 
5315*5113495bSYour Name 	ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT,
5316*5113495bSYour Name 			  data->event_data_len, data->event_data);
5317*5113495bSYour Name 
5318*5113495bSYour Name 	if (ret_val) {
5319*5113495bSYour Name 		hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail");
5320*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(vendor_event);
5321*5113495bSYour Name 
5322*5113495bSYour Name 		return;
5323*5113495bSYour Name 	}
5324*5113495bSYour Name 
5325*5113495bSYour Name 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
5326*5113495bSYour Name 
5327*5113495bSYour Name }
5328*5113495bSYour Name 
5329*5113495bSYour Name void
wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,struct sir_sme_rx_aggr_hole_ind * pmsg)5330*5113495bSYour Name wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,
5331*5113495bSYour Name 				      struct sir_sme_rx_aggr_hole_ind *pmsg)
5332*5113495bSYour Name {
5333*5113495bSYour Name 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
5334*5113495bSYour Name 	int status;
5335*5113495bSYour Name 	uint32_t data_size, hole_info_size;
5336*5113495bSYour Name 	struct sk_buff *vendor_event;
5337*5113495bSYour Name 	enum qca_nl80211_vendor_subcmds_index index =
5338*5113495bSYour Name 		QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX;
5339*5113495bSYour Name 
5340*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
5341*5113495bSYour Name 	if (0 != status)
5342*5113495bSYour Name 		return;
5343*5113495bSYour Name 
5344*5113495bSYour Name 	if (!pmsg) {
5345*5113495bSYour Name 		hdd_err("msg received here is null");
5346*5113495bSYour Name 		return;
5347*5113495bSYour Name 	}
5348*5113495bSYour Name 
5349*5113495bSYour Name 	hole_info_size = (pmsg->hole_cnt)*sizeof(pmsg->hole_info_array[0]);
5350*5113495bSYour Name 	data_size = sizeof(struct sir_sme_rx_aggr_hole_ind) + hole_info_size;
5351*5113495bSYour Name 
5352*5113495bSYour Name 	vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
5353*5113495bSYour Name 							data_size +
5354*5113495bSYour Name 							NLMSG_HDRLEN +
5355*5113495bSYour Name 							NLMSG_HDRLEN,
5356*5113495bSYour Name 							index, GFP_KERNEL);
5357*5113495bSYour Name 	if (!vendor_event) {
5358*5113495bSYour Name 		hdd_err("vendor_event_alloc failed for STATS_EXT2");
5359*5113495bSYour Name 		return;
5360*5113495bSYour Name 	}
5361*5113495bSYour Name 
5362*5113495bSYour Name 	if (nla_put_u32(vendor_event,
5363*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM,
5364*5113495bSYour Name 			pmsg->hole_cnt)) {
5365*5113495bSYour Name 		hdd_err("%s put fail",
5366*5113495bSYour Name 			"QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM");
5367*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(vendor_event);
5368*5113495bSYour Name 		return;
5369*5113495bSYour Name 	}
5370*5113495bSYour Name 	if (nla_put(vendor_event,
5371*5113495bSYour Name 		    QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO,
5372*5113495bSYour Name 		    hole_info_size,
5373*5113495bSYour Name 		    (void *)(pmsg->hole_info_array))) {
5374*5113495bSYour Name 		hdd_err("%s put fail",
5375*5113495bSYour Name 			"QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO");
5376*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(vendor_event);
5377*5113495bSYour Name 		return;
5378*5113495bSYour Name 	}
5379*5113495bSYour Name 
5380*5113495bSYour Name 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
5381*5113495bSYour Name }
5382*5113495bSYour Name 
5383*5113495bSYour Name #else
wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,struct stats_ext_event * data)5384*5113495bSYour Name void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle,
5385*5113495bSYour Name 					  struct stats_ext_event *data)
5386*5113495bSYour Name {
5387*5113495bSYour Name }
5388*5113495bSYour Name 
5389*5113495bSYour Name void
wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,struct sir_sme_rx_aggr_hole_ind * pmsg)5390*5113495bSYour Name wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle,
5391*5113495bSYour Name 				      struct sir_sme_rx_aggr_hole_ind *pmsg)
5392*5113495bSYour Name {
5393*5113495bSYour Name }
5394*5113495bSYour Name #endif /* End of WLAN_FEATURE_STATS_EXT */
5395*5113495bSYour Name 
5396*5113495bSYour Name #ifdef WLAN_FEATURE_ROAM_OFFLOAD
5397*5113495bSYour Name /**
5398*5113495bSYour Name  * enum roam_event_rt_info_reset - Reset the notif param value of struct
5399*5113495bSYour Name  * roam_event_rt_info to 0
5400*5113495bSYour Name  * @ROAM_EVENT_RT_INFO_RESET: Reset the value to 0
5401*5113495bSYour Name  */
5402*5113495bSYour Name enum roam_event_rt_info_reset {
5403*5113495bSYour Name 	ROAM_EVENT_RT_INFO_RESET = 0,
5404*5113495bSYour Name };
5405*5113495bSYour Name 
5406*5113495bSYour Name /**
5407*5113495bSYour Name  * struct roam_ap - Roamed/Failed AP info
5408*5113495bSYour Name  * @num_cand: number of candidate APs
5409*5113495bSYour Name  * @bssid:    BSSID of roamed/failed AP
5410*5113495bSYour Name  * @rssi:     RSSI of roamed/failed AP
5411*5113495bSYour Name  * @freq:     Frequency of roamed/failed AP
5412*5113495bSYour Name  */
5413*5113495bSYour Name struct roam_ap {
5414*5113495bSYour Name 	uint32_t num_cand;
5415*5113495bSYour Name 	struct qdf_mac_addr bssid;
5416*5113495bSYour Name 	int8_t rssi;
5417*5113495bSYour Name 	uint16_t freq;
5418*5113495bSYour Name };
5419*5113495bSYour Name 
5420*5113495bSYour Name /**
5421*5113495bSYour Name  * hdd_get_roam_rt_stats_event_len() - calculate length of skb required for
5422*5113495bSYour Name  * sending roam events stats.
5423*5113495bSYour Name  * @roam_stats: pointer to roam_stats_event structure
5424*5113495bSYour Name  * @idx:          TLV index of roam stats event
5425*5113495bSYour Name  *
5426*5113495bSYour Name  * Return: length of skb
5427*5113495bSYour Name  */
5428*5113495bSYour Name static uint32_t
hdd_get_roam_rt_stats_event_len(struct roam_stats_event * roam_stats,uint8_t idx)5429*5113495bSYour Name hdd_get_roam_rt_stats_event_len(struct roam_stats_event *roam_stats,
5430*5113495bSYour Name 				uint8_t idx)
5431*5113495bSYour Name {
5432*5113495bSYour Name 	uint32_t len = 0;
5433*5113495bSYour Name 	uint8_t i = 0, num_cand = 0;
5434*5113495bSYour Name 
5435*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON  */
5436*5113495bSYour Name 	if (roam_stats->trigger[idx].present)
5437*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
5438*5113495bSYour Name 
5439*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON */
5440*5113495bSYour Name 	if (roam_stats->roam_event_param.roam_invoke_fail_reason)
5441*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
5442*5113495bSYour Name 
5443*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE */
5444*5113495bSYour Name 	if (roam_stats->roam_event_param.roam_scan_state)
5445*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
5446*5113495bSYour Name 
5447*5113495bSYour Name 	if (roam_stats->scan[idx].present) {
5448*5113495bSYour Name 		if (roam_stats->scan[idx].num_chan &&
5449*5113495bSYour Name 		    roam_stats->scan[idx].type == ROAM_STATS_SCAN_TYPE_PARTIAL)
5450*5113495bSYour Name 			for (i = 0; i < roam_stats->scan[idx].num_chan;)
5451*5113495bSYour Name 				i++;
5452*5113495bSYour Name 
5453*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST */
5454*5113495bSYour Name 		len += (nla_total_size(sizeof(uint32_t)) * i);
5455*5113495bSYour Name 
5456*5113495bSYour Name 		if (roam_stats->result[idx].present &&
5457*5113495bSYour Name 		    roam_stats->result[idx].fail_reason) {
5458*5113495bSYour Name 			num_cand++;
5459*5113495bSYour Name 		} else if (roam_stats->trigger[idx].present) {
5460*5113495bSYour Name 			for (i = 0; i < roam_stats->scan[idx].num_ap; i++) {
5461*5113495bSYour Name 				if (roam_stats->scan[idx].ap[i].type == 2)
5462*5113495bSYour Name 					num_cand++;
5463*5113495bSYour Name 			}
5464*5113495bSYour Name 		}
5465*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO */
5466*5113495bSYour Name 		len += NLA_HDRLEN;
5467*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID */
5468*5113495bSYour Name 		len += (nla_total_size(QDF_MAC_ADDR_SIZE) * num_cand);
5469*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI */
5470*5113495bSYour Name 		len += (nla_total_size(sizeof(int32_t)) * num_cand);
5471*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ */
5472*5113495bSYour Name 		len += (nla_total_size(sizeof(uint32_t)) * num_cand);
5473*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON */
5474*5113495bSYour Name 		len += (nla_total_size(sizeof(uint32_t)) * num_cand);
5475*5113495bSYour Name 	}
5476*5113495bSYour Name 
5477*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE */
5478*5113495bSYour Name 	if (len)
5479*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
5480*5113495bSYour Name 
5481*5113495bSYour Name 	return len;
5482*5113495bSYour Name }
5483*5113495bSYour Name 
5484*5113495bSYour Name #define SUBCMD_ROAM_EVENTS_INDEX \
5485*5113495bSYour Name 	QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS_INDEX
5486*5113495bSYour Name #define ROAM_SCAN_FREQ_LIST \
5487*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST
5488*5113495bSYour Name #define ROAM_INVOKE_FAIL_REASON \
5489*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON
5490*5113495bSYour Name #define ROAM_SCAN_STATE         QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE
5491*5113495bSYour Name #define ROAM_EVENTS_CANDIDATE   QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO
5492*5113495bSYour Name #define CANDIDATE_BSSID \
5493*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID
5494*5113495bSYour Name #define CANDIDATE_RSSI \
5495*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI
5496*5113495bSYour Name #define CANDIDATE_FREQ \
5497*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ
5498*5113495bSYour Name #define ROAM_FAIL_REASON \
5499*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON
5500*5113495bSYour Name 
5501*5113495bSYour Name /**
5502*5113495bSYour Name  * roam_rt_stats_fill_scan_freq() - Fill the scan frequency list from the
5503*5113495bSYour Name  * roam stats event.
5504*5113495bSYour Name  * @vendor_event: pointer to sk_buff structure
5505*5113495bSYour Name  * @idx:          TLV index of roam stats event
5506*5113495bSYour Name  * @roam_stats:   pointer to roam_stats_event structure
5507*5113495bSYour Name  *
5508*5113495bSYour Name  * Return: none
5509*5113495bSYour Name  */
5510*5113495bSYour Name static void
roam_rt_stats_fill_scan_freq(struct sk_buff * vendor_event,uint8_t idx,struct roam_stats_event * roam_stats)5511*5113495bSYour Name roam_rt_stats_fill_scan_freq(struct sk_buff *vendor_event, uint8_t idx,
5512*5113495bSYour Name 			     struct roam_stats_event *roam_stats)
5513*5113495bSYour Name {
5514*5113495bSYour Name 	struct nlattr *nl_attr;
5515*5113495bSYour Name 	uint8_t i;
5516*5113495bSYour Name 
5517*5113495bSYour Name 	nl_attr = nla_nest_start(vendor_event, ROAM_SCAN_FREQ_LIST);
5518*5113495bSYour Name 	if (!nl_attr) {
5519*5113495bSYour Name 		hdd_err("nla nest start fail");
5520*5113495bSYour Name 		kfree_skb(vendor_event);
5521*5113495bSYour Name 		return;
5522*5113495bSYour Name 	}
5523*5113495bSYour Name 	if (roam_stats->scan[idx].num_chan &&
5524*5113495bSYour Name 	    roam_stats->scan[idx].type == ROAM_STATS_SCAN_TYPE_PARTIAL) {
5525*5113495bSYour Name 		for (i = 0; i < roam_stats->scan[idx].num_chan; i++) {
5526*5113495bSYour Name 			if (nla_put_u32(vendor_event, i,
5527*5113495bSYour Name 					roam_stats->scan[idx].chan_freq[i])) {
5528*5113495bSYour Name 				hdd_err("failed to put freq at index %d", i);
5529*5113495bSYour Name 				kfree_skb(vendor_event);
5530*5113495bSYour Name 				return;
5531*5113495bSYour Name 			}
5532*5113495bSYour Name 		}
5533*5113495bSYour Name 	}
5534*5113495bSYour Name 	nla_nest_end(vendor_event, nl_attr);
5535*5113495bSYour Name }
5536*5113495bSYour Name 
5537*5113495bSYour Name /**
5538*5113495bSYour Name  * roam_rt_stats_fill_cand_info() - Fill the roamed/failed AP info from the
5539*5113495bSYour Name  * roam stats event.
5540*5113495bSYour Name  * @vendor_event: pointer to sk_buff structure
5541*5113495bSYour Name  * @idx:          TLV index of roam stats event
5542*5113495bSYour Name  * @roam_stats:   pointer to roam_stats_event structure
5543*5113495bSYour Name  *
5544*5113495bSYour Name  * Return: none
5545*5113495bSYour Name  */
5546*5113495bSYour Name static void
roam_rt_stats_fill_cand_info(struct sk_buff * vendor_event,uint8_t idx,struct roam_stats_event * roam_stats)5547*5113495bSYour Name roam_rt_stats_fill_cand_info(struct sk_buff *vendor_event, uint8_t idx,
5548*5113495bSYour Name 			     struct roam_stats_event *roam_stats)
5549*5113495bSYour Name {
5550*5113495bSYour Name 	struct nlattr *nl_attr, *nl_array;
5551*5113495bSYour Name 	struct roam_ap cand_ap = {0};
5552*5113495bSYour Name 	uint8_t i, num_cand = 0;
5553*5113495bSYour Name 
5554*5113495bSYour Name 	if (roam_stats->result[idx].present &&
5555*5113495bSYour Name 	    roam_stats->result[idx].fail_reason &&
5556*5113495bSYour Name 	    roam_stats->result[idx].fail_reason != ROAM_FAIL_REASON_UNKNOWN) {
5557*5113495bSYour Name 		num_cand++;
5558*5113495bSYour Name 		for (i = 0; i < roam_stats->scan[idx].num_ap; i++) {
5559*5113495bSYour Name 			if (roam_stats->scan[idx].ap[i].type == 0 &&
5560*5113495bSYour Name 			    qdf_is_macaddr_equal(&roam_stats->
5561*5113495bSYour Name 						 result[idx].fail_bssid,
5562*5113495bSYour Name 						 &roam_stats->
5563*5113495bSYour Name 						 scan[idx].ap[i].bssid)) {
5564*5113495bSYour Name 				qdf_copy_macaddr(&cand_ap.bssid,
5565*5113495bSYour Name 						 &roam_stats->
5566*5113495bSYour Name 						 scan[idx].ap[i].bssid);
5567*5113495bSYour Name 				cand_ap.rssi = roam_stats->scan[idx].ap[i].rssi;
5568*5113495bSYour Name 				cand_ap.freq = roam_stats->scan[idx].ap[i].freq;
5569*5113495bSYour Name 			}
5570*5113495bSYour Name 		}
5571*5113495bSYour Name 	} else if (roam_stats->trigger[idx].present) {
5572*5113495bSYour Name 		for (i = 0; i < roam_stats->scan[idx].num_ap; i++) {
5573*5113495bSYour Name 			if (roam_stats->scan[idx].ap[i].type == 2) {
5574*5113495bSYour Name 				num_cand++;
5575*5113495bSYour Name 				qdf_copy_macaddr(&cand_ap.bssid,
5576*5113495bSYour Name 						 &roam_stats->
5577*5113495bSYour Name 						 scan[idx].ap[i].bssid);
5578*5113495bSYour Name 				cand_ap.rssi = roam_stats->scan[idx].ap[i].rssi;
5579*5113495bSYour Name 				cand_ap.freq = roam_stats->scan[idx].ap[i].freq;
5580*5113495bSYour Name 			}
5581*5113495bSYour Name 		}
5582*5113495bSYour Name 	}
5583*5113495bSYour Name 
5584*5113495bSYour Name 	nl_array = nla_nest_start(vendor_event, ROAM_EVENTS_CANDIDATE);
5585*5113495bSYour Name 	if (!nl_array) {
5586*5113495bSYour Name 		hdd_err("nl array nest start fail");
5587*5113495bSYour Name 		kfree_skb(vendor_event);
5588*5113495bSYour Name 		return;
5589*5113495bSYour Name 	}
5590*5113495bSYour Name 	for (i = 0; i < num_cand; i++) {
5591*5113495bSYour Name 		nl_attr = nla_nest_start(vendor_event, i);
5592*5113495bSYour Name 		if (!nl_attr) {
5593*5113495bSYour Name 			hdd_err("nl attr nest start fail");
5594*5113495bSYour Name 			kfree_skb(vendor_event);
5595*5113495bSYour Name 			return;
5596*5113495bSYour Name 		}
5597*5113495bSYour Name 		if (nla_put(vendor_event, CANDIDATE_BSSID,
5598*5113495bSYour Name 			    sizeof(cand_ap.bssid), cand_ap.bssid.bytes)) {
5599*5113495bSYour Name 			hdd_err("%s put fail",
5600*5113495bSYour Name 				"ROAM_EVENTS_CANDIDATE_INFO_BSSID");
5601*5113495bSYour Name 			kfree_skb(vendor_event);
5602*5113495bSYour Name 			return;
5603*5113495bSYour Name 		}
5604*5113495bSYour Name 		if (nla_put_s32(vendor_event, CANDIDATE_RSSI, cand_ap.rssi)) {
5605*5113495bSYour Name 			hdd_err("%s put fail",
5606*5113495bSYour Name 				"ROAM_EVENTS_CANDIDATE_INFO_RSSI");
5607*5113495bSYour Name 			kfree_skb(vendor_event);
5608*5113495bSYour Name 			return;
5609*5113495bSYour Name 		}
5610*5113495bSYour Name 		if (nla_put_u32(vendor_event, CANDIDATE_FREQ, cand_ap.freq)) {
5611*5113495bSYour Name 			hdd_err("%s put fail",
5612*5113495bSYour Name 				"ROAM_EVENTS_CANDIDATE_INFO_FREQ");
5613*5113495bSYour Name 			kfree_skb(vendor_event);
5614*5113495bSYour Name 			return;
5615*5113495bSYour Name 		}
5616*5113495bSYour Name 		if (roam_stats->result[idx].present &&
5617*5113495bSYour Name 		    roam_stats->result[idx].fail_reason) {
5618*5113495bSYour Name 			if (nla_put_u32(vendor_event, ROAM_FAIL_REASON,
5619*5113495bSYour Name 					roam_stats->result[idx].fail_reason)) {
5620*5113495bSYour Name 				hdd_err("%s put fail",
5621*5113495bSYour Name 					"ROAM_EVENTS_CANDIDATE_FAIL_REASON");
5622*5113495bSYour Name 				kfree_skb(vendor_event);
5623*5113495bSYour Name 				return;
5624*5113495bSYour Name 			}
5625*5113495bSYour Name 		}
5626*5113495bSYour Name 		nla_nest_end(vendor_event, nl_attr);
5627*5113495bSYour Name 	}
5628*5113495bSYour Name 	nla_nest_end(vendor_event, nl_array);
5629*5113495bSYour Name }
5630*5113495bSYour Name 
5631*5113495bSYour Name static void
wlan_hdd_cfg80211_typical_roam_events_callback(struct wlan_hdd_link_info * link_info,struct roam_stats_event * roam_stats,uint8_t idx)5632*5113495bSYour Name wlan_hdd_cfg80211_typical_roam_events_callback(struct wlan_hdd_link_info *link_info,
5633*5113495bSYour Name 					       struct roam_stats_event *roam_stats,
5634*5113495bSYour Name 					       uint8_t idx)
5635*5113495bSYour Name {
5636*5113495bSYour Name 	uint32_t data_size, roam_event_type = 0;
5637*5113495bSYour Name 	struct sk_buff *vendor_event;
5638*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
5639*5113495bSYour Name 
5640*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx)) {
5641*5113495bSYour Name 		hdd_err("Invalid hdd_ctx");
5642*5113495bSYour Name 		return;
5643*5113495bSYour Name 	}
5644*5113495bSYour Name 
5645*5113495bSYour Name 	data_size = hdd_get_roam_rt_stats_event_len(roam_stats, idx);
5646*5113495bSYour Name 	if (!data_size) {
5647*5113495bSYour Name 		hdd_err("No data requested");
5648*5113495bSYour Name 		return;
5649*5113495bSYour Name 	}
5650*5113495bSYour Name 
5651*5113495bSYour Name 	data_size += NLMSG_HDRLEN;
5652*5113495bSYour Name 	vendor_event =
5653*5113495bSYour Name 		wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
5654*5113495bSYour Name 						 &link_info->adapter->wdev,
5655*5113495bSYour Name 						 data_size,
5656*5113495bSYour Name 						 SUBCMD_ROAM_EVENTS_INDEX,
5657*5113495bSYour Name 						 GFP_KERNEL);
5658*5113495bSYour Name 
5659*5113495bSYour Name 	if (!vendor_event) {
5660*5113495bSYour Name 		hdd_err("vendor_event_alloc failed for ROAM_EVENTS_STATS");
5661*5113495bSYour Name 		return;
5662*5113495bSYour Name 	}
5663*5113495bSYour Name 
5664*5113495bSYour Name 	if (roam_stats->scan[idx].present && roam_stats->trigger[idx].present) {
5665*5113495bSYour Name 		roam_rt_stats_fill_scan_freq(vendor_event, idx, roam_stats);
5666*5113495bSYour Name 		roam_rt_stats_fill_cand_info(vendor_event, idx, roam_stats);
5667*5113495bSYour Name 	}
5668*5113495bSYour Name 
5669*5113495bSYour Name 	if (roam_stats->roam_event_param.roam_scan_state) {
5670*5113495bSYour Name 		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_ROAM_SCAN_STATE;
5671*5113495bSYour Name 		if (nla_put_u8(vendor_event, ROAM_SCAN_STATE,
5672*5113495bSYour Name 			       roam_stats->roam_event_param.roam_scan_state)) {
5673*5113495bSYour Name 			hdd_err("%s put fail",
5674*5113495bSYour Name 				"VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE");
5675*5113495bSYour Name 			wlan_cfg80211_vendor_free_skb(vendor_event);
5676*5113495bSYour Name 			return;
5677*5113495bSYour Name 		}
5678*5113495bSYour Name 		roam_stats->roam_event_param.roam_scan_state =
5679*5113495bSYour Name 						ROAM_EVENT_RT_INFO_RESET;
5680*5113495bSYour Name 	}
5681*5113495bSYour Name 	if (roam_stats->trigger[idx].present) {
5682*5113495bSYour Name 		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_TRIGGER_REASON;
5683*5113495bSYour Name 		if (nla_put_u32(vendor_event,
5684*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON,
5685*5113495bSYour Name 				roam_stats->trigger[idx].trigger_reason)) {
5686*5113495bSYour Name 			hdd_err("%s put fail",
5687*5113495bSYour Name 				"VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON");
5688*5113495bSYour Name 			wlan_cfg80211_vendor_free_skb(vendor_event);
5689*5113495bSYour Name 			return;
5690*5113495bSYour Name 		}
5691*5113495bSYour Name 	}
5692*5113495bSYour Name 	if (roam_stats->roam_event_param.roam_invoke_fail_reason) {
5693*5113495bSYour Name 		roam_event_type |=
5694*5113495bSYour Name 			QCA_WLAN_VENDOR_ROAM_EVENT_INVOKE_FAIL_REASON;
5695*5113495bSYour Name 		if (nla_put_u32(vendor_event, ROAM_INVOKE_FAIL_REASON,
5696*5113495bSYour Name 				roam_stats->
5697*5113495bSYour Name 				roam_event_param.roam_invoke_fail_reason)) {
5698*5113495bSYour Name 			hdd_err("%s put fail",
5699*5113495bSYour Name 				"VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON");
5700*5113495bSYour Name 			wlan_cfg80211_vendor_free_skb(vendor_event);
5701*5113495bSYour Name 			return;
5702*5113495bSYour Name 		}
5703*5113495bSYour Name 		roam_stats->roam_event_param.roam_invoke_fail_reason =
5704*5113495bSYour Name 						ROAM_EVENT_RT_INFO_RESET;
5705*5113495bSYour Name 	}
5706*5113495bSYour Name 	if (roam_stats->result[idx].present &&
5707*5113495bSYour Name 	    roam_stats->result[idx].fail_reason)
5708*5113495bSYour Name 		roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_FAIL_REASON;
5709*5113495bSYour Name 
5710*5113495bSYour Name 	if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE,
5711*5113495bSYour Name 			roam_event_type)) {
5712*5113495bSYour Name 		hdd_err("%s put fail", "QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE");
5713*5113495bSYour Name 			wlan_cfg80211_vendor_free_skb(vendor_event);
5714*5113495bSYour Name 		return;
5715*5113495bSYour Name 	}
5716*5113495bSYour Name 
5717*5113495bSYour Name 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
5718*5113495bSYour Name }
5719*5113495bSYour Name 
5720*5113495bSYour Name #undef SUBCMD_ROAM_EVENTS_INDEX
5721*5113495bSYour Name #undef ROAM_SCAN_FREQ_LIST
5722*5113495bSYour Name #undef ROAM_INVOKE_FAIL_REASON
5723*5113495bSYour Name #undef ROAM_SCAN_STATE
5724*5113495bSYour Name #undef ROAM_EVENTS_CANDIDATE
5725*5113495bSYour Name #undef CANDIDATE_BSSID
5726*5113495bSYour Name #undef CANDIDATE_RSSI
5727*5113495bSYour Name #undef CANDIDATE_FREQ
5728*5113495bSYour Name #undef ROAM_FAIL_REASON
5729*5113495bSYour Name #endif /* End of WLAN_FEATURE_ROAM_OFFLOAD */
5730*5113495bSYour Name 
5731*5113495bSYour Name #ifdef LINKSPEED_DEBUG_ENABLED
5732*5113495bSYour Name #define linkspeed_dbg(format, args...) pr_info(format, ## args)
5733*5113495bSYour Name #else
5734*5113495bSYour Name #define linkspeed_dbg(format, args...)
5735*5113495bSYour Name #endif /* LINKSPEED_DEBUG_ENABLED */
5736*5113495bSYour Name 
5737*5113495bSYour Name static void
wlan_hdd_fill_per_link_summary_stats(tCsrSummaryStatsInfo * stats,struct station_info * info,struct wlan_hdd_link_info * link_info)5738*5113495bSYour Name wlan_hdd_fill_per_link_summary_stats(tCsrSummaryStatsInfo *stats,
5739*5113495bSYour Name 				     struct station_info *info,
5740*5113495bSYour Name 				     struct wlan_hdd_link_info *link_info)
5741*5113495bSYour Name {
5742*5113495bSYour Name 	uint8_t i;
5743*5113495bSYour Name 	uint32_t orig_cnt;
5744*5113495bSYour Name 	uint32_t orig_fail_cnt;
5745*5113495bSYour Name 	QDF_STATUS status;
5746*5113495bSYour Name 	uint8_t *peer_mac;
5747*5113495bSYour Name 	ol_txrx_soc_handle soc;
5748*5113495bSYour Name 	struct cdp_peer_stats *peer_stats;
5749*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
5750*5113495bSYour Name 
5751*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx))
5752*5113495bSYour Name 		return;
5753*5113495bSYour Name 
5754*5113495bSYour Name 	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx))
5755*5113495bSYour Name 		return;
5756*5113495bSYour Name 
5757*5113495bSYour Name 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
5758*5113495bSYour Name 	if (!peer_stats)
5759*5113495bSYour Name 		return;
5760*5113495bSYour Name 
5761*5113495bSYour Name 	soc = cds_get_context(QDF_MODULE_ID_SOC);
5762*5113495bSYour Name 	peer_mac = link_info->session.station.conn_info.bssid.bytes;
5763*5113495bSYour Name 	status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
5764*5113495bSYour Name 						 peer_mac, peer_stats,
5765*5113495bSYour Name 						 CDP_WILD_PEER_TYPE,
5766*5113495bSYour Name 						 WLAN_MAX_MLD);
5767*5113495bSYour Name 
5768*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
5769*5113495bSYour Name 		hdd_err("Unable to get per link peer stats for the peer: "
5770*5113495bSYour Name 			QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(peer_mac));
5771*5113495bSYour Name 		goto exit;
5772*5113495bSYour Name 	}
5773*5113495bSYour Name 
5774*5113495bSYour Name 	info->tx_retries = 0;
5775*5113495bSYour Name 	info->tx_failed = 0;
5776*5113495bSYour Name 
5777*5113495bSYour Name 	for (i = 0; i < WIFI_MAX_AC; ++i) {
5778*5113495bSYour Name 		info->tx_retries += stats->multiple_retry_cnt[i];
5779*5113495bSYour Name 		info->tx_failed += stats->fail_cnt[i];
5780*5113495bSYour Name 	}
5781*5113495bSYour Name 
5782*5113495bSYour Name 	orig_cnt = info->tx_retries;
5783*5113495bSYour Name 	orig_fail_cnt = info->tx_failed;
5784*5113495bSYour Name 	info->tx_retries = peer_stats->tx.retries_mpdu;
5785*5113495bSYour Name 	info->tx_failed += peer_stats->tx.mpdu_success_with_retries;
5786*5113495bSYour Name 	hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx retries adjust from %d to %d",
5787*5113495bSYour Name 		  QDF_MAC_ADDR_REF(peer_mac), orig_cnt, info->tx_retries);
5788*5113495bSYour Name 	hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx failed adjust from %d to %d",
5789*5113495bSYour Name 		  QDF_MAC_ADDR_REF(peer_mac), orig_fail_cnt, info->tx_failed);
5790*5113495bSYour Name exit:
5791*5113495bSYour Name 	qdf_mem_free(peer_stats);
5792*5113495bSYour Name }
5793*5113495bSYour Name 
5794*5113495bSYour Name /**
5795*5113495bSYour Name  * wlan_hdd_fill_summary_stats() - populate station_info summary stats
5796*5113495bSYour Name  * @stats: summary stats to use as a source
5797*5113495bSYour Name  * @info: kernel station_info struct to use as a destination
5798*5113495bSYour Name  * @vdev_id: stats get from which vdev id
5799*5113495bSYour Name  *
5800*5113495bSYour Name  * Return: None
5801*5113495bSYour Name  */
wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo * stats,struct station_info * info,uint8_t vdev_id)5802*5113495bSYour Name static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats,
5803*5113495bSYour Name 					struct station_info *info,
5804*5113495bSYour Name 					uint8_t vdev_id)
5805*5113495bSYour Name {
5806*5113495bSYour Name 	int i;
5807*5113495bSYour Name 	struct cds_vdev_dp_stats dp_stats;
5808*5113495bSYour Name 	uint32_t orig_cnt;
5809*5113495bSYour Name 	uint32_t orig_fail_cnt;
5810*5113495bSYour Name 
5811*5113495bSYour Name 	info->rx_packets = stats->rx_frm_cnt;
5812*5113495bSYour Name 	info->tx_packets = 0;
5813*5113495bSYour Name 	info->tx_retries = 0;
5814*5113495bSYour Name 	info->tx_failed = 0;
5815*5113495bSYour Name 
5816*5113495bSYour Name 	for (i = 0; i < WIFI_MAX_AC; ++i) {
5817*5113495bSYour Name 		info->tx_packets += stats->tx_frm_cnt[i];
5818*5113495bSYour Name 		info->tx_retries += stats->multiple_retry_cnt[i];
5819*5113495bSYour Name 		info->tx_failed += stats->fail_cnt[i];
5820*5113495bSYour Name 	}
5821*5113495bSYour Name 
5822*5113495bSYour Name 	if (cds_dp_get_vdev_stats(vdev_id, &dp_stats)) {
5823*5113495bSYour Name 		orig_cnt = info->tx_retries;
5824*5113495bSYour Name 		orig_fail_cnt = info->tx_failed;
5825*5113495bSYour Name 		info->tx_retries = dp_stats.tx_retries_mpdu;
5826*5113495bSYour Name 		info->tx_failed += dp_stats.tx_mpdu_success_with_retries;
5827*5113495bSYour Name 		hdd_debug("vdev %d tx retries adjust from %d to %d",
5828*5113495bSYour Name 			  vdev_id, orig_cnt, info->tx_retries);
5829*5113495bSYour Name 		hdd_debug("tx failed adjust from %d to %d",
5830*5113495bSYour Name 			  orig_fail_cnt, info->tx_failed);
5831*5113495bSYour Name 	}
5832*5113495bSYour Name 
5833*5113495bSYour Name 	info->filled |= HDD_INFO_TX_PACKETS |
5834*5113495bSYour Name 			HDD_INFO_TX_RETRIES |
5835*5113495bSYour Name 			HDD_INFO_TX_FAILED;
5836*5113495bSYour Name }
5837*5113495bSYour Name 
5838*5113495bSYour Name /**
5839*5113495bSYour Name  * wlan_hdd_get_sap_stats() - get aggregate SAP stats
5840*5113495bSYour Name  * @link_info: Link info pointer in HDD adapter
5841*5113495bSYour Name  * @info: kernel station_info struct to populate
5842*5113495bSYour Name  *
5843*5113495bSYour Name  * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to
5844*5113495bSYour Name  * support "station dump" and "station get" for SAP vdevs, even though they
5845*5113495bSYour Name  * aren't technically stations.
5846*5113495bSYour Name  *
5847*5113495bSYour Name  * Return: errno
5848*5113495bSYour Name  */
wlan_hdd_get_sap_stats(struct wlan_hdd_link_info * link_info,struct station_info * info)5849*5113495bSYour Name static int wlan_hdd_get_sap_stats(struct wlan_hdd_link_info *link_info,
5850*5113495bSYour Name 				  struct station_info *info)
5851*5113495bSYour Name {
5852*5113495bSYour Name 	int ret;
5853*5113495bSYour Name 
5854*5113495bSYour Name 	ret = wlan_hdd_get_station_stats(link_info);
5855*5113495bSYour Name 	if (ret) {
5856*5113495bSYour Name 		hdd_err("Failed to get SAP stats; status:%d", ret);
5857*5113495bSYour Name 		return ret;
5858*5113495bSYour Name 	}
5859*5113495bSYour Name 
5860*5113495bSYour Name 	wlan_hdd_fill_summary_stats(&link_info->hdd_stats.summary_stat,
5861*5113495bSYour Name 				    info, link_info->vdev_id);
5862*5113495bSYour Name 
5863*5113495bSYour Name 	return 0;
5864*5113495bSYour Name }
5865*5113495bSYour Name 
5866*5113495bSYour Name /**
5867*5113495bSYour Name  * hdd_get_max_rate_legacy() - get max rate for legacy mode
5868*5113495bSYour Name  * @stainfo: stainfo pointer
5869*5113495bSYour Name  * @rssidx: rssi index
5870*5113495bSYour Name  *
5871*5113495bSYour Name  * This function will get max rate for legacy mode
5872*5113495bSYour Name  *
5873*5113495bSYour Name  * Return: max rate on success, otherwise 0
5874*5113495bSYour Name  */
hdd_get_max_rate_legacy(struct hdd_station_info * stainfo,uint8_t rssidx)5875*5113495bSYour Name static uint32_t hdd_get_max_rate_legacy(struct hdd_station_info *stainfo,
5876*5113495bSYour Name 					uint8_t rssidx)
5877*5113495bSYour Name {
5878*5113495bSYour Name 	uint32_t maxrate = 0;
5879*5113495bSYour Name 	/*Minimum max rate, 6Mbps*/
5880*5113495bSYour Name 	int maxidx = 12;
5881*5113495bSYour Name 	int i;
5882*5113495bSYour Name 
5883*5113495bSYour Name 	/* check supported rates */
5884*5113495bSYour Name 	if (stainfo->max_supp_idx != 0xff &&
5885*5113495bSYour Name 	    maxidx < stainfo->max_supp_idx)
5886*5113495bSYour Name 		maxidx = stainfo->max_supp_idx;
5887*5113495bSYour Name 
5888*5113495bSYour Name 	/* check extended rates */
5889*5113495bSYour Name 	if (stainfo->max_ext_idx != 0xff &&
5890*5113495bSYour Name 	    maxidx < stainfo->max_ext_idx)
5891*5113495bSYour Name 		maxidx = stainfo->max_ext_idx;
5892*5113495bSYour Name 
5893*5113495bSYour Name 	for (i = 0; i < QDF_ARRAY_SIZE(supported_data_rate); i++) {
5894*5113495bSYour Name 		if (supported_data_rate[i].beacon_rate_index == maxidx)
5895*5113495bSYour Name 			maxrate =
5896*5113495bSYour Name 				supported_data_rate[i].supported_rate[rssidx];
5897*5113495bSYour Name 	}
5898*5113495bSYour Name 
5899*5113495bSYour Name 	hdd_debug("maxrate %d", maxrate);
5900*5113495bSYour Name 
5901*5113495bSYour Name 	return maxrate;
5902*5113495bSYour Name }
5903*5113495bSYour Name 
5904*5113495bSYour Name /**
5905*5113495bSYour Name  * hdd_get_max_rate_ht() - get max rate for ht mode
5906*5113495bSYour Name  * @stainfo: stainfo pointer
5907*5113495bSYour Name  * @stats: fw txrx status pointer
5908*5113495bSYour Name  * @rate_flags: rate flags
5909*5113495bSYour Name  * @nss: number of streams
5910*5113495bSYour Name  * @maxrate: returned max rate buffer pointer
5911*5113495bSYour Name  * @max_mcs_idx: max mcs idx
5912*5113495bSYour Name  * @report_max: report max rate or actual rate
5913*5113495bSYour Name  *
5914*5113495bSYour Name  * This function will get max rate for ht mode
5915*5113495bSYour Name  *
5916*5113495bSYour Name  * Return: None
5917*5113495bSYour Name  */
hdd_get_max_rate_ht(struct hdd_station_info * stainfo,struct hdd_fw_txrx_stats * stats,uint32_t rate_flags,uint8_t nss,uint32_t * maxrate,uint8_t * max_mcs_idx,bool report_max)5918*5113495bSYour Name static void hdd_get_max_rate_ht(struct hdd_station_info *stainfo,
5919*5113495bSYour Name 				struct hdd_fw_txrx_stats *stats,
5920*5113495bSYour Name 				uint32_t rate_flags,
5921*5113495bSYour Name 				uint8_t nss,
5922*5113495bSYour Name 				uint32_t *maxrate,
5923*5113495bSYour Name 				uint8_t *max_mcs_idx,
5924*5113495bSYour Name 				bool report_max)
5925*5113495bSYour Name {
5926*5113495bSYour Name 	struct index_data_rate_type *supported_mcs_rate;
5927*5113495bSYour Name 	uint32_t tmprate;
5928*5113495bSYour Name 	uint8_t flag = 0, mcsidx;
5929*5113495bSYour Name 	int8_t rssi = stats->rssi;
5930*5113495bSYour Name 	int mode;
5931*5113495bSYour Name 	int i;
5932*5113495bSYour Name 
5933*5113495bSYour Name 	if (rate_flags & TX_RATE_HT40)
5934*5113495bSYour Name 		mode = 1;
5935*5113495bSYour Name 	else
5936*5113495bSYour Name 		mode = 0;
5937*5113495bSYour Name 
5938*5113495bSYour Name 	if (rate_flags & TX_RATE_HT40)
5939*5113495bSYour Name 		flag |= 1;
5940*5113495bSYour Name 	if (rate_flags & TX_RATE_SGI)
5941*5113495bSYour Name 		flag |= 2;
5942*5113495bSYour Name 
5943*5113495bSYour Name 	supported_mcs_rate = (struct index_data_rate_type *)
5944*5113495bSYour Name 		((nss == 1) ? &supported_mcs_rate_nss1 :
5945*5113495bSYour Name 		 &supported_mcs_rate_nss2);
5946*5113495bSYour Name 
5947*5113495bSYour Name 	if (stainfo->max_mcs_idx == 0xff) {
5948*5113495bSYour Name 		hdd_err("invalid max_mcs_idx");
5949*5113495bSYour Name 		/* report real mcs idx */
5950*5113495bSYour Name 		mcsidx = stats->tx_rate.mcs;
5951*5113495bSYour Name 	} else {
5952*5113495bSYour Name 		mcsidx = stainfo->max_mcs_idx;
5953*5113495bSYour Name 	}
5954*5113495bSYour Name 
5955*5113495bSYour Name 	if (!report_max) {
5956*5113495bSYour Name 		for (i = 0; i < MAX_HT_MCS_INDEX && i < mcsidx; i++) {
5957*5113495bSYour Name 			if (rssi <= rssi_mcs_tbl[mode][i]) {
5958*5113495bSYour Name 				mcsidx = i;
5959*5113495bSYour Name 				break;
5960*5113495bSYour Name 			}
5961*5113495bSYour Name 		}
5962*5113495bSYour Name 		if (mcsidx < stats->tx_rate.mcs &&
5963*5113495bSYour Name 		    stats->tx_rate.mcs <= MAX_HT_MCS_INDEX)
5964*5113495bSYour Name 			mcsidx = stats->tx_rate.mcs;
5965*5113495bSYour Name 	}
5966*5113495bSYour Name 
5967*5113495bSYour Name 	if (mcsidx > MAX_HT_MCS_INDEX)
5968*5113495bSYour Name 		mcsidx = MAX_HT_MCS_INDEX;
5969*5113495bSYour Name 	tmprate = supported_mcs_rate[mcsidx].supported_rate[flag];
5970*5113495bSYour Name 
5971*5113495bSYour Name 	hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
5972*5113495bSYour Name 
5973*5113495bSYour Name 	*maxrate = tmprate;
5974*5113495bSYour Name 	*max_mcs_idx = mcsidx;
5975*5113495bSYour Name }
5976*5113495bSYour Name 
5977*5113495bSYour Name /**
5978*5113495bSYour Name  * hdd_get_max_rate_vht() - get max rate for vht mode
5979*5113495bSYour Name  * @stainfo: stainfo pointer
5980*5113495bSYour Name  * @stats: fw txrx status pointer
5981*5113495bSYour Name  * @rate_flags: rate flags
5982*5113495bSYour Name  * @nss: number of streams
5983*5113495bSYour Name  * @maxrate: returned max rate buffer pointer
5984*5113495bSYour Name  * @max_mcs_idx: max mcs idx
5985*5113495bSYour Name  * @report_max: report max rate or actual rate
5986*5113495bSYour Name  *
5987*5113495bSYour Name  * This function will get max rate for vht mode
5988*5113495bSYour Name  *
5989*5113495bSYour Name  * Return: None
5990*5113495bSYour Name  */
hdd_get_max_rate_vht(struct hdd_station_info * stainfo,struct hdd_fw_txrx_stats * stats,uint32_t rate_flags,uint8_t nss,uint32_t * maxrate,uint8_t * max_mcs_idx,bool report_max)5991*5113495bSYour Name static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo,
5992*5113495bSYour Name 				 struct hdd_fw_txrx_stats *stats,
5993*5113495bSYour Name 				 uint32_t rate_flags,
5994*5113495bSYour Name 				 uint8_t nss,
5995*5113495bSYour Name 				 uint32_t *maxrate,
5996*5113495bSYour Name 				 uint8_t *max_mcs_idx,
5997*5113495bSYour Name 				 bool report_max)
5998*5113495bSYour Name {
5999*5113495bSYour Name 	struct index_vht_data_rate_type *supported_vht_mcs_rate;
6000*5113495bSYour Name 	uint32_t tmprate = 0;
6001*5113495bSYour Name 	uint32_t vht_max_mcs;
6002*5113495bSYour Name 	uint8_t flag = 0, mcsidx = INVALID_MCS_IDX;
6003*5113495bSYour Name 	int8_t rssi = stats->rssi;
6004*5113495bSYour Name 	int mode;
6005*5113495bSYour Name 	int i;
6006*5113495bSYour Name 
6007*5113495bSYour Name 	supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
6008*5113495bSYour Name 		((nss == 1) ?
6009*5113495bSYour Name 		 &supported_vht_mcs_rate_nss1 :
6010*5113495bSYour Name 		 &supported_vht_mcs_rate_nss2);
6011*5113495bSYour Name 
6012*5113495bSYour Name 	if (rate_flags & TX_RATE_VHT80)
6013*5113495bSYour Name 		mode = 2;
6014*5113495bSYour Name 	else if (rate_flags & TX_RATE_VHT40)
6015*5113495bSYour Name 		mode = 1;
6016*5113495bSYour Name 	else
6017*5113495bSYour Name 		mode = 0;
6018*5113495bSYour Name 
6019*5113495bSYour Name 	if (rate_flags &
6020*5113495bSYour Name 	    (TX_RATE_VHT20 | TX_RATE_VHT40 | TX_RATE_VHT80)) {
6021*5113495bSYour Name 		vht_max_mcs =
6022*5113495bSYour Name 			(enum data_rate_11ac_max_mcs)
6023*5113495bSYour Name 			(stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK);
6024*5113495bSYour Name 		if (rate_flags & TX_RATE_SGI)
6025*5113495bSYour Name 			flag |= 1;
6026*5113495bSYour Name 
6027*5113495bSYour Name 		if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) {
6028*5113495bSYour Name 			mcsidx = 7;
6029*5113495bSYour Name 		} else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) {
6030*5113495bSYour Name 			mcsidx = 8;
6031*5113495bSYour Name 		} else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) {
6032*5113495bSYour Name 			/*
6033*5113495bSYour Name 			 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
6034*5113495bSYour Name 			 * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6
6035*5113495bSYour Name 			 * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8
6036*5113495bSYour Name 			 */
6037*5113495bSYour Name 			if ((rate_flags & TX_RATE_VHT20) &&
6038*5113495bSYour Name 			    (nss != 3 && nss != 6))
6039*5113495bSYour Name 				mcsidx = 8;
6040*5113495bSYour Name 			else
6041*5113495bSYour Name 				mcsidx = 9;
6042*5113495bSYour Name 		} else {
6043*5113495bSYour Name 			hdd_err("invalid vht_max_mcs");
6044*5113495bSYour Name 			/* report real mcs idx */
6045*5113495bSYour Name 			mcsidx = stats->tx_rate.mcs;
6046*5113495bSYour Name 		}
6047*5113495bSYour Name 
6048*5113495bSYour Name 		if (!report_max) {
6049*5113495bSYour Name 			for (i = 0; i <= mcsidx && i < MAX_RSSI_MCS_INDEX; i++) {
6050*5113495bSYour Name 				if (rssi <= rssi_mcs_tbl[mode][i]) {
6051*5113495bSYour Name 					mcsidx = i;
6052*5113495bSYour Name 					break;
6053*5113495bSYour Name 				}
6054*5113495bSYour Name 			}
6055*5113495bSYour Name 			if (mcsidx < stats->tx_rate.mcs)
6056*5113495bSYour Name 				mcsidx = stats->tx_rate.mcs;
6057*5113495bSYour Name 		}
6058*5113495bSYour Name 
6059*5113495bSYour Name 		if (rate_flags & TX_RATE_VHT80)
6060*5113495bSYour Name 			tmprate =
6061*5113495bSYour Name 		    supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag];
6062*5113495bSYour Name 		else if (rate_flags & TX_RATE_VHT40)
6063*5113495bSYour Name 			tmprate =
6064*5113495bSYour Name 		    supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag];
6065*5113495bSYour Name 		else if (rate_flags & TX_RATE_VHT20)
6066*5113495bSYour Name 			tmprate =
6067*5113495bSYour Name 		    supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag];
6068*5113495bSYour Name 	}
6069*5113495bSYour Name 
6070*5113495bSYour Name 	hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx);
6071*5113495bSYour Name 
6072*5113495bSYour Name 	*maxrate = tmprate;
6073*5113495bSYour Name 	*max_mcs_idx = mcsidx;
6074*5113495bSYour Name }
6075*5113495bSYour Name 
6076*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
6077*5113495bSYour Name #if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC)
hdd_fill_eht_bw_mcs(struct rate_info * rate_info,enum tx_rate_info rate_flags,uint8_t mcsidx,uint8_t nss,uint8_t rate_info_flag)6078*5113495bSYour Name static bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info,
6079*5113495bSYour Name 				enum tx_rate_info rate_flags,
6080*5113495bSYour Name 				uint8_t mcsidx,
6081*5113495bSYour Name 				uint8_t nss,
6082*5113495bSYour Name 				uint8_t rate_info_flag)
6083*5113495bSYour Name {
6084*5113495bSYour Name 	if (rate_info_flag == RATE_INFO_FLAGS_EHT_MCS) {
6085*5113495bSYour Name 		rate_info->nss = nss;
6086*5113495bSYour Name 		rate_info->mcs = mcsidx;
6087*5113495bSYour Name 		rate_info->flags |= RATE_INFO_FLAGS_EHT_MCS;
6088*5113495bSYour Name 		if (rate_flags & TX_RATE_EHT320)
6089*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_320;
6090*5113495bSYour Name 		else if (rate_flags & TX_RATE_EHT160)
6091*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_160;
6092*5113495bSYour Name 		else if (rate_flags & TX_RATE_EHT80)
6093*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_80;
6094*5113495bSYour Name 		else if (rate_flags & TX_RATE_EHT40)
6095*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_40;
6096*5113495bSYour Name 		else if (rate_flags & TX_RATE_EHT20)
6097*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_20;
6098*5113495bSYour Name 
6099*5113495bSYour Name 		return true;
6100*5113495bSYour Name 	}
6101*5113495bSYour Name 
6102*5113495bSYour Name 	return false;
6103*5113495bSYour Name }
6104*5113495bSYour Name #else
hdd_fill_eht_bw_mcs(struct rate_info * rate_info,enum tx_rate_info rate_flags,uint8_t mcsidx,uint8_t nss,uint8_t rate_info_flag)6105*5113495bSYour Name static inline bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info,
6106*5113495bSYour Name 				       enum tx_rate_info rate_flags,
6107*5113495bSYour Name 				       uint8_t mcsidx,
6108*5113495bSYour Name 				       uint8_t nss,
6109*5113495bSYour Name 				       uint8_t rate_info_flag)
6110*5113495bSYour Name {
6111*5113495bSYour Name 	return false;
6112*5113495bSYour Name }
6113*5113495bSYour Name #endif
6114*5113495bSYour Name /**
6115*5113495bSYour Name  * hdd_fill_bw_mcs() - fill ch width and mcs flags
6116*5113495bSYour Name  * @rate_info: pointer to struct rate_info
6117*5113495bSYour Name  * @rate_flags: HDD rate flags
6118*5113495bSYour Name  * @mcsidx: mcs index
6119*5113495bSYour Name  * @nss: number of streams
6120*5113495bSYour Name  * @rate_info_flag: rate info flags
6121*5113495bSYour Name  *
6122*5113495bSYour Name  * This function will fill ch width and mcs flags
6123*5113495bSYour Name  *
6124*5113495bSYour Name  * Return: None
6125*5113495bSYour Name  */
hdd_fill_bw_mcs(struct rate_info * rate_info,enum tx_rate_info rate_flags,uint8_t mcsidx,uint8_t nss,uint8_t rate_info_flag)6126*5113495bSYour Name static void hdd_fill_bw_mcs(struct rate_info *rate_info,
6127*5113495bSYour Name 			    enum tx_rate_info rate_flags,
6128*5113495bSYour Name 			    uint8_t mcsidx,
6129*5113495bSYour Name 			    uint8_t nss,
6130*5113495bSYour Name 			    uint8_t rate_info_flag)
6131*5113495bSYour Name {
6132*5113495bSYour Name 	if (hdd_fill_eht_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6133*5113495bSYour Name 				rate_info_flag))
6134*5113495bSYour Name 		return;
6135*5113495bSYour Name 
6136*5113495bSYour Name 	if (rate_info_flag == RATE_INFO_FLAGS_HE_MCS) {
6137*5113495bSYour Name 		rate_info->nss = nss;
6138*5113495bSYour Name 		rate_info->mcs = mcsidx;
6139*5113495bSYour Name 		rate_info->flags |= RATE_INFO_FLAGS_HE_MCS;
6140*5113495bSYour Name 		if (rate_flags & TX_RATE_HE160)
6141*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_160;
6142*5113495bSYour Name 		else if (rate_flags & TX_RATE_HE80)
6143*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_80;
6144*5113495bSYour Name 		else if (rate_flags & TX_RATE_HE40)
6145*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_40;
6146*5113495bSYour Name 		else if (rate_flags & TX_RATE_HE20)
6147*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_20;
6148*5113495bSYour Name 	} else if (rate_info_flag == RATE_INFO_FLAGS_VHT_MCS) {
6149*5113495bSYour Name 		rate_info->nss = nss;
6150*5113495bSYour Name 		rate_info->mcs = mcsidx;
6151*5113495bSYour Name 		rate_info->flags |= RATE_INFO_FLAGS_VHT_MCS;
6152*5113495bSYour Name 		if (rate_flags & TX_RATE_VHT160)
6153*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_160;
6154*5113495bSYour Name 		else if (rate_flags & TX_RATE_VHT80)
6155*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_80;
6156*5113495bSYour Name 		else if (rate_flags & TX_RATE_VHT40)
6157*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_40;
6158*5113495bSYour Name 		else if (rate_flags & TX_RATE_VHT20)
6159*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_20;
6160*5113495bSYour Name 	} else {
6161*5113495bSYour Name 		rate_info->mcs = (nss - 1) << 3;
6162*5113495bSYour Name 		rate_info->mcs |= mcsidx;
6163*5113495bSYour Name 		rate_info->flags |= RATE_INFO_FLAGS_MCS;
6164*5113495bSYour Name 		if (rate_flags & TX_RATE_HT40)
6165*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_40;
6166*5113495bSYour Name 	}
6167*5113495bSYour Name }
6168*5113495bSYour Name #else
6169*5113495bSYour Name /**
6170*5113495bSYour Name  * hdd_fill_bw_mcs() - fill ch width and mcs flags
6171*5113495bSYour Name  * @rate_info: pointer to struct rate_info
6172*5113495bSYour Name  * @rate_flags: HDD rate flags
6173*5113495bSYour Name  * @mcsidx: mcs index
6174*5113495bSYour Name  * @nss: number of streams
6175*5113495bSYour Name  * @rate_info_flag: rate info flags
6176*5113495bSYour Name  *
6177*5113495bSYour Name  * This function will fill ch width and mcs flags
6178*5113495bSYour Name  *
6179*5113495bSYour Name  * Return: None
6180*5113495bSYour Name  */
hdd_fill_bw_mcs(struct rate_info * rate_info,enum tx_rate_info rate_flags,uint8_t mcsidx,uint8_t nss,uint8_t rate_info_flag)6181*5113495bSYour Name static void hdd_fill_bw_mcs(struct rate_info *rate_info,
6182*5113495bSYour Name 			    enum tx_rate_info rate_flags,
6183*5113495bSYour Name 			    uint8_t mcsidx,
6184*5113495bSYour Name 			    uint8_t nss,
6185*5113495bSYour Name 			    uint8_t rate_info_flag)
6186*5113495bSYour Name {
6187*5113495bSYour Name 	if (rate_info_flag == RATE_INFO_FLAGS_VHT_MCS) {
6188*5113495bSYour Name 		rate_info->nss = nss;
6189*5113495bSYour Name 		rate_info->mcs = mcsidx;
6190*5113495bSYour Name 		rate_info->flags |= RATE_INFO_FLAGS_VHT_MCS;
6191*5113495bSYour Name 		if (rate_flags & TX_RATE_VHT80)
6192*5113495bSYour Name 			rate_info->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
6193*5113495bSYour Name 		else if (rate_flags & TX_RATE_VHT40)
6194*5113495bSYour Name 			rate_info->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
6195*5113495bSYour Name 		else if (rate_flags & TX_RATE_VHT20)
6196*5113495bSYour Name 			rate_info->bw = RATE_INFO_BW_20;
6197*5113495bSYour Name 	} else {
6198*5113495bSYour Name 		rate_info->mcs = (nss - 1) << 3;
6199*5113495bSYour Name 		rate_info->mcs |= mcsidx;
6200*5113495bSYour Name 		rate_info->flags |= RATE_INFO_FLAGS_MCS;
6201*5113495bSYour Name 		if (rate_flags & TX_RATE_HT40)
6202*5113495bSYour Name 			rate_info->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
6203*5113495bSYour Name 	}
6204*5113495bSYour Name }
6205*5113495bSYour Name #endif
6206*5113495bSYour Name 
6207*5113495bSYour Name #if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC)
hdd_fill_sinfo_eht_rate_info(struct rate_info * rate_info,uint32_t rate_flags,uint8_t mcsidx,uint8_t nss)6208*5113495bSYour Name static void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info,
6209*5113495bSYour Name 					 uint32_t rate_flags, uint8_t mcsidx,
6210*5113495bSYour Name 					 uint8_t nss)
6211*5113495bSYour Name {
6212*5113495bSYour Name 	if (rate_flags &
6213*5113495bSYour Name 			(TX_RATE_EHT320 |
6214*5113495bSYour Name 			 TX_RATE_EHT160 |
6215*5113495bSYour Name 			 TX_RATE_EHT80 |
6216*5113495bSYour Name 			 TX_RATE_EHT40 |
6217*5113495bSYour Name 			 TX_RATE_EHT20)) {
6218*5113495bSYour Name 		hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6219*5113495bSYour Name 				RATE_INFO_FLAGS_EHT_MCS);
6220*5113495bSYour Name 	}
6221*5113495bSYour Name }
6222*5113495bSYour Name #else
hdd_fill_sinfo_eht_rate_info(struct rate_info * rate_info,uint32_t rate_flags,uint8_t mcsidx,uint8_t nss)6223*5113495bSYour Name static inline void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info,
6224*5113495bSYour Name 						uint32_t rate_flags,
6225*5113495bSYour Name 						uint8_t mcsidx,
6226*5113495bSYour Name 						uint8_t nss)
6227*5113495bSYour Name {
6228*5113495bSYour Name }
6229*5113495bSYour Name #endif
6230*5113495bSYour Name 
6231*5113495bSYour Name /**
6232*5113495bSYour Name  * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct
6233*5113495bSYour Name  * @sinfo: pointer to struct station_info
6234*5113495bSYour Name  * @rate_flags: HDD rate flags
6235*5113495bSYour Name  * @mcsidx: mcs index
6236*5113495bSYour Name  * @nss: number of streams
6237*5113495bSYour Name  * @rate: data rate (kbps)
6238*5113495bSYour Name  * @is_tx: flag to indicate whether it is tx or rx
6239*5113495bSYour Name  *
6240*5113495bSYour Name  * This function will fill rate info of sinfo struct
6241*5113495bSYour Name  *
6242*5113495bSYour Name  * Return: None
6243*5113495bSYour Name  */
hdd_fill_sinfo_rate_info(struct station_info * sinfo,uint32_t rate_flags,uint8_t mcsidx,uint8_t nss,uint32_t rate,bool is_tx)6244*5113495bSYour Name static void hdd_fill_sinfo_rate_info(struct station_info *sinfo,
6245*5113495bSYour Name 				     uint32_t rate_flags,
6246*5113495bSYour Name 				     uint8_t mcsidx,
6247*5113495bSYour Name 				     uint8_t nss,
6248*5113495bSYour Name 				     uint32_t rate,
6249*5113495bSYour Name 				     bool is_tx)
6250*5113495bSYour Name {
6251*5113495bSYour Name 	struct rate_info *rate_info;
6252*5113495bSYour Name 
6253*5113495bSYour Name 	if (is_tx)
6254*5113495bSYour Name 		rate_info = &sinfo->txrate;
6255*5113495bSYour Name 	else
6256*5113495bSYour Name 		rate_info = &sinfo->rxrate;
6257*5113495bSYour Name 
6258*5113495bSYour Name 	if (rate_flags & TX_RATE_LEGACY) {
6259*5113495bSYour Name 		/* provide to the UI in units of 100kbps */
6260*5113495bSYour Name 		rate_info->legacy = rate;
6261*5113495bSYour Name 	} else {
6262*5113495bSYour Name 		/* must be MCS */
6263*5113495bSYour Name 		hdd_fill_sinfo_eht_rate_info(rate_info, rate_flags, mcsidx,
6264*5113495bSYour Name 					     nss);
6265*5113495bSYour Name 
6266*5113495bSYour Name 		if (rate_flags &
6267*5113495bSYour Name 				(TX_RATE_HE160 |
6268*5113495bSYour Name 				 TX_RATE_HE80 |
6269*5113495bSYour Name 				 TX_RATE_HE40 |
6270*5113495bSYour Name 				 TX_RATE_HE20)) {
6271*5113495bSYour Name 			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6272*5113495bSYour Name 					RATE_INFO_FLAGS_HE_MCS);
6273*5113495bSYour Name 		}
6274*5113495bSYour Name 		if (rate_flags &
6275*5113495bSYour Name 				(TX_RATE_VHT160 |
6276*5113495bSYour Name 				 TX_RATE_VHT80 |
6277*5113495bSYour Name 				 TX_RATE_VHT40 |
6278*5113495bSYour Name 				 TX_RATE_VHT20)) {
6279*5113495bSYour Name 			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6280*5113495bSYour Name 					RATE_INFO_FLAGS_VHT_MCS);
6281*5113495bSYour Name 		}
6282*5113495bSYour Name 		if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) {
6283*5113495bSYour Name 			hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss,
6284*5113495bSYour Name 					RATE_INFO_FLAGS_MCS);
6285*5113495bSYour Name 		}
6286*5113495bSYour Name 		if (rate_flags & TX_RATE_SGI) {
6287*5113495bSYour Name 			if (!(rate_info->flags & RATE_INFO_FLAGS_VHT_MCS))
6288*5113495bSYour Name 				rate_info->flags |= RATE_INFO_FLAGS_MCS;
6289*5113495bSYour Name 			rate_info->flags |= RATE_INFO_FLAGS_SHORT_GI;
6290*5113495bSYour Name 		}
6291*5113495bSYour Name 	}
6292*5113495bSYour Name 
6293*5113495bSYour Name 	hdd_debug("flag %x mcs %d legacy %d nss %d",
6294*5113495bSYour Name 		  rate_info->flags,
6295*5113495bSYour Name 		  rate_info->mcs,
6296*5113495bSYour Name 		  rate_info->legacy,
6297*5113495bSYour Name 		  rate_info->nss);
6298*5113495bSYour Name 
6299*5113495bSYour Name 	if (is_tx)
6300*5113495bSYour Name 		sinfo->filled |= HDD_INFO_TX_BITRATE;
6301*5113495bSYour Name 	else
6302*5113495bSYour Name 		sinfo->filled |= HDD_INFO_RX_BITRATE;
6303*5113495bSYour Name }
6304*5113495bSYour Name 
6305*5113495bSYour Name /**
6306*5113495bSYour Name  * hdd_fill_sta_flags() - fill sta flags of sinfo
6307*5113495bSYour Name  * @sinfo: station_info struct pointer
6308*5113495bSYour Name  * @stainfo: stainfo pointer
6309*5113495bSYour Name  *
6310*5113495bSYour Name  * This function will fill sta flags of sinfo
6311*5113495bSYour Name  *
6312*5113495bSYour Name  * Return: None
6313*5113495bSYour Name  */
hdd_fill_sta_flags(struct station_info * sinfo,struct hdd_station_info * stainfo)6314*5113495bSYour Name static void hdd_fill_sta_flags(struct station_info *sinfo,
6315*5113495bSYour Name 			       struct hdd_station_info *stainfo)
6316*5113495bSYour Name {
6317*5113495bSYour Name 	sinfo->sta_flags.mask = NL80211_STA_FLAG_WME;
6318*5113495bSYour Name 
6319*5113495bSYour Name 	if (stainfo->is_qos_enabled)
6320*5113495bSYour Name 		sinfo->sta_flags.set |= NL80211_STA_FLAG_WME;
6321*5113495bSYour Name 	else
6322*5113495bSYour Name 		sinfo->sta_flags.set &= ~NL80211_STA_FLAG_WME;
6323*5113495bSYour Name 
6324*5113495bSYour Name 	sinfo->filled |= HDD_INFO_STA_FLAGS;
6325*5113495bSYour Name }
6326*5113495bSYour Name 
6327*5113495bSYour Name /**
6328*5113495bSYour Name  * hdd_fill_per_chain_avg_signal() - fill per chain avg rssi of sinfo
6329*5113495bSYour Name  * @sinfo: station_info struct pointer
6330*5113495bSYour Name  * @stainfo: stainfo pointer
6331*5113495bSYour Name  *
6332*5113495bSYour Name  * This function will fill per chain avg rssi of sinfo
6333*5113495bSYour Name  *
6334*5113495bSYour Name  * Return: None
6335*5113495bSYour Name  */
hdd_fill_per_chain_avg_signal(struct station_info * sinfo,struct hdd_station_info * stainfo)6336*5113495bSYour Name static void hdd_fill_per_chain_avg_signal(struct station_info *sinfo,
6337*5113495bSYour Name 					  struct hdd_station_info *stainfo)
6338*5113495bSYour Name {
6339*5113495bSYour Name 	bool rssi_stats_valid = false;
6340*5113495bSYour Name 	uint8_t i;
6341*5113495bSYour Name 
6342*5113495bSYour Name 	sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
6343*5113495bSYour Name 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
6344*5113495bSYour Name 		sinfo->chain_signal_avg[i] = stainfo->peer_rssi_per_chain[i];
6345*5113495bSYour Name 		sinfo->chains |= 1 << i;
6346*5113495bSYour Name 		if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
6347*5113495bSYour Name 		    sinfo->chain_signal_avg[i] != 0)
6348*5113495bSYour Name 			sinfo->signal_avg = sinfo->chain_signal_avg[i];
6349*5113495bSYour Name 
6350*5113495bSYour Name 		if (sinfo->chain_signal_avg[i])
6351*5113495bSYour Name 			rssi_stats_valid = true;
6352*5113495bSYour Name 	}
6353*5113495bSYour Name 
6354*5113495bSYour Name 	if (rssi_stats_valid) {
6355*5113495bSYour Name 		sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG;
6356*5113495bSYour Name 		sinfo->filled |= HDD_INFO_SIGNAL_AVG;
6357*5113495bSYour Name 	}
6358*5113495bSYour Name }
6359*5113495bSYour Name 
6360*5113495bSYour Name /**
6361*5113495bSYour Name  * hdd_fill_rate_info() - fill rate info of sinfo
6362*5113495bSYour Name  * @psoc: psoc context
6363*5113495bSYour Name  * @sinfo: station_info struct pointer
6364*5113495bSYour Name  * @stainfo: stainfo pointer
6365*5113495bSYour Name  * @stats: fw txrx status pointer
6366*5113495bSYour Name  *
6367*5113495bSYour Name  * This function will fill rate info of sinfo
6368*5113495bSYour Name  *
6369*5113495bSYour Name  * Return: None
6370*5113495bSYour Name  */
hdd_fill_rate_info(struct wlan_objmgr_psoc * psoc,struct station_info * sinfo,struct hdd_station_info * stainfo,struct hdd_fw_txrx_stats * stats)6371*5113495bSYour Name static void hdd_fill_rate_info(struct wlan_objmgr_psoc *psoc,
6372*5113495bSYour Name 			       struct station_info *sinfo,
6373*5113495bSYour Name 			       struct hdd_station_info *stainfo,
6374*5113495bSYour Name 			       struct hdd_fw_txrx_stats *stats)
6375*5113495bSYour Name {
6376*5113495bSYour Name 	enum tx_rate_info rate_flags;
6377*5113495bSYour Name 	uint8_t mcsidx = 0xff;
6378*5113495bSYour Name 	uint32_t tx_rate, rx_rate, maxrate, tmprate;
6379*5113495bSYour Name 	int rssidx;
6380*5113495bSYour Name 	int nss = 1;
6381*5113495bSYour Name 	int link_speed_rssi_high = 0;
6382*5113495bSYour Name 	int link_speed_rssi_mid = 0;
6383*5113495bSYour Name 	int link_speed_rssi_low = 0;
6384*5113495bSYour Name 	uint32_t link_speed_rssi_report = 0;
6385*5113495bSYour Name 
6386*5113495bSYour Name 	ucfg_mlme_stats_get_cfg_values(psoc,
6387*5113495bSYour Name 				       &link_speed_rssi_high,
6388*5113495bSYour Name 				       &link_speed_rssi_mid,
6389*5113495bSYour Name 				       &link_speed_rssi_low,
6390*5113495bSYour Name 				       &link_speed_rssi_report);
6391*5113495bSYour Name 
6392*5113495bSYour Name 	hdd_debug("reportMaxLinkSpeed %d", link_speed_rssi_report);
6393*5113495bSYour Name 
6394*5113495bSYour Name 	/* convert to 100kbps expected in rate table */
6395*5113495bSYour Name 	tx_rate = stats->tx_rate.rate / 100;
6396*5113495bSYour Name 	rate_flags = stainfo->rate_flags;
6397*5113495bSYour Name 	if (!(rate_flags & TX_RATE_LEGACY)) {
6398*5113495bSYour Name 		nss = stainfo->nss;
6399*5113495bSYour Name 		if (ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
6400*5113495bSYour Name 			/* Get current rate flags if report actual */
6401*5113495bSYour Name 			if (stats->tx_rate.rate_flags)
6402*5113495bSYour Name 				rate_flags =
6403*5113495bSYour Name 					stats->tx_rate.rate_flags;
6404*5113495bSYour Name 			nss = stats->tx_rate.nss;
6405*5113495bSYour Name 		}
6406*5113495bSYour Name 
6407*5113495bSYour Name 		if (stats->tx_rate.mcs == INVALID_MCS_IDX)
6408*5113495bSYour Name 			rate_flags = TX_RATE_LEGACY;
6409*5113495bSYour Name 	}
6410*5113495bSYour Name 
6411*5113495bSYour Name 	if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc)) {
6412*5113495bSYour Name 		/* we do not want to necessarily report the current speed */
6413*5113495bSYour Name 		if (ucfg_mlme_stats_is_link_speed_report_max(psoc)) {
6414*5113495bSYour Name 			/* report the max possible speed */
6415*5113495bSYour Name 			rssidx = 0;
6416*5113495bSYour Name 		} else if (ucfg_mlme_stats_is_link_speed_report_max_scaled(
6417*5113495bSYour Name 					psoc)) {
6418*5113495bSYour Name 			/* report the max possible speed with RSSI scaling */
6419*5113495bSYour Name 			if (stats->rssi >= link_speed_rssi_high) {
6420*5113495bSYour Name 				/* report the max possible speed */
6421*5113495bSYour Name 				rssidx = 0;
6422*5113495bSYour Name 			} else if (stats->rssi >= link_speed_rssi_mid) {
6423*5113495bSYour Name 				/* report middle speed */
6424*5113495bSYour Name 				rssidx = 1;
6425*5113495bSYour Name 			} else if (stats->rssi >= link_speed_rssi_low) {
6426*5113495bSYour Name 				/* report low speed */
6427*5113495bSYour Name 				rssidx = 2;
6428*5113495bSYour Name 			} else {
6429*5113495bSYour Name 				/* report actual speed */
6430*5113495bSYour Name 				rssidx = 3;
6431*5113495bSYour Name 			}
6432*5113495bSYour Name 		} else {
6433*5113495bSYour Name 			/* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */
6434*5113495bSYour Name 			hdd_err("Invalid value for reportMaxLinkSpeed: %u",
6435*5113495bSYour Name 				link_speed_rssi_report);
6436*5113495bSYour Name 			rssidx = 0;
6437*5113495bSYour Name 		}
6438*5113495bSYour Name 
6439*5113495bSYour Name 		maxrate = hdd_get_max_rate_legacy(stainfo, rssidx);
6440*5113495bSYour Name 
6441*5113495bSYour Name 		/*
6442*5113495bSYour Name 		 * Get MCS Rate Set --
6443*5113495bSYour Name 		 * Only if we are connected in non legacy mode and not
6444*5113495bSYour Name 		 * reporting actual speed
6445*5113495bSYour Name 		 */
6446*5113495bSYour Name 		if ((rssidx != 3) &&
6447*5113495bSYour Name 		    !(rate_flags & TX_RATE_LEGACY)) {
6448*5113495bSYour Name 			hdd_get_max_rate_vht(stainfo,
6449*5113495bSYour Name 					     stats,
6450*5113495bSYour Name 					     rate_flags,
6451*5113495bSYour Name 					     nss,
6452*5113495bSYour Name 					     &tmprate,
6453*5113495bSYour Name 					     &mcsidx,
6454*5113495bSYour Name 					     rssidx == 0);
6455*5113495bSYour Name 
6456*5113495bSYour Name 			if (maxrate < tmprate &&
6457*5113495bSYour Name 			    mcsidx != INVALID_MCS_IDX)
6458*5113495bSYour Name 				maxrate = tmprate;
6459*5113495bSYour Name 
6460*5113495bSYour Name 			if (mcsidx == INVALID_MCS_IDX)
6461*5113495bSYour Name 				hdd_get_max_rate_ht(stainfo,
6462*5113495bSYour Name 						    stats,
6463*5113495bSYour Name 						    rate_flags,
6464*5113495bSYour Name 						    nss,
6465*5113495bSYour Name 						    &tmprate,
6466*5113495bSYour Name 						    &mcsidx,
6467*5113495bSYour Name 						    rssidx == 0);
6468*5113495bSYour Name 
6469*5113495bSYour Name 			if (maxrate < tmprate &&
6470*5113495bSYour Name 			    mcsidx != INVALID_MCS_IDX)
6471*5113495bSYour Name 				maxrate = tmprate;
6472*5113495bSYour Name 		} else if (!(rate_flags & TX_RATE_LEGACY)) {
6473*5113495bSYour Name 			maxrate = tx_rate;
6474*5113495bSYour Name 			mcsidx = stats->tx_rate.mcs;
6475*5113495bSYour Name 		}
6476*5113495bSYour Name 
6477*5113495bSYour Name 		/*
6478*5113495bSYour Name 		 * make sure we report a value at least as big as our
6479*5113495bSYour Name 		 * current rate
6480*5113495bSYour Name 		 */
6481*5113495bSYour Name 		if (maxrate < tx_rate || maxrate == 0) {
6482*5113495bSYour Name 			maxrate = tx_rate;
6483*5113495bSYour Name 			if (!(rate_flags & TX_RATE_LEGACY)) {
6484*5113495bSYour Name 				mcsidx = stats->tx_rate.mcs;
6485*5113495bSYour Name 				/*
6486*5113495bSYour Name 				 * 'IEEE_P802.11ac_2013.pdf' page 325, 326
6487*5113495bSYour Name 				 * - MCS9 is valid for VHT20 when Nss = 3 or
6488*5113495bSYour Name 				 *   Nss = 6
6489*5113495bSYour Name 				 * - MCS9 is not valid for VHT20 when
6490*5113495bSYour Name 				 *   Nss = 1,2,4,5,7,8
6491*5113495bSYour Name 				 */
6492*5113495bSYour Name 				if ((rate_flags & TX_RATE_VHT20) &&
6493*5113495bSYour Name 				    (mcsidx > 8) &&
6494*5113495bSYour Name 				    (nss != 3 && nss != 6))
6495*5113495bSYour Name 					mcsidx = 8;
6496*5113495bSYour Name 			}
6497*5113495bSYour Name 		}
6498*5113495bSYour Name 	} else {
6499*5113495bSYour Name 		/* report current rate instead of max rate */
6500*5113495bSYour Name 		maxrate = tx_rate;
6501*5113495bSYour Name 		if (!(rate_flags & TX_RATE_LEGACY))
6502*5113495bSYour Name 			mcsidx = stats->tx_rate.mcs;
6503*5113495bSYour Name 	}
6504*5113495bSYour Name 
6505*5113495bSYour Name 	hdd_fill_sinfo_rate_info(sinfo, rate_flags, mcsidx, nss,
6506*5113495bSYour Name 				 maxrate, true);
6507*5113495bSYour Name 
6508*5113495bSYour Name 	/* convert to 100kbps expected in rate table */
6509*5113495bSYour Name 	rx_rate = stats->rx_rate.rate / 100;
6510*5113495bSYour Name 
6511*5113495bSYour Name 	/* report current rx rate*/
6512*5113495bSYour Name 	rate_flags = stainfo->rate_flags;
6513*5113495bSYour Name 	if (!(rate_flags & TX_RATE_LEGACY)) {
6514*5113495bSYour Name 		if (stats->rx_rate.rate_flags)
6515*5113495bSYour Name 			rate_flags = stats->rx_rate.rate_flags;
6516*5113495bSYour Name 		nss = stats->rx_rate.nss;
6517*5113495bSYour Name 		if (stats->rx_rate.mcs == INVALID_MCS_IDX)
6518*5113495bSYour Name 			rate_flags = TX_RATE_LEGACY;
6519*5113495bSYour Name 	}
6520*5113495bSYour Name 	if (!(rate_flags & TX_RATE_LEGACY))
6521*5113495bSYour Name 		mcsidx = stats->rx_rate.mcs;
6522*5113495bSYour Name 
6523*5113495bSYour Name 	hdd_fill_sinfo_rate_info(sinfo, rate_flags, mcsidx, nss,
6524*5113495bSYour Name 				 rx_rate, false);
6525*5113495bSYour Name 
6526*5113495bSYour Name 	sinfo->expected_throughput = stainfo->max_phy_rate;
6527*5113495bSYour Name 	sinfo->filled |= HDD_INFO_EXPECTED_THROUGHPUT;
6528*5113495bSYour Name }
6529*5113495bSYour Name 
6530*5113495bSYour Name /**
6531*5113495bSYour Name  * wlan_hdd_fill_station_info() - fill station_info struct
6532*5113495bSYour Name  * @psoc: psoc context
6533*5113495bSYour Name  * @adapter: The HDD adapter structure
6534*5113495bSYour Name  * @sinfo: station_info struct pointer
6535*5113495bSYour Name  * @stainfo: stainfo pointer
6536*5113495bSYour Name  * @stats: fw txrx status pointer
6537*5113495bSYour Name  *
6538*5113495bSYour Name  * This function will fill station_info struct
6539*5113495bSYour Name  *
6540*5113495bSYour Name  * Return: None
6541*5113495bSYour Name  */
wlan_hdd_fill_station_info(struct wlan_objmgr_psoc * psoc,struct hdd_adapter * adapter,struct station_info * sinfo,struct hdd_station_info * stainfo,struct hdd_fw_txrx_stats * stats)6542*5113495bSYour Name static void wlan_hdd_fill_station_info(struct wlan_objmgr_psoc *psoc,
6543*5113495bSYour Name 				       struct hdd_adapter *adapter,
6544*5113495bSYour Name 				       struct station_info *sinfo,
6545*5113495bSYour Name 				       struct hdd_station_info *stainfo,
6546*5113495bSYour Name 				       struct hdd_fw_txrx_stats *stats)
6547*5113495bSYour Name {
6548*5113495bSYour Name 	qdf_time_t curr_time, dur;
6549*5113495bSYour Name 	struct cdp_peer_stats *peer_stats;
6550*5113495bSYour Name 	QDF_STATUS status;
6551*5113495bSYour Name 
6552*5113495bSYour Name 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
6553*5113495bSYour Name 	if (!peer_stats)
6554*5113495bSYour Name 		return;
6555*5113495bSYour Name 
6556*5113495bSYour Name 	status =
6557*5113495bSYour Name 		cdp_host_get_peer_stats(cds_get_context(QDF_MODULE_ID_SOC),
6558*5113495bSYour Name 					adapter->deflink->vdev_id,
6559*5113495bSYour Name 					stainfo->sta_mac.bytes,
6560*5113495bSYour Name 					peer_stats);
6561*5113495bSYour Name 
6562*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
6563*5113495bSYour Name 		hdd_err("cdp_host_get_peer_stats failed. error: %u", status);
6564*5113495bSYour Name 		qdf_mem_free(peer_stats);
6565*5113495bSYour Name 		return;
6566*5113495bSYour Name 	}
6567*5113495bSYour Name 
6568*5113495bSYour Name 	stainfo->last_tx_rx_ts =
6569*5113495bSYour Name 		peer_stats->tx.last_tx_ts > peer_stats->rx.last_rx_ts ?
6570*5113495bSYour Name 		peer_stats->tx.last_tx_ts : peer_stats->rx.last_rx_ts;
6571*5113495bSYour Name 
6572*5113495bSYour Name 	qdf_mem_free(peer_stats);
6573*5113495bSYour Name 
6574*5113495bSYour Name 	curr_time = qdf_system_ticks();
6575*5113495bSYour Name 	dur = curr_time - stainfo->assoc_ts;
6576*5113495bSYour Name 	sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000;
6577*5113495bSYour Name 	sinfo->filled |= HDD_INFO_CONNECTED_TIME;
6578*5113495bSYour Name 	dur = curr_time - stainfo->last_tx_rx_ts;
6579*5113495bSYour Name 	sinfo->inactive_time = qdf_system_ticks_to_msecs(dur);
6580*5113495bSYour Name 	sinfo->filled |= HDD_INFO_INACTIVE_TIME;
6581*5113495bSYour Name 	sinfo->signal = stats->rssi;
6582*5113495bSYour Name 	sinfo->filled |= HDD_INFO_SIGNAL;
6583*5113495bSYour Name 	sinfo->tx_bytes = stats->tx_bytes;
6584*5113495bSYour Name 	sinfo->filled |= HDD_INFO_TX_BYTES | HDD_INFO_TX_BYTES64;
6585*5113495bSYour Name 	sinfo->tx_packets = stats->tx_packets;
6586*5113495bSYour Name 	sinfo->filled |= HDD_INFO_TX_PACKETS;
6587*5113495bSYour Name 	sinfo->rx_bytes = stats->rx_bytes;
6588*5113495bSYour Name 	sinfo->filled |= HDD_INFO_RX_BYTES | HDD_INFO_RX_BYTES64;
6589*5113495bSYour Name 	sinfo->rx_packets = stats->rx_packets;
6590*5113495bSYour Name 	sinfo->filled |= HDD_INFO_RX_PACKETS;
6591*5113495bSYour Name 	sinfo->tx_failed = stats->tx_failed;
6592*5113495bSYour Name 	sinfo->filled |= HDD_INFO_TX_FAILED;
6593*5113495bSYour Name 	sinfo->tx_retries = stats->tx_retries;
6594*5113495bSYour Name 
6595*5113495bSYour Name 	/* sta flags */
6596*5113495bSYour Name 	hdd_fill_sta_flags(sinfo, stainfo);
6597*5113495bSYour Name 
6598*5113495bSYour Name 	/* per chain avg rssi */
6599*5113495bSYour Name 	hdd_fill_per_chain_avg_signal(sinfo, stainfo);
6600*5113495bSYour Name 
6601*5113495bSYour Name 	/* tx / rx rate info */
6602*5113495bSYour Name 	hdd_fill_rate_info(psoc, sinfo, stainfo, stats);
6603*5113495bSYour Name 
6604*5113495bSYour Name 	/* assoc req ies */
6605*5113495bSYour Name 	sinfo->assoc_req_ies = stainfo->assoc_req_ies.ptr;
6606*5113495bSYour Name 	sinfo->assoc_req_ies_len = stainfo->assoc_req_ies.len;
6607*5113495bSYour Name 
6608*5113495bSYour Name 	/* dump sta info*/
6609*5113495bSYour Name 	hdd_debug("dump stainfo");
6610*5113495bSYour Name 	hdd_debug("con_time %d inact_time %d tx_pkts %d rx_pkts %d",
6611*5113495bSYour Name 		  sinfo->connected_time, sinfo->inactive_time,
6612*5113495bSYour Name 		  sinfo->tx_packets, sinfo->rx_packets);
6613*5113495bSYour Name 	hdd_debug("failed %d retries %d tx_bytes %lld rx_bytes %lld",
6614*5113495bSYour Name 		  sinfo->tx_failed, sinfo->tx_retries,
6615*5113495bSYour Name 		  sinfo->tx_bytes, sinfo->rx_bytes);
6616*5113495bSYour Name 	hdd_debug("rssi %d tx mcs %d legacy %d nss %d flags %x",
6617*5113495bSYour Name 		  sinfo->signal, sinfo->txrate.mcs,
6618*5113495bSYour Name 		  sinfo->txrate.legacy, sinfo->txrate.nss,
6619*5113495bSYour Name 		  sinfo->txrate.flags);
6620*5113495bSYour Name 	hdd_debug("rx mcs %d legacy %d nss %d flags %x",
6621*5113495bSYour Name 		  sinfo->rxrate.mcs, sinfo->rxrate.legacy,
6622*5113495bSYour Name 		  sinfo->rxrate.nss, sinfo->rxrate.flags);
6623*5113495bSYour Name }
6624*5113495bSYour Name 
6625*5113495bSYour Name /**
6626*5113495bSYour Name  * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs
6627*5113495bSYour Name  * @rate: Data rate (100 kbps)
6628*5113495bSYour Name  * @nss: Number of streams
6629*5113495bSYour Name  * @mcs: HT mcs index
6630*5113495bSYour Name  *
6631*5113495bSYour Name  * This function is used to construct HT rate flag with rate, nss and mcs
6632*5113495bSYour Name  *
6633*5113495bSYour Name  * Return: rate flags for success, 0 on failure.
6634*5113495bSYour Name  */
hdd_get_rate_flags_ht(uint32_t rate,uint8_t nss,uint8_t mcs)6635*5113495bSYour Name static uint8_t hdd_get_rate_flags_ht(uint32_t rate,
6636*5113495bSYour Name 				     uint8_t nss,
6637*5113495bSYour Name 				     uint8_t mcs)
6638*5113495bSYour Name {
6639*5113495bSYour Name 	struct index_data_rate_type *mcs_rate;
6640*5113495bSYour Name 	uint8_t flags = 0;
6641*5113495bSYour Name 
6642*5113495bSYour Name 	mcs_rate = (struct index_data_rate_type *)
6643*5113495bSYour Name 		((nss == 1) ? &supported_mcs_rate_nss1 :
6644*5113495bSYour Name 		 &supported_mcs_rate_nss2);
6645*5113495bSYour Name 
6646*5113495bSYour Name 	if (rate == mcs_rate[mcs].supported_rate[0]) {
6647*5113495bSYour Name 		flags |= TX_RATE_HT20;
6648*5113495bSYour Name 	} else if (rate == mcs_rate[mcs].supported_rate[1]) {
6649*5113495bSYour Name 		flags |= TX_RATE_HT40;
6650*5113495bSYour Name 	} else if (rate == mcs_rate[mcs].supported_rate[2]) {
6651*5113495bSYour Name 		flags |= TX_RATE_HT20;
6652*5113495bSYour Name 		flags |= TX_RATE_SGI;
6653*5113495bSYour Name 	} else if (rate == mcs_rate[mcs].supported_rate[3]) {
6654*5113495bSYour Name 		flags |= TX_RATE_HT40;
6655*5113495bSYour Name 		flags |= TX_RATE_SGI;
6656*5113495bSYour Name 	} else {
6657*5113495bSYour Name 		hdd_err("invalid params rate %d nss %d mcs %d",
6658*5113495bSYour Name 			rate, nss, mcs);
6659*5113495bSYour Name 	}
6660*5113495bSYour Name 
6661*5113495bSYour Name 	return flags;
6662*5113495bSYour Name }
6663*5113495bSYour Name 
6664*5113495bSYour Name /**
6665*5113495bSYour Name  * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs
6666*5113495bSYour Name  * @rate: Data rate (100 kbps)
6667*5113495bSYour Name  * @nss: Number of streams
6668*5113495bSYour Name  * @mcs: VHT mcs index
6669*5113495bSYour Name  *
6670*5113495bSYour Name  * This function is used to construct VHT rate flag with rate, nss and mcs
6671*5113495bSYour Name  *
6672*5113495bSYour Name  * Return: rate flags for success, 0 on failure.
6673*5113495bSYour Name  */
hdd_get_rate_flags_vht(uint32_t rate,uint8_t nss,uint8_t mcs)6674*5113495bSYour Name static uint8_t hdd_get_rate_flags_vht(uint32_t rate,
6675*5113495bSYour Name 				      uint8_t nss,
6676*5113495bSYour Name 				      uint8_t mcs)
6677*5113495bSYour Name {
6678*5113495bSYour Name 	struct index_vht_data_rate_type *mcs_rate;
6679*5113495bSYour Name 	uint8_t flags = 0;
6680*5113495bSYour Name 
6681*5113495bSYour Name 	if (mcs >= ARRAY_SIZE(supported_vht_mcs_rate_nss1)) {
6682*5113495bSYour Name 		hdd_err("Invalid mcs index %d", mcs);
6683*5113495bSYour Name 		return flags;
6684*5113495bSYour Name 	}
6685*5113495bSYour Name 
6686*5113495bSYour Name 	mcs_rate = (struct index_vht_data_rate_type *)
6687*5113495bSYour Name 		((nss == 1) ?
6688*5113495bSYour Name 		 &supported_vht_mcs_rate_nss1 :
6689*5113495bSYour Name 		 &supported_vht_mcs_rate_nss2);
6690*5113495bSYour Name 
6691*5113495bSYour Name 	if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
6692*5113495bSYour Name 		flags |= TX_RATE_VHT80;
6693*5113495bSYour Name 	} else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
6694*5113495bSYour Name 		flags |= TX_RATE_VHT80;
6695*5113495bSYour Name 		flags |= TX_RATE_SGI;
6696*5113495bSYour Name 	} else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
6697*5113495bSYour Name 		flags |= TX_RATE_VHT40;
6698*5113495bSYour Name 	} else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
6699*5113495bSYour Name 		flags |= TX_RATE_VHT40;
6700*5113495bSYour Name 		flags |= TX_RATE_SGI;
6701*5113495bSYour Name 	} else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
6702*5113495bSYour Name 		flags |= TX_RATE_VHT20;
6703*5113495bSYour Name 	} else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
6704*5113495bSYour Name 		flags |= TX_RATE_VHT20;
6705*5113495bSYour Name 		flags |= TX_RATE_SGI;
6706*5113495bSYour Name 	} else {
6707*5113495bSYour Name 		hdd_err("invalid params rate %d nss %d mcs %d",
6708*5113495bSYour Name 			rate, nss, mcs);
6709*5113495bSYour Name 	}
6710*5113495bSYour Name 
6711*5113495bSYour Name 	return flags;
6712*5113495bSYour Name }
6713*5113495bSYour Name 
6714*5113495bSYour Name /**
6715*5113495bSYour Name  * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs
6716*5113495bSYour Name  * @rate: Data rate (100 kbps)
6717*5113495bSYour Name  * @mode: Tx/Rx mode
6718*5113495bSYour Name  * @nss: Number of streams
6719*5113495bSYour Name  * @mcs: Mcs index
6720*5113495bSYour Name  *
6721*5113495bSYour Name  * This function is used to construct rate flag with rate, nss and mcs
6722*5113495bSYour Name  *
6723*5113495bSYour Name  * Return: rate flags for success, 0 on failure.
6724*5113495bSYour Name  */
hdd_get_rate_flags(uint32_t rate,uint8_t mode,uint8_t nss,uint8_t mcs)6725*5113495bSYour Name static uint8_t hdd_get_rate_flags(uint32_t rate,
6726*5113495bSYour Name 				  uint8_t mode,
6727*5113495bSYour Name 				  uint8_t nss,
6728*5113495bSYour Name 				  uint8_t mcs)
6729*5113495bSYour Name {
6730*5113495bSYour Name 	uint8_t flags = 0;
6731*5113495bSYour Name 
6732*5113495bSYour Name 	if (mode == SIR_SME_PHY_MODE_HT)
6733*5113495bSYour Name 		flags = hdd_get_rate_flags_ht(rate, nss, mcs);
6734*5113495bSYour Name 	else if (mode == SIR_SME_PHY_MODE_VHT)
6735*5113495bSYour Name 		flags = hdd_get_rate_flags_vht(rate, nss, mcs);
6736*5113495bSYour Name 	else
6737*5113495bSYour Name 		hdd_debug("invalid mode param %d", mode);
6738*5113495bSYour Name 
6739*5113495bSYour Name 	return flags;
6740*5113495bSYour Name }
6741*5113495bSYour Name 
6742*5113495bSYour Name /**
6743*5113495bSYour Name  * wlan_hdd_fill_rate_info() - fill HDD rate info from peer info
6744*5113495bSYour Name  * @txrx_stats: pointer to txrx stats to be filled with rate info
6745*5113495bSYour Name  * @peer_info: peer info pointer
6746*5113495bSYour Name  *
6747*5113495bSYour Name  * This function is used to fill HDD rate info from peer info
6748*5113495bSYour Name  *
6749*5113495bSYour Name  * Return: None
6750*5113495bSYour Name  */
wlan_hdd_fill_rate_info(struct hdd_fw_txrx_stats * txrx_stats,struct peer_stats_info_ext_event * peer_info)6751*5113495bSYour Name static void wlan_hdd_fill_rate_info(struct hdd_fw_txrx_stats *txrx_stats,
6752*5113495bSYour Name 				    struct peer_stats_info_ext_event *peer_info)
6753*5113495bSYour Name {
6754*5113495bSYour Name 	uint8_t flags;
6755*5113495bSYour Name 	uint32_t rate_code;
6756*5113495bSYour Name 
6757*5113495bSYour Name 	/* tx rate info */
6758*5113495bSYour Name 	txrx_stats->tx_rate.rate = peer_info->tx_rate;
6759*5113495bSYour Name 	rate_code = peer_info->tx_rate_code;
6760*5113495bSYour Name 
6761*5113495bSYour Name 	if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6762*5113495bSYour Name 			WMI_RATE_PREAMBLE_HT)
6763*5113495bSYour Name 		txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_HT;
6764*5113495bSYour Name 	else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6765*5113495bSYour Name 			WMI_RATE_PREAMBLE_VHT)
6766*5113495bSYour Name 		txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_VHT;
6767*5113495bSYour Name 	else
6768*5113495bSYour Name 		txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
6769*5113495bSYour Name 
6770*5113495bSYour Name 	txrx_stats->tx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
6771*5113495bSYour Name 	txrx_stats->tx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
6772*5113495bSYour Name 
6773*5113495bSYour Name 	flags = hdd_get_rate_flags(txrx_stats->tx_rate.rate / 100,
6774*5113495bSYour Name 				   txrx_stats->tx_rate.mode,
6775*5113495bSYour Name 				   txrx_stats->tx_rate.nss,
6776*5113495bSYour Name 				   txrx_stats->tx_rate.mcs);
6777*5113495bSYour Name 
6778*5113495bSYour Name 	txrx_stats->tx_rate.rate_flags = flags;
6779*5113495bSYour Name 
6780*5113495bSYour Name 	hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x",
6781*5113495bSYour Name 		  txrx_stats->tx_rate.mode,
6782*5113495bSYour Name 		  txrx_stats->tx_rate.nss,
6783*5113495bSYour Name 		  txrx_stats->tx_rate.mcs,
6784*5113495bSYour Name 		  txrx_stats->tx_rate.rate_flags,
6785*5113495bSYour Name 		  flags);
6786*5113495bSYour Name 
6787*5113495bSYour Name 	/* rx rate info */
6788*5113495bSYour Name 	txrx_stats->rx_rate.rate = peer_info->rx_rate;
6789*5113495bSYour Name 	rate_code = peer_info->rx_rate_code;
6790*5113495bSYour Name 
6791*5113495bSYour Name 	if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6792*5113495bSYour Name 			WMI_RATE_PREAMBLE_HT)
6793*5113495bSYour Name 		txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_HT;
6794*5113495bSYour Name 	else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) ==
6795*5113495bSYour Name 			WMI_RATE_PREAMBLE_VHT)
6796*5113495bSYour Name 		txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_VHT;
6797*5113495bSYour Name 	else
6798*5113495bSYour Name 		txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_LEGACY;
6799*5113495bSYour Name 
6800*5113495bSYour Name 	txrx_stats->rx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1;
6801*5113495bSYour Name 	txrx_stats->rx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code);
6802*5113495bSYour Name 
6803*5113495bSYour Name 	flags = hdd_get_rate_flags(txrx_stats->rx_rate.rate / 100,
6804*5113495bSYour Name 				   txrx_stats->rx_rate.mode,
6805*5113495bSYour Name 				   txrx_stats->rx_rate.nss,
6806*5113495bSYour Name 				   txrx_stats->rx_rate.mcs);
6807*5113495bSYour Name 
6808*5113495bSYour Name 	txrx_stats->rx_rate.rate_flags = flags;
6809*5113495bSYour Name 
6810*5113495bSYour Name 	hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x",
6811*5113495bSYour Name 		 txrx_stats->rx_rate.mode,
6812*5113495bSYour Name 		 txrx_stats->rx_rate.nss,
6813*5113495bSYour Name 		 txrx_stats->rx_rate.mcs,
6814*5113495bSYour Name 		 txrx_stats->rx_rate.rate_flags,
6815*5113495bSYour Name 		 flags);
6816*5113495bSYour Name }
6817*5113495bSYour Name 
6818*5113495bSYour Name /**
6819*5113495bSYour Name  * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP
6820*5113495bSYour Name  * @wiphy: pointer to wiphy
6821*5113495bSYour Name  * @dev: pointer to net_device structure
6822*5113495bSYour Name  * @stainfo: request peer station info
6823*5113495bSYour Name  * @sinfo: pointer to station_info struct
6824*5113495bSYour Name  *
6825*5113495bSYour Name  * This function will get remote peer info from fw and fill sinfo struct
6826*5113495bSYour Name  *
6827*5113495bSYour Name  * Return: 0 on success, otherwise error value
6828*5113495bSYour Name  */
wlan_hdd_get_station_remote(struct wiphy * wiphy,struct net_device * dev,struct hdd_station_info * stainfo,struct station_info * sinfo)6829*5113495bSYour Name static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
6830*5113495bSYour Name 				       struct net_device *dev,
6831*5113495bSYour Name 				       struct hdd_station_info *stainfo,
6832*5113495bSYour Name 				       struct station_info *sinfo)
6833*5113495bSYour Name {
6834*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
6835*5113495bSYour Name 	struct hdd_context *hddctx = wiphy_priv(wiphy);
6836*5113495bSYour Name 	struct stats_event *stats;
6837*5113495bSYour Name 	struct hdd_fw_txrx_stats txrx_stats;
6838*5113495bSYour Name 	int i, status;
6839*5113495bSYour Name 
6840*5113495bSYour Name 	stats = wlan_cfg80211_mc_cp_stats_get_peer_stats(adapter->deflink->vdev,
6841*5113495bSYour Name 							 stainfo->sta_mac.bytes,
6842*5113495bSYour Name 							 &status);
6843*5113495bSYour Name 	if (status || !stats) {
6844*5113495bSYour Name 		wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
6845*5113495bSYour Name 		hdd_err("fail to get peer info from fw");
6846*5113495bSYour Name 		return -EPERM;
6847*5113495bSYour Name 	}
6848*5113495bSYour Name 
6849*5113495bSYour Name 	for (i = 0; i < WMI_MAX_CHAINS; i++)
6850*5113495bSYour Name 		stainfo->peer_rssi_per_chain[i] =
6851*5113495bSYour Name 			    stats->peer_stats_info_ext->peer_rssi_per_chain[i];
6852*5113495bSYour Name 
6853*5113495bSYour Name 	qdf_mem_zero(&txrx_stats, sizeof(txrx_stats));
6854*5113495bSYour Name 	txrx_stats.tx_packets = stats->peer_stats_info_ext->tx_packets;
6855*5113495bSYour Name 	txrx_stats.tx_bytes = stats->peer_stats_info_ext->tx_bytes;
6856*5113495bSYour Name 	txrx_stats.rx_packets = stats->peer_stats_info_ext->rx_packets;
6857*5113495bSYour Name 	txrx_stats.rx_bytes = stats->peer_stats_info_ext->rx_bytes;
6858*5113495bSYour Name 	txrx_stats.tx_retries = stats->peer_stats_info_ext->tx_retries;
6859*5113495bSYour Name 	txrx_stats.tx_failed = stats->peer_stats_info_ext->tx_failed;
6860*5113495bSYour Name 	txrx_stats.tx_succeed = stats->peer_stats_info_ext->tx_succeed;
6861*5113495bSYour Name 	txrx_stats.rssi = stats->peer_stats_info_ext->rssi;
6862*5113495bSYour Name 	wlan_hdd_fill_rate_info(&txrx_stats, stats->peer_stats_info_ext);
6863*5113495bSYour Name 	wlan_hdd_fill_station_info(hddctx->psoc, adapter,
6864*5113495bSYour Name 				   sinfo, stainfo, &txrx_stats);
6865*5113495bSYour Name 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
6866*5113495bSYour Name 
6867*5113495bSYour Name 	return status;
6868*5113495bSYour Name }
6869*5113495bSYour Name 
6870*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \
6871*5113495bSYour Name 	defined(WLAN_FEATURE_11AX)
6872*5113495bSYour Name /**
6873*5113495bSYour Name  * hdd_map_he_gi_to_os() - map txrate_gi to os guard interval
6874*5113495bSYour Name  * @guard_interval: guard interval get from fw rate
6875*5113495bSYour Name  *
6876*5113495bSYour Name  * Return: os guard interval value
6877*5113495bSYour Name  */
hdd_map_he_gi_to_os(enum txrate_gi guard_interval)6878*5113495bSYour Name static inline uint8_t hdd_map_he_gi_to_os(enum txrate_gi guard_interval)
6879*5113495bSYour Name {
6880*5113495bSYour Name 	switch (guard_interval) {
6881*5113495bSYour Name 	case TXRATE_GI_0_8_US:
6882*5113495bSYour Name 		return NL80211_RATE_INFO_HE_GI_0_8;
6883*5113495bSYour Name 	case TXRATE_GI_1_6_US:
6884*5113495bSYour Name 		return NL80211_RATE_INFO_HE_GI_1_6;
6885*5113495bSYour Name 	case TXRATE_GI_3_2_US:
6886*5113495bSYour Name 		return NL80211_RATE_INFO_HE_GI_3_2;
6887*5113495bSYour Name 	default:
6888*5113495bSYour Name 		return NL80211_RATE_INFO_HE_GI_0_8;
6889*5113495bSYour Name 	}
6890*5113495bSYour Name }
6891*5113495bSYour Name 
6892*5113495bSYour Name /**
6893*5113495bSYour Name  * wlan_hdd_fill_os_he_rateflags() - Fill HE related rate_info
6894*5113495bSYour Name  * @os_rate: rate info for os
6895*5113495bSYour Name  * @rate_flags: rate flags
6896*5113495bSYour Name  * @dcm: dcm from rate
6897*5113495bSYour Name  * @guard_interval: guard interval from rate
6898*5113495bSYour Name  *
6899*5113495bSYour Name  * Return: none
6900*5113495bSYour Name  */
wlan_hdd_fill_os_he_rateflags(struct rate_info * os_rate,enum tx_rate_info rate_flags,uint8_t dcm,enum txrate_gi guard_interval)6901*5113495bSYour Name static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
6902*5113495bSYour Name 					  enum tx_rate_info rate_flags,
6903*5113495bSYour Name 					  uint8_t dcm,
6904*5113495bSYour Name 					  enum txrate_gi guard_interval)
6905*5113495bSYour Name {
6906*5113495bSYour Name 	/* as fw not yet report ofdma to host, so we doesn't
6907*5113495bSYour Name 	 * fill RATE_INFO_BW_HE_RU.
6908*5113495bSYour Name 	 */
6909*5113495bSYour Name 	if (rate_flags & (TX_RATE_HE80 | TX_RATE_HE40 |
6910*5113495bSYour Name 		TX_RATE_HE20 | TX_RATE_HE160)) {
6911*5113495bSYour Name 		if (rate_flags & TX_RATE_HE160)
6912*5113495bSYour Name 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_160);
6913*5113495bSYour Name 		else if (rate_flags & TX_RATE_HE80)
6914*5113495bSYour Name 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
6915*5113495bSYour Name 		else if (rate_flags & TX_RATE_HE40)
6916*5113495bSYour Name 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
6917*5113495bSYour Name 
6918*5113495bSYour Name 		os_rate->flags |= RATE_INFO_FLAGS_HE_MCS;
6919*5113495bSYour Name 
6920*5113495bSYour Name 		os_rate->he_gi = hdd_map_he_gi_to_os(guard_interval);
6921*5113495bSYour Name 		os_rate->he_dcm = dcm;
6922*5113495bSYour Name 	}
6923*5113495bSYour Name }
6924*5113495bSYour Name #else
wlan_hdd_fill_os_he_rateflags(struct rate_info * os_rate,enum tx_rate_info rate_flags,uint8_t dcm,enum txrate_gi guard_interval)6925*5113495bSYour Name static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
6926*5113495bSYour Name 					  enum tx_rate_info rate_flags,
6927*5113495bSYour Name 					  uint8_t dcm,
6928*5113495bSYour Name 					  enum txrate_gi guard_interval)
6929*5113495bSYour Name {}
6930*5113495bSYour Name #endif
6931*5113495bSYour Name 
6932*5113495bSYour Name /**
6933*5113495bSYour Name  * wlan_hdd_fill_os_rate_info() - Fill os related rate_info
6934*5113495bSYour Name  * @rate_flags: rate flags
6935*5113495bSYour Name  * @legacy_rate: 802.11abg rate
6936*5113495bSYour Name  * @os_rate: rate info for os
6937*5113495bSYour Name  * @mcs_index: mcs
6938*5113495bSYour Name  * @nss: number of spatial streams
6939*5113495bSYour Name  * @dcm: dcm from rate
6940*5113495bSYour Name  * @guard_interval: guard interval from rate
6941*5113495bSYour Name  *
6942*5113495bSYour Name  * Return: none
6943*5113495bSYour Name  */
wlan_hdd_fill_os_rate_info(enum tx_rate_info rate_flags,uint16_t legacy_rate,struct rate_info * os_rate,uint8_t mcs_index,uint8_t nss,uint8_t dcm,enum txrate_gi guard_interval)6944*5113495bSYour Name static void wlan_hdd_fill_os_rate_info(enum tx_rate_info rate_flags,
6945*5113495bSYour Name 				       uint16_t legacy_rate,
6946*5113495bSYour Name 				       struct rate_info *os_rate,
6947*5113495bSYour Name 				       uint8_t mcs_index, uint8_t nss,
6948*5113495bSYour Name 				       uint8_t dcm,
6949*5113495bSYour Name 				       enum txrate_gi guard_interval)
6950*5113495bSYour Name {
6951*5113495bSYour Name 	os_rate->nss = nss;
6952*5113495bSYour Name 	if (rate_flags & TX_RATE_LEGACY) {
6953*5113495bSYour Name 		os_rate->legacy = legacy_rate;
6954*5113495bSYour Name 		hdd_debug("Reporting legacy rate %d", os_rate->legacy);
6955*5113495bSYour Name 		return;
6956*5113495bSYour Name 	}
6957*5113495bSYour Name 
6958*5113495bSYour Name 	/* assume basic BW. anything else will override this later */
6959*5113495bSYour Name 	hdd_set_rate_bw(os_rate, HDD_RATE_BW_20);
6960*5113495bSYour Name 	os_rate->mcs = mcs_index;
6961*5113495bSYour Name 
6962*5113495bSYour Name 	wlan_hdd_fill_os_eht_rateflags(os_rate, rate_flags, dcm,
6963*5113495bSYour Name 				       guard_interval);
6964*5113495bSYour Name 	wlan_hdd_fill_os_he_rateflags(os_rate, rate_flags, dcm, guard_interval);
6965*5113495bSYour Name 
6966*5113495bSYour Name 	if (rate_flags & (TX_RATE_VHT160 | TX_RATE_VHT80 | TX_RATE_VHT40 |
6967*5113495bSYour Name 	    TX_RATE_VHT20)) {
6968*5113495bSYour Name 		if (rate_flags & TX_RATE_VHT160)
6969*5113495bSYour Name 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_160);
6970*5113495bSYour Name 		else if (rate_flags & TX_RATE_VHT80)
6971*5113495bSYour Name 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
6972*5113495bSYour Name 		else if (rate_flags & TX_RATE_VHT40)
6973*5113495bSYour Name 			hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
6974*5113495bSYour Name 		os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
6975*5113495bSYour Name 	}
6976*5113495bSYour Name 
6977*5113495bSYour Name 	if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) {
6978*5113495bSYour Name 		if (rate_flags & TX_RATE_HT40)
6979*5113495bSYour Name 			hdd_set_rate_bw(os_rate,
6980*5113495bSYour Name 					HDD_RATE_BW_40);
6981*5113495bSYour Name 		os_rate->flags |= RATE_INFO_FLAGS_MCS;
6982*5113495bSYour Name 	}
6983*5113495bSYour Name 
6984*5113495bSYour Name 	if (rate_flags & TX_RATE_SGI)
6985*5113495bSYour Name 		os_rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
6986*5113495bSYour Name }
6987*5113495bSYour Name 
hdd_get_max_tx_bitrate(struct wlan_hdd_link_info * link_info)6988*5113495bSYour Name void hdd_get_max_tx_bitrate(struct wlan_hdd_link_info *link_info)
6989*5113495bSYour Name {
6990*5113495bSYour Name 	struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx;
6991*5113495bSYour Name 	struct station_info sinfo;
6992*5113495bSYour Name 	enum tx_rate_info tx_rate_flags;
6993*5113495bSYour Name 	uint8_t tx_mcs_index, tx_nss = 1;
6994*5113495bSYour Name 	uint16_t my_tx_rate;
6995*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx;
6996*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
6997*5113495bSYour Name 
6998*5113495bSYour Name 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
6999*5113495bSYour Name 
7000*5113495bSYour Name 	qdf_mem_zero(&sinfo, sizeof(struct station_info));
7001*5113495bSYour Name 
7002*5113495bSYour Name 	sinfo.signal = link_info->rssi;
7003*5113495bSYour Name 	tx_mcs_index = link_info->hdd_stats.class_a_stat.tx_mcs_index;
7004*5113495bSYour Name 	my_tx_rate = link_info->hdd_stats.class_a_stat.tx_rate;
7005*5113495bSYour Name 	tx_rate_flags = link_info->hdd_stats.class_a_stat.tx_rx_rate_flags;
7006*5113495bSYour Name 
7007*5113495bSYour Name 	if (!(tx_rate_flags & TX_RATE_LEGACY)) {
7008*5113495bSYour Name 		vdev = hdd_objmgr_get_vdev_by_user(link_info,
7009*5113495bSYour Name 						   WLAN_OSIF_STATS_ID);
7010*5113495bSYour Name 		if (vdev) {
7011*5113495bSYour Name 			/*
7012*5113495bSYour Name 			 * Take static NSS for reporting max rates.
7013*5113495bSYour Name 			 * NSS from FW is not reliable as it changes
7014*5113495bSYour Name 			 * as per the environment quality.
7015*5113495bSYour Name 			 */
7016*5113495bSYour Name 			tx_nss = wlan_vdev_mlme_get_nss(vdev);
7017*5113495bSYour Name 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
7018*5113495bSYour Name 		} else {
7019*5113495bSYour Name 			tx_nss = link_info->hdd_stats.class_a_stat.tx_nss;
7020*5113495bSYour Name 		}
7021*5113495bSYour Name 		hdd_check_and_update_nss(hdd_ctx, &tx_nss, NULL);
7022*5113495bSYour Name 
7023*5113495bSYour Name 		if (tx_mcs_index == INVALID_MCS_IDX)
7024*5113495bSYour Name 			tx_mcs_index = 0;
7025*5113495bSYour Name 	}
7026*5113495bSYour Name 
7027*5113495bSYour Name 	if (hdd_report_max_rate(link_info, hdd_ctx->mac_handle, &sinfo.txrate,
7028*5113495bSYour Name 				sinfo.signal, tx_rate_flags, tx_mcs_index,
7029*5113495bSYour Name 				my_tx_rate, tx_nss)) {
7030*5113495bSYour Name 		hdd_sta_ctx->cache_conn_info.max_tx_bitrate = sinfo.txrate;
7031*5113495bSYour Name 		hdd_debug("Reporting max tx rate flags %d mcs %d nss %d bw %d",
7032*5113495bSYour Name 			  sinfo.txrate.flags, sinfo.txrate.mcs,
7033*5113495bSYour Name 			  sinfo.txrate.nss, sinfo.txrate.bw);
7034*5113495bSYour Name 	}
7035*5113495bSYour Name }
7036*5113495bSYour Name 
hdd_report_max_rate(struct wlan_hdd_link_info * link_info,mac_handle_t mac_handle,struct rate_info * rate,int8_t signal,enum tx_rate_info rate_flags,uint8_t mcs_index,uint16_t fw_rate,uint8_t nss)7037*5113495bSYour Name bool hdd_report_max_rate(struct wlan_hdd_link_info *link_info,
7038*5113495bSYour Name 			 mac_handle_t mac_handle,
7039*5113495bSYour Name 			 struct rate_info *rate,
7040*5113495bSYour Name 			 int8_t signal,
7041*5113495bSYour Name 			 enum tx_rate_info rate_flags,
7042*5113495bSYour Name 			 uint8_t mcs_index,
7043*5113495bSYour Name 			 uint16_t fw_rate, uint8_t nss)
7044*5113495bSYour Name {
7045*5113495bSYour Name 	uint8_t i, j, rssidx = 0;
7046*5113495bSYour Name 	uint16_t max_rate = 0;
7047*5113495bSYour Name 	uint32_t vht_mcs_map;
7048*5113495bSYour Name 	bool is_vht20_mcs9 = false;
7049*5113495bSYour Name 	uint16_t he_mcs_12_13_map = 0;
7050*5113495bSYour Name 	uint16_t current_rate = 0;
7051*5113495bSYour Name 	qdf_size_t or_leng;
7052*5113495bSYour Name 	uint8_t operational_rates[CSR_DOT11_SUPPORTED_RATES_MAX];
7053*5113495bSYour Name 	uint8_t extended_rates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
7054*5113495bSYour Name 	qdf_size_t er_leng;
7055*5113495bSYour Name 	uint8_t mcs_rates[SIZE_OF_BASIC_MCS_SET];
7056*5113495bSYour Name 	qdf_size_t mcs_len;
7057*5113495bSYour Name 	struct index_data_rate_type *supported_mcs_rate;
7058*5113495bSYour Name 	enum data_rate_11ac_max_mcs vht_max_mcs;
7059*5113495bSYour Name 	uint8_t max_mcs_idx = 0;
7060*5113495bSYour Name 	uint8_t max_ht_mcs_idx;
7061*5113495bSYour Name 	uint8_t rate_flag = 1;
7062*5113495bSYour Name 	int mode = 0, max_ht_idx;
7063*5113495bSYour Name 	QDF_STATUS stat = QDF_STATUS_E_FAILURE;
7064*5113495bSYour Name 	struct hdd_context *hdd_ctx;
7065*5113495bSYour Name 	int link_speed_rssi_high = 0;
7066*5113495bSYour Name 	int link_speed_rssi_mid = 0;
7067*5113495bSYour Name 	int link_speed_rssi_low = 0;
7068*5113495bSYour Name 	uint32_t link_speed_rssi_report = 0;
7069*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
7070*5113495bSYour Name 
7071*5113495bSYour Name 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
7072*5113495bSYour Name 	if (!hdd_ctx)
7073*5113495bSYour Name 		return false;
7074*5113495bSYour Name 
7075*5113495bSYour Name 	ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
7076*5113495bSYour Name 				       &link_speed_rssi_high,
7077*5113495bSYour Name 				       &link_speed_rssi_mid,
7078*5113495bSYour Name 				       &link_speed_rssi_low,
7079*5113495bSYour Name 				       &link_speed_rssi_report);
7080*5113495bSYour Name 
7081*5113495bSYour Name 	if (ucfg_mlme_stats_is_link_speed_report_max_scaled(hdd_ctx->psoc)) {
7082*5113495bSYour Name 		/* report the max possible speed with RSSI scaling */
7083*5113495bSYour Name 		if (signal >= link_speed_rssi_high) {
7084*5113495bSYour Name 			/* report the max possible speed */
7085*5113495bSYour Name 			rssidx = 0;
7086*5113495bSYour Name 		} else if (signal >= link_speed_rssi_mid) {
7087*5113495bSYour Name 			/* report middle speed */
7088*5113495bSYour Name 			rssidx = 1;
7089*5113495bSYour Name 		} else if (signal >= link_speed_rssi_low) {
7090*5113495bSYour Name 			/* report middle speed */
7091*5113495bSYour Name 			rssidx = 2;
7092*5113495bSYour Name 		} else {
7093*5113495bSYour Name 			/* report actual speed */
7094*5113495bSYour Name 			rssidx = 3;
7095*5113495bSYour Name 		}
7096*5113495bSYour Name 	}
7097*5113495bSYour Name 
7098*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
7099*5113495bSYour Name 	if (!vdev) {
7100*5113495bSYour Name 		hdd_err("failed to get vdev");
7101*5113495bSYour Name 		return false;
7102*5113495bSYour Name 	}
7103*5113495bSYour Name 
7104*5113495bSYour Name 	/* Get Basic Rate Set */
7105*5113495bSYour Name 	or_leng = ucfg_mlme_get_opr_rate(vdev, operational_rates,
7106*5113495bSYour Name 					 sizeof(operational_rates));
7107*5113495bSYour Name 	for (i = 0; i < or_leng; i++) {
7108*5113495bSYour Name 		for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) {
7109*5113495bSYour Name 			/* Validate Rate Set */
7110*5113495bSYour Name 			if (supported_data_rate[j].beacon_rate_index ==
7111*5113495bSYour Name 				(operational_rates[i] & 0x7F)) {
7112*5113495bSYour Name 				current_rate =
7113*5113495bSYour Name 					supported_data_rate[j].
7114*5113495bSYour Name 					supported_rate[rssidx];
7115*5113495bSYour Name 				break;
7116*5113495bSYour Name 			}
7117*5113495bSYour Name 		}
7118*5113495bSYour Name 		/* Update MAX rate */
7119*5113495bSYour Name 		max_rate = (current_rate > max_rate) ? current_rate : max_rate;
7120*5113495bSYour Name 	}
7121*5113495bSYour Name 
7122*5113495bSYour Name 	/* Get Extended Rate Set */
7123*5113495bSYour Name 	er_leng = ucfg_mlme_get_ext_opr_rate(vdev, extended_rates,
7124*5113495bSYour Name 					     sizeof(extended_rates));
7125*5113495bSYour Name 	he_mcs_12_13_map = wlan_vdev_mlme_get_he_mcs_12_13_map(vdev);
7126*5113495bSYour Name 
7127*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
7128*5113495bSYour Name 	for (i = 0; i < er_leng; i++) {
7129*5113495bSYour Name 		for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) {
7130*5113495bSYour Name 			if (supported_data_rate[j].beacon_rate_index ==
7131*5113495bSYour Name 			    (extended_rates[i] & 0x7F)) {
7132*5113495bSYour Name 				current_rate = supported_data_rate[j].
7133*5113495bSYour Name 					       supported_rate[rssidx];
7134*5113495bSYour Name 				break;
7135*5113495bSYour Name 			}
7136*5113495bSYour Name 		}
7137*5113495bSYour Name 		/* Update MAX rate */
7138*5113495bSYour Name 		max_rate = (current_rate > max_rate) ? current_rate : max_rate;
7139*5113495bSYour Name 	}
7140*5113495bSYour Name 	/* Get MCS Rate Set --
7141*5113495bSYour Name 	 * Only if we are connected in non legacy mode and not reporting
7142*5113495bSYour Name 	 * actual speed
7143*5113495bSYour Name 	 */
7144*5113495bSYour Name 	if ((3 != rssidx) && !(rate_flags & TX_RATE_LEGACY)) {
7145*5113495bSYour Name 		rate_flag = 0;
7146*5113495bSYour Name 		if (rate_flags & (TX_RATE_VHT80 | TX_RATE_HE80 |
7147*5113495bSYour Name 				TX_RATE_HE160 | TX_RATE_VHT160 |
7148*5113495bSYour Name 				TX_RATE_EHT80 | TX_RATE_EHT160 |
7149*5113495bSYour Name 				TX_RATE_EHT320))
7150*5113495bSYour Name 			mode = 2;
7151*5113495bSYour Name 		else if (rate_flags & (TX_RATE_HT40 |
7152*5113495bSYour Name 			 TX_RATE_VHT40 | TX_RATE_HE40 | TX_RATE_EHT40))
7153*5113495bSYour Name 			mode = 1;
7154*5113495bSYour Name 		else
7155*5113495bSYour Name 			mode = 0;
7156*5113495bSYour Name 
7157*5113495bSYour Name 		if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 |
7158*5113495bSYour Name 		    TX_RATE_VHT80 | TX_RATE_HE20 | TX_RATE_HE40 |
7159*5113495bSYour Name 		    TX_RATE_HE80 | TX_RATE_HE160 | TX_RATE_VHT160 |
7160*5113495bSYour Name 		    TX_RATE_EHT20 | TX_RATE_EHT40 | TX_RATE_EHT80 |
7161*5113495bSYour Name 		    TX_RATE_EHT160 | TX_RATE_EHT320)) {
7162*5113495bSYour Name 			stat = ucfg_mlme_cfg_get_vht_tx_mcs_map(hdd_ctx->psoc,
7163*5113495bSYour Name 								&vht_mcs_map);
7164*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(stat))
7165*5113495bSYour Name 				hdd_err("failed to get tx_mcs_map");
7166*5113495bSYour Name 
7167*5113495bSYour Name 			stat = ucfg_mlme_get_vht20_mcs9(hdd_ctx->psoc,
7168*5113495bSYour Name 							&is_vht20_mcs9);
7169*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(stat))
7170*5113495bSYour Name 				hdd_err("Failed to get VHT20 MCS9 enable val");
7171*5113495bSYour Name 
7172*5113495bSYour Name 			vht_max_mcs = (enum data_rate_11ac_max_mcs)
7173*5113495bSYour Name 				(vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
7174*5113495bSYour Name 			if (rate_flags & TX_RATE_SGI)
7175*5113495bSYour Name 				rate_flag |= 1;
7176*5113495bSYour Name 
7177*5113495bSYour Name 			if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs) {
7178*5113495bSYour Name 				max_mcs_idx = 7;
7179*5113495bSYour Name 			} else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs) {
7180*5113495bSYour Name 				max_mcs_idx = 8;
7181*5113495bSYour Name 			} else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs) {
7182*5113495bSYour Name 				/*
7183*5113495bSYour Name 				 * If the ini enable_vht20_mcs9 is disabled,
7184*5113495bSYour Name 				 * then max mcs index should not be set to 9
7185*5113495bSYour Name 				 * for TX_RATE_VHT20
7186*5113495bSYour Name 				 */
7187*5113495bSYour Name 				if (!is_vht20_mcs9 &&
7188*5113495bSYour Name 				    (rate_flags & TX_RATE_VHT20))
7189*5113495bSYour Name 					max_mcs_idx = 8;
7190*5113495bSYour Name 				else
7191*5113495bSYour Name 					max_mcs_idx = 9;
7192*5113495bSYour Name 			}
7193*5113495bSYour Name 
7194*5113495bSYour Name 			if (rate_flags & (TX_RATE_EHT20 | TX_RATE_EHT40 |
7195*5113495bSYour Name 			    TX_RATE_EHT80 | TX_RATE_EHT160 | TX_RATE_EHT320))
7196*5113495bSYour Name 				max_mcs_idx = 13;
7197*5113495bSYour Name 
7198*5113495bSYour Name 			if (rate_flags & (TX_RATE_HE20 | TX_RATE_HE40 |
7199*5113495bSYour Name 			    TX_RATE_HE80 | TX_RATE_HE160)) {
7200*5113495bSYour Name 				max_mcs_idx = 11;
7201*5113495bSYour Name 				if (he_mcs_12_13_map)
7202*5113495bSYour Name 					max_mcs_idx = 13;
7203*5113495bSYour Name 			}
7204*5113495bSYour Name 
7205*5113495bSYour Name 			if (rssidx != 0) {
7206*5113495bSYour Name 				for (i = 0; i <= max_mcs_idx; i++) {
7207*5113495bSYour Name 					if (signal <= rssi_mcs_tbl[mode][i]) {
7208*5113495bSYour Name 						max_mcs_idx = i;
7209*5113495bSYour Name 						break;
7210*5113495bSYour Name 					}
7211*5113495bSYour Name 				}
7212*5113495bSYour Name 			}
7213*5113495bSYour Name 
7214*5113495bSYour Name 			max_mcs_idx = (max_mcs_idx > mcs_index) ?
7215*5113495bSYour Name 				max_mcs_idx : mcs_index;
7216*5113495bSYour Name 		} else {
7217*5113495bSYour Name 			mcs_len = ucfg_mlme_get_mcs_rate(link_info->vdev,
7218*5113495bSYour Name 							 mcs_rates,
7219*5113495bSYour Name 							 sizeof(mcs_rates));
7220*5113495bSYour Name 			if (!mcs_len) {
7221*5113495bSYour Name 				hdd_err("Failed to get current mcs rate set");
7222*5113495bSYour Name 				/*To keep GUI happy */
7223*5113495bSYour Name 				return false;
7224*5113495bSYour Name 			}
7225*5113495bSYour Name 
7226*5113495bSYour Name 			if (rate_flags & TX_RATE_HT40)
7227*5113495bSYour Name 				rate_flag |= 1;
7228*5113495bSYour Name 			if (rate_flags & TX_RATE_SGI)
7229*5113495bSYour Name 				rate_flag |= 2;
7230*5113495bSYour Name 
7231*5113495bSYour Name 			supported_mcs_rate =
7232*5113495bSYour Name 				(struct index_data_rate_type *)
7233*5113495bSYour Name 				((nss == 1) ? &supported_mcs_rate_nss1 :
7234*5113495bSYour Name 				 &supported_mcs_rate_nss2);
7235*5113495bSYour Name 			max_ht_mcs_idx =
7236*5113495bSYour Name 				QDF_ARRAY_SIZE(supported_mcs_rate_nss1);
7237*5113495bSYour Name 			max_ht_idx = max_ht_mcs_idx;
7238*5113495bSYour Name 			if (rssidx != 0) {
7239*5113495bSYour Name 				for (i = 0; i < max_ht_mcs_idx; i++) {
7240*5113495bSYour Name 					if (signal <= rssi_mcs_tbl[mode][i]) {
7241*5113495bSYour Name 						max_ht_idx = i + 1;
7242*5113495bSYour Name 						break;
7243*5113495bSYour Name 					}
7244*5113495bSYour Name 				}
7245*5113495bSYour Name 			}
7246*5113495bSYour Name 
7247*5113495bSYour Name 			for (i = 0; i < mcs_len; i++) {
7248*5113495bSYour Name 				for (j = 0; j < max_ht_idx; j++) {
7249*5113495bSYour Name 					if (supported_mcs_rate[j].
7250*5113495bSYour Name 						beacon_rate_index ==
7251*5113495bSYour Name 						mcs_rates[i]) {
7252*5113495bSYour Name 						current_rate =
7253*5113495bSYour Name 						  supported_mcs_rate[j].
7254*5113495bSYour Name 						  supported_rate
7255*5113495bSYour Name 						  [rate_flag];
7256*5113495bSYour Name 						max_mcs_idx =
7257*5113495bSYour Name 						  supported_mcs_rate[j].
7258*5113495bSYour Name 						  beacon_rate_index;
7259*5113495bSYour Name 						break;
7260*5113495bSYour Name 					}
7261*5113495bSYour Name 				}
7262*5113495bSYour Name 
7263*5113495bSYour Name 				if ((j < max_ht_mcs_idx) &&
7264*5113495bSYour Name 				    (current_rate > max_rate))
7265*5113495bSYour Name 					max_rate = current_rate;
7266*5113495bSYour Name 			}
7267*5113495bSYour Name 
7268*5113495bSYour Name 			if (nss == 2)
7269*5113495bSYour Name 				max_mcs_idx += max_ht_mcs_idx;
7270*5113495bSYour Name 			max_mcs_idx = (max_mcs_idx > mcs_index) ?
7271*5113495bSYour Name 				max_mcs_idx : mcs_index;
7272*5113495bSYour Name 		}
7273*5113495bSYour Name 	}
7274*5113495bSYour Name 
7275*5113495bSYour Name 	else if (!(rate_flags & TX_RATE_LEGACY)) {
7276*5113495bSYour Name 		max_rate = fw_rate;
7277*5113495bSYour Name 		max_mcs_idx = mcs_index;
7278*5113495bSYour Name 	}
7279*5113495bSYour Name 	/* report a value at least as big as current rate */
7280*5113495bSYour Name 	if ((max_rate < fw_rate) || (0 == max_rate)) {
7281*5113495bSYour Name 		max_rate = fw_rate;
7282*5113495bSYour Name 	}
7283*5113495bSYour Name 	hdd_debug("RLMS %u, rate_flags 0x%x, max_rate %d mcs %d nss %d",
7284*5113495bSYour Name 		  link_speed_rssi_report, rate_flags,
7285*5113495bSYour Name 		  max_rate, max_mcs_idx, nss);
7286*5113495bSYour Name 	wlan_hdd_fill_os_rate_info(rate_flags, max_rate, rate,
7287*5113495bSYour Name 				   max_mcs_idx, nss, 0, 0);
7288*5113495bSYour Name 
7289*5113495bSYour Name 	return true;
7290*5113495bSYour Name }
7291*5113495bSYour Name 
7292*5113495bSYour Name /**
7293*5113495bSYour Name  * hdd_report_actual_rate() - Fill the actual rate stats.
7294*5113495bSYour Name  * @rate_flags: The rate flags computed from rate
7295*5113495bSYour Name  * @my_rate: The rate from fw stats
7296*5113495bSYour Name  * @rate: The station_info struct member struct rate_info to be filled
7297*5113495bSYour Name  * @mcs_index: The mcs index computed from rate
7298*5113495bSYour Name  * @nss: The NSS from fw stats
7299*5113495bSYour Name  * @dcm: the dcm computed from rate
7300*5113495bSYour Name  * @guard_interval: the guard interval computed from rate
7301*5113495bSYour Name  *
7302*5113495bSYour Name  * Return: None
7303*5113495bSYour Name  */
hdd_report_actual_rate(enum tx_rate_info rate_flags,uint16_t my_rate,struct rate_info * rate,uint8_t mcs_index,uint8_t nss,uint8_t dcm,enum txrate_gi guard_interval)7304*5113495bSYour Name static void hdd_report_actual_rate(enum tx_rate_info rate_flags,
7305*5113495bSYour Name 				   uint16_t my_rate,
7306*5113495bSYour Name 				   struct rate_info *rate, uint8_t mcs_index,
7307*5113495bSYour Name 				   uint8_t nss, uint8_t dcm,
7308*5113495bSYour Name 				   enum txrate_gi guard_interval)
7309*5113495bSYour Name {
7310*5113495bSYour Name 	/* report current rate instead of max rate */
7311*5113495bSYour Name 	wlan_hdd_fill_os_rate_info(rate_flags, my_rate, rate,
7312*5113495bSYour Name 				   mcs_index, nss, dcm, guard_interval);
7313*5113495bSYour Name }
7314*5113495bSYour Name 
7315*5113495bSYour Name /**
7316*5113495bSYour Name  * hdd_wlan_fill_per_chain_rssi_stats() - Fill per chain rssi stats
7317*5113495bSYour Name  *
7318*5113495bSYour Name  * @sinfo: The station_info structure to be filled.
7319*5113495bSYour Name  * @link_info: pointer to link_info struct in adapter
7320*5113495bSYour Name  *
7321*5113495bSYour Name  * Return: None
7322*5113495bSYour Name  */
7323*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
7324*5113495bSYour Name static void
hdd_wlan_fill_per_chain_rssi_stats(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)7325*5113495bSYour Name hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
7326*5113495bSYour Name 				   struct wlan_hdd_link_info *link_info)
7327*5113495bSYour Name {
7328*5113495bSYour Name 	bool rssi_stats_valid = false;
7329*5113495bSYour Name 	uint8_t i;
7330*5113495bSYour Name 
7331*5113495bSYour Name 	sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM;
7332*5113495bSYour Name 	for (i = 0; i < NUM_CHAINS_MAX; i++) {
7333*5113495bSYour Name 		sinfo->chain_signal_avg[i] =
7334*5113495bSYour Name 			   link_info->hdd_stats.per_chain_rssi_stats.rssi[i];
7335*5113495bSYour Name 		sinfo->chains |= 1 << i;
7336*5113495bSYour Name 		if (sinfo->chain_signal_avg[i] > sinfo->signal_avg &&
7337*5113495bSYour Name 		    sinfo->chain_signal_avg[i] != 0)
7338*5113495bSYour Name 			sinfo->signal_avg = sinfo->chain_signal_avg[i];
7339*5113495bSYour Name 
7340*5113495bSYour Name 		hdd_debug("RSSI for chain %d, vdev_id %d is %d",
7341*5113495bSYour Name 			  i, link_info->vdev_id, sinfo->chain_signal_avg[i]);
7342*5113495bSYour Name 
7343*5113495bSYour Name 		if (!rssi_stats_valid && sinfo->chain_signal_avg[i])
7344*5113495bSYour Name 			rssi_stats_valid = true;
7345*5113495bSYour Name 	}
7346*5113495bSYour Name 
7347*5113495bSYour Name 	if (rssi_stats_valid) {
7348*5113495bSYour Name 		sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG;
7349*5113495bSYour Name 		sinfo->filled |= HDD_INFO_SIGNAL_AVG;
7350*5113495bSYour Name 	}
7351*5113495bSYour Name }
7352*5113495bSYour Name #else
7353*5113495bSYour Name static inline void
hdd_wlan_fill_per_chain_rssi_stats(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)7354*5113495bSYour Name hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
7355*5113495bSYour Name 				   struct wlan_hdd_link_info *link_info)
7356*5113495bSYour Name {
7357*5113495bSYour Name }
7358*5113495bSYour Name #endif
7359*5113495bSYour Name 
7360*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) || \
7361*5113495bSYour Name 	defined(CFG80211_RX_FCS_ERROR_REPORTING_SUPPORT)
hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7362*5113495bSYour Name static void hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info *link_info,
7363*5113495bSYour Name 					struct station_info *sinfo)
7364*5113495bSYour Name {
7365*5113495bSYour Name 	sinfo->rx_mpdu_count = link_info->hdd_stats.peer_stats.rx_count;
7366*5113495bSYour Name 	sinfo->fcs_err_count = link_info->hdd_stats.peer_stats.fcs_count;
7367*5113495bSYour Name 	hdd_debug("RX mpdu count %d fcs_err_count %d",
7368*5113495bSYour Name 		  sinfo->rx_mpdu_count, sinfo->fcs_err_count);
7369*5113495bSYour Name 	sinfo->filled |= HDD_INFO_FCS_ERROR_COUNT | HDD_INFO_RX_MPDUS;
7370*5113495bSYour Name }
7371*5113495bSYour Name #else
hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7372*5113495bSYour Name static void hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info *link_info,
7373*5113495bSYour Name 					struct station_info *sinfo)
7374*5113495bSYour Name {
7375*5113495bSYour Name }
7376*5113495bSYour Name #endif
7377*5113495bSYour Name 
hdd_check_and_update_nss(struct hdd_context * hdd_ctx,uint8_t * tx_nss,uint8_t * rx_nss)7378*5113495bSYour Name void hdd_check_and_update_nss(struct hdd_context *hdd_ctx,
7379*5113495bSYour Name 			      uint8_t *tx_nss, uint8_t *rx_nss)
7380*5113495bSYour Name {
7381*5113495bSYour Name 	if (tx_nss && (*tx_nss > 1) &&
7382*5113495bSYour Name 	    policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
7383*5113495bSYour Name 	    !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
7384*5113495bSYour Name 		hdd_debug("Hw mode is DBS, Reduce tx nss(%d) to 1", *tx_nss);
7385*5113495bSYour Name 		(*tx_nss)--;
7386*5113495bSYour Name 	}
7387*5113495bSYour Name 
7388*5113495bSYour Name 	if (rx_nss && (*rx_nss > 1) &&
7389*5113495bSYour Name 	    policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) &&
7390*5113495bSYour Name 	    !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) {
7391*5113495bSYour Name 		hdd_debug("Hw mode is DBS, Reduce rx nss(%d) to 1", *rx_nss);
7392*5113495bSYour Name 		(*rx_nss)--;
7393*5113495bSYour Name 	}
7394*5113495bSYour Name }
7395*5113495bSYour Name 
7396*5113495bSYour Name #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER
7397*5113495bSYour Name static void
wlan_hdd_refill_os_bw(struct rate_info * os_rate,enum rx_tlv_bw bw)7398*5113495bSYour Name wlan_hdd_refill_os_bw(struct rate_info *os_rate, enum rx_tlv_bw bw)
7399*5113495bSYour Name {
7400*5113495bSYour Name 	if (bw == RX_TLV_BW_20MHZ)
7401*5113495bSYour Name 		os_rate->bw = RATE_INFO_BW_20;
7402*5113495bSYour Name 	else if (bw == RX_TLV_BW_40MHZ)
7403*5113495bSYour Name 		os_rate->bw = RATE_INFO_BW_40;
7404*5113495bSYour Name 	else if (bw == RX_TLV_BW_80MHZ)
7405*5113495bSYour Name 		os_rate->bw = RATE_INFO_BW_80;
7406*5113495bSYour Name 	else if (bw == RX_TLV_BW_160MHZ)
7407*5113495bSYour Name 		os_rate->bw = RATE_INFO_BW_160;
7408*5113495bSYour Name 	else
7409*5113495bSYour Name 		wlan_hdd_refill_os_eht_bw(os_rate, bw);
7410*5113495bSYour Name }
7411*5113495bSYour Name 
7412*5113495bSYour Name static void
wlan_hdd_refill_os_rateflags(struct rate_info * os_rate,uint8_t preamble)7413*5113495bSYour Name wlan_hdd_refill_os_rateflags(struct rate_info *os_rate, uint8_t preamble)
7414*5113495bSYour Name {
7415*5113495bSYour Name 	if (preamble == DOT11_N)
7416*5113495bSYour Name 		os_rate->flags |= RATE_INFO_FLAGS_MCS;
7417*5113495bSYour Name 	else if (preamble == DOT11_AC)
7418*5113495bSYour Name 		os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
7419*5113495bSYour Name 	else if (preamble == DOT11_AX)
7420*5113495bSYour Name 		os_rate->flags |= RATE_INFO_FLAGS_HE_MCS;
7421*5113495bSYour Name 	else
7422*5113495bSYour Name 		wlan_hdd_refill_os_eht_rateflags(os_rate, preamble);
7423*5113495bSYour Name }
7424*5113495bSYour Name 
7425*5113495bSYour Name /**
7426*5113495bSYour Name  * wlan_hdd_refill_actual_rate() - Refill actual rates info stats
7427*5113495bSYour Name  * @sinfo: kernel station_info struct to populate
7428*5113495bSYour Name  * @link_info: pointer to link_info struct in adapter,
7429*5113495bSYour Name  *             where hdd_stats is located in this struct
7430*5113495bSYour Name  *
7431*5113495bSYour Name  * This function is to replace RX rates which was previously filled by fw.
7432*5113495bSYour Name  *
7433*5113495bSYour Name  * Return: None
7434*5113495bSYour Name  */
7435*5113495bSYour Name static void
wlan_hdd_refill_actual_rate(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)7436*5113495bSYour Name wlan_hdd_refill_actual_rate(struct station_info *sinfo,
7437*5113495bSYour Name 			    struct wlan_hdd_link_info *link_info)
7438*5113495bSYour Name {
7439*5113495bSYour Name 	uint8_t preamble = link_info->hdd_stats.class_a_stat.rx_preamble;
7440*5113495bSYour Name 
7441*5113495bSYour Name 	sinfo->rxrate.nss = link_info->hdd_stats.class_a_stat.rx_nss;
7442*5113495bSYour Name 	if (preamble == DOT11_A || preamble == DOT11_B) {
7443*5113495bSYour Name 		/* Clear rxrate which may have been set previously */
7444*5113495bSYour Name 		qdf_mem_zero(&sinfo->rxrate, sizeof(sinfo->rxrate));
7445*5113495bSYour Name 		sinfo->rxrate.legacy =
7446*5113495bSYour Name 			link_info->hdd_stats.class_a_stat.rx_rate;
7447*5113495bSYour Name 		hdd_debug("Reporting legacy rate %d", sinfo->rxrate.legacy);
7448*5113495bSYour Name 		return;
7449*5113495bSYour Name 	} else if (qdf_unlikely(preamble == INVALID_PREAMBLE)) {
7450*5113495bSYour Name 		/*
7451*5113495bSYour Name 		 * If preamble is invalid, it means that DP has not received
7452*5113495bSYour Name 		 * a data frame since assoc or roaming so there is no rates.
7453*5113495bSYour Name 		 * In this case, using FW rates which was set previously.
7454*5113495bSYour Name 		 */
7455*5113495bSYour Name 		hdd_debug("Driver failed to get rate, reporting FW rate");
7456*5113495bSYour Name 		return;
7457*5113495bSYour Name 	}
7458*5113495bSYour Name 
7459*5113495bSYour Name 	wlan_hdd_refill_os_rateflags(&sinfo->rxrate, preamble);
7460*5113495bSYour Name 
7461*5113495bSYour Name 	sinfo->rxrate.mcs = link_info->hdd_stats.class_a_stat.rx_mcs_index;
7462*5113495bSYour Name 
7463*5113495bSYour Name 	wlan_hdd_refill_os_bw(&sinfo->rxrate,
7464*5113495bSYour Name 			      link_info->hdd_stats.class_a_stat.rx_bw);
7465*5113495bSYour Name 	/* Fill out gi and dcm in HE mode */
7466*5113495bSYour Name 	sinfo->rxrate.he_gi =
7467*5113495bSYour Name 		hdd_map_he_gi_to_os(link_info->hdd_stats.class_a_stat.rx_gi);
7468*5113495bSYour Name 	sinfo->rxrate.he_dcm = 0;
7469*5113495bSYour Name 
7470*5113495bSYour Name 	if (link_info->hdd_stats.class_a_stat.rx_gi == TXRATE_GI_0_4_US)
7471*5113495bSYour Name 		sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
7472*5113495bSYour Name 
7473*5113495bSYour Name 	hdd_debug("sgi=%d, preamble=%d, bw=%d, mcs=%d, nss=%d, rate_flag=0x%x",
7474*5113495bSYour Name 		  link_info->hdd_stats.class_a_stat.rx_gi, preamble,
7475*5113495bSYour Name 		  link_info->hdd_stats.class_a_stat.rx_bw,
7476*5113495bSYour Name 		  link_info->hdd_stats.class_a_stat.rx_mcs_index,
7477*5113495bSYour Name 		  link_info->hdd_stats.class_a_stat.rx_nss,
7478*5113495bSYour Name 		  sinfo->rxrate.flags);
7479*5113495bSYour Name }
7480*5113495bSYour Name #else
7481*5113495bSYour Name static inline void
wlan_hdd_refill_actual_rate(struct station_info * sinfo,struct wlan_hdd_link_info * link_info)7482*5113495bSYour Name wlan_hdd_refill_actual_rate(struct station_info *sinfo,
7483*5113495bSYour Name 			    struct wlan_hdd_link_info *link_info)
7484*5113495bSYour Name {
7485*5113495bSYour Name }
7486*5113495bSYour Name #endif
7487*5113495bSYour Name 
wlan_hdd_update_rssi(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7488*5113495bSYour Name static void wlan_hdd_update_rssi(struct wlan_hdd_link_info *link_info,
7489*5113495bSYour Name 				 struct station_info *sinfo)
7490*5113495bSYour Name {
7491*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
7492*5113495bSYour Name 	int8_t snr;
7493*5113495bSYour Name 	mac_handle_t mac_handle;
7494*5113495bSYour Name 
7495*5113495bSYour Name 	mac_handle = hdd_adapter_get_mac_handle(link_info->adapter);
7496*5113495bSYour Name 	if (!mac_handle) {
7497*5113495bSYour Name 		hdd_err("mac ctx NULL");
7498*5113495bSYour Name 		return;
7499*5113495bSYour Name 	}
7500*5113495bSYour Name 
7501*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7502*5113495bSYour Name 	link_info->rssi = link_info->hdd_stats.summary_stat.rssi;
7503*5113495bSYour Name 	link_info->snr = link_info->hdd_stats.summary_stat.snr;
7504*5113495bSYour Name 	snr = link_info->snr;
7505*5113495bSYour Name 
7506*5113495bSYour Name 	/* for new connection there might be no valid previous RSSI */
7507*5113495bSYour Name 	if (!link_info->rssi) {
7508*5113495bSYour Name 		hdd_get_rssi_snr_by_bssid(mac_handle,
7509*5113495bSYour Name 					  sta_ctx->conn_info.bssid.bytes,
7510*5113495bSYour Name 					  &link_info->rssi, &snr);
7511*5113495bSYour Name 	}
7512*5113495bSYour Name 
7513*5113495bSYour Name 	/* If RSSi is reported as positive then it is invalid */
7514*5113495bSYour Name 	if (link_info->rssi >= 0) {
7515*5113495bSYour Name 		hdd_debug_rl("Invalid RSSI %d, reset to -1", link_info->rssi);
7516*5113495bSYour Name 		link_info->rssi = -1;
7517*5113495bSYour Name 		link_info->hdd_stats.summary_stat.rssi = -1;
7518*5113495bSYour Name 	}
7519*5113495bSYour Name 
7520*5113495bSYour Name 	sinfo->signal = link_info->rssi;
7521*5113495bSYour Name 	hdd_debug("snr: %d, rssi: %d",
7522*5113495bSYour Name 		  link_info->hdd_stats.summary_stat.snr,
7523*5113495bSYour Name 		  link_info->hdd_stats.summary_stat.rssi);
7524*5113495bSYour Name 	sta_ctx->conn_info.signal = sinfo->signal;
7525*5113495bSYour Name 	sta_ctx->conn_info.noise = sta_ctx->conn_info.signal - snr;
7526*5113495bSYour Name 	sta_ctx->cache_conn_info.signal = sinfo->signal;
7527*5113495bSYour Name 	sta_ctx->cache_conn_info.noise = sta_ctx->conn_info.noise;
7528*5113495bSYour Name 	sinfo->filled |= HDD_INFO_SIGNAL;
7529*5113495bSYour Name }
7530*5113495bSYour Name 
7531*5113495bSYour Name static void
wlan_hdd_update_mlo_peer_stats(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7532*5113495bSYour Name wlan_hdd_update_mlo_peer_stats(struct wlan_hdd_link_info *link_info,
7533*5113495bSYour Name 			       struct station_info *sinfo)
7534*5113495bSYour Name {
7535*5113495bSYour Name 	ol_txrx_soc_handle soc;
7536*5113495bSYour Name 	uint8_t *peer_mac;
7537*5113495bSYour Name 	struct cdp_peer_stats *peer_stats;
7538*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
7539*5113495bSYour Name 
7540*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx)) {
7541*5113495bSYour Name 		hdd_err("invalid hdd_ctx");
7542*5113495bSYour Name 		return;
7543*5113495bSYour Name 	}
7544*5113495bSYour Name 
7545*5113495bSYour Name 	soc = cds_get_context(QDF_MODULE_ID_SOC);
7546*5113495bSYour Name 	peer_mac = link_info->session.station.conn_info.bssid.bytes;
7547*5113495bSYour Name 
7548*5113495bSYour Name 	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx))
7549*5113495bSYour Name 		return;
7550*5113495bSYour Name 
7551*5113495bSYour Name 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
7552*5113495bSYour Name 	if (!peer_stats) {
7553*5113495bSYour Name 		hdd_err("Failed to allocated memory for peer_stats");
7554*5113495bSYour Name 		return;
7555*5113495bSYour Name 	}
7556*5113495bSYour Name 
7557*5113495bSYour Name 	ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
7558*5113495bSYour Name 					peer_mac, peer_stats,
7559*5113495bSYour Name 					CDP_WILD_PEER_TYPE,
7560*5113495bSYour Name 					WLAN_MAX_MLD);
7561*5113495bSYour Name 
7562*5113495bSYour Name 	sinfo->tx_bytes = peer_stats->tx.tx_success.bytes;
7563*5113495bSYour Name 	sinfo->rx_bytes = peer_stats->rx.rcvd.bytes;
7564*5113495bSYour Name 	sinfo->rx_packets = peer_stats->rx.rcvd.num;
7565*5113495bSYour Name 
7566*5113495bSYour Name 	hdd_nofl_debug("Updated sinfo with per peer stats");
7567*5113495bSYour Name 	qdf_mem_free(peer_stats);
7568*5113495bSYour Name }
7569*5113495bSYour Name 
wlan_hdd_update_rate_info(struct wlan_hdd_link_info * link_info,struct station_info * sinfo)7570*5113495bSYour Name static int wlan_hdd_update_rate_info(struct wlan_hdd_link_info *link_info,
7571*5113495bSYour Name 				     struct station_info *sinfo)
7572*5113495bSYour Name {
7573*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
7574*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
7575*5113495bSYour Name 	mac_handle_t mac_handle;
7576*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
7577*5113495bSYour Name 	enum tx_rate_info rate_flags, tx_rate_flags, rx_rate_flags;
7578*5113495bSYour Name 	enum txrate_gi tx_gi, rx_gi;
7579*5113495bSYour Name 	uint32_t link_speed_rssi_report = 0;
7580*5113495bSYour Name 	int link_speed_rssi_high = 0;
7581*5113495bSYour Name 	int link_speed_rssi_mid = 0;
7582*5113495bSYour Name 	int link_speed_rssi_low = 0;
7583*5113495bSYour Name 	uint16_t my_tx_rate, my_rx_rate;
7584*5113495bSYour Name 	uint8_t tx_mcs_index, rx_mcs_index;
7585*5113495bSYour Name 	uint8_t tx_nss = 1, rx_nss = 1, tx_dcm, rx_dcm;
7586*5113495bSYour Name 	qdf_net_dev_stats stats = {0};
7587*5113495bSYour Name 	struct hdd_stats *hdd_stats;
7588*5113495bSYour Name 
7589*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7590*5113495bSYour Name 	ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc,
7591*5113495bSYour Name 				       &link_speed_rssi_high,
7592*5113495bSYour Name 				       &link_speed_rssi_mid,
7593*5113495bSYour Name 				       &link_speed_rssi_low,
7594*5113495bSYour Name 				       &link_speed_rssi_report);
7595*5113495bSYour Name 
7596*5113495bSYour Name 	hdd_stats = &link_info->hdd_stats;
7597*5113495bSYour Name 	rate_flags = hdd_stats->class_a_stat.tx_rx_rate_flags;
7598*5113495bSYour Name 	tx_rate_flags = rx_rate_flags = rate_flags;
7599*5113495bSYour Name 
7600*5113495bSYour Name 	tx_mcs_index = hdd_stats->class_a_stat.tx_mcs_index;
7601*5113495bSYour Name 	rx_mcs_index = hdd_stats->class_a_stat.rx_mcs_index;
7602*5113495bSYour Name 	mac_handle = hdd_ctx->mac_handle;
7603*5113495bSYour Name 
7604*5113495bSYour Name 	/* convert to the UI units of 100kbps */
7605*5113495bSYour Name 	my_tx_rate = hdd_stats->class_a_stat.tx_rate;
7606*5113495bSYour Name 	my_rx_rate = hdd_stats->class_a_stat.rx_rate;
7607*5113495bSYour Name 
7608*5113495bSYour Name 	tx_dcm = hdd_stats->class_a_stat.tx_dcm;
7609*5113495bSYour Name 	rx_dcm = hdd_stats->class_a_stat.rx_dcm;
7610*5113495bSYour Name 	tx_gi = hdd_stats->class_a_stat.tx_gi;
7611*5113495bSYour Name 	rx_gi = hdd_stats->class_a_stat.rx_gi;
7612*5113495bSYour Name 
7613*5113495bSYour Name 	if (!(rate_flags & TX_RATE_LEGACY)) {
7614*5113495bSYour Name 		tx_nss = hdd_stats->class_a_stat.tx_nss;
7615*5113495bSYour Name 		rx_nss = hdd_stats->class_a_stat.rx_nss;
7616*5113495bSYour Name 
7617*5113495bSYour Name 		hdd_check_and_update_nss(hdd_ctx, &tx_nss, &rx_nss);
7618*5113495bSYour Name 
7619*5113495bSYour Name 		if (ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) {
7620*5113495bSYour Name 			/* Get current rate flags if report actual */
7621*5113495bSYour Name 			/* WMA fails to find mcs_index for legacy tx rates */
7622*5113495bSYour Name 			if (tx_mcs_index == INVALID_MCS_IDX && my_tx_rate)
7623*5113495bSYour Name 				tx_rate_flags = TX_RATE_LEGACY;
7624*5113495bSYour Name 			else
7625*5113495bSYour Name 				tx_rate_flags =
7626*5113495bSYour Name 				    hdd_stats->class_a_stat.tx_mcs_rate_flags;
7627*5113495bSYour Name 
7628*5113495bSYour Name 			if (rx_mcs_index == INVALID_MCS_IDX && my_rx_rate)
7629*5113495bSYour Name 				rx_rate_flags = TX_RATE_LEGACY;
7630*5113495bSYour Name 			else
7631*5113495bSYour Name 				rx_rate_flags =
7632*5113495bSYour Name 				    hdd_stats->class_a_stat.rx_mcs_rate_flags;
7633*5113495bSYour Name 		}
7634*5113495bSYour Name 
7635*5113495bSYour Name 		if (tx_mcs_index == INVALID_MCS_IDX)
7636*5113495bSYour Name 			tx_mcs_index = 0;
7637*5113495bSYour Name 		if (rx_mcs_index == INVALID_MCS_IDX)
7638*5113495bSYour Name 			rx_mcs_index = 0;
7639*5113495bSYour Name 	}
7640*5113495bSYour Name 
7641*5113495bSYour Name 	hdd_debug("[RSSI %d, RLMS %u, rssi high %d, rssi mid %d, rssi low %d]-"
7642*5113495bSYour Name 		  "[Rate info: TX: %d, RX: %d]-[Rate flags: TX: 0x%x, RX: 0x%x]"
7643*5113495bSYour Name 		  "-[MCS Index: TX: %d, RX: %d]-[NSS: TX: %d, RX: %d]-"
7644*5113495bSYour Name 		  "[dcm: TX: %d, RX: %d]-[guard interval: TX: %d, RX: %d",
7645*5113495bSYour Name 		  sinfo->signal, link_speed_rssi_report,
7646*5113495bSYour Name 		  link_speed_rssi_high, link_speed_rssi_mid,
7647*5113495bSYour Name 		  link_speed_rssi_low, my_tx_rate, my_rx_rate,
7648*5113495bSYour Name 		  (int)tx_rate_flags, (int)rx_rate_flags, (int)tx_mcs_index,
7649*5113495bSYour Name 		  (int)rx_mcs_index, (int)tx_nss, (int)rx_nss,
7650*5113495bSYour Name 		  (int)tx_dcm, (int)rx_dcm, (int)tx_gi, (int)rx_gi);
7651*5113495bSYour Name 
7652*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
7653*5113495bSYour Name 
7654*5113495bSYour Name 	if (!vdev) {
7655*5113495bSYour Name 		hdd_nofl_debug("vdev object NULL");
7656*5113495bSYour Name 		return -EINVAL;
7657*5113495bSYour Name 	}
7658*5113495bSYour Name 
7659*5113495bSYour Name 	if (sinfo->signal == WLAN_INVALID_RSSI_VALUE) {
7660*5113495bSYour Name 		hdd_debug("don't fill tx rx rate for inactive link");
7661*5113495bSYour Name 	} else if (!ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) {
7662*5113495bSYour Name 		bool tx_rate_calc, rx_rate_calc;
7663*5113495bSYour Name 		uint8_t tx_nss_max, rx_nss_max;
7664*5113495bSYour Name 
7665*5113495bSYour Name 		/*
7666*5113495bSYour Name 		 * Take static NSS for reporting max rates. NSS from the FW
7667*5113495bSYour Name 		 * is not reliable as it changes as per the environment
7668*5113495bSYour Name 		 * quality.
7669*5113495bSYour Name 		 */
7670*5113495bSYour Name 		tx_nss_max = wlan_vdev_mlme_get_nss(vdev);
7671*5113495bSYour Name 		rx_nss_max = wlan_vdev_mlme_get_nss(vdev);
7672*5113495bSYour Name 
7673*5113495bSYour Name 		hdd_check_and_update_nss(hdd_ctx, &tx_nss_max, &rx_nss_max);
7674*5113495bSYour Name 
7675*5113495bSYour Name 		tx_rate_calc = hdd_report_max_rate(link_info, mac_handle,
7676*5113495bSYour Name 						   &sinfo->txrate,
7677*5113495bSYour Name 						   sinfo->signal,
7678*5113495bSYour Name 						   tx_rate_flags,
7679*5113495bSYour Name 						   tx_mcs_index,
7680*5113495bSYour Name 						   my_tx_rate,
7681*5113495bSYour Name 						   tx_nss_max);
7682*5113495bSYour Name 
7683*5113495bSYour Name 		rx_rate_calc = hdd_report_max_rate(link_info, mac_handle,
7684*5113495bSYour Name 						   &sinfo->rxrate,
7685*5113495bSYour Name 						   sinfo->signal,
7686*5113495bSYour Name 						   rx_rate_flags,
7687*5113495bSYour Name 						   rx_mcs_index,
7688*5113495bSYour Name 						   my_rx_rate,
7689*5113495bSYour Name 						   rx_nss_max);
7690*5113495bSYour Name 
7691*5113495bSYour Name 		if (!tx_rate_calc || !rx_rate_calc) {
7692*5113495bSYour Name 			hdd_report_actual_rate(tx_rate_flags, my_tx_rate,
7693*5113495bSYour Name 					       &sinfo->txrate, tx_mcs_index,
7694*5113495bSYour Name 					       tx_nss, tx_dcm, tx_gi);
7695*5113495bSYour Name 
7696*5113495bSYour Name 			hdd_report_actual_rate(rx_rate_flags, my_rx_rate,
7697*5113495bSYour Name 					       &sinfo->rxrate, rx_mcs_index,
7698*5113495bSYour Name 					       rx_nss, rx_dcm, rx_gi);
7699*5113495bSYour Name 		}
7700*5113495bSYour Name 	} else {
7701*5113495bSYour Name 		/* Fill TX stats */
7702*5113495bSYour Name 		hdd_report_actual_rate(tx_rate_flags, my_tx_rate,
7703*5113495bSYour Name 				       &sinfo->txrate, tx_mcs_index,
7704*5113495bSYour Name 				       tx_nss, tx_dcm, tx_gi);
7705*5113495bSYour Name 
7706*5113495bSYour Name 		/* Fill RX stats */
7707*5113495bSYour Name 		hdd_report_actual_rate(rx_rate_flags, my_rx_rate,
7708*5113495bSYour Name 				       &sinfo->rxrate, rx_mcs_index,
7709*5113495bSYour Name 				       rx_nss, rx_dcm, rx_gi);
7710*5113495bSYour Name 
7711*5113495bSYour Name 		/* Using driver RX rate to replace the FW RX rate */
7712*5113495bSYour Name 		wlan_hdd_refill_actual_rate(sinfo, link_info);
7713*5113495bSYour Name 	}
7714*5113495bSYour Name 
7715*5113495bSYour Name 	wlan_hdd_fill_summary_stats(&hdd_stats->summary_stat,
7716*5113495bSYour Name 				    sinfo, link_info->vdev_id);
7717*5113495bSYour Name 
7718*5113495bSYour Name 	wlan_hdd_fill_per_link_summary_stats(&hdd_stats->summary_stat,
7719*5113495bSYour Name 					     sinfo, link_info);
7720*5113495bSYour Name 
7721*5113495bSYour Name 	ucfg_dp_get_net_dev_stats(vdev, &stats);
7722*5113495bSYour Name 	sinfo->tx_bytes = stats.tx_bytes;
7723*5113495bSYour Name 	sinfo->rx_bytes = stats.rx_bytes;
7724*5113495bSYour Name 	sinfo->rx_packets = stats.rx_packets;
7725*5113495bSYour Name 	wlan_hdd_update_mlo_peer_stats(link_info, sinfo);
7726*5113495bSYour Name 
7727*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
7728*5113495bSYour Name 
7729*5113495bSYour Name 	qdf_mem_copy(&sta_ctx->conn_info.txrate,
7730*5113495bSYour Name 		     &sinfo->txrate, sizeof(sinfo->txrate));
7731*5113495bSYour Name 	qdf_mem_copy(&sta_ctx->cache_conn_info.txrate,
7732*5113495bSYour Name 		     &sinfo->txrate, sizeof(sinfo->txrate));
7733*5113495bSYour Name 
7734*5113495bSYour Name 	qdf_mem_copy(&sta_ctx->conn_info.rxrate,
7735*5113495bSYour Name 		     &sinfo->rxrate, sizeof(sinfo->rxrate));
7736*5113495bSYour Name 
7737*5113495bSYour Name 	sinfo->filled |= HDD_INFO_TX_BITRATE |
7738*5113495bSYour Name 			 HDD_INFO_RX_BITRATE |
7739*5113495bSYour Name 			 HDD_INFO_TX_BYTES   |
7740*5113495bSYour Name 			 HDD_INFO_RX_BYTES   |
7741*5113495bSYour Name 			 HDD_INFO_RX_PACKETS;
7742*5113495bSYour Name 
7743*5113495bSYour Name 	if (tx_rate_flags & TX_RATE_LEGACY) {
7744*5113495bSYour Name 		hdd_debug("[TX: Reporting legacy rate %d pkt cnt %d]-"
7745*5113495bSYour Name 			  "[RX: Reporting legacy rate %d pkt cnt %d]",
7746*5113495bSYour Name 			  sinfo->txrate.legacy, sinfo->tx_packets,
7747*5113495bSYour Name 			  sinfo->rxrate.legacy, sinfo->rx_packets);
7748*5113495bSYour Name 	} else {
7749*5113495bSYour Name 		hdd_debug("[TX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d]-"
7750*5113495bSYour Name 			  "[RX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d]",
7751*5113495bSYour Name 			  sinfo->txrate.mcs, sinfo->txrate.flags,
7752*5113495bSYour Name 			  sinfo->tx_packets, sinfo->txrate.nss,
7753*5113495bSYour Name 			  sinfo->txrate.bw, sinfo->rxrate.mcs,
7754*5113495bSYour Name 			  sinfo->rxrate.flags, sinfo->rx_packets,
7755*5113495bSYour Name 			  sinfo->rxrate.nss, sinfo->rxrate.bw);
7756*5113495bSYour Name 	}
7757*5113495bSYour Name 
7758*5113495bSYour Name 	return 0;
7759*5113495bSYour Name }
7760*5113495bSYour Name 
7761*5113495bSYour Name /**
7762*5113495bSYour Name  * wlan_hdd_get_sta_stats() - get aggregate STA stats
7763*5113495bSYour Name  * @link_info: Link info pointer of STA adapter to get stats for
7764*5113495bSYour Name  * @mac: mac address of sta
7765*5113495bSYour Name  * @sinfo: kernel station_info struct to populate
7766*5113495bSYour Name  *
7767*5113495bSYour Name  * Fetch the vdev-level aggregate stats for the given STA adapter. This is to
7768*5113495bSYour Name  * support "station dump" and "station get" for STA vdevs
7769*5113495bSYour Name  *
7770*5113495bSYour Name  * Return: errno
7771*5113495bSYour Name  */
wlan_hdd_get_sta_stats(struct wlan_hdd_link_info * link_info,const uint8_t * mac,struct station_info * sinfo)7772*5113495bSYour Name static int wlan_hdd_get_sta_stats(struct wlan_hdd_link_info *link_info,
7773*5113495bSYour Name 				  const uint8_t *mac,
7774*5113495bSYour Name 				  struct station_info *sinfo)
7775*5113495bSYour Name {
7776*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
7777*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7778*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
7779*5113495bSYour Name 	uint8_t *link_mac;
7780*5113495bSYour Name 	int32_t rcpi_value;
7781*5113495bSYour Name 
7782*5113495bSYour Name 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
7783*5113495bSYour Name 		   TRACE_CODE_HDD_CFG80211_GET_STA,
7784*5113495bSYour Name 		   link_info->vdev_id, 0);
7785*5113495bSYour Name 
7786*5113495bSYour Name 	if (link_info->vdev_id == WLAN_UMAC_VDEV_ID_MAX) {
7787*5113495bSYour Name 		wlan_hdd_update_sinfo(sinfo, link_info);
7788*5113495bSYour Name 		hdd_debug_rl("Sending Cached stats for standby link");
7789*5113495bSYour Name 		return 0;
7790*5113495bSYour Name 	}
7791*5113495bSYour Name 
7792*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(link_info)) {
7793*5113495bSYour Name 		hdd_debug("Not associated");
7794*5113495bSYour Name 		/*To keep GUI happy */
7795*5113495bSYour Name 		return 0;
7796*5113495bSYour Name 	}
7797*5113495bSYour Name 
7798*5113495bSYour Name 	if (hdd_is_roam_sync_in_progress(hdd_ctx, link_info->vdev_id)) {
7799*5113495bSYour Name 		hdd_debug("Roam sync is in progress, cannot continue with this request");
7800*5113495bSYour Name 		/*
7801*5113495bSYour Name 		 * supplicant reports very low rssi to upper layer
7802*5113495bSYour Name 		 * and handover happens to cellular.
7803*5113495bSYour Name 		 * send the cached rssi when get_station
7804*5113495bSYour Name 		 */
7805*5113495bSYour Name 		sinfo->signal = link_info->rssi;
7806*5113495bSYour Name 		sinfo->filled |= HDD_INFO_SIGNAL;
7807*5113495bSYour Name 		return 0;
7808*5113495bSYour Name 	}
7809*5113495bSYour Name 
7810*5113495bSYour Name 	if (hdd_ctx->rcpi_enabled)
7811*5113495bSYour Name 		wlan_hdd_get_rcpi(adapter, (uint8_t *)mac, &rcpi_value,
7812*5113495bSYour Name 				  RCPI_MEASUREMENT_TYPE_AVG_MGMT);
7813*5113495bSYour Name 
7814*5113495bSYour Name 	wlan_hdd_get_station_stats(link_info);
7815*5113495bSYour Name 
7816*5113495bSYour Name 	wlan_hdd_get_peer_rx_rate_stats(link_info);
7817*5113495bSYour Name 
7818*5113495bSYour Name 	wlan_hdd_update_rssi(link_info, sinfo);
7819*5113495bSYour Name 
7820*5113495bSYour Name 	/*
7821*5113495bSYour Name 	 * we notify connect to lpass here instead of during actual
7822*5113495bSYour Name 	 * connect processing because rssi info is not accurate during
7823*5113495bSYour Name 	 * actual connection.  lpass will ensure the notification is
7824*5113495bSYour Name 	 * only processed once per association.
7825*5113495bSYour Name 	 */
7826*5113495bSYour Name 	hdd_lpass_notify_connect(link_info);
7827*5113495bSYour Name 
7828*5113495bSYour Name 	if (wlan_hdd_update_rate_info(link_info, sinfo))
7829*5113495bSYour Name 		/* Keep GUI happy */
7830*5113495bSYour Name 		return 0;
7831*5113495bSYour Name 
7832*5113495bSYour Name 	hdd_fill_fcs_and_mpdu_count(link_info, sinfo);
7833*5113495bSYour Name 
7834*5113495bSYour Name 	hdd_wlan_fill_per_chain_rssi_stats(sinfo, link_info);
7835*5113495bSYour Name 
7836*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7837*5113495bSYour Name 	link_mac = sta_ctx->conn_info.bssid.bytes;
7838*5113495bSYour Name 	hdd_nofl_debug("Sending station stats for link " QDF_MAC_ADDR_FMT,
7839*5113495bSYour Name 		       QDF_MAC_ADDR_REF(link_mac));
7840*5113495bSYour Name 
7841*5113495bSYour Name 	wlan_hdd_copy_sinfo_to_link_info(link_info, sinfo);
7842*5113495bSYour Name 
7843*5113495bSYour Name 	hdd_exit();
7844*5113495bSYour Name 
7845*5113495bSYour Name 	return 0;
7846*5113495bSYour Name }
7847*5113495bSYour Name 
7848*5113495bSYour Name #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
7849*5113495bSYour Name /*
7850*5113495bSYour Name  * wlan_hdd_update_mlo_rate_info() - Populate mlo station stats rate info
7851*5113495bSYour Name  * @hdd_sinfo: Pointer to hdd stats station info struct
7852*5113495bSYour Name  * @sinfo: Pointer to kernel station info struct
7853*5113495bSYour Name  *
7854*5113495bSYour Name  * Return: none
7855*5113495bSYour Name  */
7856*5113495bSYour Name static void
wlan_hdd_update_mlo_rate_info(struct wlan_hdd_station_stats_info * hdd_sinfo,struct station_info * sinfo)7857*5113495bSYour Name wlan_hdd_update_mlo_rate_info(struct wlan_hdd_station_stats_info *hdd_sinfo,
7858*5113495bSYour Name 			      struct station_info *sinfo)
7859*5113495bSYour Name {
7860*5113495bSYour Name 	uint8_t i;
7861*5113495bSYour Name 
7862*5113495bSYour Name 	hdd_sinfo->signal = sinfo->signal;
7863*5113495bSYour Name 	hdd_sinfo->signal_avg = sinfo->signal_avg;
7864*5113495bSYour Name 	for (i = 0; i < IEEE80211_MAX_CHAINS; i++)
7865*5113495bSYour Name 		hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i];
7866*5113495bSYour Name 
7867*5113495bSYour Name 	qdf_mem_copy(&hdd_sinfo->txrate,
7868*5113495bSYour Name 		     &sinfo->txrate, sizeof(sinfo->txrate));
7869*5113495bSYour Name 
7870*5113495bSYour Name 	qdf_mem_copy(&hdd_sinfo->rxrate,
7871*5113495bSYour Name 		     &sinfo->rxrate, sizeof(sinfo->rxrate));
7872*5113495bSYour Name }
7873*5113495bSYour Name 
7874*5113495bSYour Name /*
7875*5113495bSYour Name  * wlan_hdd_update_mlo_sinfo() - Populate mlo stats station info
7876*5113495bSYour Name  * @link_info: Link info pointer of STA adapter
7877*5113495bSYour Name  * @hdd_sinfo: Pointer to hdd stats station info struct
7878*5113495bSYour Name  * @sinfo: Pointer to kernel station info struct
7879*5113495bSYour Name  *
7880*5113495bSYour Name  * Return: none
7881*5113495bSYour Name  */
7882*5113495bSYour Name static void
wlan_hdd_update_mlo_sinfo(struct wlan_hdd_link_info * link_info,struct wlan_hdd_station_stats_info * hdd_sinfo,struct station_info * sinfo)7883*5113495bSYour Name wlan_hdd_update_mlo_sinfo(struct wlan_hdd_link_info *link_info,
7884*5113495bSYour Name 			  struct wlan_hdd_station_stats_info *hdd_sinfo,
7885*5113495bSYour Name 			  struct station_info *sinfo)
7886*5113495bSYour Name {
7887*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
7888*5113495bSYour Name 
7889*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7890*5113495bSYour Name 
7891*5113495bSYour Name 	if (!link_info->is_mlo_vdev_active)
7892*5113495bSYour Name 		hdd_nofl_debug("vdev_id[%d] is inactive", link_info->vdev_id);
7893*5113495bSYour Name 
7894*5113495bSYour Name 	/* Update the rate info for link with best RSSI */
7895*5113495bSYour Name 	if (sinfo->signal > hdd_sinfo->signal) {
7896*5113495bSYour Name 		hdd_nofl_debug("Updating rates for link_id %d",
7897*5113495bSYour Name 			       sta_ctx->conn_info.ieee_link_id);
7898*5113495bSYour Name 		wlan_hdd_update_mlo_rate_info(hdd_sinfo, sinfo);
7899*5113495bSYour Name 	}
7900*5113495bSYour Name 
7901*5113495bSYour Name 	/* Send cumulative Tx/Rx packets and bytes data
7902*5113495bSYour Name 	 * of all active links to userspace
7903*5113495bSYour Name 	 */
7904*5113495bSYour Name 	hdd_sinfo->rx_bytes += sinfo->rx_bytes;
7905*5113495bSYour Name 	hdd_sinfo->tx_bytes += sinfo->tx_bytes;
7906*5113495bSYour Name 	hdd_sinfo->rx_packets += sinfo->rx_packets;
7907*5113495bSYour Name 	hdd_sinfo->tx_packets += sinfo->tx_packets;
7908*5113495bSYour Name 	hdd_sinfo->tx_retries += sinfo->tx_retries;
7909*5113495bSYour Name 	hdd_sinfo->tx_failed += sinfo->tx_failed;
7910*5113495bSYour Name 	hdd_sinfo->rx_mpdu_count += sinfo->rx_mpdu_count;
7911*5113495bSYour Name 	hdd_sinfo->fcs_err_count += sinfo->fcs_err_count;
7912*5113495bSYour Name }
7913*5113495bSYour Name 
7914*5113495bSYour Name #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
7915*5113495bSYour Name /**
7916*5113495bSYour Name  * wlan_hdd_get_mlo_sta_stats - get aggregate STA stats for MLO
7917*5113495bSYour Name  * @adapter: HDD adapter
7918*5113495bSYour Name  * @mac: mac address
7919*5113495bSYour Name  * @sinfo: kernel station_info struct to populate
7920*5113495bSYour Name  *
7921*5113495bSYour Name  * Return: 0 on success; errno on failure
7922*5113495bSYour Name  */
wlan_hdd_get_mlo_sta_stats(struct hdd_adapter * adapter,const uint8_t * mac,struct station_info * sinfo)7923*5113495bSYour Name static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
7924*5113495bSYour Name 				      const uint8_t *mac,
7925*5113495bSYour Name 				      struct station_info *sinfo)
7926*5113495bSYour Name {
7927*5113495bSYour Name 	struct hdd_adapter *ml_adapter, *link_adapter;
7928*5113495bSYour Name 	struct hdd_mlo_adapter_info *mlo_adapter_info;
7929*5113495bSYour Name 	struct wlan_hdd_station_stats_info hdd_sinfo = {0};
7930*5113495bSYour Name 	uint8_t i;
7931*5113495bSYour Name 
7932*5113495bSYour Name 	/* Initialize the signal value to a default RSSI of -128dBm */
7933*5113495bSYour Name 	hdd_sinfo.signal = WLAN_INVALID_RSSI_VALUE;
7934*5113495bSYour Name 
7935*5113495bSYour Name 	ml_adapter = adapter;
7936*5113495bSYour Name 	if (hdd_adapter_is_link_adapter(ml_adapter))
7937*5113495bSYour Name 		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
7938*5113495bSYour Name 
7939*5113495bSYour Name 	wlan_hdd_get_sta_stats(ml_adapter->deflink, mac, sinfo);
7940*5113495bSYour Name 	wlan_hdd_update_mlo_sinfo(ml_adapter->deflink, &hdd_sinfo, sinfo);
7941*5113495bSYour Name 
7942*5113495bSYour Name 	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
7943*5113495bSYour Name 	for (i = 0; i < WLAN_MAX_MLD; i++) {
7944*5113495bSYour Name 		link_adapter = mlo_adapter_info->link_adapter[i];
7945*5113495bSYour Name 		if (!link_adapter ||
7946*5113495bSYour Name 		    hdd_adapter_is_associated_with_ml_adapter(link_adapter))
7947*5113495bSYour Name 			continue;
7948*5113495bSYour Name 
7949*5113495bSYour Name 		wlan_hdd_get_sta_stats(link_adapter->deflink, mac, sinfo);
7950*5113495bSYour Name 		wlan_hdd_update_mlo_sinfo(link_adapter->deflink, &hdd_sinfo,
7951*5113495bSYour Name 					  sinfo);
7952*5113495bSYour Name 	}
7953*5113495bSYour Name 
7954*5113495bSYour Name 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo);
7955*5113495bSYour Name 	hdd_nofl_debug("Sending aggregated mlo station stats");
7956*5113495bSYour Name 
7957*5113495bSYour Name 	hdd_exit();
7958*5113495bSYour Name 
7959*5113495bSYour Name 	return 0;
7960*5113495bSYour Name }
7961*5113495bSYour Name #else
wlan_hdd_get_mlo_sta_stats(struct hdd_adapter * adapter,const uint8_t * mac,struct station_info * sinfo)7962*5113495bSYour Name static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
7963*5113495bSYour Name 				      const uint8_t *mac,
7964*5113495bSYour Name 				      struct station_info *sinfo)
7965*5113495bSYour Name {
7966*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
7967*5113495bSYour Name 	struct wlan_hdd_station_stats_info hdd_sinfo = {0};
7968*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
7969*5113495bSYour Name 
7970*5113495bSYour Name 	/* Initialize the signal value to a default RSSI of -128dBm */
7971*5113495bSYour Name 	hdd_sinfo.signal = WLAN_INVALID_RSSI_VALUE;
7972*5113495bSYour Name 
7973*5113495bSYour Name 	hdd_adapter_for_each_link_info(adapter, link_info) {
7974*5113495bSYour Name 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
7975*5113495bSYour Name 		if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID)
7976*5113495bSYour Name 			continue;
7977*5113495bSYour Name 		wlan_hdd_get_sta_stats(link_info, mac, sinfo);
7978*5113495bSYour Name 		wlan_hdd_update_mlo_sinfo(link_info, &hdd_sinfo, sinfo);
7979*5113495bSYour Name 	}
7980*5113495bSYour Name 
7981*5113495bSYour Name 	wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo);
7982*5113495bSYour Name 	hdd_nofl_debug("Sending aggregated mlo station stats");
7983*5113495bSYour Name 
7984*5113495bSYour Name 	hdd_exit();
7985*5113495bSYour Name 
7986*5113495bSYour Name 	return 0;
7987*5113495bSYour Name }
7988*5113495bSYour Name #endif
7989*5113495bSYour Name #else
wlan_hdd_get_mlo_sta_stats(struct hdd_adapter * adapter,const uint8_t * mac,struct station_info * sinfo)7990*5113495bSYour Name static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter,
7991*5113495bSYour Name 				      const uint8_t *mac,
7992*5113495bSYour Name 				      struct station_info *sinfo)
7993*5113495bSYour Name {
7994*5113495bSYour Name 	return wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
7995*5113495bSYour Name }
7996*5113495bSYour Name #endif
7997*5113495bSYour Name 
7998*5113495bSYour Name /*
7999*5113495bSYour Name  * wlan_is_mlo_aggregated_stats_allowed() - Is aggregated stats requested
8000*5113495bSYour Name  * @adapter: HDD adapter
8001*5113495bSYour Name  * @mac: mac address
8002*5113495bSYour Name  *
8003*5113495bSYour Name  * Return: True if req is on mld_mac and FW supports per link stats, else False
8004*5113495bSYour Name  */
8005*5113495bSYour Name static bool
wlan_is_mlo_aggregated_stats_allowed(struct hdd_adapter * adapter,const uint8_t * mac)8006*5113495bSYour Name wlan_is_mlo_aggregated_stats_allowed(struct hdd_adapter *adapter,
8007*5113495bSYour Name 				     const uint8_t *mac)
8008*5113495bSYour Name {
8009*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8010*5113495bSYour Name 	bool is_mld_req = false;
8011*5113495bSYour Name 	bool per_link_stats_cap = false;
8012*5113495bSYour Name 	struct qdf_mac_addr peer_mld_mac;
8013*5113495bSYour Name 	QDF_STATUS status;
8014*5113495bSYour Name 
8015*5113495bSYour Name 	if (!hdd_ctx) {
8016*5113495bSYour Name 		hdd_err("invalid hdd_ctx");
8017*5113495bSYour Name 		return false;
8018*5113495bSYour Name 	}
8019*5113495bSYour Name 
8020*5113495bSYour Name 	status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink, &peer_mld_mac);
8021*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
8022*5113495bSYour Name 		hdd_err_rl("mlo_vdev_stats: failed to get bss peer mld mac");
8023*5113495bSYour Name 		return false;
8024*5113495bSYour Name 	}
8025*5113495bSYour Name 
8026*5113495bSYour Name 	is_mld_req = qdf_is_macaddr_equal(&peer_mld_mac,
8027*5113495bSYour Name 					  (struct qdf_mac_addr *)mac);
8028*5113495bSYour Name 	per_link_stats_cap = wlan_hdd_is_per_link_stats_supported(hdd_ctx);
8029*5113495bSYour Name 
8030*5113495bSYour Name 	if (is_mld_req && per_link_stats_cap) {
8031*5113495bSYour Name 		hdd_debug_rl("Fetching Aggregated station stats");
8032*5113495bSYour Name 		return true;
8033*5113495bSYour Name 	}
8034*5113495bSYour Name 
8035*5113495bSYour Name 	return false;
8036*5113495bSYour Name }
8037*5113495bSYour Name 
8038*5113495bSYour Name /**
8039*5113495bSYour Name  * wlan_hdd_send_mlo_station_stats() - send station stats to userspace
8040*5113495bSYour Name  * @adapter: Pointer to hdd adapter
8041*5113495bSYour Name  * @hdd_ctx: Pointer to hdd context
8042*5113495bSYour Name  * @mac: mac address
8043*5113495bSYour Name  * @sinfo: kernel station_info struct to populate
8044*5113495bSYour Name  *
8045*5113495bSYour Name  * Return: 0 on success; errno on failure
8046*5113495bSYour Name  */
wlan_hdd_send_mlo_station_stats(struct hdd_adapter * adapter,struct hdd_context * hdd_ctx,const uint8_t * mac,struct station_info * sinfo)8047*5113495bSYour Name static int wlan_hdd_send_mlo_station_stats(struct hdd_adapter *adapter,
8048*5113495bSYour Name 					   struct hdd_context *hdd_ctx,
8049*5113495bSYour Name 					   const uint8_t *mac,
8050*5113495bSYour Name 					   struct station_info *sinfo)
8051*5113495bSYour Name {
8052*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
8053*5113495bSYour Name 
8054*5113495bSYour Name 	if (!wlan_hdd_is_mlo_connection(adapter->deflink)) {
8055*5113495bSYour Name 		hdd_nofl_debug("Fetching station stats for legacy connection");
8056*5113495bSYour Name 		return wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
8057*5113495bSYour Name 	}
8058*5113495bSYour Name 
8059*5113495bSYour Name 	link_info = hdd_get_link_info_by_bssid(hdd_ctx, mac);
8060*5113495bSYour Name 	if (!link_info) {
8061*5113495bSYour Name 		if (wlan_is_mlo_aggregated_stats_allowed(adapter, mac))
8062*5113495bSYour Name 			return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo);
8063*5113495bSYour Name 
8064*5113495bSYour Name 		hdd_debug_rl("Invalid bssid");
8065*5113495bSYour Name 		return -EINVAL;
8066*5113495bSYour Name 	}
8067*5113495bSYour Name 	return wlan_hdd_get_sta_stats(link_info, mac, sinfo);
8068*5113495bSYour Name }
8069*5113495bSYour Name 
8070*5113495bSYour Name /**
8071*5113495bSYour Name  * __wlan_hdd_cfg80211_get_station() - get station statistics
8072*5113495bSYour Name  * @wiphy: Pointer to wiphy
8073*5113495bSYour Name  * @dev: Pointer to network device
8074*5113495bSYour Name  * @mac: Pointer to mac
8075*5113495bSYour Name  * @sinfo: Pointer to station info
8076*5113495bSYour Name  *
8077*5113495bSYour Name  * Return: 0 for success, non-zero for failure
8078*5113495bSYour Name  */
__wlan_hdd_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const uint8_t * mac,struct station_info * sinfo)8079*5113495bSYour Name static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
8080*5113495bSYour Name 					   struct net_device *dev,
8081*5113495bSYour Name 					   const uint8_t *mac,
8082*5113495bSYour Name 					   struct station_info *sinfo)
8083*5113495bSYour Name {
8084*5113495bSYour Name 	int errno;
8085*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8086*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
8087*5113495bSYour Name 	struct hdd_station_info *stainfo;
8088*5113495bSYour Name 	bool get_peer_info_enable;
8089*5113495bSYour Name 	QDF_STATUS qdf_status;
8090*5113495bSYour Name 	struct wlan_hdd_link_info *link_info = adapter->deflink;
8091*5113495bSYour Name 
8092*5113495bSYour Name 	hdd_enter_dev(dev);
8093*5113495bSYour Name 
8094*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
8095*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
8096*5113495bSYour Name 		return -EINVAL;
8097*5113495bSYour Name 	}
8098*5113495bSYour Name 
8099*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx))
8100*5113495bSYour Name 		return -EINVAL;
8101*5113495bSYour Name 
8102*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
8103*5113495bSYour Name 		return -EINVAL;
8104*5113495bSYour Name 
8105*5113495bSYour Name 	hdd_nofl_debug("Stats request on MAC: " QDF_MAC_ADDR_FMT,
8106*5113495bSYour Name 		       QDF_MAC_ADDR_REF(mac));
8107*5113495bSYour Name 
8108*5113495bSYour Name 	if (!mac || qdf_is_macaddr_zero((struct qdf_mac_addr *)mac)) {
8109*5113495bSYour Name 		hdd_err("Invalid MAC addr");
8110*5113495bSYour Name 		return -EINVAL;
8111*5113495bSYour Name 	}
8112*5113495bSYour Name 
8113*5113495bSYour Name 	if (adapter->device_mode == QDF_SAP_MODE ||
8114*5113495bSYour Name 	    adapter->device_mode == QDF_P2P_GO_MODE) {
8115*5113495bSYour Name 		qdf_status = ucfg_mlme_get_sap_get_peer_info(
8116*5113495bSYour Name 				hdd_ctx->psoc, &get_peer_info_enable);
8117*5113495bSYour Name 		if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) {
8118*5113495bSYour Name 			stainfo = hdd_get_sta_info_by_mac(
8119*5113495bSYour Name 					&adapter->sta_info_list, mac,
8120*5113495bSYour Name 					STA_INFO_WLAN_HDD_CFG80211_GET_STATION);
8121*5113495bSYour Name 			if (!stainfo) {
8122*5113495bSYour Name 				hdd_debug("Peer " QDF_MAC_ADDR_FMT " not found",
8123*5113495bSYour Name 					  QDF_MAC_ADDR_REF(mac));
8124*5113495bSYour Name 				return -EINVAL;
8125*5113495bSYour Name 			}
8126*5113495bSYour Name 
8127*5113495bSYour Name 			errno = wlan_hdd_get_station_remote(wiphy, dev,
8128*5113495bSYour Name 							    stainfo, sinfo);
8129*5113495bSYour Name 			hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo,
8130*5113495bSYour Name 					     true,
8131*5113495bSYour Name 					STA_INFO_WLAN_HDD_CFG80211_GET_STATION
8132*5113495bSYour Name 					);
8133*5113495bSYour Name 			if (!errno)
8134*5113495bSYour Name 				return 0;
8135*5113495bSYour Name 		}
8136*5113495bSYour Name 		return wlan_hdd_get_sap_stats(link_info, sinfo);
8137*5113495bSYour Name 	}
8138*5113495bSYour Name 
8139*5113495bSYour Name 	return wlan_hdd_send_mlo_station_stats(adapter, hdd_ctx, mac, sinfo);
8140*5113495bSYour Name }
8141*5113495bSYour Name 
8142*5113495bSYour Name /**
8143*5113495bSYour Name  * _wlan_hdd_cfg80211_get_station() - get station statistics
8144*5113495bSYour Name  *
8145*5113495bSYour Name  * @wiphy: Pointer to wiphy
8146*5113495bSYour Name  * @dev: Pointer to network device
8147*5113495bSYour Name  * @mac: Pointer to mac
8148*5113495bSYour Name  * @sinfo: Pointer to station info
8149*5113495bSYour Name  *
8150*5113495bSYour Name  * This API tries runtime PM suspend right away after getting station
8151*5113495bSYour Name  * statistics.
8152*5113495bSYour Name  *
8153*5113495bSYour Name  * Return: 0 for success, non-zero for failure
8154*5113495bSYour Name  */
_wlan_hdd_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const uint8_t * mac,struct station_info * sinfo)8155*5113495bSYour Name static int _wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
8156*5113495bSYour Name 					  struct net_device *dev,
8157*5113495bSYour Name 					  const uint8_t *mac,
8158*5113495bSYour Name 					  struct station_info *sinfo)
8159*5113495bSYour Name {
8160*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
8161*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8162*5113495bSYour Name 	int errno;
8163*5113495bSYour Name 	QDF_STATUS status;
8164*5113495bSYour Name 
8165*5113495bSYour Name 	errno = wlan_hdd_validate_context(hdd_ctx);
8166*5113495bSYour Name 	if (errno)
8167*5113495bSYour Name 		return errno;
8168*5113495bSYour Name 
8169*5113495bSYour Name 	if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) {
8170*5113495bSYour Name 		hdd_debug("Link Switch in progress, can't process request");
8171*5113495bSYour Name 		return -EBUSY;
8172*5113495bSYour Name 	}
8173*5113495bSYour Name 
8174*5113495bSYour Name 	status = wlan_hdd_stats_request_needed(adapter);
8175*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
8176*5113495bSYour Name 		if (status == QDF_STATUS_E_ALREADY)
8177*5113495bSYour Name 			get_station_fw_request_needed = false;
8178*5113495bSYour Name 		else
8179*5113495bSYour Name 			return -EINVAL;
8180*5113495bSYour Name 	}
8181*5113495bSYour Name 
8182*5113495bSYour Name 	if (get_station_fw_request_needed) {
8183*5113495bSYour Name 		errno = wlan_hdd_qmi_get_sync_resume();
8184*5113495bSYour Name 		if (errno) {
8185*5113495bSYour Name 			hdd_err("qmi sync resume failed: %d", errno);
8186*5113495bSYour Name 			return errno;
8187*5113495bSYour Name 		}
8188*5113495bSYour Name 	}
8189*5113495bSYour Name 
8190*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
8191*5113495bSYour Name 
8192*5113495bSYour Name 	if (get_station_fw_request_needed)
8193*5113495bSYour Name 		wlan_hdd_qmi_put_suspend();
8194*5113495bSYour Name 
8195*5113495bSYour Name 	get_station_fw_request_needed = true;
8196*5113495bSYour Name 
8197*5113495bSYour Name 	return errno;
8198*5113495bSYour Name }
8199*5113495bSYour Name 
8200*5113495bSYour Name /**
8201*5113495bSYour Name  * wlan_hdd_cfg80211_get_station() - get station statistics
8202*5113495bSYour Name  * @wiphy: Pointer to wiphy
8203*5113495bSYour Name  * @dev: Pointer to network device
8204*5113495bSYour Name  * @mac: Pointer to mac
8205*5113495bSYour Name  * @sinfo: Pointer to station info
8206*5113495bSYour Name  *
8207*5113495bSYour Name  * Return: 0 for success, non-zero for failure
8208*5113495bSYour Name  */
wlan_hdd_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const uint8_t * mac,struct station_info * sinfo)8209*5113495bSYour Name int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
8210*5113495bSYour Name 				  struct net_device *dev, const uint8_t *mac,
8211*5113495bSYour Name 				  struct station_info *sinfo)
8212*5113495bSYour Name {
8213*5113495bSYour Name 	int errno;
8214*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
8215*5113495bSYour Name 
8216*5113495bSYour Name 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
8217*5113495bSYour Name 	if (errno)
8218*5113495bSYour Name 		return errno;
8219*5113495bSYour Name 
8220*5113495bSYour Name 	errno = _wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
8221*5113495bSYour Name 
8222*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
8223*5113495bSYour Name 
8224*5113495bSYour Name 	return errno;
8225*5113495bSYour Name }
8226*5113495bSYour Name 
8227*5113495bSYour Name /**
8228*5113495bSYour Name  * __wlan_hdd_cfg80211_dump_station() - dump station statistics
8229*5113495bSYour Name  * @wiphy: Pointer to wiphy
8230*5113495bSYour Name  * @dev: Pointer to network device
8231*5113495bSYour Name  * @idx: variable to station index, kernel iterate all stations over idx
8232*5113495bSYour Name  * @mac: Pointer to mac
8233*5113495bSYour Name  * @sinfo: Pointer to station info
8234*5113495bSYour Name  *
8235*5113495bSYour Name  * Return: 0 for success, non-zero for failure
8236*5113495bSYour Name  */
__wlan_hdd_cfg80211_dump_station(struct wiphy * wiphy,struct net_device * dev,int idx,u8 * mac,struct station_info * sinfo)8237*5113495bSYour Name static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
8238*5113495bSYour Name 				struct net_device *dev,
8239*5113495bSYour Name 				int idx, u8 *mac,
8240*5113495bSYour Name 				struct station_info *sinfo)
8241*5113495bSYour Name {
8242*5113495bSYour Name 	int errno;
8243*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8244*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
8245*5113495bSYour Name 	struct hdd_station_info *stainfo;
8246*5113495bSYour Name 	bool get_peer_info_enable;
8247*5113495bSYour Name 	QDF_STATUS qdf_status;
8248*5113495bSYour Name 
8249*5113495bSYour Name 	hdd_debug("idx: %d", idx);
8250*5113495bSYour Name 
8251*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
8252*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
8253*5113495bSYour Name 		return -EINVAL;
8254*5113495bSYour Name 	}
8255*5113495bSYour Name 
8256*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx))
8257*5113495bSYour Name 		return -EINVAL;
8258*5113495bSYour Name 
8259*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
8260*5113495bSYour Name 		return -EINVAL;
8261*5113495bSYour Name 
8262*5113495bSYour Name 	if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) {
8263*5113495bSYour Name 		hdd_debug("Link Switch in progress, can't process request");
8264*5113495bSYour Name 		return -EBUSY;
8265*5113495bSYour Name 	}
8266*5113495bSYour Name 
8267*5113495bSYour Name 	if (adapter->device_mode == QDF_SAP_MODE ||
8268*5113495bSYour Name 	    adapter->device_mode == QDF_P2P_GO_MODE) {
8269*5113495bSYour Name 		qdf_status = ucfg_mlme_get_sap_get_peer_info(
8270*5113495bSYour Name 				hdd_ctx->psoc, &get_peer_info_enable);
8271*5113495bSYour Name 		if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) {
8272*5113495bSYour Name 			stainfo = hdd_get_sta_info_by_id(
8273*5113495bSYour Name 					&adapter->sta_info_list,
8274*5113495bSYour Name 					idx,
8275*5113495bSYour Name 					STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION
8276*5113495bSYour Name 					);
8277*5113495bSYour Name 			if (!stainfo) {
8278*5113495bSYour Name 				hdd_err("peer idx %d NOT FOUND", idx);
8279*5113495bSYour Name 				return -ENOENT;
8280*5113495bSYour Name 			}
8281*5113495bSYour Name 
8282*5113495bSYour Name 			qdf_mem_copy(mac, &stainfo->sta_mac.bytes,
8283*5113495bSYour Name 				     QDF_MAC_ADDR_SIZE);
8284*5113495bSYour Name 			errno = wlan_hdd_get_station_remote(wiphy, dev,
8285*5113495bSYour Name 							    stainfo, sinfo);
8286*5113495bSYour Name 			hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo,
8287*5113495bSYour Name 					     true,
8288*5113495bSYour Name 					STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION
8289*5113495bSYour Name 					);
8290*5113495bSYour Name 		} else {
8291*5113495bSYour Name 			errno = -EINVAL;
8292*5113495bSYour Name 			hdd_err("sap get peer info disabled!");
8293*5113495bSYour Name 		}
8294*5113495bSYour Name 	} else {
8295*5113495bSYour Name 		if (idx != 0)
8296*5113495bSYour Name 			return -ENOENT;
8297*5113495bSYour Name 
8298*5113495bSYour Name 		qdf_mem_copy(mac, dev->dev_addr, QDF_MAC_ADDR_SIZE);
8299*5113495bSYour Name 
8300*5113495bSYour Name 		if (wlan_hdd_is_mlo_connection(adapter->deflink) &&
8301*5113495bSYour Name 		    wlan_hdd_is_per_link_stats_supported(hdd_ctx))
8302*5113495bSYour Name 			return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo);
8303*5113495bSYour Name 
8304*5113495bSYour Name 		hdd_nofl_debug("Sending Assoc Link stats");
8305*5113495bSYour Name 		errno = wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo);
8306*5113495bSYour Name 	}
8307*5113495bSYour Name 	return errno;
8308*5113495bSYour Name }
8309*5113495bSYour Name 
8310*5113495bSYour Name /**
8311*5113495bSYour Name  * wlan_hdd_cfg80211_dump_station() - dump station statistics
8312*5113495bSYour Name  * @wiphy: Pointer to wiphy
8313*5113495bSYour Name  * @dev: Pointer to network device
8314*5113495bSYour Name  * @idx: variable to determine whether to get stats or not
8315*5113495bSYour Name  * @mac: Pointer to mac
8316*5113495bSYour Name  * @sinfo: Pointer to station info
8317*5113495bSYour Name  *
8318*5113495bSYour Name  * Return: 0 for success, non-zero for failure
8319*5113495bSYour Name  */
wlan_hdd_cfg80211_dump_station(struct wiphy * wiphy,struct net_device * dev,int idx,u8 * mac,struct station_info * sinfo)8320*5113495bSYour Name int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy,
8321*5113495bSYour Name 				struct net_device *dev,
8322*5113495bSYour Name 				int idx, u8 *mac,
8323*5113495bSYour Name 				struct station_info *sinfo)
8324*5113495bSYour Name {
8325*5113495bSYour Name 	int errno;
8326*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
8327*5113495bSYour Name 
8328*5113495bSYour Name 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
8329*5113495bSYour Name 	if (errno)
8330*5113495bSYour Name 		return errno;
8331*5113495bSYour Name 
8332*5113495bSYour Name 	errno = wlan_hdd_qmi_get_sync_resume();
8333*5113495bSYour Name 	if (errno) {
8334*5113495bSYour Name 		hdd_err("qmi sync resume failed: %d", errno);
8335*5113495bSYour Name 		goto end;
8336*5113495bSYour Name 	}
8337*5113495bSYour Name 
8338*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo);
8339*5113495bSYour Name 
8340*5113495bSYour Name 	wlan_hdd_qmi_put_suspend();
8341*5113495bSYour Name 
8342*5113495bSYour Name end:
8343*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
8344*5113495bSYour Name 
8345*5113495bSYour Name 	return errno;
8346*5113495bSYour Name }
8347*5113495bSYour Name 
8348*5113495bSYour Name /**
8349*5113495bSYour Name  * hdd_get_stats() - Function to retrieve interface statistics
8350*5113495bSYour Name  * @dev: pointer to network device
8351*5113495bSYour Name  *
8352*5113495bSYour Name  * This function is the ndo_get_stats method for all netdevs
8353*5113495bSYour Name  * registered with the kernel
8354*5113495bSYour Name  *
8355*5113495bSYour Name  * Return: pointer to net_device_stats structure
8356*5113495bSYour Name  */
hdd_get_stats(struct net_device * dev)8357*5113495bSYour Name struct net_device_stats *hdd_get_stats(struct net_device *dev)
8358*5113495bSYour Name {
8359*5113495bSYour Name 	return (struct net_device_stats *)ucfg_dp_get_dev_stats(dev);
8360*5113495bSYour Name }
8361*5113495bSYour Name 
8362*5113495bSYour Name /*
8363*5113495bSYour Name  * FW sends value of cycle_count, rx_clear_count and tx_frame_count in usec.
8364*5113495bSYour Name  */
8365*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
wlan_fill_survey_result(struct survey_info * survey,int opfreq,struct scan_chan_info * chan_info,struct ieee80211_channel * channels)8366*5113495bSYour Name static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
8367*5113495bSYour Name 				    struct scan_chan_info *chan_info,
8368*5113495bSYour Name 				    struct ieee80211_channel *channels)
8369*5113495bSYour Name {
8370*5113495bSYour Name 	if (channels->center_freq != (uint16_t)chan_info->freq)
8371*5113495bSYour Name 		return false;
8372*5113495bSYour Name 
8373*5113495bSYour Name 	survey->channel = channels;
8374*5113495bSYour Name 	survey->noise = chan_info->noise_floor;
8375*5113495bSYour Name 	survey->filled = 0;
8376*5113495bSYour Name 
8377*5113495bSYour Name 	if (chan_info->noise_floor)
8378*5113495bSYour Name 		survey->filled |= SURVEY_INFO_NOISE_DBM;
8379*5113495bSYour Name 
8380*5113495bSYour Name 	if (opfreq == chan_info->freq)
8381*5113495bSYour Name 		survey->filled |= SURVEY_INFO_IN_USE;
8382*5113495bSYour Name 
8383*5113495bSYour Name 	survey->time = chan_info->cycle_count;
8384*5113495bSYour Name 	survey->time_busy = chan_info->rx_clear_count;
8385*5113495bSYour Name 	survey->time_tx = chan_info->tx_frame_count;
8386*5113495bSYour Name 
8387*5113495bSYour Name 	survey->filled |= SURVEY_INFO_TIME |
8388*5113495bSYour Name 			  SURVEY_INFO_TIME_BUSY |
8389*5113495bSYour Name 			  SURVEY_INFO_TIME_TX;
8390*5113495bSYour Name 	return true;
8391*5113495bSYour Name }
8392*5113495bSYour Name #else
wlan_fill_survey_result(struct survey_info * survey,int opfreq,struct scan_chan_info * chan_info,struct ieee80211_channel * channels)8393*5113495bSYour Name static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
8394*5113495bSYour Name 				    struct scan_chan_info *chan_info,
8395*5113495bSYour Name 				    struct ieee80211_channel *channels)
8396*5113495bSYour Name {
8397*5113495bSYour Name 	if (channels->center_freq != (uint16_t)chan_info->freq)
8398*5113495bSYour Name 		return false;
8399*5113495bSYour Name 
8400*5113495bSYour Name 	survey->channel = channels;
8401*5113495bSYour Name 	survey->noise = chan_info->noise_floor;
8402*5113495bSYour Name 	survey->filled = 0;
8403*5113495bSYour Name 
8404*5113495bSYour Name 	if (chan_info->noise_floor)
8405*5113495bSYour Name 		survey->filled |= SURVEY_INFO_NOISE_DBM;
8406*5113495bSYour Name 
8407*5113495bSYour Name 	if (opfreq == chan_info->freq)
8408*5113495bSYour Name 		survey->filled |= SURVEY_INFO_IN_USE;
8409*5113495bSYour Name 
8410*5113495bSYour Name 	survey->channel_time = chan_info->cycle_count;
8411*5113495bSYour Name 	survey->channel_time_busy = chan_info->rx_clear_count;
8412*5113495bSYour Name 	survey->channel_time_tx = chan_info->tx_frame_count;
8413*5113495bSYour Name 
8414*5113495bSYour Name 	survey->filled |= SURVEY_INFO_CHANNEL_TIME |
8415*5113495bSYour Name 			  SURVEY_INFO_CHANNEL_TIME_BUSY |
8416*5113495bSYour Name 			  SURVEY_INFO_CHANNEL_TIME_TX;
8417*5113495bSYour Name 	return true;
8418*5113495bSYour Name }
8419*5113495bSYour Name #endif
8420*5113495bSYour Name 
wlan_hdd_update_survey_info(struct wiphy * wiphy,struct hdd_adapter * adapter,struct survey_info * survey,int idx)8421*5113495bSYour Name static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
8422*5113495bSYour Name 					struct hdd_adapter *adapter,
8423*5113495bSYour Name 					struct survey_info *survey, int idx)
8424*5113495bSYour Name {
8425*5113495bSYour Name 	bool filled = false;
8426*5113495bSYour Name 	int i, j = 0;
8427*5113495bSYour Name 	uint32_t opfreq = 0; /* Initialization Required */
8428*5113495bSYour Name 	struct hdd_context *hdd_ctx;
8429*5113495bSYour Name 
8430*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8431*5113495bSYour Name 	sme_get_operation_channel(hdd_ctx->mac_handle, &opfreq,
8432*5113495bSYour Name 				  adapter->deflink->vdev_id);
8433*5113495bSYour Name 
8434*5113495bSYour Name 	mutex_lock(&hdd_ctx->chan_info_lock);
8435*5113495bSYour Name 
8436*5113495bSYour Name 	for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) {
8437*5113495bSYour Name 		if (!wiphy->bands[i])
8438*5113495bSYour Name 			continue;
8439*5113495bSYour Name 
8440*5113495bSYour Name 		for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
8441*5113495bSYour Name 			struct ieee80211_supported_band *band = wiphy->bands[i];
8442*5113495bSYour Name 
8443*5113495bSYour Name 			filled = wlan_fill_survey_result(survey, opfreq,
8444*5113495bSYour Name 				&hdd_ctx->chan_info[idx],
8445*5113495bSYour Name 				&band->channels[j]);
8446*5113495bSYour Name 		}
8447*5113495bSYour Name 	}
8448*5113495bSYour Name 	mutex_unlock(&hdd_ctx->chan_info_lock);
8449*5113495bSYour Name 
8450*5113495bSYour Name 	return filled;
8451*5113495bSYour Name }
8452*5113495bSYour Name 
8453*5113495bSYour Name /**
8454*5113495bSYour Name  * __wlan_hdd_cfg80211_dump_survey() - get survey related info
8455*5113495bSYour Name  * @wiphy: Pointer to wiphy
8456*5113495bSYour Name  * @dev: Pointer to network device
8457*5113495bSYour Name  * @idx: Index
8458*5113495bSYour Name  * @survey: Pointer to survey info
8459*5113495bSYour Name  *
8460*5113495bSYour Name  * Return: 0 for success, non-zero for failure
8461*5113495bSYour Name  */
__wlan_hdd_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * dev,int idx,struct survey_info * survey)8462*5113495bSYour Name static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
8463*5113495bSYour Name 					   struct net_device *dev,
8464*5113495bSYour Name 					   int idx, struct survey_info *survey)
8465*5113495bSYour Name {
8466*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
8467*5113495bSYour Name 	struct hdd_context *hdd_ctx;
8468*5113495bSYour Name 	int status;
8469*5113495bSYour Name 	bool filled = false;
8470*5113495bSYour Name 
8471*5113495bSYour Name 	if (idx > NUM_CHANNELS - 1)
8472*5113495bSYour Name 		return -ENOENT;
8473*5113495bSYour Name 
8474*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8475*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
8476*5113495bSYour Name 	if (0 != status)
8477*5113495bSYour Name 		return status;
8478*5113495bSYour Name 
8479*5113495bSYour Name 	if (!hdd_ctx->chan_info) {
8480*5113495bSYour Name 		hdd_debug("chan_info is NULL");
8481*5113495bSYour Name 		return -EINVAL;
8482*5113495bSYour Name 	}
8483*5113495bSYour Name 
8484*5113495bSYour Name 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
8485*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
8486*5113495bSYour Name 		return -EINVAL;
8487*5113495bSYour Name 	}
8488*5113495bSYour Name 
8489*5113495bSYour Name 	if (!ucfg_scan_is_snr_monitor_enabled(hdd_ctx->psoc))
8490*5113495bSYour Name 		return -ENONET;
8491*5113495bSYour Name 
8492*5113495bSYour Name 	if (hdd_cm_is_vdev_roaming(adapter->deflink)) {
8493*5113495bSYour Name 		hdd_debug("Roaming in progress, hence return");
8494*5113495bSYour Name 		return -ENONET;
8495*5113495bSYour Name 	}
8496*5113495bSYour Name 
8497*5113495bSYour Name 	filled = wlan_hdd_update_survey_info(wiphy, adapter, survey, idx);
8498*5113495bSYour Name 
8499*5113495bSYour Name 	if (!filled)
8500*5113495bSYour Name 		return -ENOENT;
8501*5113495bSYour Name 
8502*5113495bSYour Name 	return 0;
8503*5113495bSYour Name }
8504*5113495bSYour Name 
8505*5113495bSYour Name /**
8506*5113495bSYour Name  * wlan_hdd_cfg80211_dump_survey() - get survey related info
8507*5113495bSYour Name  * @wiphy: Pointer to wiphy
8508*5113495bSYour Name  * @dev: Pointer to network device
8509*5113495bSYour Name  * @idx: Index
8510*5113495bSYour Name  * @survey: Pointer to survey info
8511*5113495bSYour Name  *
8512*5113495bSYour Name  * Return: 0 for success, non-zero for failure
8513*5113495bSYour Name  */
wlan_hdd_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * dev,int idx,struct survey_info * survey)8514*5113495bSYour Name int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
8515*5113495bSYour Name 				  struct net_device *dev,
8516*5113495bSYour Name 				  int idx, struct survey_info *survey)
8517*5113495bSYour Name {
8518*5113495bSYour Name 	int errno;
8519*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
8520*5113495bSYour Name 
8521*5113495bSYour Name 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
8522*5113495bSYour Name 	if (errno)
8523*5113495bSYour Name 		return errno;
8524*5113495bSYour Name 
8525*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey);
8526*5113495bSYour Name 
8527*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
8528*5113495bSYour Name 
8529*5113495bSYour Name 	return errno;
8530*5113495bSYour Name }
8531*5113495bSYour Name 
8532*5113495bSYour Name /**
8533*5113495bSYour Name  * hdd_display_hif_stats() - display hif stats
8534*5113495bSYour Name  *
8535*5113495bSYour Name  * Return: none
8536*5113495bSYour Name  *
8537*5113495bSYour Name  */
hdd_display_hif_stats(void)8538*5113495bSYour Name void hdd_display_hif_stats(void)
8539*5113495bSYour Name {
8540*5113495bSYour Name 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
8541*5113495bSYour Name 
8542*5113495bSYour Name 	if (!hif_ctx)
8543*5113495bSYour Name 		return;
8544*5113495bSYour Name 
8545*5113495bSYour Name 	hif_display_stats(hif_ctx);
8546*5113495bSYour Name }
8547*5113495bSYour Name 
8548*5113495bSYour Name /**
8549*5113495bSYour Name  * hdd_clear_hif_stats() - clear hif stats
8550*5113495bSYour Name  *
8551*5113495bSYour Name  * Return: none
8552*5113495bSYour Name  */
hdd_clear_hif_stats(void)8553*5113495bSYour Name void hdd_clear_hif_stats(void)
8554*5113495bSYour Name {
8555*5113495bSYour Name 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
8556*5113495bSYour Name 
8557*5113495bSYour Name 	if (!hif_ctx)
8558*5113495bSYour Name 		return;
8559*5113495bSYour Name 	hif_clear_stats(hif_ctx);
8560*5113495bSYour Name }
8561*5113495bSYour Name 
8562*5113495bSYour Name /**
8563*5113495bSYour Name  * hdd_is_rcpi_applicable() - validates RCPI request
8564*5113495bSYour Name  * @adapter: adapter upon which the measurement is requested
8565*5113495bSYour Name  * @mac_addr: peer addr for which measurement is requested
8566*5113495bSYour Name  * @rcpi_value: pointer to where the RCPI should be returned
8567*5113495bSYour Name  * @reassoc: used to return cached RCPI during reassoc
8568*5113495bSYour Name  *
8569*5113495bSYour Name  * Return: true for success, false for failure
8570*5113495bSYour Name  */
8571*5113495bSYour Name 
hdd_is_rcpi_applicable(struct hdd_adapter * adapter,struct qdf_mac_addr * mac_addr,int32_t * rcpi_value,bool * reassoc)8572*5113495bSYour Name static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter,
8573*5113495bSYour Name 				   struct qdf_mac_addr *mac_addr,
8574*5113495bSYour Name 				   int32_t *rcpi_value,
8575*5113495bSYour Name 				   bool *reassoc)
8576*5113495bSYour Name {
8577*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx;
8578*5113495bSYour Name 
8579*5113495bSYour Name 	if (adapter->device_mode == QDF_STA_MODE ||
8580*5113495bSYour Name 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
8581*5113495bSYour Name 		hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
8582*5113495bSYour Name 		if (!hdd_cm_is_vdev_associated(adapter->deflink))
8583*5113495bSYour Name 			return false;
8584*5113495bSYour Name 
8585*5113495bSYour Name 		if (hdd_cm_is_vdev_roaming(adapter->deflink)) {
8586*5113495bSYour Name 			/* return the cached rcpi, if mac addr matches */
8587*5113495bSYour Name 			hdd_debug("Roaming in progress, return cached RCPI");
8588*5113495bSYour Name 			if (!qdf_mem_cmp(&adapter->rcpi.mac_addr,
8589*5113495bSYour Name 					 mac_addr, sizeof(*mac_addr))) {
8590*5113495bSYour Name 				*rcpi_value = adapter->rcpi.rcpi;
8591*5113495bSYour Name 				*reassoc = true;
8592*5113495bSYour Name 				return true;
8593*5113495bSYour Name 			}
8594*5113495bSYour Name 			return false;
8595*5113495bSYour Name 		}
8596*5113495bSYour Name 
8597*5113495bSYour Name 		if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssid,
8598*5113495bSYour Name 				sizeof(*mac_addr))) {
8599*5113495bSYour Name 			hdd_err("mac addr is different from bssid connected");
8600*5113495bSYour Name 			return false;
8601*5113495bSYour Name 		}
8602*5113495bSYour Name 	} else if (adapter->device_mode == QDF_SAP_MODE ||
8603*5113495bSYour Name 		   adapter->device_mode == QDF_P2P_GO_MODE) {
8604*5113495bSYour Name 		if (!test_bit(SOFTAP_BSS_STARTED,
8605*5113495bSYour Name 			      &adapter->deflink->link_flags)) {
8606*5113495bSYour Name 			hdd_err("Invalid rcpi request, softap not started");
8607*5113495bSYour Name 			return false;
8608*5113495bSYour Name 		}
8609*5113495bSYour Name 
8610*5113495bSYour Name 		/* check if peer mac addr is associated to softap */
8611*5113495bSYour Name 		if (!hdd_is_peer_associated(adapter, mac_addr)) {
8612*5113495bSYour Name 			hdd_err("invalid peer mac-addr: not associated");
8613*5113495bSYour Name 			return false;
8614*5113495bSYour Name 		}
8615*5113495bSYour Name 	} else {
8616*5113495bSYour Name 		hdd_err("Invalid rcpi request");
8617*5113495bSYour Name 		return false;
8618*5113495bSYour Name 	}
8619*5113495bSYour Name 
8620*5113495bSYour Name 	*reassoc = false;
8621*5113495bSYour Name 	return true;
8622*5113495bSYour Name }
8623*5113495bSYour Name 
8624*5113495bSYour Name /**
8625*5113495bSYour Name  * wlan_hdd_get_rcpi_cb() - callback function for rcpi response
8626*5113495bSYour Name  * @context: Pointer to rcpi context
8627*5113495bSYour Name  * @mac_addr: peer MAC address
8628*5113495bSYour Name  * @rcpi: RCPI response
8629*5113495bSYour Name  * @status: QDF_STATUS of the request
8630*5113495bSYour Name  *
8631*5113495bSYour Name  * Return: None
8632*5113495bSYour Name  */
wlan_hdd_get_rcpi_cb(void * context,struct qdf_mac_addr mac_addr,int32_t rcpi,QDF_STATUS status)8633*5113495bSYour Name static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr,
8634*5113495bSYour Name 				 int32_t rcpi, QDF_STATUS status)
8635*5113495bSYour Name {
8636*5113495bSYour Name 	struct osif_request *request;
8637*5113495bSYour Name 	struct rcpi_info *priv;
8638*5113495bSYour Name 
8639*5113495bSYour Name 	if (!context) {
8640*5113495bSYour Name 		hdd_err("No rcpi context");
8641*5113495bSYour Name 		return;
8642*5113495bSYour Name 	}
8643*5113495bSYour Name 
8644*5113495bSYour Name 	request = osif_request_get(context);
8645*5113495bSYour Name 	if (!request) {
8646*5113495bSYour Name 		hdd_err("Obsolete RCPI request");
8647*5113495bSYour Name 		return;
8648*5113495bSYour Name 	}
8649*5113495bSYour Name 
8650*5113495bSYour Name 	priv = osif_request_priv(request);
8651*5113495bSYour Name 	priv->mac_addr = mac_addr;
8652*5113495bSYour Name 
8653*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status)) {
8654*5113495bSYour Name 		priv->rcpi = 0;
8655*5113495bSYour Name 		hdd_err("Error in computing RCPI");
8656*5113495bSYour Name 	} else {
8657*5113495bSYour Name 		priv->rcpi = rcpi;
8658*5113495bSYour Name 	}
8659*5113495bSYour Name 
8660*5113495bSYour Name 	osif_request_complete(request);
8661*5113495bSYour Name 	osif_request_put(request);
8662*5113495bSYour Name }
8663*5113495bSYour Name 
8664*5113495bSYour Name /**
8665*5113495bSYour Name  * wlan_hdd_get_rcpi() - local function to get RCPI
8666*5113495bSYour Name  * @adapter: adapter upon which the measurement is requested
8667*5113495bSYour Name  * @mac: peer addr for which measurement is requested
8668*5113495bSYour Name  * @rcpi_value: pointer to where the RCPI should be returned
8669*5113495bSYour Name  * @measurement_type: type of rcpi measurement
8670*5113495bSYour Name  *
8671*5113495bSYour Name  * Return: 0 for success, non-zero for failure
8672*5113495bSYour Name  */
wlan_hdd_get_rcpi(struct hdd_adapter * adapter,uint8_t * mac,int32_t * rcpi_value,enum rcpi_measurement_type measurement_type)8673*5113495bSYour Name int wlan_hdd_get_rcpi(struct hdd_adapter *adapter,
8674*5113495bSYour Name 		      uint8_t *mac,
8675*5113495bSYour Name 		      int32_t *rcpi_value,
8676*5113495bSYour Name 		      enum rcpi_measurement_type measurement_type)
8677*5113495bSYour Name {
8678*5113495bSYour Name 	struct hdd_context *hdd_ctx;
8679*5113495bSYour Name 	int status = 0, ret = 0;
8680*5113495bSYour Name 	struct qdf_mac_addr mac_addr;
8681*5113495bSYour Name 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
8682*5113495bSYour Name 	struct sme_rcpi_req *rcpi_req;
8683*5113495bSYour Name 	void *cookie;
8684*5113495bSYour Name 	struct rcpi_info *priv;
8685*5113495bSYour Name 	struct osif_request *request;
8686*5113495bSYour Name 	static const struct osif_request_params params = {
8687*5113495bSYour Name 		.priv_size = sizeof(*priv),
8688*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_RCPI,
8689*5113495bSYour Name 	};
8690*5113495bSYour Name 	bool reassoc;
8691*5113495bSYour Name 
8692*5113495bSYour Name 	hdd_enter();
8693*5113495bSYour Name 
8694*5113495bSYour Name 	/* initialize the rcpi value to zero, useful in error cases */
8695*5113495bSYour Name 	*rcpi_value = 0;
8696*5113495bSYour Name 
8697*5113495bSYour Name 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
8698*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
8699*5113495bSYour Name 		return -EINVAL;
8700*5113495bSYour Name 	}
8701*5113495bSYour Name 
8702*5113495bSYour Name 	if (!adapter) {
8703*5113495bSYour Name 		hdd_warn("adapter context is NULL");
8704*5113495bSYour Name 		return -EINVAL;
8705*5113495bSYour Name 	}
8706*5113495bSYour Name 
8707*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
8708*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
8709*5113495bSYour Name 	if (status)
8710*5113495bSYour Name 		return -EINVAL;
8711*5113495bSYour Name 
8712*5113495bSYour Name 	if (!hdd_ctx->rcpi_enabled) {
8713*5113495bSYour Name 		hdd_debug("RCPI not supported");
8714*5113495bSYour Name 		return -EINVAL;
8715*5113495bSYour Name 	}
8716*5113495bSYour Name 
8717*5113495bSYour Name 	if (!mac) {
8718*5113495bSYour Name 		hdd_warn("RCPI peer mac-addr is NULL");
8719*5113495bSYour Name 		return -EINVAL;
8720*5113495bSYour Name 	}
8721*5113495bSYour Name 
8722*5113495bSYour Name 	qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE);
8723*5113495bSYour Name 
8724*5113495bSYour Name 	if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc))
8725*5113495bSYour Name 		return -EINVAL;
8726*5113495bSYour Name 	if (reassoc)
8727*5113495bSYour Name 		return 0;
8728*5113495bSYour Name 
8729*5113495bSYour Name 	rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
8730*5113495bSYour Name 	if (!rcpi_req)
8731*5113495bSYour Name 		return -EINVAL;
8732*5113495bSYour Name 
8733*5113495bSYour Name 	request = osif_request_alloc(&params);
8734*5113495bSYour Name 	if (!request) {
8735*5113495bSYour Name 		hdd_err("Request allocation failure");
8736*5113495bSYour Name 		qdf_mem_free(rcpi_req);
8737*5113495bSYour Name 		return -ENOMEM;
8738*5113495bSYour Name 	}
8739*5113495bSYour Name 	cookie = osif_request_cookie(request);
8740*5113495bSYour Name 
8741*5113495bSYour Name 	rcpi_req->mac_addr = mac_addr;
8742*5113495bSYour Name 	rcpi_req->session_id = adapter->deflink->vdev_id;
8743*5113495bSYour Name 	rcpi_req->measurement_type = measurement_type;
8744*5113495bSYour Name 	rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb;
8745*5113495bSYour Name 	rcpi_req->rcpi_context = cookie;
8746*5113495bSYour Name 
8747*5113495bSYour Name 	qdf_status = sme_get_rcpi(hdd_ctx->mac_handle, rcpi_req);
8748*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
8749*5113495bSYour Name 		hdd_err("Unable to retrieve RCPI");
8750*5113495bSYour Name 		status = qdf_status_to_os_return(qdf_status);
8751*5113495bSYour Name 		goto out;
8752*5113495bSYour Name 	}
8753*5113495bSYour Name 
8754*5113495bSYour Name 	/* request was sent -- wait for the response */
8755*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
8756*5113495bSYour Name 	if (ret) {
8757*5113495bSYour Name 		hdd_err("SME timed out while retrieving RCPI");
8758*5113495bSYour Name 		status = -EINVAL;
8759*5113495bSYour Name 		goto out;
8760*5113495bSYour Name 	}
8761*5113495bSYour Name 
8762*5113495bSYour Name 	/* update the adapter with the fresh results */
8763*5113495bSYour Name 	priv = osif_request_priv(request);
8764*5113495bSYour Name 	adapter->rcpi.mac_addr = priv->mac_addr;
8765*5113495bSYour Name 	adapter->rcpi.rcpi = priv->rcpi;
8766*5113495bSYour Name 	if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) {
8767*5113495bSYour Name 		hdd_err("mis match of mac addr from call-back");
8768*5113495bSYour Name 		status = -EINVAL;
8769*5113495bSYour Name 		goto out;
8770*5113495bSYour Name 	}
8771*5113495bSYour Name 
8772*5113495bSYour Name 	*rcpi_value = adapter->rcpi.rcpi;
8773*5113495bSYour Name 	hdd_debug("RCPI = %d", *rcpi_value);
8774*5113495bSYour Name out:
8775*5113495bSYour Name 	qdf_mem_free(rcpi_req);
8776*5113495bSYour Name 	osif_request_put(request);
8777*5113495bSYour Name 
8778*5113495bSYour Name 	hdd_exit();
8779*5113495bSYour Name 	return status;
8780*5113495bSYour Name }
8781*5113495bSYour Name 
8782*5113495bSYour Name #ifdef WLAN_FEATURE_MIB_STATS
wlan_hdd_get_mib_stats(struct hdd_adapter * adapter)8783*5113495bSYour Name QDF_STATUS wlan_hdd_get_mib_stats(struct hdd_adapter *adapter)
8784*5113495bSYour Name {
8785*5113495bSYour Name 	int ret = 0;
8786*5113495bSYour Name 	struct stats_event *stats;
8787*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
8788*5113495bSYour Name 
8789*5113495bSYour Name 	if (!adapter) {
8790*5113495bSYour Name 		hdd_err("Invalid context, adapter");
8791*5113495bSYour Name 		return QDF_STATUS_E_FAULT;
8792*5113495bSYour Name 	}
8793*5113495bSYour Name 
8794*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
8795*5113495bSYour Name 					   WLAN_OSIF_STATS_ID);
8796*5113495bSYour Name 	if (!vdev)
8797*5113495bSYour Name 		return QDF_STATUS_E_FAULT;
8798*5113495bSYour Name 
8799*5113495bSYour Name 	stats = wlan_cfg80211_mc_cp_stats_get_mib_stats(vdev, &ret);
8800*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
8801*5113495bSYour Name 	if (ret || !stats) {
8802*5113495bSYour Name 		wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
8803*5113495bSYour Name 		return ret;
8804*5113495bSYour Name 	}
8805*5113495bSYour Name 
8806*5113495bSYour Name 	hdd_debugfs_process_mib_stats(adapter, stats);
8807*5113495bSYour Name 
8808*5113495bSYour Name 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
8809*5113495bSYour Name 	return ret;
8810*5113495bSYour Name }
8811*5113495bSYour Name #endif
8812*5113495bSYour Name 
wlan_hdd_get_rssi(struct wlan_hdd_link_info * link_info,int8_t * rssi_value)8813*5113495bSYour Name QDF_STATUS wlan_hdd_get_rssi(struct wlan_hdd_link_info *link_info,
8814*5113495bSYour Name 			     int8_t *rssi_value)
8815*5113495bSYour Name {
8816*5113495bSYour Name 	int ret = 0, i;
8817*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
8818*5113495bSYour Name 	struct stats_event *rssi_info;
8819*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
8820*5113495bSYour Name 
8821*5113495bSYour Name 	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
8822*5113495bSYour Name 		hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
8823*5113495bSYour Name 			cds_get_driver_state());
8824*5113495bSYour Name 		/* return a cached value */
8825*5113495bSYour Name 		*rssi_value = link_info->rssi;
8826*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
8827*5113495bSYour Name 	}
8828*5113495bSYour Name 
8829*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
8830*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(link_info)) {
8831*5113495bSYour Name 		hdd_debug("Not associated!, rssi on disconnect %d",
8832*5113495bSYour Name 			  link_info->rssi_on_disconnect);
8833*5113495bSYour Name 		*rssi_value = link_info->rssi_on_disconnect;
8834*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
8835*5113495bSYour Name 	}
8836*5113495bSYour Name 
8837*5113495bSYour Name 	if (hdd_cm_is_vdev_roaming(link_info)) {
8838*5113495bSYour Name 		hdd_debug("Roaming in progress, return cached RSSI");
8839*5113495bSYour Name 		*rssi_value = link_info->rssi;
8840*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
8841*5113495bSYour Name 	}
8842*5113495bSYour Name 
8843*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
8844*5113495bSYour Name 	if (!vdev) {
8845*5113495bSYour Name 		*rssi_value = link_info->rssi;
8846*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
8847*5113495bSYour Name 	}
8848*5113495bSYour Name 
8849*5113495bSYour Name 	rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi(
8850*5113495bSYour Name 			vdev,
8851*5113495bSYour Name 			sta_ctx->conn_info.bssid.bytes,
8852*5113495bSYour Name 			&ret);
8853*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
8854*5113495bSYour Name 	if (ret || !rssi_info) {
8855*5113495bSYour Name 		wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
8856*5113495bSYour Name 		return ret;
8857*5113495bSYour Name 	}
8858*5113495bSYour Name 
8859*5113495bSYour Name 	for (i = 0; i < rssi_info->num_peer_stats; i++) {
8860*5113495bSYour Name 		if (!qdf_mem_cmp(rssi_info->peer_stats[i].peer_macaddr,
8861*5113495bSYour Name 				 sta_ctx->conn_info.bssid.bytes,
8862*5113495bSYour Name 				 QDF_MAC_ADDR_SIZE)) {
8863*5113495bSYour Name 			*rssi_value = rssi_info->peer_stats[i].peer_rssi;
8864*5113495bSYour Name 			hdd_debug("RSSI = %d", *rssi_value);
8865*5113495bSYour Name 			wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
8866*5113495bSYour Name 			return QDF_STATUS_SUCCESS;
8867*5113495bSYour Name 		}
8868*5113495bSYour Name 	}
8869*5113495bSYour Name 
8870*5113495bSYour Name 	wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info);
8871*5113495bSYour Name 	hdd_err("bss peer not present in returned result");
8872*5113495bSYour Name 	return QDF_STATUS_E_FAULT;
8873*5113495bSYour Name }
8874*5113495bSYour Name 
8875*5113495bSYour Name struct snr_priv {
8876*5113495bSYour Name 	int8_t snr;
8877*5113495bSYour Name };
8878*5113495bSYour Name 
8879*5113495bSYour Name /**
8880*5113495bSYour Name  * hdd_get_snr_cb() - "Get SNR" callback function
8881*5113495bSYour Name  * @snr: Current SNR of the station
8882*5113495bSYour Name  * @context: opaque context originally passed to SME.  HDD always passes
8883*5113495bSYour Name  *	a cookie for the request context
8884*5113495bSYour Name  *
8885*5113495bSYour Name  * Return: None
8886*5113495bSYour Name  */
hdd_get_snr_cb(int8_t snr,void * context)8887*5113495bSYour Name static void hdd_get_snr_cb(int8_t snr, void *context)
8888*5113495bSYour Name {
8889*5113495bSYour Name 	struct osif_request *request;
8890*5113495bSYour Name 	struct snr_priv *priv;
8891*5113495bSYour Name 
8892*5113495bSYour Name 	request = osif_request_get(context);
8893*5113495bSYour Name 	if (!request) {
8894*5113495bSYour Name 		hdd_err("Obsolete request");
8895*5113495bSYour Name 		return;
8896*5113495bSYour Name 	}
8897*5113495bSYour Name 
8898*5113495bSYour Name 	/* propagate response back to requesting thread */
8899*5113495bSYour Name 	priv = osif_request_priv(request);
8900*5113495bSYour Name 	priv->snr = snr;
8901*5113495bSYour Name 	osif_request_complete(request);
8902*5113495bSYour Name 	osif_request_put(request);
8903*5113495bSYour Name }
8904*5113495bSYour Name 
wlan_hdd_get_snr(struct wlan_hdd_link_info * link_info,int8_t * snr)8905*5113495bSYour Name QDF_STATUS wlan_hdd_get_snr(struct wlan_hdd_link_info *link_info, int8_t *snr)
8906*5113495bSYour Name {
8907*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
8908*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
8909*5113495bSYour Name 	QDF_STATUS status;
8910*5113495bSYour Name 	int ret;
8911*5113495bSYour Name 	void *cookie;
8912*5113495bSYour Name 	struct osif_request *request;
8913*5113495bSYour Name 	struct snr_priv *priv;
8914*5113495bSYour Name 	static const struct osif_request_params params = {
8915*5113495bSYour Name 		.priv_size = sizeof(*priv),
8916*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_STATS,
8917*5113495bSYour Name 	};
8918*5113495bSYour Name 
8919*5113495bSYour Name 	hdd_enter();
8920*5113495bSYour Name 
8921*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
8922*5113495bSYour Name 	if (ret)
8923*5113495bSYour Name 		return QDF_STATUS_E_FAULT;
8924*5113495bSYour Name 
8925*5113495bSYour Name 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
8926*5113495bSYour Name 
8927*5113495bSYour Name 	request = osif_request_alloc(&params);
8928*5113495bSYour Name 	if (!request) {
8929*5113495bSYour Name 		hdd_err("Request allocation failure");
8930*5113495bSYour Name 		return QDF_STATUS_E_FAULT;
8931*5113495bSYour Name 	}
8932*5113495bSYour Name 	cookie = osif_request_cookie(request);
8933*5113495bSYour Name 
8934*5113495bSYour Name 	status = sme_get_snr(hdd_ctx->mac_handle, hdd_get_snr_cb,
8935*5113495bSYour Name 			     sta_ctx->conn_info.bssid, cookie);
8936*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
8937*5113495bSYour Name 		hdd_err("Unable to retrieve RSSI");
8938*5113495bSYour Name 		/* we'll returned a cached value below */
8939*5113495bSYour Name 	} else {
8940*5113495bSYour Name 		/* request was sent -- wait for the response */
8941*5113495bSYour Name 		ret = osif_request_wait_for_response(request);
8942*5113495bSYour Name 		if (ret) {
8943*5113495bSYour Name 			hdd_err("SME timed out while retrieving SNR");
8944*5113495bSYour Name 			/* we'll now returned a cached value below */
8945*5113495bSYour Name 		} else {
8946*5113495bSYour Name 			/* update the adapter with the fresh results */
8947*5113495bSYour Name 			priv = osif_request_priv(request);
8948*5113495bSYour Name 			link_info->snr = priv->snr;
8949*5113495bSYour Name 		}
8950*5113495bSYour Name 	}
8951*5113495bSYour Name 
8952*5113495bSYour Name 	/*
8953*5113495bSYour Name 	 * either we never sent a request, we sent a request and
8954*5113495bSYour Name 	 * received a response or we sent a request and timed out.
8955*5113495bSYour Name 	 * regardless we are done with the request.
8956*5113495bSYour Name 	 */
8957*5113495bSYour Name 	osif_request_put(request);
8958*5113495bSYour Name 
8959*5113495bSYour Name 	*snr = link_info->snr;
8960*5113495bSYour Name 	hdd_exit();
8961*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
8962*5113495bSYour Name }
8963*5113495bSYour Name 
8964*5113495bSYour Name struct linkspeed_priv {
8965*5113495bSYour Name 	struct link_speed_info linkspeed_info;
8966*5113495bSYour Name };
8967*5113495bSYour Name 
8968*5113495bSYour Name static void
hdd_get_link_speed_cb(struct link_speed_info * linkspeed_info,void * context)8969*5113495bSYour Name hdd_get_link_speed_cb(struct link_speed_info *linkspeed_info, void *context)
8970*5113495bSYour Name {
8971*5113495bSYour Name 	struct osif_request *request;
8972*5113495bSYour Name 	struct linkspeed_priv *priv;
8973*5113495bSYour Name 
8974*5113495bSYour Name 	if (!linkspeed_info) {
8975*5113495bSYour Name 		hdd_err("NULL linkspeed");
8976*5113495bSYour Name 		return;
8977*5113495bSYour Name 	}
8978*5113495bSYour Name 
8979*5113495bSYour Name 	request = osif_request_get(context);
8980*5113495bSYour Name 	if (!request) {
8981*5113495bSYour Name 		hdd_err("Obsolete request");
8982*5113495bSYour Name 		return;
8983*5113495bSYour Name 	}
8984*5113495bSYour Name 
8985*5113495bSYour Name 	priv = osif_request_priv(request);
8986*5113495bSYour Name 	priv->linkspeed_info = *linkspeed_info;
8987*5113495bSYour Name 	osif_request_complete(request);
8988*5113495bSYour Name 	osif_request_put(request);
8989*5113495bSYour Name }
8990*5113495bSYour Name 
wlan_hdd_get_linkspeed_for_peermac(struct wlan_hdd_link_info * link_info,struct qdf_mac_addr * mac_address,uint32_t * linkspeed)8991*5113495bSYour Name int wlan_hdd_get_linkspeed_for_peermac(struct wlan_hdd_link_info *link_info,
8992*5113495bSYour Name 				       struct qdf_mac_addr *mac_address,
8993*5113495bSYour Name 				       uint32_t *linkspeed)
8994*5113495bSYour Name {
8995*5113495bSYour Name 	int ret;
8996*5113495bSYour Name 	QDF_STATUS status;
8997*5113495bSYour Name 	void *cookie;
8998*5113495bSYour Name 	struct link_speed_info *linkspeed_info;
8999*5113495bSYour Name 	struct osif_request *request;
9000*5113495bSYour Name 	struct linkspeed_priv *priv;
9001*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
9002*5113495bSYour Name 	static const struct osif_request_params params = {
9003*5113495bSYour Name 		.priv_size = sizeof(*priv),
9004*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_STATS,
9005*5113495bSYour Name 	};
9006*5113495bSYour Name 
9007*5113495bSYour Name 	if (!linkspeed) {
9008*5113495bSYour Name 		hdd_err("NULL argument");
9009*5113495bSYour Name 		return -EINVAL;
9010*5113495bSYour Name 	}
9011*5113495bSYour Name 
9012*5113495bSYour Name 	request = osif_request_alloc(&params);
9013*5113495bSYour Name 	if (!request) {
9014*5113495bSYour Name 		hdd_err("Request allocation failure");
9015*5113495bSYour Name 		ret = -ENOMEM;
9016*5113495bSYour Name 		goto return_cached_value;
9017*5113495bSYour Name 	}
9018*5113495bSYour Name 
9019*5113495bSYour Name 	cookie = osif_request_cookie(request);
9020*5113495bSYour Name 	priv = osif_request_priv(request);
9021*5113495bSYour Name 
9022*5113495bSYour Name 	linkspeed_info = &priv->linkspeed_info;
9023*5113495bSYour Name 	qdf_copy_macaddr(&linkspeed_info->peer_macaddr, mac_address);
9024*5113495bSYour Name 	status = sme_get_link_speed(adapter->hdd_ctx->mac_handle,
9025*5113495bSYour Name 				    linkspeed_info,
9026*5113495bSYour Name 				    cookie, hdd_get_link_speed_cb);
9027*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
9028*5113495bSYour Name 		hdd_err("Unable to retrieve statistics for link speed");
9029*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
9030*5113495bSYour Name 		goto cleanup;
9031*5113495bSYour Name 	}
9032*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
9033*5113495bSYour Name 	if (ret) {
9034*5113495bSYour Name 		hdd_err("SME timed out while retrieving link speed");
9035*5113495bSYour Name 		goto cleanup;
9036*5113495bSYour Name 	}
9037*5113495bSYour Name 	link_info->estimated_linkspeed = linkspeed_info->estLinkSpeed;
9038*5113495bSYour Name 
9039*5113495bSYour Name cleanup:
9040*5113495bSYour Name 	/*
9041*5113495bSYour Name 	 * either we never sent a request, we sent a request and
9042*5113495bSYour Name 	 * received a response or we sent a request and timed out.
9043*5113495bSYour Name 	 * regardless we are done with the request.
9044*5113495bSYour Name 	 */
9045*5113495bSYour Name 	osif_request_put(request);
9046*5113495bSYour Name 
9047*5113495bSYour Name return_cached_value:
9048*5113495bSYour Name 	*linkspeed = link_info->estimated_linkspeed;
9049*5113495bSYour Name 
9050*5113495bSYour Name 	return ret;
9051*5113495bSYour Name }
9052*5113495bSYour Name 
9053*5113495bSYour Name static uint32_t
wlan_hdd_get_per_link_speed(struct wlan_hdd_link_info * link_info)9054*5113495bSYour Name wlan_hdd_get_per_link_speed(struct wlan_hdd_link_info *link_info)
9055*5113495bSYour Name {
9056*5113495bSYour Name 	uint32_t link_speed;
9057*5113495bSYour Name 	struct qdf_mac_addr bssid;
9058*5113495bSYour Name 
9059*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(link_info)) {
9060*5113495bSYour Name 		/* we are not connected so we don't have a classAstats */
9061*5113495bSYour Name 		hdd_debug("Not connected");
9062*5113495bSYour Name 		return 0;
9063*5113495bSYour Name 	}
9064*5113495bSYour Name 	qdf_copy_macaddr(&bssid,
9065*5113495bSYour Name 			 &link_info->session.station.conn_info.bssid);
9066*5113495bSYour Name 
9067*5113495bSYour Name 	if (wlan_hdd_get_linkspeed_for_peermac(link_info,
9068*5113495bSYour Name 					       &bssid, &link_speed)) {
9069*5113495bSYour Name 		hdd_err("Unable to retrieve SME linkspeed");
9070*5113495bSYour Name 		return 0;
9071*5113495bSYour Name 	}
9072*5113495bSYour Name 	hdd_debug("linkspeed = %d", link_speed);
9073*5113495bSYour Name 	return link_speed;
9074*5113495bSYour Name }
9075*5113495bSYour Name 
9076*5113495bSYour Name #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
9077*5113495bSYour Name #ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
9078*5113495bSYour Name static uint32_t
wlan_hdd_get_mlo_link_speed(struct hdd_adapter * adapter)9079*5113495bSYour Name wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
9080*5113495bSYour Name {
9081*5113495bSYour Name 	struct hdd_adapter *ml_adapter = NULL;
9082*5113495bSYour Name 	struct hdd_adapter *link_adapter = NULL;
9083*5113495bSYour Name 	struct hdd_mlo_adapter_info *mlo_adapter_info = NULL;
9084*5113495bSYour Name 	uint32_t link_speed = 0;
9085*5113495bSYour Name 	uint32_t per_speed;
9086*5113495bSYour Name 	uint8_t link_id;
9087*5113495bSYour Name 
9088*5113495bSYour Name 	ml_adapter = adapter;
9089*5113495bSYour Name 	if (hdd_adapter_is_link_adapter(ml_adapter))
9090*5113495bSYour Name 		ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter);
9091*5113495bSYour Name 
9092*5113495bSYour Name 	mlo_adapter_info = &ml_adapter->mlo_adapter_info;
9093*5113495bSYour Name 	for (link_id = 0; link_id < WLAN_MAX_MLD; link_id++) {
9094*5113495bSYour Name 		link_adapter = mlo_adapter_info->link_adapter[link_id];
9095*5113495bSYour Name 		if (qdf_unlikely(!link_adapter)) {
9096*5113495bSYour Name 			hdd_err("link_adapter[%d] is Null", link_id);
9097*5113495bSYour Name 			continue;
9098*5113495bSYour Name 		}
9099*5113495bSYour Name 		per_speed = wlan_hdd_get_per_link_speed(ml_adapter->deflink);
9100*5113495bSYour Name 		link_speed += per_speed;
9101*5113495bSYour Name 		hdd_debug("Link%d speed=%d, total speed=%d",
9102*5113495bSYour Name 			  link_id, per_speed, link_speed);
9103*5113495bSYour Name 	}
9104*5113495bSYour Name 	return link_speed;
9105*5113495bSYour Name }
9106*5113495bSYour Name #else
9107*5113495bSYour Name static uint32_t
wlan_hdd_get_mlo_link_speed(struct hdd_adapter * adapter)9108*5113495bSYour Name wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
9109*5113495bSYour Name {
9110*5113495bSYour Name 	struct wlan_hdd_link_info *link_info = NULL;
9111*5113495bSYour Name 	uint32_t link_speed = 0;
9112*5113495bSYour Name 	uint32_t per_speed;
9113*5113495bSYour Name 
9114*5113495bSYour Name 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
9115*5113495bSYour Name 		per_speed = wlan_hdd_get_per_link_speed(link_info);
9116*5113495bSYour Name 		link_speed += per_speed;
9117*5113495bSYour Name 		hdd_debug("per_speed=%d, link_speed=%d", per_speed, link_speed);
9118*5113495bSYour Name 	}
9119*5113495bSYour Name 	return link_speed;
9120*5113495bSYour Name }
9121*5113495bSYour Name #endif
9122*5113495bSYour Name 
9123*5113495bSYour Name #else
9124*5113495bSYour Name static uint32_t
wlan_hdd_get_mlo_link_speed(struct hdd_adapter * adapter)9125*5113495bSYour Name wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter)
9126*5113495bSYour Name {
9127*5113495bSYour Name 	uint32_t link_speed = wlan_hdd_get_per_link_speed(adapter->deflink);
9128*5113495bSYour Name 
9129*5113495bSYour Name 	hdd_debug("Not support MLO, linkspeed = %d", link_speed);
9130*5113495bSYour Name 	return link_speed;
9131*5113495bSYour Name }
9132*5113495bSYour Name #endif
9133*5113495bSYour Name 
wlan_hdd_get_link_speed(struct wlan_hdd_link_info * link_info,uint32_t * link_speed)9134*5113495bSYour Name int wlan_hdd_get_link_speed(struct wlan_hdd_link_info *link_info,
9135*5113495bSYour Name 			    uint32_t *link_speed)
9136*5113495bSYour Name {
9137*5113495bSYour Name 	struct hdd_adapter *adapter =  link_info->adapter;
9138*5113495bSYour Name 	struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter);
9139*5113495bSYour Name 	int ret;
9140*5113495bSYour Name 
9141*5113495bSYour Name 	ret = wlan_hdd_validate_context(hddctx);
9142*5113495bSYour Name 	if (ret)
9143*5113495bSYour Name 		return ret;
9144*5113495bSYour Name 
9145*5113495bSYour Name 	/* Linkspeed is allowed for CLIENT/STA mode */
9146*5113495bSYour Name 	if (adapter->device_mode != QDF_P2P_CLIENT_MODE &&
9147*5113495bSYour Name 	    adapter->device_mode != QDF_STA_MODE) {
9148*5113495bSYour Name 		hdd_err("Link Speed is not allowed in Device mode %s(%d)",
9149*5113495bSYour Name 			qdf_opmode_str(adapter->device_mode),
9150*5113495bSYour Name 			adapter->device_mode);
9151*5113495bSYour Name 		return -ENOTSUPP;
9152*5113495bSYour Name 	}
9153*5113495bSYour Name 
9154*5113495bSYour Name 	if (wlan_hdd_is_mlo_connection(link_info))
9155*5113495bSYour Name 		*link_speed = wlan_hdd_get_mlo_link_speed(adapter);
9156*5113495bSYour Name 	else
9157*5113495bSYour Name 		*link_speed = wlan_hdd_get_per_link_speed(link_info);
9158*5113495bSYour Name 
9159*5113495bSYour Name 	/* linkspeed in units of 500 kbps */
9160*5113495bSYour Name 	*link_speed = (*link_speed) / 500;
9161*5113495bSYour Name 	return 0;
9162*5113495bSYour Name }
9163*5113495bSYour Name 
wlan_hdd_get_sap_go_peer_linkspeed(struct wlan_hdd_link_info * link_info,uint32_t * link_speed,uint8_t * command,uint8_t command_len)9164*5113495bSYour Name int wlan_hdd_get_sap_go_peer_linkspeed(struct wlan_hdd_link_info *link_info,
9165*5113495bSYour Name 				       uint32_t *link_speed,
9166*5113495bSYour Name 				       uint8_t *command,
9167*5113495bSYour Name 				       uint8_t command_len)
9168*5113495bSYour Name {
9169*5113495bSYour Name 	int ret;
9170*5113495bSYour Name 	struct qdf_mac_addr mac_address;
9171*5113495bSYour Name 	char macaddr_string[MAC_ADDRESS_STR_LEN + 1];
9172*5113495bSYour Name 	uint8_t *value = command;
9173*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
9174*5113495bSYour Name 	struct hdd_station_info *sta_info, *tmp = NULL;
9175*5113495bSYour Name 
9176*5113495bSYour Name 	value = value + command_len;
9177*5113495bSYour Name 	ret = sscanf(value, "%17s", macaddr_string);
9178*5113495bSYour Name 
9179*5113495bSYour Name 	if (ret != 1)
9180*5113495bSYour Name 		return -EINVAL;
9181*5113495bSYour Name 
9182*5113495bSYour Name 	macaddr_string[MAC_ADDRESS_STR_LEN - 1] = '\0';
9183*5113495bSYour Name 	if (!mac_pton(macaddr_string, mac_address.bytes)) {
9184*5113495bSYour Name 		hdd_err("String to Hex conversion Failed");
9185*5113495bSYour Name 		return -EINVAL;
9186*5113495bSYour Name 	}
9187*5113495bSYour Name 
9188*5113495bSYour Name 	hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp,
9189*5113495bSYour Name 				  STA_INFO_GET_SOFTAP_LINKSPEED) {
9190*5113495bSYour Name 		if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) {
9191*5113495bSYour Name 			if (qdf_is_macaddr_equal(&mac_address,
9192*5113495bSYour Name 						 &sta_info->sta_mac)) {
9193*5113495bSYour Name 				ret = wlan_hdd_get_linkspeed_for_peermac(
9194*5113495bSYour Name 							adapter->deflink,
9195*5113495bSYour Name 							&mac_address,
9196*5113495bSYour Name 							link_speed);
9197*5113495bSYour Name 				hdd_put_sta_info_ref(
9198*5113495bSYour Name 						&adapter->sta_info_list,
9199*5113495bSYour Name 						&sta_info, true,
9200*5113495bSYour Name 						STA_INFO_GET_SOFTAP_LINKSPEED);
9201*5113495bSYour Name 				if (tmp)
9202*5113495bSYour Name 					hdd_put_sta_info_ref(
9203*5113495bSYour Name 						&adapter->sta_info_list,
9204*5113495bSYour Name 						&tmp, true,
9205*5113495bSYour Name 						STA_INFO_GET_SOFTAP_LINKSPEED);
9206*5113495bSYour Name 				break;
9207*5113495bSYour Name 			}
9208*5113495bSYour Name 		}
9209*5113495bSYour Name 		hdd_put_sta_info_ref(&adapter->sta_info_list,
9210*5113495bSYour Name 				     &sta_info, true,
9211*5113495bSYour Name 				     STA_INFO_GET_SOFTAP_LINKSPEED);
9212*5113495bSYour Name 	}
9213*5113495bSYour Name 
9214*5113495bSYour Name 	if (ret) {
9215*5113495bSYour Name 		hdd_err("Unable to retrieve SAP/GO linkspeed");
9216*5113495bSYour Name 		return ret;
9217*5113495bSYour Name 	}
9218*5113495bSYour Name 
9219*5113495bSYour Name 	*link_speed = (*link_speed) / 500;
9220*5113495bSYour Name 	return 0;
9221*5113495bSYour Name }
9222*5113495bSYour Name #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER
9223*5113495bSYour Name /**
9224*5113495bSYour Name  * wlan_hdd_get_per_peer_stats - get per peer stats if supported by FW
9225*5113495bSYour Name  * @link_info: Link info pointer of STA adapter to get stats for
9226*5113495bSYour Name  * @peer_stats: Pointer to peer_stats
9227*5113495bSYour Name  *
9228*5113495bSYour Name  * Return: QDF_STATUS
9229*5113495bSYour Name  */
9230*5113495bSYour Name static QDF_STATUS
wlan_hdd_get_per_peer_stats(struct wlan_hdd_link_info * link_info,struct cdp_peer_stats * peer_stats)9231*5113495bSYour Name wlan_hdd_get_per_peer_stats(struct wlan_hdd_link_info *link_info,
9232*5113495bSYour Name 			    struct cdp_peer_stats *peer_stats)
9233*5113495bSYour Name {
9234*5113495bSYour Name 	QDF_STATUS status;
9235*5113495bSYour Name 	ol_txrx_soc_handle soc;
9236*5113495bSYour Name 	uint8_t *peer_mac;
9237*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
9238*5113495bSYour Name 
9239*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx)) {
9240*5113495bSYour Name 		hdd_err("invalid hdd_ctx");
9241*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
9242*5113495bSYour Name 	}
9243*5113495bSYour Name 
9244*5113495bSYour Name 	soc = cds_get_context(QDF_MODULE_ID_SOC);
9245*5113495bSYour Name 	peer_mac = link_info->session.station.conn_info.bssid.bytes;
9246*5113495bSYour Name 
9247*5113495bSYour Name 	if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx)) {
9248*5113495bSYour Name 		hdd_debug("mlo per link stats is not supported by FW");
9249*5113495bSYour Name 		status = cdp_host_get_peer_stats(soc, link_info->vdev_id,
9250*5113495bSYour Name 						 peer_mac, peer_stats);
9251*5113495bSYour Name 		return status;
9252*5113495bSYour Name 	}
9253*5113495bSYour Name 
9254*5113495bSYour Name 	status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id,
9255*5113495bSYour Name 						 peer_mac, peer_stats,
9256*5113495bSYour Name 						 CDP_WILD_PEER_TYPE,
9257*5113495bSYour Name 						 WLAN_MAX_MLD);
9258*5113495bSYour Name 	return status;
9259*5113495bSYour Name }
9260*5113495bSYour Name 
wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info * link_info)9261*5113495bSYour Name void wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info *link_info)
9262*5113495bSYour Name {
9263*5113495bSYour Name 	struct cdp_peer_stats *peer_stats;
9264*5113495bSYour Name 	QDF_STATUS status;
9265*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
9266*5113495bSYour Name 	struct hdd_stats *hdd_stats = &link_info->hdd_stats;
9267*5113495bSYour Name 
9268*5113495bSYour Name 	psoc = link_info->adapter->hdd_ctx->psoc;
9269*5113495bSYour Name 	if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc))
9270*5113495bSYour Name 		return;
9271*5113495bSYour Name 
9272*5113495bSYour Name 	peer_stats = qdf_mem_malloc(sizeof(*peer_stats));
9273*5113495bSYour Name 	if (!peer_stats) {
9274*5113495bSYour Name 		hdd_err("Failed to malloc peer_stats");
9275*5113495bSYour Name 		return;
9276*5113495bSYour Name 	}
9277*5113495bSYour Name 
9278*5113495bSYour Name 	/*
9279*5113495bSYour Name 	 * If failed to get RX rates info, assign an invalid value to the
9280*5113495bSYour Name 	 * preamble, used to tell driver to report max rates. The rx_rate
9281*5113495bSYour Name 	 * and rx_mcs_index are also assigned with tx_rate and tx_mcs_index
9282*5113495bSYour Name 	 * if they are invalid after ASSOC/REASSOC/ROAMING
9283*5113495bSYour Name 	 */
9284*5113495bSYour Name 	status = wlan_hdd_get_per_peer_stats(link_info, peer_stats);
9285*5113495bSYour Name 	if (qdf_unlikely(QDF_IS_STATUS_ERROR(status)) ||
9286*5113495bSYour Name 	    qdf_unlikely(peer_stats->rx.last_rx_rate == 0)) {
9287*5113495bSYour Name 		hdd_debug("Driver failed to get rx rates, rx mcs=%d, status=%d",
9288*5113495bSYour Name 			  hdd_stats->class_a_stat.rx_mcs_index, status);
9289*5113495bSYour Name 		hdd_stats->class_a_stat.rx_preamble = INVALID_PREAMBLE;
9290*5113495bSYour Name 		if (hdd_stats->class_a_stat.rx_mcs_index == INVALID_MCS_IDX) {
9291*5113495bSYour Name 			hdd_stats->class_a_stat.rx_rate =
9292*5113495bSYour Name 				hdd_stats->class_a_stat.tx_rate;
9293*5113495bSYour Name 			hdd_stats->class_a_stat.rx_mcs_index =
9294*5113495bSYour Name 				hdd_stats->class_a_stat.tx_mcs_index;
9295*5113495bSYour Name 		}
9296*5113495bSYour Name 		qdf_mem_free(peer_stats);
9297*5113495bSYour Name 		return;
9298*5113495bSYour Name 	}
9299*5113495bSYour Name 
9300*5113495bSYour Name 	/*
9301*5113495bSYour Name 	 * The linkspeed calculated by driver is in kbps so we
9302*5113495bSYour Name 	 * convert it in units of 100 kbps expected by userspace
9303*5113495bSYour Name 	 */
9304*5113495bSYour Name 	hdd_stats->class_a_stat.rx_rate = peer_stats->rx.last_rx_rate / 100;
9305*5113495bSYour Name 	hdd_stats->class_a_stat.rx_mcs_index = peer_stats->rx.mcs_info;
9306*5113495bSYour Name 	hdd_stats->class_a_stat.rx_nss = peer_stats->rx.nss_info;
9307*5113495bSYour Name 	hdd_stats->class_a_stat.rx_gi = peer_stats->rx.gi_info;
9308*5113495bSYour Name 	hdd_stats->class_a_stat.rx_preamble = peer_stats->rx.preamble_info;
9309*5113495bSYour Name 	hdd_stats->class_a_stat.rx_bw = peer_stats->rx.bw_info;
9310*5113495bSYour Name 
9311*5113495bSYour Name 	qdf_mem_free(peer_stats);
9312*5113495bSYour Name }
9313*5113495bSYour Name #endif
9314*5113495bSYour Name 
wlan_hdd_get_station_stats(struct wlan_hdd_link_info * link_info)9315*5113495bSYour Name int wlan_hdd_get_station_stats(struct wlan_hdd_link_info *link_info)
9316*5113495bSYour Name {
9317*5113495bSYour Name 	int ret = 0;
9318*5113495bSYour Name 	struct stats_event *stats;
9319*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
9320*5113495bSYour Name 
9321*5113495bSYour Name 	if (!get_station_fw_request_needed) {
9322*5113495bSYour Name 		hdd_debug("return cached get_station stats");
9323*5113495bSYour Name 		return 0;
9324*5113495bSYour Name 	}
9325*5113495bSYour Name 
9326*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
9327*5113495bSYour Name 	if (!vdev)
9328*5113495bSYour Name 		return -EINVAL;
9329*5113495bSYour Name 
9330*5113495bSYour Name 	stats = wlan_cfg80211_mc_cp_stats_get_station_stats(vdev, &ret);
9331*5113495bSYour Name 	if (ret || !stats) {
9332*5113495bSYour Name 		hdd_err("Invalid stats");
9333*5113495bSYour Name 		goto out;
9334*5113495bSYour Name 	}
9335*5113495bSYour Name 
9336*5113495bSYour Name 	if (!stats->vdev_summary_stats || !stats->vdev_chain_rssi ||
9337*5113495bSYour Name 	    !stats->peer_adv_stats || !stats->pdev_stats) {
9338*5113495bSYour Name 		hdd_err("Invalid:%s%s%s%s",
9339*5113495bSYour Name 			stats->vdev_summary_stats ? "" : " vdev_summary_stats",
9340*5113495bSYour Name 			stats->vdev_chain_rssi ? "" : " vdev_chain_rssi",
9341*5113495bSYour Name 			stats->peer_adv_stats ? "" : " peer_adv_stats",
9342*5113495bSYour Name 			stats->pdev_stats ? "" : " pdev_stats");
9343*5113495bSYour Name 		ret = -EINVAL;
9344*5113495bSYour Name 		goto out;
9345*5113495bSYour Name 	}
9346*5113495bSYour Name 
9347*5113495bSYour Name 	/* update get stats cached time stamp */
9348*5113495bSYour Name 	hdd_update_station_stats_cached_timestamp(link_info->adapter);
9349*5113495bSYour Name 	hdd_update_link_state_cached_timestamp(link_info->adapter);
9350*5113495bSYour Name 	copy_station_stats_to_adapter(link_info, stats);
9351*5113495bSYour Name out:
9352*5113495bSYour Name 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
9353*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
9354*5113495bSYour Name 	return ret;
9355*5113495bSYour Name }
9356*5113495bSYour Name 
9357*5113495bSYour Name #ifdef WLAN_FEATURE_BIG_DATA_STATS
wlan_hdd_get_big_data_station_stats(struct wlan_hdd_link_info * link_info)9358*5113495bSYour Name int wlan_hdd_get_big_data_station_stats(struct wlan_hdd_link_info *link_info)
9359*5113495bSYour Name {
9360*5113495bSYour Name 	int ret = 0;
9361*5113495bSYour Name 	struct big_data_stats_event *big_data_stats;
9362*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
9363*5113495bSYour Name 
9364*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
9365*5113495bSYour Name 	if (!vdev)
9366*5113495bSYour Name 		return -EINVAL;
9367*5113495bSYour Name 
9368*5113495bSYour Name 	big_data_stats = wlan_cfg80211_mc_cp_get_big_data_stats(vdev, &ret);
9369*5113495bSYour Name 	if (ret || !big_data_stats)
9370*5113495bSYour Name 		goto out;
9371*5113495bSYour Name 
9372*5113495bSYour Name 	copy_station_big_data_stats_to_adapter(link_info, big_data_stats);
9373*5113495bSYour Name out:
9374*5113495bSYour Name 	if (big_data_stats)
9375*5113495bSYour Name 		wlan_cfg80211_mc_cp_stats_free_big_data_stats_event(
9376*5113495bSYour Name 								big_data_stats);
9377*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
9378*5113495bSYour Name 	return ret;
9379*5113495bSYour Name }
9380*5113495bSYour Name #endif
9381*5113495bSYour Name 
9382*5113495bSYour Name struct temperature_priv {
9383*5113495bSYour Name 	int temperature;
9384*5113495bSYour Name };
9385*5113495bSYour Name 
9386*5113495bSYour Name /**
9387*5113495bSYour Name  * hdd_get_temperature_cb() - "Get Temperature" callback function
9388*5113495bSYour Name  * @temperature: measured temperature
9389*5113495bSYour Name  * @context: callback context
9390*5113495bSYour Name  *
9391*5113495bSYour Name  * This function is passed to sme_get_temperature() as the callback
9392*5113495bSYour Name  * function to be invoked when the temperature measurement is
9393*5113495bSYour Name  * available.
9394*5113495bSYour Name  *
9395*5113495bSYour Name  * Return: None
9396*5113495bSYour Name  */
hdd_get_temperature_cb(int temperature,void * context)9397*5113495bSYour Name static void hdd_get_temperature_cb(int temperature, void *context)
9398*5113495bSYour Name {
9399*5113495bSYour Name 	struct osif_request *request;
9400*5113495bSYour Name 	struct temperature_priv *priv;
9401*5113495bSYour Name 
9402*5113495bSYour Name 	hdd_enter();
9403*5113495bSYour Name 
9404*5113495bSYour Name 	request = osif_request_get(context);
9405*5113495bSYour Name 	if (!request) {
9406*5113495bSYour Name 		hdd_err("Obsolete request");
9407*5113495bSYour Name 		return;
9408*5113495bSYour Name 	}
9409*5113495bSYour Name 
9410*5113495bSYour Name 	priv = osif_request_priv(request);
9411*5113495bSYour Name 	priv->temperature = temperature;
9412*5113495bSYour Name 	osif_request_complete(request);
9413*5113495bSYour Name 	osif_request_put(request);
9414*5113495bSYour Name 	hdd_exit();
9415*5113495bSYour Name }
9416*5113495bSYour Name 
wlan_hdd_get_temperature(struct hdd_adapter * adapter,int * temperature)9417*5113495bSYour Name int wlan_hdd_get_temperature(struct hdd_adapter *adapter, int *temperature)
9418*5113495bSYour Name {
9419*5113495bSYour Name 	QDF_STATUS status;
9420*5113495bSYour Name 	int ret;
9421*5113495bSYour Name 	void *cookie;
9422*5113495bSYour Name 	struct osif_request *request;
9423*5113495bSYour Name 	struct temperature_priv *priv;
9424*5113495bSYour Name 	static const struct osif_request_params params = {
9425*5113495bSYour Name 		.priv_size = sizeof(*priv),
9426*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_STATS,
9427*5113495bSYour Name 	};
9428*5113495bSYour Name 
9429*5113495bSYour Name 	hdd_enter();
9430*5113495bSYour Name 	if (!adapter) {
9431*5113495bSYour Name 		hdd_err("adapter is NULL");
9432*5113495bSYour Name 		return -EPERM;
9433*5113495bSYour Name 	}
9434*5113495bSYour Name 
9435*5113495bSYour Name 	if (!wlan_psoc_nif_fw_ext_cap_get(adapter->hdd_ctx->psoc,
9436*5113495bSYour Name 					  WLAN_SOC_CEXT_TT_SUPPORT)) {
9437*5113495bSYour Name 		hdd_err("WMI_SERVICE_THERM_THROT service from FW is disable");
9438*5113495bSYour Name 		return -EINVAL;
9439*5113495bSYour Name 	}
9440*5113495bSYour Name 
9441*5113495bSYour Name 	request = osif_request_alloc(&params);
9442*5113495bSYour Name 	if (!request) {
9443*5113495bSYour Name 		hdd_err("Request allocation failure");
9444*5113495bSYour Name 		return -ENOMEM;
9445*5113495bSYour Name 	}
9446*5113495bSYour Name 	cookie = osif_request_cookie(request);
9447*5113495bSYour Name 	status = sme_get_temperature(adapter->hdd_ctx->mac_handle, cookie,
9448*5113495bSYour Name 				     hdd_get_temperature_cb);
9449*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
9450*5113495bSYour Name 		hdd_err("Unable to retrieve temperature");
9451*5113495bSYour Name 	} else {
9452*5113495bSYour Name 		ret = osif_request_wait_for_response(request);
9453*5113495bSYour Name 		if (ret) {
9454*5113495bSYour Name 			hdd_err("SME timed out while retrieving temperature");
9455*5113495bSYour Name 		} else {
9456*5113495bSYour Name 			/* update the adapter with the fresh results */
9457*5113495bSYour Name 			priv = osif_request_priv(request);
9458*5113495bSYour Name 			if (priv->temperature)
9459*5113495bSYour Name 				adapter->temperature = priv->temperature;
9460*5113495bSYour Name 		}
9461*5113495bSYour Name 	}
9462*5113495bSYour Name 
9463*5113495bSYour Name 	/*
9464*5113495bSYour Name 	 * either we never sent a request, we sent a request and
9465*5113495bSYour Name 	 * received a response or we sent a request and timed out.
9466*5113495bSYour Name 	 * regardless we are done with the request.
9467*5113495bSYour Name 	 */
9468*5113495bSYour Name 	osif_request_put(request);
9469*5113495bSYour Name 
9470*5113495bSYour Name 	*temperature = adapter->temperature;
9471*5113495bSYour Name 	hdd_exit();
9472*5113495bSYour Name 	return 0;
9473*5113495bSYour Name }
9474*5113495bSYour Name 
9475*5113495bSYour Name #ifdef TX_MULTIQ_PER_AC
wlan_hdd_display_tx_multiq_stats(hdd_cb_handle context,qdf_netdev_t netdev)9476*5113495bSYour Name void wlan_hdd_display_tx_multiq_stats(hdd_cb_handle context,
9477*5113495bSYour Name 				      qdf_netdev_t netdev)
9478*5113495bSYour Name {
9479*5113495bSYour Name 	struct hdd_adapter *adapter;
9480*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
9481*5113495bSYour Name 	struct hdd_tx_rx_stats *stats;
9482*5113495bSYour Name 	uint32_t total_inv_sk_and_skb_hash = 0;
9483*5113495bSYour Name 	uint32_t total_qselect_existing_skb_hash = 0;
9484*5113495bSYour Name 	uint32_t total_qselect_sk_tx_map = 0;
9485*5113495bSYour Name 	uint32_t total_qselect_skb_hash = 0;
9486*5113495bSYour Name 	unsigned int i;
9487*5113495bSYour Name 
9488*5113495bSYour Name 	adapter = WLAN_HDD_GET_PRIV_PTR(netdev);
9489*5113495bSYour Name 	if (!adapter) {
9490*5113495bSYour Name 		hdd_err("adapter is null");
9491*5113495bSYour Name 		return;
9492*5113495bSYour Name 	}
9493*5113495bSYour Name 
9494*5113495bSYour Name 	link_info = adapter->deflink;
9495*5113495bSYour Name 
9496*5113495bSYour Name 	stats = &link_info->hdd_stats.tx_rx_stats;
9497*5113495bSYour Name 
9498*5113495bSYour Name 	for (i = 0; i < NUM_CPUS; i++) {
9499*5113495bSYour Name 		total_inv_sk_and_skb_hash +=
9500*5113495bSYour Name 					  stats->per_cpu[i].inv_sk_and_skb_hash;
9501*5113495bSYour Name 		total_qselect_existing_skb_hash +=
9502*5113495bSYour Name 				    stats->per_cpu[i].qselect_existing_skb_hash;
9503*5113495bSYour Name 		total_qselect_sk_tx_map += stats->per_cpu[i].qselect_sk_tx_map;
9504*5113495bSYour Name 		total_qselect_skb_hash +=
9505*5113495bSYour Name 					stats->per_cpu[i].qselect_skb_hash_calc;
9506*5113495bSYour Name 	}
9507*5113495bSYour Name 
9508*5113495bSYour Name 	hdd_debug("TX_MULTIQ: INV %u skb_hash %u sk_tx_map %u skb_hash_calc %u",
9509*5113495bSYour Name 		  total_inv_sk_and_skb_hash, total_qselect_existing_skb_hash,
9510*5113495bSYour Name 		  total_qselect_sk_tx_map, total_qselect_skb_hash);
9511*5113495bSYour Name }
9512*5113495bSYour Name #endif
9513*5113495bSYour Name 
9514*5113495bSYour Name #ifdef QCA_SUPPORT_CP_STATS
9515*5113495bSYour Name /**
9516*5113495bSYour Name  * hdd_lost_link_cp_stats_info_cb() - callback function to get lost
9517*5113495bSYour Name  * link information
9518*5113495bSYour Name  * @stats_ev: Stats event pointer
9519*5113495bSYour Name  * FW sends vdev stats on vdev down, this callback is registered
9520*5113495bSYour Name  * with cp_stats component to get the last available vdev stats
9521*5113495bSYour Name  * From the FW.
9522*5113495bSYour Name  *
9523*5113495bSYour Name  * Return: None
9524*5113495bSYour Name  */
9525*5113495bSYour Name 
hdd_lost_link_cp_stats_info_cb(void * stats_ev)9526*5113495bSYour Name static void hdd_lost_link_cp_stats_info_cb(void *stats_ev)
9527*5113495bSYour Name {
9528*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
9529*5113495bSYour Name 	struct stats_event *ev = stats_ev;
9530*5113495bSYour Name 	uint8_t i, vdev_id;
9531*5113495bSYour Name 	int8_t rssi;
9532*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx;
9533*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
9534*5113495bSYour Name 	struct qdf_mac_addr *mac_addr;
9535*5113495bSYour Name 
9536*5113495bSYour Name 	if (wlan_hdd_validate_context(hdd_ctx))
9537*5113495bSYour Name 		return;
9538*5113495bSYour Name 
9539*5113495bSYour Name 	for (i = 0; i < ev->num_summary_stats; i++) {
9540*5113495bSYour Name 		vdev_id = ev->vdev_summary_stats[i].vdev_id;
9541*5113495bSYour Name 		link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
9542*5113495bSYour Name 		if (!link_info) {
9543*5113495bSYour Name 			hdd_debug("invalid vdev %d", vdev_id);
9544*5113495bSYour Name 			continue;
9545*5113495bSYour Name 		}
9546*5113495bSYour Name 
9547*5113495bSYour Name 		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
9548*5113495bSYour Name 
9549*5113495bSYour Name 		rssi = ev->vdev_summary_stats[i].stats.rssi;
9550*5113495bSYour Name 		if (rssi == 0) {
9551*5113495bSYour Name 			hdd_debug_rl("Invalid RSSI value sent by FW");
9552*5113495bSYour Name 			return;
9553*5113495bSYour Name 		}
9554*5113495bSYour Name 		link_info->rssi_on_disconnect = rssi;
9555*5113495bSYour Name 		sta_ctx->cache_conn_info.signal = rssi;
9556*5113495bSYour Name 
9557*5113495bSYour Name 		mac_addr = hdd_adapter_get_link_mac_addr(link_info);
9558*5113495bSYour Name 		if (!mac_addr)
9559*5113495bSYour Name 			return;
9560*5113495bSYour Name 
9561*5113495bSYour Name 		hdd_debug("rssi %d for " QDF_MAC_ADDR_FMT,
9562*5113495bSYour Name 			  link_info->rssi_on_disconnect,
9563*5113495bSYour Name 			  QDF_MAC_ADDR_REF(&mac_addr->bytes[0]));
9564*5113495bSYour Name 
9565*5113495bSYour Name 	}
9566*5113495bSYour Name }
9567*5113495bSYour Name 
wlan_hdd_register_cp_stats_cb(struct hdd_context * hdd_ctx)9568*5113495bSYour Name void wlan_hdd_register_cp_stats_cb(struct hdd_context *hdd_ctx)
9569*5113495bSYour Name {
9570*5113495bSYour Name 	ucfg_mc_cp_stats_register_lost_link_info_cb(
9571*5113495bSYour Name 					hdd_ctx->psoc,
9572*5113495bSYour Name 					hdd_lost_link_cp_stats_info_cb);
9573*5113495bSYour Name }
9574*5113495bSYour Name #endif
9575*5113495bSYour Name 
9576*5113495bSYour Name #if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_ROAM_INFO_STATS)
9577*5113495bSYour Name #define ROAM_CACHED_STATS_MAX QCA_WLAN_VENDOR_ATTR_ROAM_CACHED_STATS_MAX
9578*5113495bSYour Name 
9579*5113495bSYour Name #define EVENTS_CONFIGURE QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CONFIGURE
9580*5113495bSYour Name #define SUSPEND_STATE    QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_SUSPEND_STATE
9581*5113495bSYour Name 
9582*5113495bSYour Name #define ROAM_STATS_ROAM_TRIGGER_TIMESTAMP \
9583*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_TRIGGER_TIMESTAMP
9584*5113495bSYour Name #define ROAM_STATS_TRIGGER_REASON \
9585*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TRIGGER_REASON
9586*5113495bSYour Name #define ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT \
9587*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT
9588*5113495bSYour Name #define ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT \
9589*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT
9590*5113495bSYour Name #define ROAM_STATS_FINAL_BMISS_CNT \
9591*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FINAL_BMISS_CNT
9592*5113495bSYour Name #define ROAM_STATS_CONSECUTIVE_BMISS_CNT \
9593*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONSECUTIVE_BMISS_CNT
9594*5113495bSYour Name #define ROAM_STATS_BMISS_QOS_NULL_SUCCESS \
9595*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BMISS_QOS_NULL_SUCCESS
9596*5113495bSYour Name #define ROAM_STATS_POOR_RSSI_CURRENT_RSSI \
9597*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_CURRENT_RSSI
9598*5113495bSYour Name #define ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD \
9599*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD
9600*5113495bSYour Name #define ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS \
9601*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS
9602*5113495bSYour Name #define ROAM_STATS_BETTER_RSSI_CURRENT_RSSI \
9603*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_CURRENT_RSSI
9604*5113495bSYour Name #define ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD \
9605*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD
9606*5113495bSYour Name #define ROAM_STATS_CONGESTION_RX_TPUT \
9607*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_RX_TPUT
9608*5113495bSYour Name #define ROAM_STATS_CONGESTION_TX_TPUT \
9609*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_TX_TPUT
9610*5113495bSYour Name #define ROAM_STATS_CONGESTION_ROAMABLE_CNT \
9611*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_ROAMABLE_CNT
9612*5113495bSYour Name #define ROAM_STATS_USER_TRIGGER_INVOKE_REASON \
9613*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_USER_TRIGGER_INVOKE_REASON
9614*5113495bSYour Name #define ROAM_STATS_BTM_REQUEST_MODE \
9615*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQUEST_MODE
9616*5113495bSYour Name #define ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME \
9617*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME
9618*5113495bSYour Name #define ROAM_STATS_BTM_VALID_INTERNAL \
9619*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_VALID_INTERNAL
9620*5113495bSYour Name #define ROAM_STATS_BTM_CANDIDATE_LIST_CNT \
9621*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_CANDIDATE_LIST_CNT
9622*5113495bSYour Name #define ROAM_STATS_BTM_RESPONSE_STATUS_CODE \
9623*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_RESPONSE_STATUS_CODE
9624*5113495bSYour Name #define ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT \
9625*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT
9626*5113495bSYour Name #define ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT \
9627*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT
9628*5113495bSYour Name #define ROAM_STATS_BTM_REQ_DIALOG_TOKEN \
9629*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQ_DIALOG_TOKEN
9630*5113495bSYour Name #define ROAM_STATS_BSS_CU_LOAD \
9631*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BSS_CU_LOAD
9632*5113495bSYour Name #define ROAM_STATS_DISCONNECTION_TYPE \
9633*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_TYPE
9634*5113495bSYour Name #define ROAM_STATS_DISCONNECTION_REASON \
9635*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_REASON
9636*5113495bSYour Name #define ROAM_STATS_PERIODIC_TIMER_MS \
9637*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PERIODIC_TIMER_MS
9638*5113495bSYour Name #define ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI \
9639*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI
9640*5113495bSYour Name #define ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI \
9641*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI
9642*5113495bSYour Name #define ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH \
9643*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_THRESH
9644*5113495bSYour Name #define ROAM_STATS_TX_FAILURES_THRESHOLD \
9645*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_THRESHOLD
9646*5113495bSYour Name #define ROAM_STATS_TX_FAILURES_REASON \
9647*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_REASON
9648*5113495bSYour Name #define ROAM_STATS_ABORT_REASON \
9649*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ABORT_REASON
9650*5113495bSYour Name #define ROAM_STATS_DATA_RSSI \
9651*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI
9652*5113495bSYour Name #define ROAM_STATS_DATA_RSSI_THRESHOLD \
9653*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI_THRESHOLD
9654*5113495bSYour Name #define ROAM_STATS_DATA_RX_LINKSPEED_STATUS \
9655*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RX_LINKSPEED_STATUS
9656*5113495bSYour Name #define ROAM_STATS_SCAN_TYPE \
9657*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_TYPE
9658*5113495bSYour Name #define ROAM_STATS_ROAM_STATUS \
9659*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_STATUS
9660*5113495bSYour Name #define ROAM_STATS_FAIL_REASON \
9661*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FAIL_REASON
9662*5113495bSYour Name #define ROAM_STATS_SCAN_CHAN_INFO \
9663*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHAN_INFO
9664*5113495bSYour Name #define ROAM_STATS_TOTAL_SCAN_TIME \
9665*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TOTAL_SCAN_TIME
9666*5113495bSYour Name #define ROAM_STATS_FRAME_INFO  \
9667*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO
9668*5113495bSYour Name #define ROAM_STATS_SCAN_CHANNEL_FREQ \
9669*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHANNEL_FREQ
9670*5113495bSYour Name #define ROAM_STATS_SCAN_DWELL_TYPE \
9671*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_DWELL_TYPE
9672*5113495bSYour Name #define ROAM_STATS_MAX_DWELL_TIME \
9673*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_MAX_DWELL_TIME
9674*5113495bSYour Name #define ROAM_STATS_FRAME_SUBTYPE \
9675*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_SUBTYPE
9676*5113495bSYour Name #define ROAM_STATS_FRAME_STATUS \
9677*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_STATUS
9678*5113495bSYour Name #define ROAM_STATS_FRAME_TIMESTAMP \
9679*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_TIMESTAMP
9680*5113495bSYour Name #define ROAM_STATS_EVENT_INDEX \
9681*5113495bSYour Name 	QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS_INDEX
9682*5113495bSYour Name 
9683*5113495bSYour Name static enum qca_roam_reason
hdd_convert_roam_trigger_reason(enum roam_trigger_reason reason)9684*5113495bSYour Name hdd_convert_roam_trigger_reason(enum roam_trigger_reason reason)
9685*5113495bSYour Name {
9686*5113495bSYour Name 	switch (reason) {
9687*5113495bSYour Name 	case ROAM_TRIGGER_REASON_NONE:
9688*5113495bSYour Name 		return QCA_ROAM_REASON_UNKNOWN;
9689*5113495bSYour Name 	case ROAM_TRIGGER_REASON_PER:
9690*5113495bSYour Name 		return QCA_ROAM_REASON_PER;
9691*5113495bSYour Name 	case ROAM_TRIGGER_REASON_BMISS:
9692*5113495bSYour Name 		return QCA_ROAM_REASON_BEACON_MISS;
9693*5113495bSYour Name 	case ROAM_TRIGGER_REASON_LOW_RSSI:
9694*5113495bSYour Name 		return QCA_ROAM_REASON_POOR_RSSI;
9695*5113495bSYour Name 	case ROAM_TRIGGER_REASON_HIGH_RSSI:
9696*5113495bSYour Name 		return QCA_ROAM_REASON_BETTER_RSSI;
9697*5113495bSYour Name 	case ROAM_TRIGGER_REASON_PERIODIC:
9698*5113495bSYour Name 		return QCA_ROAM_REASON_PERIODIC_TIMER;
9699*5113495bSYour Name 	case ROAM_TRIGGER_REASON_DENSE:
9700*5113495bSYour Name 		return QCA_ROAM_REASON_CONGESTION;
9701*5113495bSYour Name 	case ROAM_TRIGGER_REASON_BACKGROUND:
9702*5113495bSYour Name 		return QCA_ROAM_REASON_BACKGROUND_SCAN;
9703*5113495bSYour Name 	case ROAM_TRIGGER_REASON_FORCED:
9704*5113495bSYour Name 		return QCA_ROAM_REASON_USER_TRIGGER;
9705*5113495bSYour Name 	case ROAM_TRIGGER_REASON_BTM:
9706*5113495bSYour Name 		return QCA_ROAM_REASON_BTM;
9707*5113495bSYour Name 	case ROAM_TRIGGER_REASON_BSS_LOAD:
9708*5113495bSYour Name 		return QCA_ROAM_REASON_BSS_LOAD;
9709*5113495bSYour Name 	case ROAM_TRIGGER_REASON_DEAUTH:
9710*5113495bSYour Name 		return QCA_ROAM_REASON_DISCONNECTION;
9711*5113495bSYour Name 	case ROAM_TRIGGER_REASON_STA_KICKOUT:
9712*5113495bSYour Name 		return QCA_ROAM_REASON_STA_KICKOUT;
9713*5113495bSYour Name 	default:
9714*5113495bSYour Name 		hdd_err("Invalid invoke reason received: %d", reason);
9715*5113495bSYour Name 		break;
9716*5113495bSYour Name 	}
9717*5113495bSYour Name 
9718*5113495bSYour Name 	return QCA_ROAM_REASON_UNKNOWN;
9719*5113495bSYour Name }
9720*5113495bSYour Name 
9721*5113495bSYour Name static enum qca_wlan_roam_stats_invoke_reason
hdd_convert_roam_invoke_reason(enum roam_invoke_reason invoke)9722*5113495bSYour Name hdd_convert_roam_invoke_reason(enum roam_invoke_reason invoke)
9723*5113495bSYour Name {
9724*5113495bSYour Name 	switch (invoke) {
9725*5113495bSYour Name 	case WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED:
9726*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED;
9727*5113495bSYour Name 	case WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE:
9728*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE;
9729*5113495bSYour Name 	case WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE:
9730*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE;
9731*5113495bSYour Name 	default:
9732*5113495bSYour Name 		hdd_err("Invalid invoke reason received: %d", invoke);
9733*5113495bSYour Name 		break;
9734*5113495bSYour Name 	}
9735*5113495bSYour Name 
9736*5113495bSYour Name 	return QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED;
9737*5113495bSYour Name }
9738*5113495bSYour Name 
9739*5113495bSYour Name static enum qca_wlan_roam_stats_tx_failures_reason
hdd_convert_roam_tx_failures_reason(enum roam_tx_failures_reason tx_failures)9740*5113495bSYour Name hdd_convert_roam_tx_failures_reason(enum roam_tx_failures_reason tx_failures)
9741*5113495bSYour Name {
9742*5113495bSYour Name 	switch (tx_failures) {
9743*5113495bSYour Name 	case WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED:
9744*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED;
9745*5113495bSYour Name 	case WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY:
9746*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY;
9747*5113495bSYour Name 	case WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY:
9748*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY;
9749*5113495bSYour Name 	case WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT:
9750*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT;
9751*5113495bSYour Name 	case WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT:
9752*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT;
9753*5113495bSYour Name 	case WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT:
9754*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT;
9755*5113495bSYour Name 	case WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT:
9756*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT;
9757*5113495bSYour Name 	default:
9758*5113495bSYour Name 		hdd_err("Invalid tx_failures reason received: %d", tx_failures);
9759*5113495bSYour Name 		break;
9760*5113495bSYour Name 	}
9761*5113495bSYour Name 
9762*5113495bSYour Name 	return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED;
9763*5113495bSYour Name }
9764*5113495bSYour Name 
9765*5113495bSYour Name static enum qca_wlan_roam_stats_abort_reason
hdd_convert_roam_abort_reason(enum roam_abort_reason abort)9766*5113495bSYour Name hdd_convert_roam_abort_reason(enum roam_abort_reason abort)
9767*5113495bSYour Name {
9768*5113495bSYour Name 	switch (abort) {
9769*5113495bSYour Name 	case WLAN_ROAM_STATS_ABORT_UNSPECIFIED:
9770*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED;
9771*5113495bSYour Name 	case WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH:
9772*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH;
9773*5113495bSYour Name 	case WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD:
9774*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD;
9775*5113495bSYour Name 	case WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH:
9776*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH;
9777*5113495bSYour Name 	case WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD:
9778*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD;
9779*5113495bSYour Name 	default:
9780*5113495bSYour Name 		hdd_err("Invalid abort reason received: %d", abort);
9781*5113495bSYour Name 		break;
9782*5113495bSYour Name 	}
9783*5113495bSYour Name 
9784*5113495bSYour Name 	return QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED;
9785*5113495bSYour Name }
9786*5113495bSYour Name 
9787*5113495bSYour Name static enum qca_wlan_roam_stats_scan_type
hdd_convert_roam_scan_type(enum roam_stats_scan_type type)9788*5113495bSYour Name hdd_convert_roam_scan_type(enum roam_stats_scan_type              type)
9789*5113495bSYour Name {
9790*5113495bSYour Name 	switch (type) {
9791*5113495bSYour Name 	case ROAM_STATS_SCAN_TYPE_PARTIAL:
9792*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL;
9793*5113495bSYour Name 	case ROAM_STATS_SCAN_TYPE_FULL:
9794*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_FULL;
9795*5113495bSYour Name 	case ROAM_STATS_SCAN_TYPE_NO_SCAN:
9796*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_NO_SCAN;
9797*5113495bSYour Name 	case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ:
9798*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ;
9799*5113495bSYour Name 	case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ:
9800*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ;
9801*5113495bSYour Name 	default:
9802*5113495bSYour Name 		hdd_err("Invalid roam scan type received: %d", type);
9803*5113495bSYour Name 		break;
9804*5113495bSYour Name 	}
9805*5113495bSYour Name 
9806*5113495bSYour Name 	return QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL;
9807*5113495bSYour Name }
9808*5113495bSYour Name 
9809*5113495bSYour Name static enum qca_wlan_roam_stats_scan_dwell_type
hdd_convert_roam_chn_dwell_type(enum roam_scan_dwell_type type)9810*5113495bSYour Name hdd_convert_roam_chn_dwell_type(enum roam_scan_dwell_type type)
9811*5113495bSYour Name {
9812*5113495bSYour Name 	switch (type) {
9813*5113495bSYour Name 	case WLAN_ROAM_DWELL_TYPE_UNSPECIFIED:
9814*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED;
9815*5113495bSYour Name 	case WLAN_ROAM_DWELL_ACTIVE_TYPE:
9816*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_DWELL_TYPE_ACTIVE;
9817*5113495bSYour Name 	case WLAN_ROAM_DWELL_PASSIVE_TYPE:
9818*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_DWELL_TYPE_PASSIVE;
9819*5113495bSYour Name 	default:
9820*5113495bSYour Name 		hdd_err("Invalid abort reason received: %d", type);
9821*5113495bSYour Name 		break;
9822*5113495bSYour Name 	}
9823*5113495bSYour Name 
9824*5113495bSYour Name 	return QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED;
9825*5113495bSYour Name }
9826*5113495bSYour Name 
9827*5113495bSYour Name static enum qca_wlan_roam_stats_frame_subtype
hdd_convert_roam_frame_type(enum eroam_frame_subtype type)9828*5113495bSYour Name hdd_convert_roam_frame_type(enum eroam_frame_subtype type)
9829*5113495bSYour Name {
9830*5113495bSYour Name 	switch (type) {
9831*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ:
9832*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
9833*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP:
9834*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP;
9835*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ:
9836*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ;
9837*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP:
9838*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP;
9839*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1:
9840*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1;
9841*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2:
9842*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2;
9843*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3:
9844*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3;
9845*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4:
9846*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4;
9847*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1:
9848*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1;
9849*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2:
9850*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2;
9851*5113495bSYour Name 	default:
9852*5113495bSYour Name 		hdd_err_rl("Invalid roam frame type received: %d", type);
9853*5113495bSYour Name 		break;
9854*5113495bSYour Name 	}
9855*5113495bSYour Name 
9856*5113495bSYour Name 	return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ;
9857*5113495bSYour Name };
9858*5113495bSYour Name 
9859*5113495bSYour Name static enum qca_wlan_roam_stats_frame_status
hdd_convert_roam_frame_status(enum eroam_frame_status status)9860*5113495bSYour Name hdd_convert_roam_frame_status(enum eroam_frame_status status)
9861*5113495bSYour Name {
9862*5113495bSYour Name 	switch (status) {
9863*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS:
9864*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS;
9865*5113495bSYour Name 	case WLAN_ROAM_STATS_FRAME_STATUS_FAIL:
9866*5113495bSYour Name 		return QCA_WLAN_ROAM_STATS_FRAME_STATUS_FAIL;
9867*5113495bSYour Name 	default:
9868*5113495bSYour Name 		hdd_err("Invalid roam frame status received: %d", status);
9869*5113495bSYour Name 		break;
9870*5113495bSYour Name 	}
9871*5113495bSYour Name 
9872*5113495bSYour Name 	return QCA_WLAN_ROAM_STATS_FRAME_STATUS_FAIL;
9873*5113495bSYour Name };
9874*5113495bSYour Name 
9875*5113495bSYour Name static enum qca_vendor_roam_fail_reasons
hdd_convert_roam_failures_reason(enum wlan_roam_failure_reason_code fail)9876*5113495bSYour Name hdd_convert_roam_failures_reason(enum wlan_roam_failure_reason_code fail)
9877*5113495bSYour Name {
9878*5113495bSYour Name 	switch (fail) {
9879*5113495bSYour Name 	case ROAM_FAIL_REASON_NO_SCAN_START:
9880*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED;
9881*5113495bSYour Name 	case ROAM_FAIL_REASON_NO_AP_FOUND:
9882*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_NO_AP_FOUND;
9883*5113495bSYour Name 	case ROAM_FAIL_REASON_NO_CAND_AP_FOUND:
9884*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND;
9885*5113495bSYour Name 	case ROAM_FAIL_REASON_HOST:
9886*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_HOST;
9887*5113495bSYour Name 	case ROAM_FAIL_REASON_AUTH_SEND:
9888*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_AUTH_SEND;
9889*5113495bSYour Name 	case ROAM_FAIL_REASON_NO_AUTH_RESP:
9890*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_NO_AUTH_RESP;
9891*5113495bSYour Name 	case ROAM_FAIL_REASON_AUTH_RECV:
9892*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_AUTH_RECV;
9893*5113495bSYour Name 	case ROAM_FAIL_REASON_REASSOC_SEND:
9894*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_REASSOC_SEND;
9895*5113495bSYour Name 	case ROAM_FAIL_REASON_REASSOC_RECV:
9896*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_REASSOC_RECV;
9897*5113495bSYour Name 	case ROAM_FAIL_REASON_NO_REASSOC_RESP:
9898*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP;
9899*5113495bSYour Name 	case ROAM_FAIL_REASON_EAPOL_TIMEOUT:
9900*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT;
9901*5113495bSYour Name 	case ROAM_FAIL_REASON_SCAN_START:
9902*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_SCAN_FAIL;
9903*5113495bSYour Name 	case ROAM_FAIL_REASON_AUTH_NO_ACK:
9904*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_AUTH_NO_ACK;
9905*5113495bSYour Name 	case ROAM_FAIL_REASON_AUTH_INTERNAL_DROP:
9906*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP;
9907*5113495bSYour Name 	case ROAM_FAIL_REASON_REASSOC_NO_ACK:
9908*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK;
9909*5113495bSYour Name 	case ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP:
9910*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP;
9911*5113495bSYour Name 	case ROAM_FAIL_REASON_EAPOL_M2_SEND:
9912*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND;
9913*5113495bSYour Name 	case ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP:
9914*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP;
9915*5113495bSYour Name 	case ROAM_FAIL_REASON_EAPOL_M2_NO_ACK:
9916*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK;
9917*5113495bSYour Name 	case ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT:
9918*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT;
9919*5113495bSYour Name 	case ROAM_FAIL_REASON_EAPOL_M4_SEND:
9920*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND;
9921*5113495bSYour Name 	case ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP:
9922*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP;
9923*5113495bSYour Name 	case ROAM_FAIL_REASON_EAPOL_M4_NO_ACK:
9924*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK;
9925*5113495bSYour Name 	case ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BMISS:
9926*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS;
9927*5113495bSYour Name 	case ROAM_FAIL_REASON_DISCONNECT:
9928*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_DISCONNECT;
9929*5113495bSYour Name 	case ROAM_FAIL_REASON_SYNC:
9930*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_RESUME_ABORT;
9931*5113495bSYour Name 	case ROAM_FAIL_REASON_SAE_INVALID_PMKID:
9932*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID;
9933*5113495bSYour Name 	case ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT:
9934*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT;
9935*5113495bSYour Name 	case ROAM_FAIL_REASON_SAE_PREAUTH_FAIL:
9936*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL;
9937*5113495bSYour Name 	case ROAM_FAIL_REASON_CURR_AP_STILL_OK:
9938*5113495bSYour Name 		return QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK;
9939*5113495bSYour Name 	case ROAM_FAIL_REASON_MLME:
9940*5113495bSYour Name 	case ROAM_FAIL_REASON_INTERNAL_ABORT:
9941*5113495bSYour Name 	case ROAM_FAIL_REASON_UNABLE_TO_START_ROAM_HO:
9942*5113495bSYour Name 	case ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT:
9943*5113495bSYour Name 	case ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT:
9944*5113495bSYour Name 	case ROAM_FAIL_REASON_SCAN_CANCEL:
9945*5113495bSYour Name 	case ROAM_FAIL_REASON_SCREEN_ACTIVITY:
9946*5113495bSYour Name 	case ROAM_FAIL_REASON_OTHER_PRIORITY_ROAM_SCAN:
9947*5113495bSYour Name 	case ROAM_FAIL_REASON_UNKNOWN:
9948*5113495bSYour Name 		hdd_err("Invalid roam failures reason");
9949*5113495bSYour Name 		break;
9950*5113495bSYour Name 	}
9951*5113495bSYour Name 
9952*5113495bSYour Name 	return QCA_ROAM_FAIL_REASON_NONE;
9953*5113495bSYour Name }
9954*5113495bSYour Name 
9955*5113495bSYour Name /**
9956*5113495bSYour Name  * hdd_get_roam_stats_individual_record_len() - calculates the required length
9957*5113495bSYour Name  * of an individual record of roaming stats
9958*5113495bSYour Name  *
9959*5113495bSYour Name  * @roam_info: pointer to roam info
9960*5113495bSYour Name  * @index:     index of roam info cached in driver
9961*5113495bSYour Name  *
9962*5113495bSYour Name  * Return: required length of an individual record of roaming stats
9963*5113495bSYour Name  */
9964*5113495bSYour Name static uint32_t
hdd_get_roam_stats_individual_record_len(struct enhance_roam_info * roam_info,uint32_t index)9965*5113495bSYour Name hdd_get_roam_stats_individual_record_len(struct enhance_roam_info *roam_info,
9966*5113495bSYour Name 					 uint32_t index)
9967*5113495bSYour Name {
9968*5113495bSYour Name 	struct enhance_roam_info *info;
9969*5113495bSYour Name 	enum qca_roam_reason vendor_trigger_reason;
9970*5113495bSYour Name 	uint32_t len, i;
9971*5113495bSYour Name 
9972*5113495bSYour Name 	if (!roam_info) {
9973*5113495bSYour Name 		hdd_err("invalid param");
9974*5113495bSYour Name 		return 0;
9975*5113495bSYour Name 	}
9976*5113495bSYour Name 
9977*5113495bSYour Name 	info  = &roam_info[index];
9978*5113495bSYour Name 	vendor_trigger_reason =
9979*5113495bSYour Name 		hdd_convert_roam_trigger_reason(info->trigger.trigger_reason);
9980*5113495bSYour Name 
9981*5113495bSYour Name 	len = 0;
9982*5113495bSYour Name 	/* ROAM_STATS_ROAM_TRIGGER_TIMESTAMP */
9983*5113495bSYour Name 	len += nla_total_size_64bit(sizeof(uint64_t));
9984*5113495bSYour Name 	/* ROAM_STATS_TRIGGER_REASON */
9985*5113495bSYour Name 	len += nla_total_size(sizeof(uint32_t));
9986*5113495bSYour Name 
9987*5113495bSYour Name 	switch (vendor_trigger_reason) {
9988*5113495bSYour Name 	case QCA_ROAM_REASON_PER:
9989*5113495bSYour Name 		/* ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT */
9990*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
9991*5113495bSYour Name 		/* ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT */
9992*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
9993*5113495bSYour Name 		break;
9994*5113495bSYour Name 	case QCA_ROAM_REASON_BEACON_MISS:
9995*5113495bSYour Name 		/* ROAM_STATS_FINAL_BMISS_CNT */
9996*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
9997*5113495bSYour Name 		/* ROAM_STATS_CONSECUTIVE_BMISS_CNT */
9998*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
9999*5113495bSYour Name 		/* ROAM_STATS_BMISS_QOS_NULL_SUCCESS */
10000*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10001*5113495bSYour Name 		break;
10002*5113495bSYour Name 	case QCA_ROAM_REASON_POOR_RSSI:
10003*5113495bSYour Name 		/* ROAM_STATS_POOR_RSSI_CURRENT_RSSI */
10004*5113495bSYour Name 		len += nla_total_size(sizeof(int8_t));
10005*5113495bSYour Name 		/* ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD */
10006*5113495bSYour Name 		len += nla_total_size(sizeof(int8_t));
10007*5113495bSYour Name 		/* ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS */
10008*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10009*5113495bSYour Name 		break;
10010*5113495bSYour Name 	case QCA_ROAM_REASON_BETTER_RSSI:
10011*5113495bSYour Name 		/* ROAM_STATS_BETTER_RSSI_CURRENT_RSSI */
10012*5113495bSYour Name 		len += nla_total_size(sizeof(int8_t));
10013*5113495bSYour Name 		/* ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD */
10014*5113495bSYour Name 		len += nla_total_size(sizeof(int8_t));
10015*5113495bSYour Name 		break;
10016*5113495bSYour Name 	case QCA_ROAM_REASON_PERIODIC_TIMER:
10017*5113495bSYour Name 		/* ROAM_STATS_PERIODIC_TIMER_MS */
10018*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10019*5113495bSYour Name 		break;
10020*5113495bSYour Name 	case QCA_ROAM_REASON_CONGESTION:
10021*5113495bSYour Name 		/* ROAM_STATS_CONGESTION_RX_TPUT */
10022*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10023*5113495bSYour Name 		/* ROAM_STATS_CONGESTION_TX_TPUT */
10024*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10025*5113495bSYour Name 		/* ROAM_STATS_CONGESTION_ROAMABLE_CNT */
10026*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10027*5113495bSYour Name 		break;
10028*5113495bSYour Name 	case QCA_ROAM_REASON_BACKGROUND_SCAN:
10029*5113495bSYour Name 		/* ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI */
10030*5113495bSYour Name 		len += nla_total_size(sizeof(int8_t));
10031*5113495bSYour Name 		/* ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI */
10032*5113495bSYour Name 		len += nla_total_size(sizeof(int8_t));
10033*5113495bSYour Name 		/* ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH */
10034*5113495bSYour Name 		len += nla_total_size(sizeof(int8_t));
10035*5113495bSYour Name 		break;
10036*5113495bSYour Name 	case QCA_ROAM_REASON_USER_TRIGGER:
10037*5113495bSYour Name 		/* ROAM_STATS_USER_TRIGGER_INVOKE_REASON */
10038*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10039*5113495bSYour Name 		break;
10040*5113495bSYour Name 	case QCA_ROAM_REASON_BTM:
10041*5113495bSYour Name 		/* ROAM_STATS_BTM_REQUEST_MODE */
10042*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10043*5113495bSYour Name 		/* ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME */
10044*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10045*5113495bSYour Name 		/* ROAM_STATS_BTM_VALID_INTERNAL */
10046*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10047*5113495bSYour Name 		/* ROAM_STATS_BTM_CANDIDATE_LIST_CNT */
10048*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10049*5113495bSYour Name 		/* ROAM_STATS_BTM_RESPONSE_STATUS_CODE */
10050*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10051*5113495bSYour Name 		/* ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT */
10052*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10053*5113495bSYour Name 		/* ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT */
10054*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10055*5113495bSYour Name 		/* ROAM_STATS_BTM_REQ_DIALOG_TOKEN */
10056*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10057*5113495bSYour Name 		break;
10058*5113495bSYour Name 	case QCA_ROAM_REASON_BSS_LOAD:
10059*5113495bSYour Name 		/* ROAM_STATS_BSS_CU_LOAD */
10060*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10061*5113495bSYour Name 		break;
10062*5113495bSYour Name 	case QCA_ROAM_REASON_DISCONNECTION:
10063*5113495bSYour Name 		/* ROAM_STATS_DISCONNECTION_TYPE */
10064*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10065*5113495bSYour Name 		/* ROAM_STATS_DISCONNECTION_REASON */
10066*5113495bSYour Name 		len += nla_total_size(sizeof(uint16_t));
10067*5113495bSYour Name 		break;
10068*5113495bSYour Name 	case QCA_ROAM_REASON_STA_KICKOUT:
10069*5113495bSYour Name 		/* ROAM_STATS_TX_FAILURES_THRESHOLD */
10070*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10071*5113495bSYour Name 		/* ROAM_STATS_TX_FAILURES_REASON */
10072*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10073*5113495bSYour Name 		break;
10074*5113495bSYour Name 	default:
10075*5113495bSYour Name 		break;
10076*5113495bSYour Name 	}
10077*5113495bSYour Name 
10078*5113495bSYour Name 	/* ROAM_STATS_SCAN_TYPE */
10079*5113495bSYour Name 	len += nla_total_size(sizeof(uint8_t));
10080*5113495bSYour Name 	/* ROAM_STATS_ROAM_STATUS */
10081*5113495bSYour Name 	len += nla_total_size(sizeof(uint8_t));
10082*5113495bSYour Name 
10083*5113495bSYour Name 	if (info->trigger.roam_status) {
10084*5113495bSYour Name 		/* ROAM_STATS_FAIL_REASON */
10085*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10086*5113495bSYour Name 		if (info->trigger.abort.abort_reason_code) {
10087*5113495bSYour Name 			/* ROAM_STATS_ABORT_REASON */
10088*5113495bSYour Name 			len += nla_total_size(sizeof(uint8_t));
10089*5113495bSYour Name 			/* ROAM_STATS_DATA_RSSI */
10090*5113495bSYour Name 			len += nla_total_size(sizeof(int8_t));
10091*5113495bSYour Name 			/* ROAM_STATS_DATA_RSSI_THRESHOLD */
10092*5113495bSYour Name 			len += nla_total_size(sizeof(int8_t));
10093*5113495bSYour Name 			/* ROAM_STATS_DATA_RX_LINKSPEED_STATUS */
10094*5113495bSYour Name 			len += nla_total_size(sizeof(uint8_t));
10095*5113495bSYour Name 		}
10096*5113495bSYour Name 	}
10097*5113495bSYour Name 
10098*5113495bSYour Name 	/* ROAM_STATS_SCAN_CHAN_INFO */
10099*5113495bSYour Name 	len += nla_total_size(0);
10100*5113495bSYour Name 	for (i = 0; i < info->scan.num_channels; i++) {
10101*5113495bSYour Name 		/* nest attribute */
10102*5113495bSYour Name 		len += nla_total_size(0);
10103*5113495bSYour Name 		/* ROAM_STATS_SCAN_CHANNEL_FREQ */
10104*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10105*5113495bSYour Name 		/* ROAM_STATS_SCAN_DWELL_TYPE */
10106*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10107*5113495bSYour Name 		/* ROAM_STATS_MAX_DWELL_TIME */
10108*5113495bSYour Name 		len += nla_total_size(sizeof(uint32_t));
10109*5113495bSYour Name 	}
10110*5113495bSYour Name 
10111*5113495bSYour Name 	/* ROAM_STATS_TOTAL_SCAN_TIME */
10112*5113495bSYour Name 	len += nla_total_size(sizeof(uint32_t));
10113*5113495bSYour Name 
10114*5113495bSYour Name 	/* ROAM_STATS_FRAME_INFO */
10115*5113495bSYour Name 	len += nla_total_size(0);
10116*5113495bSYour Name 	for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) {
10117*5113495bSYour Name 		/* nest attribute */
10118*5113495bSYour Name 		len += nla_total_size(0);
10119*5113495bSYour Name 		/* ROAM_STATS_FRAME_SUBTYPE */
10120*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10121*5113495bSYour Name 		/* ROAM_STATS_FRAME_STATUS */
10122*5113495bSYour Name 		len += nla_total_size(sizeof(uint8_t));
10123*5113495bSYour Name 		/* ROAM_STATS_FRAME_TIMESTAMP */
10124*5113495bSYour Name 		len += nla_total_size_64bit(sizeof(uint64_t));
10125*5113495bSYour Name 	}
10126*5113495bSYour Name 
10127*5113495bSYour Name 	return len;
10128*5113495bSYour Name }
10129*5113495bSYour Name 
10130*5113495bSYour Name /**
10131*5113495bSYour Name  * hdd_get_roam_stats_info_len() - calculate the length required by skb
10132*5113495bSYour Name  * @roam_info: pointer to roam info
10133*5113495bSYour Name  * @roam_cache_num: roam cache number
10134*5113495bSYour Name  *
10135*5113495bSYour Name  * Calculate the required length to send roam stats to upper layer
10136*5113495bSYour Name  *
10137*5113495bSYour Name  * Return: required len
10138*5113495bSYour Name  */
10139*5113495bSYour Name static uint32_t
hdd_get_roam_stats_info_len(struct enhance_roam_info * roam_info,uint8_t roam_cache_num)10140*5113495bSYour Name hdd_get_roam_stats_info_len(struct enhance_roam_info *roam_info,
10141*5113495bSYour Name 			    uint8_t roam_cache_num)
10142*5113495bSYour Name {
10143*5113495bSYour Name 	uint32_t len, i;
10144*5113495bSYour Name 
10145*5113495bSYour Name 	len = 0;
10146*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO */
10147*5113495bSYour Name 	len += nla_total_size(0);
10148*5113495bSYour Name 	for (i = 0; i < roam_cache_num; i++) {
10149*5113495bSYour Name 		/* nest attribute */
10150*5113495bSYour Name 		len += nla_total_size(0);
10151*5113495bSYour Name 		len += hdd_get_roam_stats_individual_record_len(roam_info, i);
10152*5113495bSYour Name 	}
10153*5113495bSYour Name 
10154*5113495bSYour Name 	return len;
10155*5113495bSYour Name }
10156*5113495bSYour Name 
10157*5113495bSYour Name /**
10158*5113495bSYour Name  * hdd_nla_put_roam_stats_info() - put roam statistics info attribute
10159*5113495bSYour Name  * values to userspace
10160*5113495bSYour Name  *
10161*5113495bSYour Name  * @skb:       pointer to sk buff
10162*5113495bSYour Name  * @roam_info: pointer to roam info
10163*5113495bSYour Name  * @index:     index of roam info cached in driver
10164*5113495bSYour Name  *
10165*5113495bSYour Name  * Return: 0 if success else error status
10166*5113495bSYour Name  */
hdd_nla_put_roam_stats_info(struct sk_buff * skb,struct enhance_roam_info * roam_info,uint32_t index)10167*5113495bSYour Name static int hdd_nla_put_roam_stats_info(struct sk_buff *skb,
10168*5113495bSYour Name 				       struct enhance_roam_info *roam_info,
10169*5113495bSYour Name 				       uint32_t index)
10170*5113495bSYour Name {
10171*5113495bSYour Name 	struct nlattr *roam_chn_info, *roam_chn;
10172*5113495bSYour Name 	struct nlattr *roam_frame_info, *roam_frame;
10173*5113495bSYour Name 	struct enhance_roam_info *info;
10174*5113495bSYour Name 	enum roam_invoke_reason driver_invoke_reason;
10175*5113495bSYour Name 	enum qca_wlan_roam_stats_invoke_reason vendor_invoke_reason;
10176*5113495bSYour Name 	enum roam_tx_failures_reason driver_tx_failures_reason;
10177*5113495bSYour Name 	enum qca_wlan_roam_stats_tx_failures_reason vendor_tx_failures_reason;
10178*5113495bSYour Name 	enum roam_abort_reason driver_abort_reason;
10179*5113495bSYour Name 	enum qca_wlan_roam_stats_abort_reason vendor_abort_reason;
10180*5113495bSYour Name 	enum qca_wlan_roam_stats_scan_type vendor_scan_type;
10181*5113495bSYour Name 	enum roam_scan_dwell_type driver_dwell_type;
10182*5113495bSYour Name 	enum qca_wlan_roam_stats_scan_dwell_type vendor_dwell_type;
10183*5113495bSYour Name 	enum eroam_frame_subtype driver_frame_type;
10184*5113495bSYour Name 	enum qca_wlan_roam_stats_frame_subtype vendor_frame_type;
10185*5113495bSYour Name 	enum eroam_frame_status driver_frame_status;
10186*5113495bSYour Name 	enum qca_wlan_roam_stats_frame_status vendor_frame_status;
10187*5113495bSYour Name 	enum qca_roam_reason vendor_trigger_reason;
10188*5113495bSYour Name 	enum qca_vendor_roam_fail_reasons vendor_fail_reason;
10189*5113495bSYour Name 	uint32_t i;
10190*5113495bSYour Name 	int ret;
10191*5113495bSYour Name 
10192*5113495bSYour Name 	if (!roam_info) {
10193*5113495bSYour Name 		hdd_err("invalid param");
10194*5113495bSYour Name 		return -EINVAL;
10195*5113495bSYour Name 	}
10196*5113495bSYour Name 	info  = &roam_info[index];
10197*5113495bSYour Name 
10198*5113495bSYour Name 	vendor_trigger_reason =
10199*5113495bSYour Name 		hdd_convert_roam_trigger_reason(info->trigger.trigger_reason);
10200*5113495bSYour Name 
10201*5113495bSYour Name 	if (wlan_cfg80211_nla_put_u64(skb, ROAM_STATS_ROAM_TRIGGER_TIMESTAMP,
10202*5113495bSYour Name 				      info->trigger.timestamp)) {
10203*5113495bSYour Name 		hdd_err("timestamp put fail");
10204*5113495bSYour Name 		return -EINVAL;
10205*5113495bSYour Name 	}
10206*5113495bSYour Name 
10207*5113495bSYour Name 	if (nla_put_u32(skb, ROAM_STATS_TRIGGER_REASON, vendor_trigger_reason)) {
10208*5113495bSYour Name 		hdd_err(" put fail");
10209*5113495bSYour Name 		return -EINVAL;
10210*5113495bSYour Name 	}
10211*5113495bSYour Name 
10212*5113495bSYour Name 	switch (vendor_trigger_reason) {
10213*5113495bSYour Name 	case QCA_ROAM_REASON_PER:
10214*5113495bSYour Name 		if (nla_put_u8(skb,  ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT,
10215*5113495bSYour Name 			       info->trigger.condition.roam_per.rx_rate_thresh_percent)) {
10216*5113495bSYour Name 			hdd_err("roam_per.rx_rate_thresh_percent put fail");
10217*5113495bSYour Name 			return -EINVAL;
10218*5113495bSYour Name 		}
10219*5113495bSYour Name 		if (nla_put_u8(skb,  ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT,
10220*5113495bSYour Name 			       info->trigger.condition.roam_per.tx_rate_thresh_percent)) {
10221*5113495bSYour Name 			hdd_err("roam_per.rx_rate_thresh_percent put fail");
10222*5113495bSYour Name 			return -EINVAL;
10223*5113495bSYour Name 		}
10224*5113495bSYour Name 		break;
10225*5113495bSYour Name 	case QCA_ROAM_REASON_BEACON_MISS:
10226*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_FINAL_BMISS_CNT,
10227*5113495bSYour Name 				info->trigger.condition.roam_bmiss.final_bmiss_cnt)) {
10228*5113495bSYour Name 			hdd_err("roam_bmiss.final_bmiss_cnt put fail");
10229*5113495bSYour Name 			return -EINVAL;
10230*5113495bSYour Name 		}
10231*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_CONSECUTIVE_BMISS_CNT,
10232*5113495bSYour Name 				info->trigger.condition.roam_bmiss.consecutive_bmiss_cnt)) {
10233*5113495bSYour Name 			hdd_err("roam_bmiss.consecutive_bmiss_cnt put fail");
10234*5113495bSYour Name 			return -EINVAL;
10235*5113495bSYour Name 		}
10236*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_BMISS_QOS_NULL_SUCCESS,
10237*5113495bSYour Name 			       info->trigger.condition.roam_bmiss.qos_null_success)) {
10238*5113495bSYour Name 			hdd_err("roam_bmiss.qos_null_success put fail");
10239*5113495bSYour Name 			return -EINVAL;
10240*5113495bSYour Name 		}
10241*5113495bSYour Name 		break;
10242*5113495bSYour Name 	case QCA_ROAM_REASON_POOR_RSSI:
10243*5113495bSYour Name 		if (nla_put_s8(skb, ROAM_STATS_POOR_RSSI_CURRENT_RSSI,
10244*5113495bSYour Name 			       info->trigger.condition.roam_poor_rssi.current_rssi)) {
10245*5113495bSYour Name 			hdd_err("roam_poor_rssi.current_rssi put fail");
10246*5113495bSYour Name 			return -EINVAL;
10247*5113495bSYour Name 		}
10248*5113495bSYour Name 		if (nla_put_s8(skb, ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD,
10249*5113495bSYour Name 			       info->trigger.condition.roam_poor_rssi.roam_rssi_threshold)) {
10250*5113495bSYour Name 			hdd_err("roam_poor_rssi.roam_rssi_threshold put fail");
10251*5113495bSYour Name 			return -EINVAL;
10252*5113495bSYour Name 		}
10253*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS,
10254*5113495bSYour Name 			       info->trigger.condition.roam_poor_rssi.rx_linkspeed_status)) {
10255*5113495bSYour Name 			hdd_err("roam_poor_rssi.rx_linkspeed_status put fail");
10256*5113495bSYour Name 			return -EINVAL;
10257*5113495bSYour Name 		}
10258*5113495bSYour Name 		break;
10259*5113495bSYour Name 	case QCA_ROAM_REASON_BETTER_RSSI:
10260*5113495bSYour Name 		if (nla_put_s8(skb, ROAM_STATS_BETTER_RSSI_CURRENT_RSSI,
10261*5113495bSYour Name 			       info->trigger.condition.roam_better_rssi.current_rssi)) {
10262*5113495bSYour Name 			hdd_err("roam_better_rssi.current_rssi put fail");
10263*5113495bSYour Name 			return -EINVAL;
10264*5113495bSYour Name 		}
10265*5113495bSYour Name 		if (nla_put_s8(skb, ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD,
10266*5113495bSYour Name 			       info->trigger.condition.roam_better_rssi.hi_rssi_threshold)) {
10267*5113495bSYour Name 			hdd_err("roam_better_rssi.hi_rssi_threshold put fail");
10268*5113495bSYour Name 			return -EINVAL;
10269*5113495bSYour Name 		}
10270*5113495bSYour Name 		break;
10271*5113495bSYour Name 	case QCA_ROAM_REASON_PERIODIC_TIMER:
10272*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_PERIODIC_TIMER_MS,
10273*5113495bSYour Name 				info->trigger.condition.roam_periodic.periodic_timer_ms)) {
10274*5113495bSYour Name 			hdd_err("roam_periodic.periodic_timer_ms put fail");
10275*5113495bSYour Name 			return -EINVAL;
10276*5113495bSYour Name 		}
10277*5113495bSYour Name 		break;
10278*5113495bSYour Name 	case QCA_ROAM_REASON_CONGESTION:
10279*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_CONGESTION_RX_TPUT,
10280*5113495bSYour Name 				info->trigger.condition.roam_congestion.rx_tput)) {
10281*5113495bSYour Name 			hdd_err("roam_congestion.rx_tput put fail");
10282*5113495bSYour Name 			return -EINVAL;
10283*5113495bSYour Name 		}
10284*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_CONGESTION_TX_TPUT,
10285*5113495bSYour Name 				info->trigger.condition.roam_congestion.tx_tput)) {
10286*5113495bSYour Name 			hdd_err("roam_congestion.tx_tput put fail");
10287*5113495bSYour Name 			return -EINVAL;
10288*5113495bSYour Name 		}
10289*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_CONGESTION_ROAMABLE_CNT,
10290*5113495bSYour Name 			       info->trigger.condition.roam_congestion.roamable_count)) {
10291*5113495bSYour Name 			hdd_err("roam_congestion.roamable_count put fail");
10292*5113495bSYour Name 			return -EINVAL;
10293*5113495bSYour Name 		}
10294*5113495bSYour Name 		break;
10295*5113495bSYour Name 	case QCA_ROAM_REASON_BACKGROUND_SCAN:
10296*5113495bSYour Name 		if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI,
10297*5113495bSYour Name 			       info->trigger.condition.roam_background.current_rssi)) {
10298*5113495bSYour Name 			hdd_err("roam_background.current_rssi put fail");
10299*5113495bSYour Name 			return -EINVAL;
10300*5113495bSYour Name 		}
10301*5113495bSYour Name 		if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI,
10302*5113495bSYour Name 			       info->trigger.condition.roam_background.data_rssi)) {
10303*5113495bSYour Name 			hdd_err("roam_background.data_rssi put fail");
10304*5113495bSYour Name 			return -EINVAL;
10305*5113495bSYour Name 		}
10306*5113495bSYour Name 		if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH,
10307*5113495bSYour Name 			       info->trigger.condition.roam_background.data_rssi_threshold)) {
10308*5113495bSYour Name 			hdd_err("roam_background.data_rssi_threshold put fail");
10309*5113495bSYour Name 			return -EINVAL;
10310*5113495bSYour Name 		}
10311*5113495bSYour Name 		break;
10312*5113495bSYour Name 	case QCA_ROAM_REASON_USER_TRIGGER:
10313*5113495bSYour Name 		driver_invoke_reason =
10314*5113495bSYour Name 			info->trigger.condition.roam_user_trigger.invoke_reason;
10315*5113495bSYour Name 		vendor_invoke_reason = hdd_convert_roam_invoke_reason(driver_invoke_reason);
10316*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_USER_TRIGGER_INVOKE_REASON,
10317*5113495bSYour Name 			       vendor_invoke_reason)) {
10318*5113495bSYour Name 			hdd_err("roam_user_trigger.invoke_reason put fail");
10319*5113495bSYour Name 			return -EINVAL;
10320*5113495bSYour Name 		}
10321*5113495bSYour Name 		break;
10322*5113495bSYour Name 	case QCA_ROAM_REASON_BTM:
10323*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_BTM_REQUEST_MODE,
10324*5113495bSYour Name 			       info->trigger.condition.roam_btm.btm_request_mode)) {
10325*5113495bSYour Name 			hdd_err("roam_btm.btm_request_mode put fail");
10326*5113495bSYour Name 			return -EINVAL;
10327*5113495bSYour Name 		}
10328*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME,
10329*5113495bSYour Name 				info->trigger.condition.roam_btm.disassoc_imminent_timer)) {
10330*5113495bSYour Name 			hdd_err("roam_btm.disassoc_imminent_timer put fail");
10331*5113495bSYour Name 			return -EINVAL;
10332*5113495bSYour Name 		}
10333*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_BTM_VALID_INTERNAL,
10334*5113495bSYour Name 				info->trigger.condition.roam_btm.validity_internal)) {
10335*5113495bSYour Name 			hdd_err("roam_btm.validity_internal put fail");
10336*5113495bSYour Name 			return -EINVAL;
10337*5113495bSYour Name 		}
10338*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_BTM_CANDIDATE_LIST_CNT,
10339*5113495bSYour Name 			       info->trigger.condition.roam_btm.candidate_list_count)) {
10340*5113495bSYour Name 			hdd_err("roam_btm.candidate_list_count put fail");
10341*5113495bSYour Name 			return -EINVAL;
10342*5113495bSYour Name 		}
10343*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_BTM_RESPONSE_STATUS_CODE,
10344*5113495bSYour Name 			       info->trigger.condition.roam_btm.btm_response_status_code)) {
10345*5113495bSYour Name 			hdd_err("roam_btm.btm_response_status_code put fail");
10346*5113495bSYour Name 			return -EINVAL;
10347*5113495bSYour Name 		}
10348*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT,
10349*5113495bSYour Name 				info->trigger.condition.roam_btm.btm_bss_termination_timeout)) {
10350*5113495bSYour Name 			hdd_err("roam btm_bss_termination_timeout put fail");
10351*5113495bSYour Name 			return -EINVAL;
10352*5113495bSYour Name 		}
10353*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT,
10354*5113495bSYour Name 				info->trigger.condition.roam_btm.btm_mbo_assoc_retry_timeout)) {
10355*5113495bSYour Name 			hdd_err("roam btm_mbo_assoc_retry_timeout put fail");
10356*5113495bSYour Name 			return -EINVAL;
10357*5113495bSYour Name 		}
10358*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_BTM_REQ_DIALOG_TOKEN,
10359*5113495bSYour Name 			       info->trigger.condition.roam_btm.btm_req_dialog_token)) {
10360*5113495bSYour Name 			hdd_err("roam_btm.btm_req_dialog_token put fail");
10361*5113495bSYour Name 			return -EINVAL;
10362*5113495bSYour Name 		}
10363*5113495bSYour Name 		break;
10364*5113495bSYour Name 	case QCA_ROAM_REASON_BSS_LOAD:
10365*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_BSS_CU_LOAD,
10366*5113495bSYour Name 			       info->trigger.condition.roam_bss_load.cu_load)) {
10367*5113495bSYour Name 			hdd_err("roam_bss_load.cu_load put fail");
10368*5113495bSYour Name 			return -EINVAL;
10369*5113495bSYour Name 		}
10370*5113495bSYour Name 		break;
10371*5113495bSYour Name 	case QCA_ROAM_REASON_DISCONNECTION:
10372*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_DISCONNECTION_TYPE,
10373*5113495bSYour Name 			       info->trigger.condition.roam_disconnection.deauth_type)) {
10374*5113495bSYour Name 			hdd_err("roam_disconnection.deauth_type put fail");
10375*5113495bSYour Name 			return -EINVAL;
10376*5113495bSYour Name 		}
10377*5113495bSYour Name 		if (nla_put_u16(skb, ROAM_STATS_DISCONNECTION_REASON,
10378*5113495bSYour Name 				info->trigger.condition.roam_disconnection.deauth_reason)) {
10379*5113495bSYour Name 			hdd_err("roam_disconnection.deauth_reason put fail");
10380*5113495bSYour Name 			return -EINVAL;
10381*5113495bSYour Name 		}
10382*5113495bSYour Name 		break;
10383*5113495bSYour Name 	case QCA_ROAM_REASON_STA_KICKOUT:
10384*5113495bSYour Name 		driver_tx_failures_reason =
10385*5113495bSYour Name 			info->trigger.condition.roam_tx_failures.kickout_threshold;
10386*5113495bSYour Name 		vendor_tx_failures_reason =
10387*5113495bSYour Name 			hdd_convert_roam_tx_failures_reason(driver_tx_failures_reason);
10388*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_TX_FAILURES_THRESHOLD,
10389*5113495bSYour Name 				vendor_tx_failures_reason)) {
10390*5113495bSYour Name 			hdd_err("roam_tx_failures.kickout_threshold put fail");
10391*5113495bSYour Name 			return -EINVAL;
10392*5113495bSYour Name 		}
10393*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_TX_FAILURES_REASON,
10394*5113495bSYour Name 			       info->trigger.condition.roam_tx_failures.kickout_reason)) {
10395*5113495bSYour Name 			hdd_err("roam_tx_failures.kickout_reason put fail");
10396*5113495bSYour Name 			return -EINVAL;
10397*5113495bSYour Name 		}
10398*5113495bSYour Name 		break;
10399*5113495bSYour Name 	default:
10400*5113495bSYour Name 		break;
10401*5113495bSYour Name 	}
10402*5113495bSYour Name 
10403*5113495bSYour Name 	vendor_scan_type = hdd_convert_roam_scan_type(info->trigger.roam_scan_type);
10404*5113495bSYour Name 	if (nla_put_u8(skb, ROAM_STATS_SCAN_TYPE, vendor_scan_type)) {
10405*5113495bSYour Name 		hdd_err("roam_scan_type put fail");
10406*5113495bSYour Name 		return -EINVAL;
10407*5113495bSYour Name 	}
10408*5113495bSYour Name 
10409*5113495bSYour Name 	if (nla_put_u8(skb, ROAM_STATS_ROAM_STATUS,
10410*5113495bSYour Name 		       info->trigger.roam_status)) {
10411*5113495bSYour Name 		hdd_err("roam_status put fail");
10412*5113495bSYour Name 		return -EINVAL;
10413*5113495bSYour Name 	}
10414*5113495bSYour Name 
10415*5113495bSYour Name 	if (info->trigger.roam_status) {
10416*5113495bSYour Name 		vendor_fail_reason = hdd_convert_roam_failures_reason(info->trigger.roam_fail_reason);
10417*5113495bSYour Name 		if (nla_put_u8(skb, ROAM_STATS_FAIL_REASON,
10418*5113495bSYour Name 			       vendor_fail_reason)) {
10419*5113495bSYour Name 			hdd_err("roam_fail_reason put fail");
10420*5113495bSYour Name 			return -EINVAL;
10421*5113495bSYour Name 		}
10422*5113495bSYour Name 
10423*5113495bSYour Name 		driver_abort_reason = info->trigger.abort.abort_reason_code;
10424*5113495bSYour Name 		vendor_abort_reason = hdd_convert_roam_abort_reason(driver_abort_reason);
10425*5113495bSYour Name 		if (info->trigger.abort.abort_reason_code) {
10426*5113495bSYour Name 			if (nla_put_u8(skb, ROAM_STATS_ABORT_REASON, vendor_abort_reason)) {
10427*5113495bSYour Name 				hdd_err("abort.abort_reason_code put fail");
10428*5113495bSYour Name 				return -EINVAL;
10429*5113495bSYour Name 			}
10430*5113495bSYour Name 			if (nla_put_s8(skb, ROAM_STATS_DATA_RSSI,
10431*5113495bSYour Name 				       info->trigger.abort.data_rssi)) {
10432*5113495bSYour Name 				hdd_err("abort.data_rssi put fail");
10433*5113495bSYour Name 				return -EINVAL;
10434*5113495bSYour Name 			}
10435*5113495bSYour Name 			if (nla_put_s8(skb, ROAM_STATS_DATA_RSSI_THRESHOLD,
10436*5113495bSYour Name 				       info->trigger.abort.data_rssi_threshold)) {
10437*5113495bSYour Name 				hdd_err("abort.data_rssi_threshold put fail");
10438*5113495bSYour Name 				return -EINVAL;
10439*5113495bSYour Name 			}
10440*5113495bSYour Name 			if (nla_put_u8(skb, ROAM_STATS_DATA_RX_LINKSPEED_STATUS,
10441*5113495bSYour Name 				       info->trigger.abort.rx_linkspeed_status)) {
10442*5113495bSYour Name 				hdd_err("abort.rx_linkspeed_status put fail");
10443*5113495bSYour Name 				return -EINVAL;
10444*5113495bSYour Name 			}
10445*5113495bSYour Name 		}
10446*5113495bSYour Name 	}
10447*5113495bSYour Name 
10448*5113495bSYour Name 	roam_chn_info = nla_nest_start(skb, ROAM_STATS_SCAN_CHAN_INFO);
10449*5113495bSYour Name 	if (!roam_chn_info) {
10450*5113495bSYour Name 		hdd_err("nla_nest_start fail");
10451*5113495bSYour Name 		return -EINVAL;
10452*5113495bSYour Name 	}
10453*5113495bSYour Name 
10454*5113495bSYour Name 	for (i = 0; i < info->scan.num_channels; i++) {
10455*5113495bSYour Name 		roam_chn = nla_nest_start(skb, i);
10456*5113495bSYour Name 		if (!roam_chn) {
10457*5113495bSYour Name 			hdd_err("nla_nest_start fail");
10458*5113495bSYour Name 			return -EINVAL;
10459*5113495bSYour Name 		}
10460*5113495bSYour Name 
10461*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_SCAN_CHANNEL_FREQ,
10462*5113495bSYour Name 				info->scan.roam_chn[i].chan_freq)) {
10463*5113495bSYour Name 			hdd_err("roam_chn[%u].chan_freq put fail", i);
10464*5113495bSYour Name 			return -EINVAL;
10465*5113495bSYour Name 		}
10466*5113495bSYour Name 
10467*5113495bSYour Name 		driver_dwell_type = info->scan.roam_chn[i].dwell_type;
10468*5113495bSYour Name 		vendor_dwell_type = hdd_convert_roam_chn_dwell_type(driver_dwell_type);
10469*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_SCAN_DWELL_TYPE,
10470*5113495bSYour Name 				vendor_dwell_type)) {
10471*5113495bSYour Name 			hdd_err("roam_chn[%u].dwell_type put fail", i);
10472*5113495bSYour Name 			return -EINVAL;
10473*5113495bSYour Name 		}
10474*5113495bSYour Name 		if (nla_put_u32(skb, ROAM_STATS_MAX_DWELL_TIME,
10475*5113495bSYour Name 				info->scan.roam_chn[i].max_dwell_time)) {
10476*5113495bSYour Name 			hdd_err("roam_chn[%u].max_dwell_time put fail", i);
10477*5113495bSYour Name 			return -EINVAL;
10478*5113495bSYour Name 		}
10479*5113495bSYour Name 		nla_nest_end(skb, roam_chn);
10480*5113495bSYour Name 	}
10481*5113495bSYour Name 	nla_nest_end(skb, roam_chn_info);
10482*5113495bSYour Name 
10483*5113495bSYour Name 	if (nla_put_u32(skb, ROAM_STATS_TOTAL_SCAN_TIME,
10484*5113495bSYour Name 			info->scan.total_scan_time)) {
10485*5113495bSYour Name 		hdd_err("roam_scan total_scan_time put fail");
10486*5113495bSYour Name 		return -EINVAL;
10487*5113495bSYour Name 	}
10488*5113495bSYour Name 
10489*5113495bSYour Name 	roam_frame_info = nla_nest_start(skb, ROAM_STATS_FRAME_INFO);
10490*5113495bSYour Name 	if (!roam_frame_info) {
10491*5113495bSYour Name 		hdd_err("nla_nest_start fail");
10492*5113495bSYour Name 		return -EINVAL;
10493*5113495bSYour Name 	}
10494*5113495bSYour Name 
10495*5113495bSYour Name 	for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) {
10496*5113495bSYour Name 		if (info->timestamp[i].frame_type ==
10497*5113495bSYour Name 				WLAN_ROAM_STATS_FRAME_SUBTYPE_INVALID)
10498*5113495bSYour Name 			break;
10499*5113495bSYour Name 		roam_frame = nla_nest_start(skb, i);
10500*5113495bSYour Name 		if (!roam_frame) {
10501*5113495bSYour Name 			hdd_err("nla_nest_start fail");
10502*5113495bSYour Name 			return -EINVAL;
10503*5113495bSYour Name 		}
10504*5113495bSYour Name 		driver_frame_type = info->timestamp[i].frame_type;
10505*5113495bSYour Name 		vendor_frame_type = hdd_convert_roam_frame_type(driver_frame_type);
10506*5113495bSYour Name 		ret = nla_put_u8(skb, ROAM_STATS_FRAME_SUBTYPE,
10507*5113495bSYour Name 				 vendor_frame_type);
10508*5113495bSYour Name 		if (ret) {
10509*5113495bSYour Name 			hdd_err("roam_frame[%u].type put fail %d", i, ret);
10510*5113495bSYour Name 			return -EINVAL;
10511*5113495bSYour Name 		}
10512*5113495bSYour Name 		driver_frame_status = info->timestamp[i].status;
10513*5113495bSYour Name 		vendor_frame_status = hdd_convert_roam_frame_status(driver_frame_status);
10514*5113495bSYour Name 		ret = nla_put_u8(skb, ROAM_STATS_FRAME_STATUS,
10515*5113495bSYour Name 				 vendor_frame_status);
10516*5113495bSYour Name 		if (ret) {
10517*5113495bSYour Name 			hdd_err("frame[%u].status put fail %d", i, ret);
10518*5113495bSYour Name 			return -EINVAL;
10519*5113495bSYour Name 		}
10520*5113495bSYour Name 		ret = wlan_cfg80211_nla_put_u64(skb, ROAM_STATS_FRAME_TIMESTAMP,
10521*5113495bSYour Name 						info->timestamp[i].timestamp);
10522*5113495bSYour Name 		if (ret) {
10523*5113495bSYour Name 			hdd_err("frame[%u].timestamp put fail %d", i, ret);
10524*5113495bSYour Name 			return -EINVAL;
10525*5113495bSYour Name 		}
10526*5113495bSYour Name 		ret = nla_put(skb,
10527*5113495bSYour Name 			      QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_BSSID,
10528*5113495bSYour Name 			      QDF_MAC_ADDR_SIZE,
10529*5113495bSYour Name 			      info->timestamp[i].bssid.bytes);
10530*5113495bSYour Name 		if (ret) {
10531*5113495bSYour Name 			hdd_err("roam candidate AP bssid put fail");
10532*5113495bSYour Name 			return -EINVAL;
10533*5113495bSYour Name 		}
10534*5113495bSYour Name 
10535*5113495bSYour Name 		nla_nest_end(skb, roam_frame);
10536*5113495bSYour Name 	}
10537*5113495bSYour Name 	nla_nest_end(skb, roam_frame_info);
10538*5113495bSYour Name 
10539*5113495bSYour Name 	if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ORIGINAL_BSSID,
10540*5113495bSYour Name 		    QDF_MAC_ADDR_SIZE, info->scan.original_bssid.bytes)) {
10541*5113495bSYour Name 		hdd_err("roam original AP bssid put fail");
10542*5113495bSYour Name 		return -EINVAL;
10543*5113495bSYour Name 	}
10544*5113495bSYour Name 	if (!info->trigger.roam_status) {
10545*5113495bSYour Name 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAMED_BSSID,
10546*5113495bSYour Name 			    QDF_MAC_ADDR_SIZE, info->scan.roamed_bssid.bytes)) {
10547*5113495bSYour Name 			hdd_err("roam roamed AP bssid put fail");
10548*5113495bSYour Name 			return -EINVAL;
10549*5113495bSYour Name 		}
10550*5113495bSYour Name 	}
10551*5113495bSYour Name 
10552*5113495bSYour Name 	return 0;
10553*5113495bSYour Name }
10554*5113495bSYour Name 
10555*5113495bSYour Name /**
10556*5113495bSYour Name  * hdd_get_roam_stats_info() - get roam statistics info to userspace,
10557*5113495bSYour Name  * for STA mode only
10558*5113495bSYour Name  * @skb:     pointer to sk buff
10559*5113495bSYour Name  * @hdd_ctx: pointer to hdd context
10560*5113495bSYour Name  * @roam_info: pointer to roam info
10561*5113495bSYour Name  * @roam_cache_num: roam cache number
10562*5113495bSYour Name  *
10563*5113495bSYour Name  * Return: 0 if success else error status
10564*5113495bSYour Name  */
hdd_get_roam_stats_info(struct sk_buff * skb,struct hdd_context * hdd_ctx,struct enhance_roam_info * roam_info,uint32_t roam_cache_num)10565*5113495bSYour Name static int hdd_get_roam_stats_info(struct sk_buff *skb,
10566*5113495bSYour Name 				   struct hdd_context *hdd_ctx,
10567*5113495bSYour Name 				   struct enhance_roam_info *roam_info,
10568*5113495bSYour Name 				   uint32_t  roam_cache_num)
10569*5113495bSYour Name {
10570*5113495bSYour Name 	struct nlattr *config, *roam_params;
10571*5113495bSYour Name 	uint32_t i;
10572*5113495bSYour Name 	int ret;
10573*5113495bSYour Name 
10574*5113495bSYour Name 	config = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO);
10575*5113495bSYour Name 	if (!config) {
10576*5113495bSYour Name 		hdd_err("nla nest start failure");
10577*5113495bSYour Name 		return -EINVAL;
10578*5113495bSYour Name 	}
10579*5113495bSYour Name 
10580*5113495bSYour Name 	/* Send all driver cached roam info to user space one time,
10581*5113495bSYour Name 	 * and don't flush them, since they will be cover by
10582*5113495bSYour Name 	 * new roam event info.
10583*5113495bSYour Name 	 */
10584*5113495bSYour Name 	for (i = 0; i < roam_cache_num; i++) {
10585*5113495bSYour Name 		roam_params = nla_nest_start(skb, i);
10586*5113495bSYour Name 		if (!roam_params)
10587*5113495bSYour Name 			return -EINVAL;
10588*5113495bSYour Name 
10589*5113495bSYour Name 		ret = hdd_nla_put_roam_stats_info(skb, roam_info, i);
10590*5113495bSYour Name 		if (ret) {
10591*5113495bSYour Name 			hdd_err("nla put failure");
10592*5113495bSYour Name 			return -EINVAL;
10593*5113495bSYour Name 		}
10594*5113495bSYour Name 
10595*5113495bSYour Name 		nla_nest_end(skb, roam_params);
10596*5113495bSYour Name 	}
10597*5113495bSYour Name 	nla_nest_end(skb, config);
10598*5113495bSYour Name 
10599*5113495bSYour Name 	return 0;
10600*5113495bSYour Name }
10601*5113495bSYour Name 
10602*5113495bSYour Name /**
10603*5113495bSYour Name  * hdd_get_roam_stats() - send roam statistics info to userspace
10604*5113495bSYour Name  * @hdd_ctx: pointer to hdd context
10605*5113495bSYour Name  * @adapter: pointer to adapter
10606*5113495bSYour Name  *
10607*5113495bSYour Name  * Return: 0 if success else error status
10608*5113495bSYour Name  */
10609*5113495bSYour Name static int
hdd_get_roam_stats(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter)10610*5113495bSYour Name hdd_get_roam_stats(struct hdd_context *hdd_ctx,
10611*5113495bSYour Name 		   struct hdd_adapter *adapter)
10612*5113495bSYour Name {
10613*5113495bSYour Name 	struct sk_buff *skb;
10614*5113495bSYour Name 	uint32_t skb_len;
10615*5113495bSYour Name 	int ret = 0;
10616*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
10617*5113495bSYour Name 	QDF_STATUS status;
10618*5113495bSYour Name 	struct enhance_roam_info *roam_info = NULL;
10619*5113495bSYour Name 	uint32_t roam_num = 0;
10620*5113495bSYour Name 
10621*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
10622*5113495bSYour Name 					   WLAN_OSIF_STATS_ID);
10623*5113495bSYour Name 	if (!vdev)
10624*5113495bSYour Name 		return -EINVAL;
10625*5113495bSYour Name 
10626*5113495bSYour Name 	status = ucfg_cm_roam_stats_info_get(vdev, &roam_info, &roam_num);
10627*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
10628*5113495bSYour Name 		hdd_err("Failed to get roam info : %d", status);
10629*5113495bSYour Name 		wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID);
10630*5113495bSYour Name 		return qdf_status_to_os_return(status);
10631*5113495bSYour Name 	}
10632*5113495bSYour Name 	wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID);
10633*5113495bSYour Name 
10634*5113495bSYour Name 	skb_len = hdd_get_roam_stats_info_len(roam_info, roam_num);
10635*5113495bSYour Name 	if (!skb_len) {
10636*5113495bSYour Name 		hdd_err("No data requested");
10637*5113495bSYour Name 		ucfg_cm_roam_stats_info_put(roam_info);
10638*5113495bSYour Name 		return -EINVAL;
10639*5113495bSYour Name 	}
10640*5113495bSYour Name 
10641*5113495bSYour Name 	skb_len += NLMSG_HDRLEN;
10642*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, skb_len);
10643*5113495bSYour Name 	if (!skb) {
10644*5113495bSYour Name 		hdd_info("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
10645*5113495bSYour Name 		ucfg_cm_roam_stats_info_put(roam_info);
10646*5113495bSYour Name 		return -ENOMEM;
10647*5113495bSYour Name 	}
10648*5113495bSYour Name 
10649*5113495bSYour Name 	ret = hdd_get_roam_stats_info(skb, hdd_ctx, roam_info, roam_num);
10650*5113495bSYour Name 	if (ret) {
10651*5113495bSYour Name 		hdd_info("get roam stats fail");
10652*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(skb);
10653*5113495bSYour Name 		ucfg_cm_roam_stats_info_put(roam_info);
10654*5113495bSYour Name 		return -ENOMEM;
10655*5113495bSYour Name 	}
10656*5113495bSYour Name 
10657*5113495bSYour Name 	ucfg_cm_roam_stats_info_put(roam_info);
10658*5113495bSYour Name 
10659*5113495bSYour Name 	return wlan_cfg80211_vendor_cmd_reply(skb);
10660*5113495bSYour Name }
10661*5113495bSYour Name 
10662*5113495bSYour Name /**
10663*5113495bSYour Name  * __wlan_hdd_cfg80211_get_roam_stats() - get roam statstics information
10664*5113495bSYour Name  * @wiphy: wiphy pointer
10665*5113495bSYour Name  * @wdev: pointer to struct wireless_dev
10666*5113495bSYour Name  * @data: pointer to incoming NL vendor data
10667*5113495bSYour Name  * @data_len: length of @data
10668*5113495bSYour Name  *
10669*5113495bSYour Name  * Return: 0 on success; error number otherwise.
10670*5113495bSYour Name  */
10671*5113495bSYour Name static int
__wlan_hdd_cfg80211_get_roam_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)10672*5113495bSYour Name __wlan_hdd_cfg80211_get_roam_stats(struct wiphy *wiphy,
10673*5113495bSYour Name 				   struct wireless_dev *wdev,
10674*5113495bSYour Name 				   const void *data,
10675*5113495bSYour Name 				   int data_len)
10676*5113495bSYour Name {
10677*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
10678*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
10679*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
10680*5113495bSYour Name 	int32_t status;
10681*5113495bSYour Name 
10682*5113495bSYour Name 	hdd_enter_dev(dev);
10683*5113495bSYour Name 
10684*5113495bSYour Name 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE ||
10685*5113495bSYour Name 	    hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) {
10686*5113495bSYour Name 		hdd_err_rl("Command not allowed in FTM / Monitor mode");
10687*5113495bSYour Name 		status = -EPERM;
10688*5113495bSYour Name 		goto out;
10689*5113495bSYour Name 	}
10690*5113495bSYour Name 
10691*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
10692*5113495bSYour Name 	if (status != 0)
10693*5113495bSYour Name 		goto out;
10694*5113495bSYour Name 
10695*5113495bSYour Name 	if (adapter->device_mode == QDF_STA_MODE) {
10696*5113495bSYour Name 		status = hdd_get_roam_stats(hdd_ctx, adapter);
10697*5113495bSYour Name 	} else {
10698*5113495bSYour Name 		hdd_err_rl("Invalid device_mode: %d", adapter->device_mode);
10699*5113495bSYour Name 		status = -EINVAL;
10700*5113495bSYour Name 	}
10701*5113495bSYour Name 
10702*5113495bSYour Name 	hdd_exit();
10703*5113495bSYour Name out:
10704*5113495bSYour Name 	return status;
10705*5113495bSYour Name }
10706*5113495bSYour Name 
10707*5113495bSYour Name /**
10708*5113495bSYour Name  * wlan_hdd_cfg80211_get_roam_stats() - get roam statstics information
10709*5113495bSYour Name  * @wiphy: wiphy pointer
10710*5113495bSYour Name  * @wdev: pointer to struct wireless_dev
10711*5113495bSYour Name  * @data: pointer to incoming NL vendor data
10712*5113495bSYour Name  * @data_len: length of @data
10713*5113495bSYour Name  *
10714*5113495bSYour Name  * Return: 0 on success; error number otherwise.
10715*5113495bSYour Name  */
wlan_hdd_cfg80211_get_roam_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)10716*5113495bSYour Name int wlan_hdd_cfg80211_get_roam_stats(struct wiphy *wiphy,
10717*5113495bSYour Name 				     struct wireless_dev *wdev,
10718*5113495bSYour Name 				     const void *data,
10719*5113495bSYour Name 				     int data_len)
10720*5113495bSYour Name {
10721*5113495bSYour Name 	int errno;
10722*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
10723*5113495bSYour Name 
10724*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
10725*5113495bSYour Name 	if (errno)
10726*5113495bSYour Name 		return errno;
10727*5113495bSYour Name 
10728*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_get_roam_stats(wiphy, wdev,
10729*5113495bSYour Name 						   data, data_len);
10730*5113495bSYour Name 
10731*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
10732*5113495bSYour Name 
10733*5113495bSYour Name 	return errno;
10734*5113495bSYour Name }
10735*5113495bSYour Name #endif
10736*5113495bSYour Name 
10737*5113495bSYour Name #ifdef WLAN_FEATURE_ROAM_OFFLOAD
10738*5113495bSYour Name #ifdef WLAN_FEATURE_ROAM_INFO_STATS
10739*5113495bSYour Name static void
wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info * link_info,struct roam_stats_event * roam_stats,uint8_t idx)10740*5113495bSYour Name wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info *link_info,
10741*5113495bSYour Name 					       struct roam_stats_event *roam_stats,
10742*5113495bSYour Name 					       uint8_t idx)
10743*5113495bSYour Name {
10744*5113495bSYour Name 	int status;
10745*5113495bSYour Name 	uint32_t data_size = 0;
10746*5113495bSYour Name 	struct sk_buff *vendor_event;
10747*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev = NULL;
10748*5113495bSYour Name 	struct enhance_roam_info *roam_info = NULL;
10749*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
10750*5113495bSYour Name 
10751*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
10752*5113495bSYour Name 	if (status) {
10753*5113495bSYour Name 		hdd_err("Invalid hdd_ctx");
10754*5113495bSYour Name 		return;
10755*5113495bSYour Name 	}
10756*5113495bSYour Name 
10757*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID);
10758*5113495bSYour Name 	if (!vdev)
10759*5113495bSYour Name 		return;
10760*5113495bSYour Name 	ucfg_cm_roam_info_get(vdev, &roam_info, idx);
10761*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID);
10762*5113495bSYour Name 
10763*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO */
10764*5113495bSYour Name 	data_size += nla_total_size(0);
10765*5113495bSYour Name 	/* nest attribute */
10766*5113495bSYour Name 	data_size += nla_total_size(0);
10767*5113495bSYour Name 
10768*5113495bSYour Name 	data_size += hdd_get_roam_stats_individual_record_len(roam_info, idx);
10769*5113495bSYour Name 
10770*5113495bSYour Name 	data_size += NLMSG_HDRLEN;
10771*5113495bSYour Name 
10772*5113495bSYour Name 	vendor_event =
10773*5113495bSYour Name 		wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
10774*5113495bSYour Name 						 &link_info->adapter->wdev,
10775*5113495bSYour Name 						 data_size,
10776*5113495bSYour Name 						 ROAM_STATS_EVENT_INDEX,
10777*5113495bSYour Name 						 GFP_KERNEL);
10778*5113495bSYour Name 
10779*5113495bSYour Name 	if (hdd_nla_put_roam_stats_info(vendor_event, roam_info, 0)) {
10780*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(vendor_event);
10781*5113495bSYour Name 		hdd_err("nla put failure");
10782*5113495bSYour Name 		return;
10783*5113495bSYour Name 	}
10784*5113495bSYour Name 
10785*5113495bSYour Name 	roam_stats->enhance_roam_rt_event = false;
10786*5113495bSYour Name 
10787*5113495bSYour Name 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
10788*5113495bSYour Name }
10789*5113495bSYour Name #else
10790*5113495bSYour Name static void
wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info * link_info,struct roam_stats_event * roam_stats,uint8_t idx)10791*5113495bSYour Name wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info *link_info,
10792*5113495bSYour Name 					       struct roam_stats_event *roam_stats,
10793*5113495bSYour Name 					       uint8_t idx)
10794*5113495bSYour Name {
10795*5113495bSYour Name }
10796*5113495bSYour Name #endif
10797*5113495bSYour Name void
wlan_hdd_cfg80211_roam_events_callback(struct roam_stats_event * roam_stats,uint8_t idx)10798*5113495bSYour Name wlan_hdd_cfg80211_roam_events_callback(struct roam_stats_event *roam_stats,
10799*5113495bSYour Name 				       uint8_t idx)
10800*5113495bSYour Name {
10801*5113495bSYour Name 	int status;
10802*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
10803*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
10804*5113495bSYour Name 
10805*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
10806*5113495bSYour Name 	if (status) {
10807*5113495bSYour Name 		hdd_err("Invalid hdd_ctx");
10808*5113495bSYour Name 		return;
10809*5113495bSYour Name 	}
10810*5113495bSYour Name 
10811*5113495bSYour Name 	if (!roam_stats) {
10812*5113495bSYour Name 		hdd_err("msg received here is null");
10813*5113495bSYour Name 		return;
10814*5113495bSYour Name 	}
10815*5113495bSYour Name 
10816*5113495bSYour Name 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, roam_stats->vdev_id);
10817*5113495bSYour Name 	if (!link_info) {
10818*5113495bSYour Name 		hdd_err("vdev_id %d does not exist with host",
10819*5113495bSYour Name 			roam_stats->vdev_id);
10820*5113495bSYour Name 		return;
10821*5113495bSYour Name 	}
10822*5113495bSYour Name 	if (roam_stats->enhance_roam_rt_event)
10823*5113495bSYour Name 		wlan_hdd_cfg80211_enhance_roam_events_callback(link_info,
10824*5113495bSYour Name 							       roam_stats, idx);
10825*5113495bSYour Name 	else
10826*5113495bSYour Name 		wlan_hdd_cfg80211_typical_roam_events_callback(link_info,
10827*5113495bSYour Name 							       roam_stats, idx);
10828*5113495bSYour Name }
10829*5113495bSYour Name #endif
10830*5113495bSYour Name 
10831*5113495bSYour Name #ifdef WLAN_FEATURE_TX_LATENCY_STATS
10832*5113495bSYour Name #define TX_LATENCY_BUCKET_DISTRIBUTION_LEN \
10833*5113495bSYour Name 	(sizeof(uint32_t) * CDP_TX_LATENCY_TYPE_MAX)
10834*5113495bSYour Name 
10835*5113495bSYour Name #define TX_LATENCY_ATTR(_name) QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ ## _name
10836*5113495bSYour Name 
10837*5113495bSYour Name static const struct nla_policy
10838*5113495bSYour Name tx_latency_bucket_policy[TX_LATENCY_ATTR(BUCKET_MAX) + 1] = {
10839*5113495bSYour Name 	[TX_LATENCY_ATTR(BUCKET_TYPE)] = {.type = NLA_U8},
10840*5113495bSYour Name 	[TX_LATENCY_ATTR(BUCKET_GRANULARITY)] = {.type = NLA_U32},
10841*5113495bSYour Name 	[TX_LATENCY_ATTR(BUCKET_AVERAGE)] = {.type = NLA_U32},
10842*5113495bSYour Name 	[TX_LATENCY_ATTR(BUCKET_DISTRIBUTION)] = {
10843*5113495bSYour Name 		.type = NLA_BINARY, .len = TX_LATENCY_BUCKET_DISTRIBUTION_LEN},
10844*5113495bSYour Name };
10845*5113495bSYour Name 
10846*5113495bSYour Name static const struct nla_policy
10847*5113495bSYour Name tx_latency_link_policy[TX_LATENCY_ATTR(LINK_MAX) + 1] = {
10848*5113495bSYour Name 	[TX_LATENCY_ATTR(LINK_MAC_REMOTE)] = {
10849*5113495bSYour Name 		.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE},
10850*5113495bSYour Name 	[TX_LATENCY_ATTR(LINK_STAT_BUCKETS)] =
10851*5113495bSYour Name 		VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_bucket_policy),
10852*5113495bSYour Name };
10853*5113495bSYour Name 
10854*5113495bSYour Name const struct nla_policy
10855*5113495bSYour Name tx_latency_policy[TX_LATENCY_ATTR(MAX) + 1] = {
10856*5113495bSYour Name 	[TX_LATENCY_ATTR(ACTION)] = {.type = NLA_U32},
10857*5113495bSYour Name 	[TX_LATENCY_ATTR(PERIODIC_REPORT)] = {.type = NLA_FLAG},
10858*5113495bSYour Name 	[TX_LATENCY_ATTR(PERIOD)] = {.type = NLA_U32 },
10859*5113495bSYour Name 	[TX_LATENCY_ATTR(BUCKETS)] =
10860*5113495bSYour Name 		VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_bucket_policy),
10861*5113495bSYour Name 	[TX_LATENCY_ATTR(LINKS)] =
10862*5113495bSYour Name 		VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_link_policy),
10863*5113495bSYour Name };
10864*5113495bSYour Name 
10865*5113495bSYour Name /**
10866*5113495bSYour Name  * struct tx_latency_link_node - Link info of remote peer
10867*5113495bSYour Name  * @node: list node for membership in the link list
10868*5113495bSYour Name  * @vdev_id: Unique value to identify VDEV
10869*5113495bSYour Name  * @mac_remote: link MAC address of the remote peer
10870*5113495bSYour Name  */
10871*5113495bSYour Name struct tx_latency_link_node {
10872*5113495bSYour Name 	qdf_list_node_t node;
10873*5113495bSYour Name 	uint8_t vdev_id;
10874*5113495bSYour Name 	struct qdf_mac_addr mac_remote;
10875*5113495bSYour Name };
10876*5113495bSYour Name 
10877*5113495bSYour Name /**
10878*5113495bSYour Name  * hdd_tx_latency_set_for_link() - set tx latency stats config for a link
10879*5113495bSYour Name  * @link_info: link specific information
10880*5113495bSYour Name  * @config: pointer to tx latency stats config
10881*5113495bSYour Name  *
10882*5113495bSYour Name  * Return: QDF_STATUS
10883*5113495bSYour Name  */
10884*5113495bSYour Name static inline QDF_STATUS
hdd_tx_latency_set_for_link(struct wlan_hdd_link_info * link_info,struct cdp_tx_latency_config * config)10885*5113495bSYour Name hdd_tx_latency_set_for_link(struct wlan_hdd_link_info *link_info,
10886*5113495bSYour Name 			    struct cdp_tx_latency_config *config)
10887*5113495bSYour Name {
10888*5113495bSYour Name 	QDF_STATUS status;
10889*5113495bSYour Name 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
10890*5113495bSYour Name 
10891*5113495bSYour Name 	if (!soc)
10892*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
10893*5113495bSYour Name 
10894*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
10895*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
10896*5113495bSYour Name 
10897*5113495bSYour Name 	status = cdp_host_tx_latency_stats_config(soc,
10898*5113495bSYour Name 						  link_info->vdev_id,
10899*5113495bSYour Name 						  config);
10900*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
10901*5113495bSYour Name 		hdd_err_rl("failed to %s for vdev id %d, status %d",
10902*5113495bSYour Name 			   config->enable ? "enable" : "disable",
10903*5113495bSYour Name 			   link_info->vdev_id, status);
10904*5113495bSYour Name 		return status;
10905*5113495bSYour Name 	}
10906*5113495bSYour Name 
10907*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
10908*5113495bSYour Name }
10909*5113495bSYour Name 
10910*5113495bSYour Name /**
10911*5113495bSYour Name  * hdd_tx_latency_restore_config() - restore tx latency stats config for a link
10912*5113495bSYour Name  * @link_info: link specific information
10913*5113495bSYour Name  *
10914*5113495bSYour Name  * Return: QDF_STATUS
10915*5113495bSYour Name  */
10916*5113495bSYour Name QDF_STATUS
hdd_tx_latency_restore_config(struct wlan_hdd_link_info * link_info)10917*5113495bSYour Name hdd_tx_latency_restore_config(struct wlan_hdd_link_info *link_info)
10918*5113495bSYour Name {
10919*5113495bSYour Name 	QDF_STATUS status;
10920*5113495bSYour Name 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
10921*5113495bSYour Name 	struct cdp_tx_latency_config *config;
10922*5113495bSYour Name 
10923*5113495bSYour Name 	if (!soc)
10924*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
10925*5113495bSYour Name 
10926*5113495bSYour Name 	if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
10927*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
10928*5113495bSYour Name 
10929*5113495bSYour Name 	config = &link_info->adapter->tx_latency_cfg;
10930*5113495bSYour Name 	status = cdp_host_tx_latency_stats_config(soc,
10931*5113495bSYour Name 						  link_info->vdev_id,
10932*5113495bSYour Name 						  config);
10933*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
10934*5113495bSYour Name 		hdd_err_rl("failed to %s for vdev id %d, status %d",
10935*5113495bSYour Name 			   config->enable ? "enable" : "disable",
10936*5113495bSYour Name 			   link_info->vdev_id, status);
10937*5113495bSYour Name 		return status;
10938*5113495bSYour Name 	}
10939*5113495bSYour Name 
10940*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
10941*5113495bSYour Name }
10942*5113495bSYour Name 
10943*5113495bSYour Name /**
10944*5113495bSYour Name  * hdd_tx_latency_set() - restore tx latency stats config for a link
10945*5113495bSYour Name  * @adapter: pointer to hdd vdev/net_device context
10946*5113495bSYour Name  * @config: pointer to tx latency stats config
10947*5113495bSYour Name  *
10948*5113495bSYour Name  * Return: 0 on success; error number otherwise.
10949*5113495bSYour Name  */
10950*5113495bSYour Name static int
hdd_tx_latency_set(struct hdd_adapter * adapter,struct cdp_tx_latency_config * config)10951*5113495bSYour Name hdd_tx_latency_set(struct hdd_adapter *adapter,
10952*5113495bSYour Name 		   struct cdp_tx_latency_config *config)
10953*5113495bSYour Name {
10954*5113495bSYour Name 	int ret;
10955*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
10956*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_NOENT;
10957*5113495bSYour Name 
10958*5113495bSYour Name 	ret = hdd_set_tsf_auto_report(adapter, config->enable,
10959*5113495bSYour Name 				      HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY);
10960*5113495bSYour Name 	if (ret) {
10961*5113495bSYour Name 		hdd_err_rl("failed to %s tsf auto report, ret %d",
10962*5113495bSYour Name 			   config->enable ? "enable" : "disable", ret);
10963*5113495bSYour Name 		return ret;
10964*5113495bSYour Name 	}
10965*5113495bSYour Name 
10966*5113495bSYour Name 	hdd_adapter_for_each_link_info(adapter, link_info) {
10967*5113495bSYour Name 		status = hdd_tx_latency_set_for_link(link_info, config);
10968*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status))
10969*5113495bSYour Name 			break;
10970*5113495bSYour Name 	}
10971*5113495bSYour Name 
10972*5113495bSYour Name 	/* restore TSF auto report config on failure */
10973*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
10974*5113495bSYour Name 		hdd_set_tsf_auto_report(adapter, !config->enable,
10975*5113495bSYour Name 					HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY);
10976*5113495bSYour Name 	else
10977*5113495bSYour Name 		qdf_mem_copy(&adapter->tx_latency_cfg, config,
10978*5113495bSYour Name 			     sizeof(*config));
10979*5113495bSYour Name 	hdd_debug("enable %d status %d", config->enable, status);
10980*5113495bSYour Name 	return qdf_status_to_os_return(status);
10981*5113495bSYour Name }
10982*5113495bSYour Name 
10983*5113495bSYour Name /**
10984*5113495bSYour Name  * hdd_tx_latency_fill_link_stats() - fill tx latency statistics info skb
10985*5113495bSYour Name  * @skb: skb to be filled
10986*5113495bSYour Name  * @latency: per link tx latency statistics
10987*5113495bSYour Name  * @idx: index of the nested attribute
10988*5113495bSYour Name  *
10989*5113495bSYour Name  * Return: 0 on success; error number otherwise.
10990*5113495bSYour Name  */
10991*5113495bSYour Name static int
hdd_tx_latency_fill_link_stats(struct sk_buff * skb,struct cdp_tx_latency * latency,int idx)10992*5113495bSYour Name hdd_tx_latency_fill_link_stats(struct sk_buff *skb,
10993*5113495bSYour Name 			       struct cdp_tx_latency *latency, int idx)
10994*5113495bSYour Name {
10995*5113495bSYour Name 	struct nlattr *link, *link_stat_buckets, *link_stat_bucket;
10996*5113495bSYour Name 	uint32_t type;
10997*5113495bSYour Name 	int ret = 0;
10998*5113495bSYour Name 
10999*5113495bSYour Name 	link = nla_nest_start(skb, idx);
11000*5113495bSYour Name 	if (!link) {
11001*5113495bSYour Name 		ret = -ENOMEM;
11002*5113495bSYour Name 		goto err;
11003*5113495bSYour Name 	}
11004*5113495bSYour Name 
11005*5113495bSYour Name 	if (nla_put(skb, TX_LATENCY_ATTR(LINK_MAC_REMOTE),
11006*5113495bSYour Name 		    QDF_MAC_ADDR_SIZE, latency->mac_remote.bytes)) {
11007*5113495bSYour Name 		ret = -ENOMEM;
11008*5113495bSYour Name 		goto err;
11009*5113495bSYour Name 	}
11010*5113495bSYour Name 
11011*5113495bSYour Name 	hdd_debug_rl("idx %d link mac " QDF_MAC_ADDR_FMT,
11012*5113495bSYour Name 		     idx, QDF_MAC_ADDR_REF(latency->mac_remote.bytes));
11013*5113495bSYour Name 	link_stat_buckets =
11014*5113495bSYour Name 		nla_nest_start(skb, TX_LATENCY_ATTR(LINK_STAT_BUCKETS));
11015*5113495bSYour Name 	for (type = 0; type < CDP_TX_LATENCY_TYPE_MAX; type++) {
11016*5113495bSYour Name 		link_stat_bucket = nla_nest_start(skb, type);
11017*5113495bSYour Name 		if (!link_stat_bucket) {
11018*5113495bSYour Name 			ret = -ENOMEM;
11019*5113495bSYour Name 			goto err;
11020*5113495bSYour Name 		}
11021*5113495bSYour Name 
11022*5113495bSYour Name 		if (nla_put_u8(skb, TX_LATENCY_ATTR(BUCKET_TYPE), type)) {
11023*5113495bSYour Name 			ret = -ENOMEM;
11024*5113495bSYour Name 			goto err;
11025*5113495bSYour Name 		}
11026*5113495bSYour Name 
11027*5113495bSYour Name 		if (nla_put_u32(skb, TX_LATENCY_ATTR(BUCKET_GRANULARITY),
11028*5113495bSYour Name 				latency->stats[type].granularity)) {
11029*5113495bSYour Name 			ret = -ENOMEM;
11030*5113495bSYour Name 			goto err;
11031*5113495bSYour Name 		}
11032*5113495bSYour Name 
11033*5113495bSYour Name 		if (nla_put_u32(skb, TX_LATENCY_ATTR(BUCKET_AVERAGE),
11034*5113495bSYour Name 				latency->stats[type].average)) {
11035*5113495bSYour Name 			ret = -ENOMEM;
11036*5113495bSYour Name 			goto err;
11037*5113495bSYour Name 		}
11038*5113495bSYour Name 
11039*5113495bSYour Name 		if (nla_put(skb, TX_LATENCY_ATTR(BUCKET_DISTRIBUTION),
11040*5113495bSYour Name 			    TX_LATENCY_BUCKET_DISTRIBUTION_LEN,
11041*5113495bSYour Name 			    latency->stats[type].distribution)) {
11042*5113495bSYour Name 			ret = -ENOMEM;
11043*5113495bSYour Name 			goto err;
11044*5113495bSYour Name 		}
11045*5113495bSYour Name 
11046*5113495bSYour Name 		nla_nest_end(skb, link_stat_bucket);
11047*5113495bSYour Name 		hdd_debug_rl("	type %u granularity %u average %u",
11048*5113495bSYour Name 			     type, latency->stats[type].granularity,
11049*5113495bSYour Name 			     latency->stats[type].average);
11050*5113495bSYour Name 	}
11051*5113495bSYour Name 
11052*5113495bSYour Name 	nla_nest_end(skb, link_stat_buckets);
11053*5113495bSYour Name 	nla_nest_end(skb, link);
11054*5113495bSYour Name 
11055*5113495bSYour Name err:
11056*5113495bSYour Name 	if (ret)
11057*5113495bSYour Name 		hdd_err("failed for link " QDF_MAC_ADDR_FMT " ret: %d",
11058*5113495bSYour Name 			QDF_MAC_ADDR_REF(latency->mac_remote.bytes), ret);
11059*5113495bSYour Name 	return ret;
11060*5113495bSYour Name }
11061*5113495bSYour Name 
11062*5113495bSYour Name /**
11063*5113495bSYour Name  * hdd_tx_latency_get_skb_len() - get required skb length for vendor command
11064*5113495bSYour Name  * response/async event
11065*5113495bSYour Name  * @num: required number of entries
11066*5113495bSYour Name  *
11067*5113495bSYour Name  * Return: the required skb length
11068*5113495bSYour Name  */
hdd_tx_latency_get_skb_len(uint32_t num)11069*5113495bSYour Name static uint32_t hdd_tx_latency_get_skb_len(uint32_t num)
11070*5113495bSYour Name {
11071*5113495bSYour Name 	int32_t peer_stat_sz = 0, per_bucket_len = 0, len;
11072*5113495bSYour Name 
11073*5113495bSYour Name 	if (!num)
11074*5113495bSYour Name 		return 0;
11075*5113495bSYour Name 
11076*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE */
11077*5113495bSYour Name 	per_bucket_len += nla_total_size(sizeof(uint8_t));
11078*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_GRANULARITY */
11079*5113495bSYour Name 	per_bucket_len += nla_total_size(sizeof(uint32_t));
11080*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_DISTRIBUTION */
11081*5113495bSYour Name 	per_bucket_len += nla_total_size(TX_LATENCY_BUCKET_DISTRIBUTION_LEN);
11082*5113495bSYour Name 	/* Nested attr */
11083*5113495bSYour Name 	per_bucket_len = nla_total_size(per_bucket_len);
11084*5113495bSYour Name 
11085*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE */
11086*5113495bSYour Name 	peer_stat_sz += nla_total_size(QDF_MAC_ADDR_SIZE);
11087*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_STAT_BUCKETS */
11088*5113495bSYour Name 	peer_stat_sz +=
11089*5113495bSYour Name 		nla_total_size(per_bucket_len * CDP_TX_LATENCY_TYPE_MAX);
11090*5113495bSYour Name 	/* Nested attr */
11091*5113495bSYour Name 	peer_stat_sz = nla_total_size(peer_stat_sz);
11092*5113495bSYour Name 
11093*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS */
11094*5113495bSYour Name 	len = nla_total_size(peer_stat_sz * num);
11095*5113495bSYour Name 	len += NLMSG_HDRLEN;
11096*5113495bSYour Name 	return len;
11097*5113495bSYour Name }
11098*5113495bSYour Name 
11099*5113495bSYour Name /**
11100*5113495bSYour Name  * hdd_tx_latency_link_list_free() - free all the nodes in the list
11101*5113495bSYour Name  * @list: list of the nodes for link info
11102*5113495bSYour Name  *
11103*5113495bSYour Name  * Return: None
11104*5113495bSYour Name  */
hdd_tx_latency_link_list_free(qdf_list_t * list)11105*5113495bSYour Name static void hdd_tx_latency_link_list_free(qdf_list_t *list)
11106*5113495bSYour Name {
11107*5113495bSYour Name 	struct tx_latency_link_node *entry, *next;
11108*5113495bSYour Name 
11109*5113495bSYour Name 	qdf_list_for_each_del(list, entry, next, node) {
11110*5113495bSYour Name 		qdf_list_remove_node(list, &entry->node);
11111*5113495bSYour Name 		qdf_mem_free(entry);
11112*5113495bSYour Name 	}
11113*5113495bSYour Name }
11114*5113495bSYour Name 
11115*5113495bSYour Name /**
11116*5113495bSYour Name  * hdd_tx_latency_link_list_add() - add a new node to the list for tx latency
11117*5113495bSYour Name  * links
11118*5113495bSYour Name  * @list: list of the nodes for link info
11119*5113495bSYour Name  * @vdev_id: Unique value to identify VDEV
11120*5113495bSYour Name  * @mac: link mac address of the remote peer
11121*5113495bSYour Name  *
11122*5113495bSYour Name  * Return: 0 on success; error number otherwise.
11123*5113495bSYour Name  */
11124*5113495bSYour Name static int
hdd_tx_latency_link_list_add(qdf_list_t * list,uint8_t vdev_id,uint8_t * mac)11125*5113495bSYour Name hdd_tx_latency_link_list_add(qdf_list_t *list, uint8_t vdev_id, uint8_t *mac)
11126*5113495bSYour Name {
11127*5113495bSYour Name 	struct tx_latency_link_node *link;
11128*5113495bSYour Name 
11129*5113495bSYour Name 	link = (struct tx_latency_link_node *)qdf_mem_malloc(sizeof(*link));
11130*5113495bSYour Name 	if (!link)
11131*5113495bSYour Name 		return -ENOMEM;
11132*5113495bSYour Name 
11133*5113495bSYour Name 	qdf_mem_copy(link->mac_remote.bytes, mac, QDF_MAC_ADDR_SIZE);
11134*5113495bSYour Name 	link->vdev_id = vdev_id;
11135*5113495bSYour Name 	qdf_list_insert_back(list, &link->node);
11136*5113495bSYour Name 	return 0;
11137*5113495bSYour Name }
11138*5113495bSYour Name 
11139*5113495bSYour Name /**
11140*5113495bSYour Name  * hdd_tx_latency_get_links_from_attr() - parse information of the links from
11141*5113495bSYour Name  * attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11142*5113495bSYour Name  * @adapter: pointer to hdd vdev/net_device context
11143*5113495bSYour Name  * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11144*5113495bSYour Name  * @list: list of the nodes for link info
11145*5113495bSYour Name  *
11146*5113495bSYour Name  * Return: 0 on success; error number otherwise.
11147*5113495bSYour Name  */
11148*5113495bSYour Name static int
hdd_tx_latency_get_links_from_attr(struct hdd_adapter * adapter,struct nlattr * links_attr,qdf_list_t * list)11149*5113495bSYour Name hdd_tx_latency_get_links_from_attr(struct hdd_adapter *adapter,
11150*5113495bSYour Name 				   struct nlattr *links_attr,
11151*5113495bSYour Name 				   qdf_list_t *list)
11152*5113495bSYour Name {
11153*5113495bSYour Name 	struct nlattr *attr, *link_mac_remote_attr;
11154*5113495bSYour Name 	struct nlattr *tb[TX_LATENCY_ATTR(LINK_MAX) + 1];
11155*5113495bSYour Name 	int ret = 0, rem;
11156*5113495bSYour Name 	uint8_t vdev_id, *mac;
11157*5113495bSYour Name 
11158*5113495bSYour Name 	if (!links_attr || !list)
11159*5113495bSYour Name 		return -EINVAL;
11160*5113495bSYour Name 
11161*5113495bSYour Name 	/* links for MLO STA are attached to different vdevs */
11162*5113495bSYour Name 	vdev_id = (adapter->device_mode == QDF_STA_MODE ?
11163*5113495bSYour Name 		   CDP_VDEV_ALL : adapter->deflink->vdev_id);
11164*5113495bSYour Name 
11165*5113495bSYour Name 	nla_for_each_nested(attr, links_attr, rem) {
11166*5113495bSYour Name 		ret = wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(LINK_MAX),
11167*5113495bSYour Name 					      nla_data(attr), nla_len(attr),
11168*5113495bSYour Name 					      tx_latency_link_policy);
11169*5113495bSYour Name 		if (ret) {
11170*5113495bSYour Name 			hdd_err("Attribute parse failed, ret %d", ret);
11171*5113495bSYour Name 			ret = -EINVAL;
11172*5113495bSYour Name 			goto out;
11173*5113495bSYour Name 		}
11174*5113495bSYour Name 
11175*5113495bSYour Name 		link_mac_remote_attr = tb[TX_LATENCY_ATTR(LINK_MAC_REMOTE)];
11176*5113495bSYour Name 		if (!link_mac_remote_attr) {
11177*5113495bSYour Name 			hdd_err("Missing link mac remote attribute");
11178*5113495bSYour Name 			ret = -EINVAL;
11179*5113495bSYour Name 			goto out;
11180*5113495bSYour Name 		}
11181*5113495bSYour Name 
11182*5113495bSYour Name 		if (nla_len(link_mac_remote_attr) < QDF_MAC_ADDR_SIZE) {
11183*5113495bSYour Name 			hdd_err("Attribute link mac remote is invalid");
11184*5113495bSYour Name 			ret = -EINVAL;
11185*5113495bSYour Name 			goto out;
11186*5113495bSYour Name 		}
11187*5113495bSYour Name 
11188*5113495bSYour Name 		mac = (uint8_t *)nla_data(link_mac_remote_attr);
11189*5113495bSYour Name 		ret = hdd_tx_latency_link_list_add(list, vdev_id, mac);
11190*5113495bSYour Name 		if (ret)
11191*5113495bSYour Name 			goto out;
11192*5113495bSYour Name 	}
11193*5113495bSYour Name 
11194*5113495bSYour Name out:
11195*5113495bSYour Name 	if (ret)
11196*5113495bSYour Name 		hdd_tx_latency_link_list_free(list);
11197*5113495bSYour Name 
11198*5113495bSYour Name 	return ret;
11199*5113495bSYour Name }
11200*5113495bSYour Name 
11201*5113495bSYour Name /**
11202*5113495bSYour Name  * hdd_tx_latency_get_links_for_sap() - get all the active links for SAP mode
11203*5113495bSYour Name  * @adapter: pointer to hdd vdev/net_device context
11204*5113495bSYour Name  * @list: list of the nodes for link info
11205*5113495bSYour Name  *
11206*5113495bSYour Name  * Return: 0 on success; error number otherwise.
11207*5113495bSYour Name  */
11208*5113495bSYour Name static int
hdd_tx_latency_get_links_for_sap(struct hdd_adapter * adapter,qdf_list_t * list)11209*5113495bSYour Name hdd_tx_latency_get_links_for_sap(struct hdd_adapter *adapter, qdf_list_t *list)
11210*5113495bSYour Name {
11211*5113495bSYour Name 	struct hdd_station_info *sta, *tmp = NULL;
11212*5113495bSYour Name 	int ret = 0;
11213*5113495bSYour Name 
11214*5113495bSYour Name 	hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta, tmp,
11215*5113495bSYour Name 				  STA_INFO_SOFTAP_GET_STA_INFO) {
11216*5113495bSYour Name 		if (QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes)) {
11217*5113495bSYour Name 			hdd_put_sta_info_ref(&adapter->sta_info_list,
11218*5113495bSYour Name 					     &sta, true,
11219*5113495bSYour Name 					     STA_INFO_SOFTAP_GET_STA_INFO);
11220*5113495bSYour Name 			continue;
11221*5113495bSYour Name 		}
11222*5113495bSYour Name 
11223*5113495bSYour Name 		ret = hdd_tx_latency_link_list_add(list,
11224*5113495bSYour Name 						   adapter->deflink->vdev_id,
11225*5113495bSYour Name 						   sta->sta_mac.bytes);
11226*5113495bSYour Name 		hdd_put_sta_info_ref(&adapter->sta_info_list, &sta, true,
11227*5113495bSYour Name 				     STA_INFO_SOFTAP_GET_STA_INFO);
11228*5113495bSYour Name 		if (ret)
11229*5113495bSYour Name 			goto out;
11230*5113495bSYour Name 	}
11231*5113495bSYour Name 
11232*5113495bSYour Name out:
11233*5113495bSYour Name 	if (ret)
11234*5113495bSYour Name 		hdd_tx_latency_link_list_free(list);
11235*5113495bSYour Name 
11236*5113495bSYour Name 	return ret;
11237*5113495bSYour Name }
11238*5113495bSYour Name 
11239*5113495bSYour Name /**
11240*5113495bSYour Name  * hdd_tx_latency_get_links_for_sta() - get all the active links for station
11241*5113495bSYour Name  * mode
11242*5113495bSYour Name  * @adapter: pointer to hdd vdev/net_device context
11243*5113495bSYour Name  * @list: list of the nodes for link info
11244*5113495bSYour Name  *
11245*5113495bSYour Name  * Return: 0 on success; error number otherwise.
11246*5113495bSYour Name  */
11247*5113495bSYour Name static int
hdd_tx_latency_get_links_for_sta(struct hdd_adapter * adapter,qdf_list_t * list)11248*5113495bSYour Name hdd_tx_latency_get_links_for_sta(struct hdd_adapter *adapter, qdf_list_t *list)
11249*5113495bSYour Name {
11250*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
11251*5113495bSYour Name 	struct hdd_station_ctx *ctx;
11252*5113495bSYour Name 	int ret = 0;
11253*5113495bSYour Name 
11254*5113495bSYour Name 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
11255*5113495bSYour Name 		if (wlan_hdd_validate_vdev_id(link_info->vdev_id))
11256*5113495bSYour Name 			continue;
11257*5113495bSYour Name 
11258*5113495bSYour Name 		ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
11259*5113495bSYour Name 		if (!hdd_cm_is_vdev_associated(link_info))
11260*5113495bSYour Name 			continue;
11261*5113495bSYour Name 
11262*5113495bSYour Name 		ret = hdd_tx_latency_link_list_add(list, link_info->vdev_id,
11263*5113495bSYour Name 						   ctx->conn_info.bssid.bytes);
11264*5113495bSYour Name 		if (ret)
11265*5113495bSYour Name 			goto out;
11266*5113495bSYour Name 	}
11267*5113495bSYour Name 
11268*5113495bSYour Name out:
11269*5113495bSYour Name 	if (ret)
11270*5113495bSYour Name 		hdd_tx_latency_link_list_free(list);
11271*5113495bSYour Name 
11272*5113495bSYour Name 	return ret;
11273*5113495bSYour Name }
11274*5113495bSYour Name 
11275*5113495bSYour Name /**
11276*5113495bSYour Name  * hdd_tx_latency_get_links() - get all the active links
11277*5113495bSYour Name  * @adapter: pointer to hdd vdev/net_device context
11278*5113495bSYour Name  * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11279*5113495bSYour Name  * @list: list of the nodes for link info
11280*5113495bSYour Name  *
11281*5113495bSYour Name  * Return: 0 on success; error number otherwise.
11282*5113495bSYour Name  */
11283*5113495bSYour Name static int
hdd_tx_latency_get_links(struct hdd_adapter * adapter,struct nlattr * links_attr,qdf_list_t * list)11284*5113495bSYour Name hdd_tx_latency_get_links(struct hdd_adapter *adapter,
11285*5113495bSYour Name 			 struct nlattr *links_attr, qdf_list_t *list)
11286*5113495bSYour Name {
11287*5113495bSYour Name 	if (!list)
11288*5113495bSYour Name 		return -EINVAL;
11289*5113495bSYour Name 
11290*5113495bSYour Name 	if (links_attr)
11291*5113495bSYour Name 		return hdd_tx_latency_get_links_from_attr(adapter,
11292*5113495bSYour Name 							  links_attr, list);
11293*5113495bSYour Name 
11294*5113495bSYour Name 	if (adapter->device_mode == QDF_SAP_MODE ||
11295*5113495bSYour Name 	    adapter->device_mode == QDF_P2P_GO_MODE)
11296*5113495bSYour Name 		return hdd_tx_latency_get_links_for_sap(adapter, list);
11297*5113495bSYour Name 	else if (adapter->device_mode == QDF_STA_MODE ||
11298*5113495bSYour Name 		 adapter->device_mode == QDF_P2P_CLIENT_MODE)
11299*5113495bSYour Name 		return hdd_tx_latency_get_links_for_sta(adapter, list);
11300*5113495bSYour Name 	else
11301*5113495bSYour Name 		return -ENOTSUPP;
11302*5113495bSYour Name }
11303*5113495bSYour Name 
11304*5113495bSYour Name /**
11305*5113495bSYour Name  * hdd_tx_latency_populate_links() - get per link tx latency stats and fill
11306*5113495bSYour Name  * into skb
11307*5113495bSYour Name  * @soc: pointer to soc context
11308*5113495bSYour Name  * @skb: skb for vendor command response/async event
11309*5113495bSYour Name  * @list: list of the nodes for link info
11310*5113495bSYour Name  *
11311*5113495bSYour Name  * Return: 0 on success; error number otherwise.
11312*5113495bSYour Name  */
11313*5113495bSYour Name static inline int
hdd_tx_latency_populate_links(void * soc,struct sk_buff * skb,qdf_list_t * list)11314*5113495bSYour Name hdd_tx_latency_populate_links(void *soc, struct sk_buff *skb, qdf_list_t *list)
11315*5113495bSYour Name {
11316*5113495bSYour Name 	struct nlattr *links;
11317*5113495bSYour Name 	struct tx_latency_link_node *entry, *next;
11318*5113495bSYour Name 	struct cdp_tx_latency latency = {0};
11319*5113495bSYour Name 	int ret, idx = 0;
11320*5113495bSYour Name 	uint8_t *mac;
11321*5113495bSYour Name 	QDF_STATUS status;
11322*5113495bSYour Name 
11323*5113495bSYour Name 	links = nla_nest_start(skb, TX_LATENCY_ATTR(LINKS));
11324*5113495bSYour Name 	if (!links)
11325*5113495bSYour Name 		return -ENOMEM;
11326*5113495bSYour Name 
11327*5113495bSYour Name 	qdf_list_for_each_del(list, entry, next, node) {
11328*5113495bSYour Name 		qdf_list_remove_node(list, &entry->node);
11329*5113495bSYour Name 		mac = entry->mac_remote.bytes;
11330*5113495bSYour Name 		status = cdp_host_tx_latency_stats_fetch(soc, entry->vdev_id,
11331*5113495bSYour Name 							 mac, &latency);
11332*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
11333*5113495bSYour Name 			qdf_mem_free(entry);
11334*5113495bSYour Name 			return qdf_status_to_os_return(status);
11335*5113495bSYour Name 		}
11336*5113495bSYour Name 
11337*5113495bSYour Name 		ret = hdd_tx_latency_fill_link_stats(skb, &latency, idx);
11338*5113495bSYour Name 		qdf_mem_free(entry);
11339*5113495bSYour Name 		if (ret)
11340*5113495bSYour Name 			return ret;
11341*5113495bSYour Name 
11342*5113495bSYour Name 		idx++;
11343*5113495bSYour Name 	}
11344*5113495bSYour Name 
11345*5113495bSYour Name 	nla_nest_end(skb, links);
11346*5113495bSYour Name 	return 0;
11347*5113495bSYour Name }
11348*5113495bSYour Name 
11349*5113495bSYour Name /**
11350*5113495bSYour Name  * hdd_tx_latency_get() - get per link tx latency stats
11351*5113495bSYour Name  * @wiphy: pointer to wiphy
11352*5113495bSYour Name  * @adapter: pointer to hdd vdev/net_device context
11353*5113495bSYour Name  * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS
11354*5113495bSYour Name  *
11355*5113495bSYour Name  * Return: 0 on success; error number otherwise.
11356*5113495bSYour Name  */
11357*5113495bSYour Name static int
hdd_tx_latency_get(struct wiphy * wiphy,struct hdd_adapter * adapter,struct nlattr * links_attr)11358*5113495bSYour Name hdd_tx_latency_get(struct wiphy *wiphy,
11359*5113495bSYour Name 		   struct hdd_adapter *adapter, struct nlattr *links_attr)
11360*5113495bSYour Name {
11361*5113495bSYour Name 	int ret;
11362*5113495bSYour Name 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
11363*5113495bSYour Name 	struct sk_buff *reply_skb = NULL;
11364*5113495bSYour Name 	uint32_t skb_len, links_num = 0;
11365*5113495bSYour Name 	qdf_list_t links_list;
11366*5113495bSYour Name 
11367*5113495bSYour Name 	if (!soc)
11368*5113495bSYour Name 		return -EINVAL;
11369*5113495bSYour Name 
11370*5113495bSYour Name 	qdf_list_create(&links_list, 0);
11371*5113495bSYour Name 	ret = hdd_tx_latency_get_links(adapter, links_attr, &links_list);
11372*5113495bSYour Name 	if (ret)
11373*5113495bSYour Name 		goto out;
11374*5113495bSYour Name 
11375*5113495bSYour Name 	links_num = qdf_list_size(&links_list);
11376*5113495bSYour Name 	if (!links_num) {
11377*5113495bSYour Name 		hdd_err_rl("no valid peers");
11378*5113495bSYour Name 		ret = -EINVAL;
11379*5113495bSYour Name 		goto out;
11380*5113495bSYour Name 	}
11381*5113495bSYour Name 
11382*5113495bSYour Name 	skb_len = hdd_tx_latency_get_skb_len(links_num);
11383*5113495bSYour Name 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
11384*5113495bSYour Name 	if (!reply_skb) {
11385*5113495bSYour Name 		ret = -ENOMEM;
11386*5113495bSYour Name 		goto out;
11387*5113495bSYour Name 	}
11388*5113495bSYour Name 
11389*5113495bSYour Name 	ret = hdd_tx_latency_populate_links(soc, reply_skb, &links_list);
11390*5113495bSYour Name 	if (ret)
11391*5113495bSYour Name 		goto free_skb;
11392*5113495bSYour Name 
11393*5113495bSYour Name 	ret = wlan_cfg80211_vendor_cmd_reply(reply_skb);
11394*5113495bSYour Name 	/* skb has been consumed regardless of the return value */
11395*5113495bSYour Name 	goto out;
11396*5113495bSYour Name 
11397*5113495bSYour Name free_skb:
11398*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(reply_skb);
11399*5113495bSYour Name 	hdd_tx_latency_link_list_free(&links_list);
11400*5113495bSYour Name out:
11401*5113495bSYour Name 	qdf_list_destroy(&links_list);
11402*5113495bSYour Name 	hdd_debug_rl("get stats with ret %d", ret);
11403*5113495bSYour Name 	return ret;
11404*5113495bSYour Name }
11405*5113495bSYour Name 
11406*5113495bSYour Name /**
11407*5113495bSYour Name  * hdd_tx_latency_enable() - enable per link tx latency stats
11408*5113495bSYour Name  * @adapter: pointer to hdd vdev/net_device context
11409*5113495bSYour Name  * @period: statistical period for transmit latency
11410*5113495bSYour Name  * @periodic_report: whether driver needs to report transmit latency
11411*5113495bSYour Name  * statistics at the end of each period
11412*5113495bSYour Name  * @buckets_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKETS
11413*5113495bSYour Name  *
11414*5113495bSYour Name  * Return: 0 on success; error number otherwise.
11415*5113495bSYour Name  */
11416*5113495bSYour Name static int
hdd_tx_latency_enable(struct hdd_adapter * adapter,uint32_t period,bool periodic_report,struct nlattr * buckets_attr)11417*5113495bSYour Name hdd_tx_latency_enable(struct hdd_adapter *adapter, uint32_t period,
11418*5113495bSYour Name 		      bool periodic_report, struct nlattr *buckets_attr)
11419*5113495bSYour Name {
11420*5113495bSYour Name 	struct nlattr *tb[TX_LATENCY_ATTR(BUCKET_MAX) + 1];
11421*5113495bSYour Name 	struct nlattr *attr, *bucket_type_attr, *bucket_granularity_attr;
11422*5113495bSYour Name 	int rem, ret;
11423*5113495bSYour Name 	uint8_t bucket_type;
11424*5113495bSYour Name 	struct cdp_tx_latency_config config = {0};
11425*5113495bSYour Name 
11426*5113495bSYour Name 	nla_for_each_nested(attr, buckets_attr, rem) {
11427*5113495bSYour Name 		ret = wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(BUCKET_MAX),
11428*5113495bSYour Name 					      nla_data(attr), nla_len(attr),
11429*5113495bSYour Name 					      tx_latency_bucket_policy);
11430*5113495bSYour Name 		if (ret) {
11431*5113495bSYour Name 			hdd_err_rl("Attribute parse failed, ret %d", ret);
11432*5113495bSYour Name 			return -EINVAL;
11433*5113495bSYour Name 		}
11434*5113495bSYour Name 
11435*5113495bSYour Name 		bucket_type_attr = tb[TX_LATENCY_ATTR(BUCKET_TYPE)];
11436*5113495bSYour Name 		if (!bucket_type_attr) {
11437*5113495bSYour Name 			hdd_err_rl("Missing bucket type attribute");
11438*5113495bSYour Name 			return -EINVAL;
11439*5113495bSYour Name 		}
11440*5113495bSYour Name 
11441*5113495bSYour Name 		bucket_granularity_attr =
11442*5113495bSYour Name 			tb[TX_LATENCY_ATTR(BUCKET_GRANULARITY)];
11443*5113495bSYour Name 		if (!bucket_granularity_attr) {
11444*5113495bSYour Name 			hdd_err_rl("Missing bucket granularity attribute");
11445*5113495bSYour Name 			return -EINVAL;
11446*5113495bSYour Name 		}
11447*5113495bSYour Name 
11448*5113495bSYour Name 		bucket_type = nla_get_u8(bucket_type_attr);
11449*5113495bSYour Name 		if (bucket_type >= CDP_TX_LATENCY_TYPE_MAX) {
11450*5113495bSYour Name 			hdd_err_rl("Invalid bucket type %u", bucket_type);
11451*5113495bSYour Name 			return -EINVAL;
11452*5113495bSYour Name 		}
11453*5113495bSYour Name 
11454*5113495bSYour Name 		config.granularity[bucket_type] =
11455*5113495bSYour Name 			nla_get_u32(bucket_granularity_attr);
11456*5113495bSYour Name 		if (!config.granularity[bucket_type]) {
11457*5113495bSYour Name 			hdd_err_rl("Invalid granularity for type %d",
11458*5113495bSYour Name 				   bucket_type);
11459*5113495bSYour Name 			return -EINVAL;
11460*5113495bSYour Name 		}
11461*5113495bSYour Name 	}
11462*5113495bSYour Name 
11463*5113495bSYour Name 	for (rem = 0; rem < CDP_TX_LATENCY_TYPE_MAX; rem++) {
11464*5113495bSYour Name 		if (config.granularity[rem])
11465*5113495bSYour Name 			continue;
11466*5113495bSYour Name 
11467*5113495bSYour Name 		hdd_err_rl("Invalid granularity for type %d", rem);
11468*5113495bSYour Name 		return -EINVAL;
11469*5113495bSYour Name 	}
11470*5113495bSYour Name 
11471*5113495bSYour Name 	config.enable = true;
11472*5113495bSYour Name 	config.report = periodic_report;
11473*5113495bSYour Name 	config.period = period;
11474*5113495bSYour Name 	return hdd_tx_latency_set(adapter, &config);
11475*5113495bSYour Name }
11476*5113495bSYour Name 
11477*5113495bSYour Name /**
11478*5113495bSYour Name  * hdd_tx_latency_disable() - disable per link tx latency stats
11479*5113495bSYour Name  * @adapter: pointer to hdd vdev/net_device context
11480*5113495bSYour Name  *
11481*5113495bSYour Name  * Return: 0 on success; error number otherwise.
11482*5113495bSYour Name  */
hdd_tx_latency_disable(struct hdd_adapter * adapter)11483*5113495bSYour Name static int hdd_tx_latency_disable(struct hdd_adapter *adapter)
11484*5113495bSYour Name {
11485*5113495bSYour Name 	struct cdp_tx_latency_config config = {0};
11486*5113495bSYour Name 
11487*5113495bSYour Name 	return hdd_tx_latency_set(adapter, &config);
11488*5113495bSYour Name }
11489*5113495bSYour Name 
11490*5113495bSYour Name /**
11491*5113495bSYour Name  * __wlan_hdd_cfg80211_tx_latency - configure/retrieve per-link transmit
11492*5113495bSYour Name  * latency statistics
11493*5113495bSYour Name  * @wiphy: wiphy handle
11494*5113495bSYour Name  * @wdev: wdev handle
11495*5113495bSYour Name  * @data: user layer input
11496*5113495bSYour Name  * @data_len: length of user layer input
11497*5113495bSYour Name  *
11498*5113495bSYour Name  * this function is called in ssr protected environment.
11499*5113495bSYour Name  *
11500*5113495bSYour Name  * return: 0 success, none zero for failure
11501*5113495bSYour Name  */
11502*5113495bSYour Name static int
__wlan_hdd_cfg80211_tx_latency(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)11503*5113495bSYour Name __wlan_hdd_cfg80211_tx_latency(struct wiphy *wiphy, struct wireless_dev *wdev,
11504*5113495bSYour Name 			       const void *data, int data_len)
11505*5113495bSYour Name {
11506*5113495bSYour Name 	int ret;
11507*5113495bSYour Name 	uint32_t action, period;
11508*5113495bSYour Name 	struct nlattr *period_attr, *buckets_attr, *links_attr;
11509*5113495bSYour Name 
11510*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
11511*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
11512*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
11513*5113495bSYour Name 	struct nlattr *tb[TX_LATENCY_ATTR(MAX) + 1];
11514*5113495bSYour Name 	bool periodic_report;
11515*5113495bSYour Name 
11516*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
11517*5113495bSYour Name 		hdd_warn("command not allowed in ftm mode");
11518*5113495bSYour Name 		return -EPERM;
11519*5113495bSYour Name 	}
11520*5113495bSYour Name 
11521*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
11522*5113495bSYour Name 	if (ret)
11523*5113495bSYour Name 		return -EINVAL;
11524*5113495bSYour Name 
11525*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(MAX),
11526*5113495bSYour Name 				    data, data_len,
11527*5113495bSYour Name 				    tx_latency_policy)) {
11528*5113495bSYour Name 		hdd_err_rl("invalid attribute");
11529*5113495bSYour Name 		return -EINVAL;
11530*5113495bSYour Name 	}
11531*5113495bSYour Name 
11532*5113495bSYour Name 	if (!tb[TX_LATENCY_ATTR(ACTION)]) {
11533*5113495bSYour Name 		hdd_err_rl("no attr action");
11534*5113495bSYour Name 		return -EINVAL;
11535*5113495bSYour Name 	}
11536*5113495bSYour Name 
11537*5113495bSYour Name 	action = nla_get_u32(tb[TX_LATENCY_ATTR(ACTION)]);
11538*5113495bSYour Name 	switch (action) {
11539*5113495bSYour Name 	case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_DISABLE:
11540*5113495bSYour Name 		if (!adapter->tx_latency_cfg.enable) {
11541*5113495bSYour Name 			ret = 0;
11542*5113495bSYour Name 			break;
11543*5113495bSYour Name 		}
11544*5113495bSYour Name 
11545*5113495bSYour Name 		ret = hdd_tx_latency_disable(adapter);
11546*5113495bSYour Name 		break;
11547*5113495bSYour Name 	case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_ENABLE:
11548*5113495bSYour Name 		period_attr = tb[TX_LATENCY_ATTR(PERIOD)];
11549*5113495bSYour Name 		if (!period_attr) {
11550*5113495bSYour Name 			hdd_err_rl("no attr period");
11551*5113495bSYour Name 			return -EINVAL;
11552*5113495bSYour Name 		}
11553*5113495bSYour Name 
11554*5113495bSYour Name 		buckets_attr = tb[TX_LATENCY_ATTR(BUCKETS)];
11555*5113495bSYour Name 		if (!buckets_attr) {
11556*5113495bSYour Name 			hdd_err_rl("no attr buckets");
11557*5113495bSYour Name 			return -EINVAL;
11558*5113495bSYour Name 		}
11559*5113495bSYour Name 
11560*5113495bSYour Name 		period = nla_get_u32(period_attr);
11561*5113495bSYour Name 		if (!period) {
11562*5113495bSYour Name 			hdd_err_rl("invalid period");
11563*5113495bSYour Name 			return -EINVAL;
11564*5113495bSYour Name 		}
11565*5113495bSYour Name 
11566*5113495bSYour Name 		periodic_report =
11567*5113495bSYour Name 			nla_get_flag(tb[TX_LATENCY_ATTR(PERIODIC_REPORT)]);
11568*5113495bSYour Name 		ret = hdd_tx_latency_enable(adapter, period,
11569*5113495bSYour Name 					    periodic_report, buckets_attr);
11570*5113495bSYour Name 		break;
11571*5113495bSYour Name 	case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_GET:
11572*5113495bSYour Name 		if (!adapter->tx_latency_cfg.enable) {
11573*5113495bSYour Name 			hdd_err_rl("please enable the feature first");
11574*5113495bSYour Name 			ret = -EINVAL;
11575*5113495bSYour Name 			break;
11576*5113495bSYour Name 		}
11577*5113495bSYour Name 
11578*5113495bSYour Name 		links_attr = tb[TX_LATENCY_ATTR(LINKS)];
11579*5113495bSYour Name 		ret = hdd_tx_latency_get(wiphy, adapter, links_attr);
11580*5113495bSYour Name 		break;
11581*5113495bSYour Name 	default:
11582*5113495bSYour Name 		ret = -EINVAL;
11583*5113495bSYour Name 		break;
11584*5113495bSYour Name 	}
11585*5113495bSYour Name 
11586*5113495bSYour Name 	return ret;
11587*5113495bSYour Name }
11588*5113495bSYour Name 
11589*5113495bSYour Name /**
11590*5113495bSYour Name  * wlan_hdd_cfg80211_tx_latency - configure/retrieve per-link transmit latency
11591*5113495bSYour Name  * statistics
11592*5113495bSYour Name  * @wiphy: wiphy handle
11593*5113495bSYour Name  * @wdev: wdev handle
11594*5113495bSYour Name  * @data: user layer input
11595*5113495bSYour Name  * @data_len: length of user layer input
11596*5113495bSYour Name  *
11597*5113495bSYour Name  * return: 0 success, einval failure
11598*5113495bSYour Name  */
wlan_hdd_cfg80211_tx_latency(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)11599*5113495bSYour Name int wlan_hdd_cfg80211_tx_latency(struct wiphy *wiphy,
11600*5113495bSYour Name 				 struct wireless_dev *wdev,
11601*5113495bSYour Name 				 const void *data, int data_len)
11602*5113495bSYour Name {
11603*5113495bSYour Name 	int errno;
11604*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
11605*5113495bSYour Name 
11606*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
11607*5113495bSYour Name 	if (errno)
11608*5113495bSYour Name 		return errno;
11609*5113495bSYour Name 
11610*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_tx_latency(wiphy, wdev, data, data_len);
11611*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
11612*5113495bSYour Name 	return errno;
11613*5113495bSYour Name }
11614*5113495bSYour Name 
11615*5113495bSYour Name /**
11616*5113495bSYour Name  * hdd_tx_latency_stats_cb() - callback function for transmit latency stats
11617*5113495bSYour Name  * @vdev_id: Unique value to identify VDEV
11618*5113495bSYour Name  * @stats_list: list of the nodes for per-link transmit latency statistics
11619*5113495bSYour Name  *
11620*5113495bSYour Name  * Return: QDF_STATUS
11621*5113495bSYour Name  */
11622*5113495bSYour Name static QDF_STATUS
hdd_tx_latency_stats_cb(uint8_t vdev_id,qdf_list_t * stats_list)11623*5113495bSYour Name hdd_tx_latency_stats_cb(uint8_t vdev_id, qdf_list_t *stats_list)
11624*5113495bSYour Name {
11625*5113495bSYour Name 	uint32_t len, stats_cnt;
11626*5113495bSYour Name 	struct sk_buff *vendor_event;
11627*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
11628*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
11629*5113495bSYour Name 	struct cdp_tx_latency *entry, *next;
11630*5113495bSYour Name 	struct nlattr *links;
11631*5113495bSYour Name 	int ret, idx = 0, flags = cds_get_gfp_flags();
11632*5113495bSYour Name 	int event_idx = QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY_INDEX;
11633*5113495bSYour Name 
11634*5113495bSYour Name 	if (!hdd_ctx) {
11635*5113495bSYour Name 		hdd_err("HDD context is NULL");
11636*5113495bSYour Name 		return QDF_STATUS_E_FAULT;
11637*5113495bSYour Name 	}
11638*5113495bSYour Name 
11639*5113495bSYour Name 	if (!stats_list || qdf_list_empty(stats_list)) {
11640*5113495bSYour Name 		hdd_err("invalid stats list");
11641*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
11642*5113495bSYour Name 	}
11643*5113495bSYour Name 
11644*5113495bSYour Name 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
11645*5113495bSYour Name 	if (!link_info) {
11646*5113495bSYour Name 		hdd_err("adapter NULL for vdev id %d", vdev_id);
11647*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
11648*5113495bSYour Name 	}
11649*5113495bSYour Name 
11650*5113495bSYour Name 	stats_cnt = qdf_list_size(stats_list);
11651*5113495bSYour Name 	len = hdd_tx_latency_get_skb_len(stats_cnt);
11652*5113495bSYour Name 	hdd_debug_rl("vdev id %d stats cnt %d", vdev_id, stats_cnt);
11653*5113495bSYour Name 	vendor_event =
11654*5113495bSYour Name 		wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
11655*5113495bSYour Name 						 &link_info->adapter->wdev,
11656*5113495bSYour Name 						 len, event_idx, flags);
11657*5113495bSYour Name 	if (!vendor_event) {
11658*5113495bSYour Name 		hdd_err("event alloc failed vdev id %d, len %d",
11659*5113495bSYour Name 			vdev_id, len);
11660*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
11661*5113495bSYour Name 	}
11662*5113495bSYour Name 
11663*5113495bSYour Name 	links = nla_nest_start(vendor_event, TX_LATENCY_ATTR(LINKS));
11664*5113495bSYour Name 	if (!links) {
11665*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(vendor_event);
11666*5113495bSYour Name 		hdd_err("failed to put peers");
11667*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
11668*5113495bSYour Name 	}
11669*5113495bSYour Name 
11670*5113495bSYour Name 	qdf_list_for_each_del(stats_list, entry, next, node) {
11671*5113495bSYour Name 		qdf_list_remove_node(stats_list, &entry->node);
11672*5113495bSYour Name 		ret = hdd_tx_latency_fill_link_stats(vendor_event, entry, idx);
11673*5113495bSYour Name 		qdf_mem_free(entry);
11674*5113495bSYour Name 		if (ret) {
11675*5113495bSYour Name 			hdd_err("failed to populate stats for idx %d", idx);
11676*5113495bSYour Name 			wlan_cfg80211_vendor_free_skb(vendor_event);
11677*5113495bSYour Name 			return QDF_STATUS_E_NOMEM;
11678*5113495bSYour Name 		}
11679*5113495bSYour Name 
11680*5113495bSYour Name 		idx++;
11681*5113495bSYour Name 	}
11682*5113495bSYour Name 
11683*5113495bSYour Name 	nla_nest_end(vendor_event, links);
11684*5113495bSYour Name 	wlan_cfg80211_vendor_event(vendor_event, flags);
11685*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
11686*5113495bSYour Name }
11687*5113495bSYour Name 
11688*5113495bSYour Name /**
11689*5113495bSYour Name  * hdd_tx_latency_register_cb() - register callback function for transmit
11690*5113495bSYour Name  * latency stats
11691*5113495bSYour Name  * @soc: pointer to soc context
11692*5113495bSYour Name  *
11693*5113495bSYour Name  * Return: QDF_STATUS
11694*5113495bSYour Name  */
hdd_tx_latency_register_cb(void * soc)11695*5113495bSYour Name QDF_STATUS hdd_tx_latency_register_cb(void *soc)
11696*5113495bSYour Name {
11697*5113495bSYour Name 	hdd_debug("Register tx latency callback");
11698*5113495bSYour Name 	return cdp_host_tx_latency_stats_register_cb(soc,
11699*5113495bSYour Name 						     hdd_tx_latency_stats_cb);
11700*5113495bSYour Name }
11701*5113495bSYour Name #endif
11702*5113495bSYour Name 
11703*5113495bSYour Name #ifdef WLAN_CHIPSET_STATS
11704*5113495bSYour Name #ifdef CNSS_GENL
nl_srv_bcast_cstats(struct sk_buff * skb)11705*5113495bSYour Name static int nl_srv_bcast_cstats(struct sk_buff *skb)
11706*5113495bSYour Name {
11707*5113495bSYour Name 	return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG);
11708*5113495bSYour Name }
11709*5113495bSYour Name #else
nl_srv_bcast_cstats(struct sk_buff * skb)11710*5113495bSYour Name static int nl_srv_bcast_cstats(struct sk_buff *skb)
11711*5113495bSYour Name {
11712*5113495bSYour Name 	return nl_srv_bcast(skb);
11713*5113495bSYour Name }
11714*5113495bSYour Name #endif
11715*5113495bSYour Name 
hdd_cstats_send_data_to_userspace(char * buff,unsigned int len,enum cstats_types type)11716*5113495bSYour Name int hdd_cstats_send_data_to_userspace(char *buff, unsigned int len,
11717*5113495bSYour Name 				      enum cstats_types type)
11718*5113495bSYour Name {
11719*5113495bSYour Name 	struct sk_buff *skb = NULL;
11720*5113495bSYour Name 	struct nlmsghdr *nlh;
11721*5113495bSYour Name 	tAniNlHdr *wnl;
11722*5113495bSYour Name 	static int nlmsg_seq;
11723*5113495bSYour Name 	int tot_msg_len;
11724*5113495bSYour Name 	int ret = -1;
11725*5113495bSYour Name 
11726*5113495bSYour Name 	if (type == CSTATS_HOST_TYPE) {
11727*5113495bSYour Name 		*(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_HOST_LOG_TYPE;
11728*5113495bSYour Name 		*(unsigned short *)(buff + 2) = len - sizeof(tAniHdr);
11729*5113495bSYour Name 	} else if (type == CSTATS_FW_TYPE) {
11730*5113495bSYour Name 		*(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_FW_LOG_TYPE;
11731*5113495bSYour Name 		*(unsigned short *)(buff + 2) = len - sizeof(tAniHdr);
11732*5113495bSYour Name 	}
11733*5113495bSYour Name 
11734*5113495bSYour Name 	skb = dev_alloc_skb(MAX_CSTATS_NODE_LENGTH);
11735*5113495bSYour Name 	if (!skb) {
11736*5113495bSYour Name 		qdf_err("dev_alloc_skb() failed");
11737*5113495bSYour Name 		return -ENOMEM;
11738*5113495bSYour Name 	}
11739*5113495bSYour Name 
11740*5113495bSYour Name 	tot_msg_len = NLMSG_SPACE(len + sizeof(wnl->radio));
11741*5113495bSYour Name 
11742*5113495bSYour Name 	nlh = nlmsg_put(skb, 0, nlmsg_seq++,
11743*5113495bSYour Name 			ANI_NL_MSG_LOG,
11744*5113495bSYour Name 			len + sizeof(wnl->radio), NLM_F_REQUEST);
11745*5113495bSYour Name 	if (!nlh) {
11746*5113495bSYour Name 		qdf_err("nlmsg_put() failed for msg size[%d]", tot_msg_len);
11747*5113495bSYour Name 		dev_kfree_skb(skb);
11748*5113495bSYour Name 		return -EINVAL;
11749*5113495bSYour Name 	}
11750*5113495bSYour Name 
11751*5113495bSYour Name 	wnl = (tAniNlHdr *)nlh;
11752*5113495bSYour Name 	wnl->radio = 0;
11753*5113495bSYour Name 
11754*5113495bSYour Name 	memcpy(nlmsg_data(nlh) + sizeof(wnl->radio), buff, len);
11755*5113495bSYour Name 
11756*5113495bSYour Name 	ret = nl_srv_bcast_cstats(skb);
11757*5113495bSYour Name 	if (ret < 0)
11758*5113495bSYour Name 		qdf_err("Send Failed %d", ret);
11759*5113495bSYour Name 
11760*5113495bSYour Name 	return ret;
11761*5113495bSYour Name }
11762*5113495bSYour Name 
11763*5113495bSYour Name struct cstats_tx_rx_ops cstats_ops = {
11764*5113495bSYour Name 	.cstats_send_data_to_usr = hdd_cstats_send_data_to_userspace,
11765*5113495bSYour Name };
11766*5113495bSYour Name 
hdd_register_cstats_ops(void)11767*5113495bSYour Name void hdd_register_cstats_ops(void)
11768*5113495bSYour Name {
11769*5113495bSYour Name 	ucfg_cp_stats_cstats_register_tx_rx_ops(&cstats_ops);
11770*5113495bSYour Name }
11771*5113495bSYour Name 
11772*5113495bSYour Name void
hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev * vdev,uint16_t transaction_id)11773*5113495bSYour Name hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev *vdev,
11774*5113495bSYour Name 				  uint16_t transaction_id)
11775*5113495bSYour Name {
11776*5113495bSYour Name 	struct cstats_nan_ndi_delete_req stat = {0};
11777*5113495bSYour Name 
11778*5113495bSYour Name 	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_DELETE_EVENT_ID;
11779*5113495bSYour Name 	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_delete_req) -
11780*5113495bSYour Name 			      sizeof(struct cstats_hdr);
11781*5113495bSYour Name 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
11782*5113495bSYour Name 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
11783*5113495bSYour Name 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
11784*5113495bSYour Name 	stat.cmn.time_tick = qdf_get_log_timestamp();
11785*5113495bSYour Name 	stat.transaction_id = transaction_id;
11786*5113495bSYour Name 
11787*5113495bSYour Name 	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_delete_req), &stat);
11788*5113495bSYour Name }
11789*5113495bSYour Name 
11790*5113495bSYour Name void
hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info * li,struct nan_datapath_inf_create_rsp * ndi_rsp)11791*5113495bSYour Name hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info *li,
11792*5113495bSYour Name 				   struct nan_datapath_inf_create_rsp *ndi_rsp)
11793*5113495bSYour Name {
11794*5113495bSYour Name 	struct cstats_nan_ndi_create_resp stat = {0};
11795*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
11796*5113495bSYour Name 	struct nan_vdev_priv_obj *priv_obj;
11797*5113495bSYour Name 
11798*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_OSIF_NAN_ID);
11799*5113495bSYour Name 	if (!vdev) {
11800*5113495bSYour Name 		hdd_err("vdev is NULL");
11801*5113495bSYour Name 		return;
11802*5113495bSYour Name 	}
11803*5113495bSYour Name 
11804*5113495bSYour Name 	priv_obj = nan_get_vdev_priv_obj(vdev);
11805*5113495bSYour Name 	if (!priv_obj) {
11806*5113495bSYour Name 		hdd_err("priv_obj is null");
11807*5113495bSYour Name 		return;
11808*5113495bSYour Name 	}
11809*5113495bSYour Name 
11810*5113495bSYour Name 	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_RESP_EVENT_ID;
11811*5113495bSYour Name 	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_resp) -
11812*5113495bSYour Name 			      sizeof(struct cstats_hdr);
11813*5113495bSYour Name 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
11814*5113495bSYour Name 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
11815*5113495bSYour Name 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
11816*5113495bSYour Name 	stat.cmn.time_tick = qdf_get_log_timestamp();
11817*5113495bSYour Name 	stat.status = ndi_rsp->status;
11818*5113495bSYour Name 	stat.reason = ndi_rsp->reason;
11819*5113495bSYour Name 	qdf_spin_lock_bh(&priv_obj->lock);
11820*5113495bSYour Name 	stat.transaction_id = priv_obj->ndp_create_transaction_id;
11821*5113495bSYour Name 	qdf_spin_unlock_bh(&priv_obj->lock);
11822*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
11823*5113495bSYour Name 
11824*5113495bSYour Name 	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_resp),
11825*5113495bSYour Name 			       &stat);
11826*5113495bSYour Name }
11827*5113495bSYour Name 
hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev * vdev,uint16_t transaction_id)11828*5113495bSYour Name void hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev *vdev,
11829*5113495bSYour Name 				       uint16_t transaction_id)
11830*5113495bSYour Name {
11831*5113495bSYour Name 	struct cstats_nan_ndi_create_req stat = {0};
11832*5113495bSYour Name 
11833*5113495bSYour Name 	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_EVENT_ID;
11834*5113495bSYour Name 	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_req) -
11835*5113495bSYour Name 			      sizeof(struct cstats_hdr);
11836*5113495bSYour Name 	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
11837*5113495bSYour Name 	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
11838*5113495bSYour Name 	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
11839*5113495bSYour Name 	stat.cmn.time_tick = qdf_get_log_timestamp();
11840*5113495bSYour Name 	stat.transaction_id = transaction_id;
11841*5113495bSYour Name 
11842*5113495bSYour Name 	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_req), &stat);
11843*5113495bSYour Name }
11844*5113495bSYour Name #endif /* WLAN_CHIPSET_STATS */
11845