1 /*
2  * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: wlan_hdd_sysfs_stats.c
20  *
21  * Implementation for creating sysfs files:
22  *
23  *   stats
24  *   dump_stats
25  *   clear_stats
26  */
27 
28 #include <wlan_hdd_includes.h>
29 #include "osif_vdev_sync.h"
30 #include <wlan_hdd_sysfs.h>
31 #include "wlan_hdd_sysfs_stats.h"
32 #include "cdp_txrx_stats.h"
33 #include "wlan_hdd_object_manager.h"
34 #include "wlan_dp_ucfg_api.h"
35 
36 static int stats_id = -1;
37 
hdd_sysfs_get_stats(struct hdd_adapter * adapter,ssize_t * length,char * buffer,size_t buf_len)38 static void hdd_sysfs_get_stats(struct hdd_adapter *adapter, ssize_t *length,
39 				char *buffer, size_t buf_len)
40 {
41 	struct hdd_tx_rx_stats *stats =
42 				&adapter->deflink->hdd_stats.tx_rx_stats;
43 	struct dp_tx_rx_stats *dp_stats;
44 	uint32_t len = 0;
45 	uint32_t total_rx_pkt = 0, total_rx_dropped = 0;
46 	uint32_t total_rx_delv = 0, total_rx_refused = 0;
47 	uint32_t total_tx_pkt = 0;
48 	uint32_t total_tx_dropped = 0;
49 	uint32_t total_tx_orphaned = 0;
50 	uint32_t total_tx_classified_ac[WLAN_MAX_AC] = {0};
51 	uint32_t total_tx_dropped_ac[WLAN_MAX_AC] = {0};
52 	int i = 0;
53 	uint8_t ac, rx_ol_con = 0, rx_ol_low_tput = 0;
54 	struct hdd_context *hdd_ctx = adapter->hdd_ctx;
55 	struct wlan_objmgr_vdev *vdev;
56 
57 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID);
58 	if (!vdev)
59 		return;
60 
61 	dp_stats = qdf_mem_malloc(sizeof(*dp_stats));
62 	if (!dp_stats) {
63 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
64 		return;
65 	}
66 
67 	if (ucfg_dp_get_txrx_stats(vdev, dp_stats)) {
68 		hdd_err("Unable to get stats from DP component");
69 		hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
70 		qdf_mem_free(dp_stats);
71 		return;
72 	}
73 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
74 
75 	ucfg_dp_get_disable_rx_ol_val(hdd_ctx->psoc,
76 				      &rx_ol_con, &rx_ol_low_tput);
77 
78 	for (; i < NUM_CPUS; i++) {
79 		total_rx_pkt += dp_stats->per_cpu[i].rx_packets;
80 		total_rx_dropped += dp_stats->per_cpu[i].rx_dropped;
81 		total_rx_delv += dp_stats->per_cpu[i].rx_delivered;
82 		total_rx_refused += dp_stats->per_cpu[i].rx_refused;
83 		total_tx_pkt += dp_stats->per_cpu[i].tx_called;
84 		total_tx_dropped += dp_stats->per_cpu[i].tx_dropped;
85 		total_tx_orphaned += dp_stats->per_cpu[i].tx_orphaned;
86 		for (ac = 0; ac < WLAN_MAX_AC; ac++) {
87 			total_tx_classified_ac[ac] +=
88 					 stats->per_cpu[i].tx_classified_ac[ac];
89 			total_tx_dropped_ac[ac] +=
90 					    stats->per_cpu[i].tx_dropped_ac[ac];
91 		}
92 	}
93 
94 	len = scnprintf(buffer, buf_len,
95 			"\nTransmit[%lu] - "
96 			"called %u, dropped %u orphan %u,"
97 			"\n[dropped]    BK %u, BE %u, VI %u, VO %u"
98 			"\n[classified] BK %u, BE %u, VI %u, VO %u"
99 			"\n\nReceive[%lu] - "
100 			"packets %u, dropped %u, unsolict_arp_n_mcast_drp %u, delivered %u, refused %u\n"
101 			"GRO - agg %u non-agg %u flush_skip %u low_tput_flush %u disabled(conc %u low-tput %u)\n",
102 			qdf_system_ticks(),
103 			total_tx_pkt,
104 			total_tx_dropped,
105 			total_tx_orphaned,
106 			total_tx_dropped_ac[SME_AC_BK],
107 			total_tx_dropped_ac[SME_AC_BE],
108 			total_tx_dropped_ac[SME_AC_VI],
109 			total_tx_dropped_ac[SME_AC_VO],
110 			total_tx_classified_ac[SME_AC_BK],
111 			total_tx_classified_ac[SME_AC_BE],
112 			total_tx_classified_ac[SME_AC_VI],
113 			total_tx_classified_ac[SME_AC_VO],
114 			qdf_system_ticks(),
115 			total_rx_pkt, total_rx_dropped,
116 			qdf_atomic_read(&dp_stats->rx_usolict_arp_n_mcast_drp),
117 			total_rx_delv,
118 			total_rx_refused,
119 			dp_stats->rx_aggregated, dp_stats->rx_non_aggregated,
120 			dp_stats->rx_gro_flush_skip,
121 			dp_stats->rx_gro_low_tput_flush,
122 			rx_ol_con,
123 			rx_ol_low_tput);
124 
125 	for (i = 0; i < NUM_CPUS; i++) {
126 		if (dp_stats->per_cpu[i].rx_packets == 0)
127 			continue;
128 		len += scnprintf(buffer + len, buf_len - len,
129 				 "Rx CPU[%d]:"
130 				 "packets %u, dropped %u, delivered %u, refused %u\n",
131 				 i, dp_stats->per_cpu[i].rx_packets,
132 				 dp_stats->per_cpu[i].rx_dropped,
133 				 dp_stats->per_cpu[i].rx_delivered,
134 				 dp_stats->per_cpu[i].rx_refused);
135 	}
136 
137 	len += scnprintf(buffer + len, buf_len - len,
138 		"\nTX_FLOW"
139 		"\nCurrent status: %s"
140 		"\ntx-flow timer start count %u"
141 		"\npause count %u, unpause count %u",
142 		(stats->is_txflow_paused == true ? "PAUSED" : "UNPAUSED"),
143 		stats->txflow_timer_cnt,
144 		stats->txflow_pause_cnt,
145 		stats->txflow_unpause_cnt);
146 
147 	len += cdp_stats(cds_get_context(QDF_MODULE_ID_SOC),
148 			 adapter->deflink->vdev_id, &buffer[len],
149 			 (buf_len - len));
150 	*length = len + 1;
151 	qdf_mem_free(dp_stats);
152 }
153 
154 static ssize_t
__hdd_sysfs_stats_show(struct net_device * net_dev,char * buf)155 __hdd_sysfs_stats_show(struct net_device *net_dev, char *buf)
156 {
157 	struct hdd_adapter *adapter = netdev_priv(net_dev);
158 	struct hdd_context *hdd_ctx;
159 	int ret;
160 	ssize_t length = 0;
161 
162 	if (hdd_validate_adapter(adapter))
163 		return -EINVAL;
164 
165 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
166 	ret = wlan_hdd_validate_context(hdd_ctx);
167 	if (ret)
168 		return ret;
169 
170 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
171 		return -EINVAL;
172 
173 	hdd_sysfs_get_stats(adapter, &length, buf, PAGE_SIZE);
174 
175 	return length;
176 }
177 
178 static ssize_t
hdd_sysfs_stats_show(struct device * dev,struct device_attribute * attr,char * buf)179 hdd_sysfs_stats_show(struct device *dev,
180 		     struct device_attribute *attr,
181 		     char *buf)
182 {
183 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
184 	struct osif_vdev_sync *vdev_sync;
185 	ssize_t err_size;
186 
187 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
188 	if (err_size)
189 		return err_size;
190 
191 	err_size = __hdd_sysfs_stats_show(net_dev, buf);
192 
193 	osif_vdev_sync_op_stop(vdev_sync);
194 
195 	return err_size;
196 }
197 
198 static DEVICE_ATTR(stats, 0440,
199 		   hdd_sysfs_stats_show, NULL);
200 
201 static ssize_t
__wlan_hdd_sysfs_dump_stats_store(struct net_device * net_dev,char const * buf,size_t count)202 __wlan_hdd_sysfs_dump_stats_store(struct net_device *net_dev, char const *buf,
203 				  size_t count)
204 {
205 	struct hdd_adapter *adapter = netdev_priv(net_dev);
206 	struct hdd_context *hdd_ctx;
207 	char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
208 	char *sptr, *token;
209 	int value, ret;
210 
211 	if (hdd_validate_adapter(adapter))
212 		return -EINVAL;
213 
214 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
215 	ret = wlan_hdd_validate_context(hdd_ctx);
216 	if (ret != 0)
217 		return ret;
218 
219 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
220 		return -EINVAL;
221 
222 	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
223 					      buf, count);
224 	if (ret) {
225 		hdd_err_rl("invalid input");
226 		return ret;
227 	}
228 
229 	sptr = buf_local;
230 	token = strsep(&sptr, " ");
231 	if (!token)
232 		return -EINVAL;
233 	if (kstrtou32(token, 0, &value))
234 		return -EINVAL;
235 
236 	hdd_debug("dump_stats %d", value);
237 
238 	stats_id = value;
239 
240 	return count;
241 }
242 
wlan_hdd_sysfs_dump_stats_store(struct device * dev,struct device_attribute * attr,char const * buf,size_t count)243 static ssize_t wlan_hdd_sysfs_dump_stats_store(struct device *dev,
244 					       struct device_attribute *attr,
245 					       char const *buf, size_t count)
246 {
247 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
248 	struct osif_vdev_sync *vdev_sync;
249 	ssize_t err_size;
250 
251 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
252 	if (err_size)
253 		return err_size;
254 
255 	err_size = __wlan_hdd_sysfs_dump_stats_store(net_dev, buf, count);
256 
257 	osif_vdev_sync_op_stop(vdev_sync);
258 
259 	return err_size;
260 }
261 
262 static ssize_t
__wlan_hdd_sysfs_dump_stats_show(struct net_device * net_dev,char * buf)263 __wlan_hdd_sysfs_dump_stats_show(struct net_device *net_dev, char *buf)
264 {
265 	struct hdd_adapter *adapter = netdev_priv(net_dev);
266 	struct hdd_context *hdd_ctx;
267 	int ret;
268 
269 	if (hdd_validate_adapter(adapter))
270 		return -EINVAL;
271 
272 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
273 	ret = wlan_hdd_validate_context(hdd_ctx);
274 	if (ret != 0)
275 		return ret;
276 
277 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
278 		return -EINVAL;
279 
280 	ret = hdd_wlan_dump_stats(adapter, stats_id);
281 
282 	return ret;
283 }
284 
wlan_hdd_sysfs_dump_stats_show(struct device * dev,struct device_attribute * attr,char * buf)285 static ssize_t wlan_hdd_sysfs_dump_stats_show(struct device *dev,
286 					      struct device_attribute *attr,
287 					      char *buf)
288 {
289 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
290 	struct osif_vdev_sync *vdev_sync;
291 	ssize_t err_size;
292 
293 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
294 	if (err_size)
295 		return err_size;
296 
297 	err_size = __wlan_hdd_sysfs_dump_stats_show(net_dev, buf);
298 
299 	osif_vdev_sync_op_stop(vdev_sync);
300 
301 	return err_size;
302 }
303 
304 static DEVICE_ATTR(dump_stats, 0660, wlan_hdd_sysfs_dump_stats_show,
305 		   wlan_hdd_sysfs_dump_stats_store);
306 
307 static ssize_t
__wlan_hdd_sysfs_clear_stats_store(struct net_device * net_dev,char const * buf,size_t count)308 __wlan_hdd_sysfs_clear_stats_store(struct net_device *net_dev, char const *buf,
309 				   size_t count)
310 {
311 	struct hdd_adapter *adapter = netdev_priv(net_dev);
312 	struct hdd_context *hdd_ctx;
313 	char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
314 	char *sptr, *token;
315 	int value, ret;
316 
317 	if (hdd_validate_adapter(adapter))
318 		return -EINVAL;
319 
320 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
321 	ret = wlan_hdd_validate_context(hdd_ctx);
322 	if (ret != 0)
323 		return ret;
324 
325 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
326 		return -EINVAL;
327 
328 	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
329 					      buf, count);
330 	if (ret) {
331 		hdd_err_rl("invalid input");
332 		return ret;
333 	}
334 
335 	sptr = buf_local;
336 	token = strsep(&sptr, " ");
337 	if (!token)
338 		return -EINVAL;
339 	if (kstrtou32(token, 0, &value))
340 		return -EINVAL;
341 
342 	hdd_debug("clear_stats %d", value);
343 
344 	ret = hdd_wlan_clear_stats(adapter, value);
345 	if (ret) {
346 		hdd_err_rl("Failed to clear stats");
347 		return ret;
348 	}
349 
350 	return count;
351 }
352 
wlan_hdd_sysfs_clear_stats_store(struct device * dev,struct device_attribute * attr,char const * buf,size_t count)353 static ssize_t wlan_hdd_sysfs_clear_stats_store(struct device *dev,
354 						struct device_attribute *attr,
355 						char const *buf, size_t count)
356 {
357 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
358 	struct osif_vdev_sync *vdev_sync;
359 	ssize_t err_size;
360 
361 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
362 	if (err_size)
363 		return err_size;
364 
365 	err_size = __wlan_hdd_sysfs_clear_stats_store(net_dev, buf, count);
366 
367 	osif_vdev_sync_op_stop(vdev_sync);
368 
369 	return err_size;
370 }
371 
372 static DEVICE_ATTR(clear_stats, 0220, NULL,
373 		   wlan_hdd_sysfs_clear_stats_store);
374 
hdd_sysfs_stats_create(struct hdd_adapter * adapter)375 int hdd_sysfs_stats_create(struct hdd_adapter *adapter)
376 {
377 	int error;
378 
379 	error = device_create_file(&adapter->dev->dev, &dev_attr_dump_stats);
380 	if (error)
381 		hdd_err("could not create dump_stats sysfs file");
382 
383 	error = device_create_file(&adapter->dev->dev, &dev_attr_clear_stats);
384 	if (error)
385 		hdd_err("could not create clear_stats sysfs file");
386 
387 	error = device_create_file(&adapter->dev->dev,  &dev_attr_stats);
388 	if (error)
389 		hdd_err("could not create stats sysfs file");
390 
391 	return error;
392 }
393 
hdd_sysfs_stats_destroy(struct hdd_adapter * adapter)394 void hdd_sysfs_stats_destroy(struct hdd_adapter *adapter)
395 {
396 	device_remove_file(&adapter->dev->dev, &dev_attr_dump_stats);
397 	device_remove_file(&adapter->dev->dev, &dev_attr_clear_stats);
398 	device_remove_file(&adapter->dev->dev, &dev_attr_stats);
399 }
400