1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * DOC: wlan_hdd_sysfs_txrx_stats_console.c
19  *
20  * implementation for creating sysfs files:
21  *
22  * txrx_stats
23  */
24 
25 #include <wlan_hdd_includes.h>
26 #include "osif_psoc_sync.h"
27 #include <wlan_hdd_sysfs.h>
28 #include <wlan_hdd_sysfs_txrx_stats_console.h>
29 #include <cds_api.h>
30 #include <qdf_status.h>
31 
32 #ifdef WLAN_SYSFS_DP_STATS
33 
34 #define HDD_WLAN_SYSFS_TXRX_STATS_USER_CMD_SIZE (10)
35 #define SYSFS_INPUT_BUF_SIZE			PAGE_SIZE
36 
37 /*
38  * __hdd_wlan_txrx_stats_store() - Calls into dp layer to
39  * update the sysfs config values.
40  * @hdd_ctx: hdd context
41  * @buf: input buffer from user space
42  * @count: input buffer size
43  *
44  * Return: Return the size of input buffer.
45  */
46 static ssize_t
__hdd_wlan_txrx_stats_store(struct hdd_context * hdd_ctx,const char * buf,size_t count)47 __hdd_wlan_txrx_stats_store(struct hdd_context *hdd_ctx,
48 			    const char  *buf, size_t count)
49 {
50 	char buf_local[HDD_WLAN_SYSFS_TXRX_STATS_USER_CMD_SIZE + 1];
51 	char *sptr, *token;
52 	uint32_t stat_type_requested;
53 	uint32_t mac_id;
54 	int ret;
55 	ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC);
56 
57 	if (!soc) {
58 		hdd_err_rl("soc is NULL");
59 		return -EINVAL;
60 	}
61 
62 	if (count > HDD_WLAN_SYSFS_TXRX_STATS_USER_CMD_SIZE)
63 		return -EINVAL;
64 
65 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
66 		return -EINVAL;
67 
68 	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
69 					      buf, count);
70 
71 	if (ret)
72 		return -EINVAL;
73 
74 	sptr = buf_local;
75 	/* get mac id */
76 	token = strsep(&sptr, " ");
77 	if (!token)
78 		return -EINVAL;
79 	if (kstrtou32(token, 0, &stat_type_requested))
80 		return -EINVAL;
81 
82 	/* get stat type requested */
83 	token = strsep(&sptr, " ");
84 	if (!token)
85 		return -EINVAL;
86 	if (kstrtou32(token, 0, &mac_id))
87 		return -EINVAL;
88 
89 	if (!soc->ops->cmn_drv_ops->txrx_sysfs_set_stat_type) {
90 		hdd_err("txrx_sysfs_set_stat_type is NULL");
91 		return -EINVAL;
92 	}
93 
94 	soc->ops->cmn_drv_ops->txrx_sysfs_set_stat_type(soc,
95 							stat_type_requested,
96 							mac_id);
97 
98 	return count;
99 }
100 
101 /*
102  * __hdd_wlan_txrx_stats_show() - Calls into dp to fill stats.
103  * @buf: output buffer
104  *
105  * Return: output buffer size.
106  */
107 static ssize_t
__hdd_wlan_txrx_stats_show(char * buf)108 __hdd_wlan_txrx_stats_show(char *buf)
109 {
110 	uint32_t size_of_output = 0;
111 	ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC);
112 
113 	if (!soc) {
114 		hdd_err_rl("hdd dp_soc cds_get_context returned NULL");
115 		return -EINVAL;
116 	}
117 
118 	if (!soc->ops->cmn_drv_ops->txrx_sysfs_fill_stats) {
119 		hdd_err_rl("txrx_sysfs_fill_stats is NULL");
120 		return -EINVAL;
121 	}
122 	soc->ops->cmn_drv_ops->txrx_sysfs_fill_stats(soc,
123 						     buf,
124 						     SYSFS_INPUT_BUF_SIZE);
125 	size_of_output = strlen(buf);
126 	return size_of_output;
127 }
128 
129 /*
130  * hdd_sysfs_dp_txrx_stats_show() - Registered as sysfs show function.
131  * @kobj: kernel object
132  * @att: kobject attribute
133  * @buf: output buffer to be filled
134  *
135  * Return: Returns the length of the output buffer.
136  */
137 static ssize_t
hdd_sysfs_dp_txrx_stats_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)138 hdd_sysfs_dp_txrx_stats_show(struct kobject *kobj,
139 			     struct kobj_attribute *attr,
140 			     char *buf)
141 {
142 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
143 	struct osif_psoc_sync *psoc_sync = NULL;
144 	ssize_t length = 0;
145 	ssize_t errno = 0;
146 
147 	errno = wlan_hdd_validate_context(hdd_ctx);
148 	if (errno)
149 		return errno;
150 
151 	errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync);
152 	if (errno)
153 		return errno;
154 
155 	length = __hdd_wlan_txrx_stats_show(buf);
156 
157 	osif_psoc_sync_op_stop(psoc_sync);
158 
159 	return length;
160 }
161 
162 /*
163  * hdd_sysfs_dp_txrx_stats_store() - Registered as sysfs write function.
164  * @kobj: kernel object
165  * @att: kobject attribute
166  * @buf: input buffer from user space
167  * @count:  size of the input buffer
168  *
169  * Return: Returns the length of the input buffer.
170  */
171 static ssize_t
hdd_sysfs_dp_txrx_stats_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)172 hdd_sysfs_dp_txrx_stats_store(struct kobject *kobj,
173 			      struct kobj_attribute *attr,
174 			      const char *buf,
175 			      size_t count)
176 {
177 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
178 	struct osif_psoc_sync *psoc_sync = NULL;
179 	ssize_t errno = 0;
180 
181 	errno = wlan_hdd_validate_context(hdd_ctx);
182 	if (errno)
183 		return errno;
184 
185 	errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync);
186 	if (errno)
187 		return errno;
188 
189 	errno = __hdd_wlan_txrx_stats_store(hdd_ctx, buf, count);
190 
191 	osif_psoc_sync_op_stop(psoc_sync);
192 
193 	return errno;
194 }
195 
196 static struct kobj_attribute dp_txrx_stats_attribute =
197 	__ATTR(txrx_stats, 0664,  hdd_sysfs_dp_txrx_stats_show,
198 	       hdd_sysfs_dp_txrx_stats_store);
199 
200 /*
201  * hdd_sysfs_dp_txrx_stats_sysfs_create() - Initialize sysfs file.
202  * @driver_kobject: driver kobject
203  *
204  * Return: return sysfs int val.
205  */
hdd_sysfs_dp_txrx_stats_sysfs_create(struct kobject * driver_kobject)206 int hdd_sysfs_dp_txrx_stats_sysfs_create(struct kobject *driver_kobject)
207 {
208 	int error = 0;
209 
210 	if (!driver_kobject) {
211 		hdd_err("could not get driver kobject");
212 		return -EINVAL;
213 	}
214 
215 	error = sysfs_create_file(driver_kobject,
216 				  &dp_txrx_stats_attribute.attr);
217 
218 	if (error)
219 		hdd_err("failed to create txrx_stats sysfs file");
220 
221 	return error;
222 }
223 
224 /*
225  * hdd_sysfs_dp_txrx_stats_sysfs_destroy() - Sysfs deinitialize.
226  * @driver_kobject: driver kobject
227  *
228  * Return: void
229  */
230 void
hdd_sysfs_dp_txrx_stats_sysfs_destroy(struct kobject * driver_kobject)231 hdd_sysfs_dp_txrx_stats_sysfs_destroy(struct kobject *driver_kobject)
232 {
233 	if (!driver_kobject) {
234 		hdd_err("failed to get driver kobject");
235 		return;
236 	}
237 
238 	sysfs_remove_file(driver_kobject, &dp_txrx_stats_attribute.attr);
239 }
240 #endif /* WLAN_SYSFS_DP_STATS */
241