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