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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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