xref: /linux/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c (revision a713222906e4f77b5fb1b5346d4f5de1adc639b4)
1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
2 /*
3  * Copyright (c) 2014-2025, Advanced Micro Devices, Inc.
4  * Copyright (c) 2014, Synopsys, Inc.
5  * All rights reserved
6  */
7 
8 #include <linux/debugfs.h>
9 #include <linux/module.h>
10 #include <linux/slab.h>
11 
12 #include "xgbe.h"
13 #include "xgbe-common.h"
14 
15 static ssize_t xgbe_common_read(char __user *buffer, size_t count,
16 				loff_t *ppos, unsigned int value)
17 {
18 	char *buf;
19 	ssize_t len;
20 
21 	if (*ppos != 0)
22 		return 0;
23 
24 	buf = kasprintf(GFP_KERNEL, "0x%08x\n", value);
25 	if (!buf)
26 		return -ENOMEM;
27 
28 	if (count < strlen(buf)) {
29 		kfree(buf);
30 		return -ENOSPC;
31 	}
32 
33 	len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
34 	kfree(buf);
35 
36 	return len;
37 }
38 
39 static ssize_t xgbe_common_write(const char __user *buffer, size_t count,
40 				 loff_t *ppos, unsigned int *value)
41 {
42 	char workarea[32];
43 	ssize_t len;
44 	int ret;
45 
46 	if (*ppos != 0)
47 		return -EINVAL;
48 
49 	if (count >= sizeof(workarea))
50 		return -ENOSPC;
51 
52 	len = simple_write_to_buffer(workarea, sizeof(workarea) - 1, ppos,
53 				     buffer, count);
54 	if (len < 0)
55 		return len;
56 
57 	workarea[len] = '\0';
58 	ret = kstrtouint(workarea, 16, value);
59 	if (ret)
60 		return -EIO;
61 
62 	return len;
63 }
64 
65 static ssize_t xgmac_reg_addr_read(struct file *filp, char __user *buffer,
66 				   size_t count, loff_t *ppos)
67 {
68 	struct xgbe_prv_data *pdata = filp->private_data;
69 
70 	return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xgmac_reg);
71 }
72 
73 static ssize_t xgmac_reg_addr_write(struct file *filp,
74 				    const char __user *buffer,
75 				    size_t count, loff_t *ppos)
76 {
77 	struct xgbe_prv_data *pdata = filp->private_data;
78 
79 	return xgbe_common_write(buffer, count, ppos,
80 				 &pdata->debugfs_xgmac_reg);
81 }
82 
83 static ssize_t xgmac_reg_value_read(struct file *filp, char __user *buffer,
84 				    size_t count, loff_t *ppos)
85 {
86 	struct xgbe_prv_data *pdata = filp->private_data;
87 	unsigned int value;
88 
89 	value = XGMAC_IOREAD(pdata, pdata->debugfs_xgmac_reg);
90 
91 	return xgbe_common_read(buffer, count, ppos, value);
92 }
93 
94 static ssize_t xgmac_reg_value_write(struct file *filp,
95 				     const char __user *buffer,
96 				     size_t count, loff_t *ppos)
97 {
98 	struct xgbe_prv_data *pdata = filp->private_data;
99 	unsigned int value;
100 	ssize_t len;
101 
102 	len = xgbe_common_write(buffer, count, ppos, &value);
103 	if (len < 0)
104 		return len;
105 
106 	XGMAC_IOWRITE(pdata, pdata->debugfs_xgmac_reg, value);
107 
108 	return len;
109 }
110 
111 static const struct file_operations xgmac_reg_addr_fops = {
112 	.owner = THIS_MODULE,
113 	.open = simple_open,
114 	.read =  xgmac_reg_addr_read,
115 	.write = xgmac_reg_addr_write,
116 };
117 
118 static const struct file_operations xgmac_reg_value_fops = {
119 	.owner = THIS_MODULE,
120 	.open = simple_open,
121 	.read =  xgmac_reg_value_read,
122 	.write = xgmac_reg_value_write,
123 };
124 
125 static ssize_t xpcs_mmd_read(struct file *filp, char __user *buffer,
126 			     size_t count, loff_t *ppos)
127 {
128 	struct xgbe_prv_data *pdata = filp->private_data;
129 
130 	return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_mmd);
131 }
132 
133 static ssize_t xpcs_mmd_write(struct file *filp, const char __user *buffer,
134 			      size_t count, loff_t *ppos)
135 {
136 	struct xgbe_prv_data *pdata = filp->private_data;
137 
138 	return xgbe_common_write(buffer, count, ppos,
139 				 &pdata->debugfs_xpcs_mmd);
140 }
141 
142 static ssize_t xpcs_reg_addr_read(struct file *filp, char __user *buffer,
143 				  size_t count, loff_t *ppos)
144 {
145 	struct xgbe_prv_data *pdata = filp->private_data;
146 
147 	return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_reg);
148 }
149 
150 static ssize_t xpcs_reg_addr_write(struct file *filp, const char __user *buffer,
151 				   size_t count, loff_t *ppos)
152 {
153 	struct xgbe_prv_data *pdata = filp->private_data;
154 
155 	return xgbe_common_write(buffer, count, ppos,
156 				 &pdata->debugfs_xpcs_reg);
157 }
158 
159 static ssize_t xpcs_reg_value_read(struct file *filp, char __user *buffer,
160 				   size_t count, loff_t *ppos)
161 {
162 	struct xgbe_prv_data *pdata = filp->private_data;
163 	unsigned int value;
164 
165 	value = XMDIO_READ(pdata, pdata->debugfs_xpcs_mmd,
166 			   pdata->debugfs_xpcs_reg);
167 
168 	return xgbe_common_read(buffer, count, ppos, value);
169 }
170 
171 static ssize_t xpcs_reg_value_write(struct file *filp,
172 				    const char __user *buffer,
173 				    size_t count, loff_t *ppos)
174 {
175 	struct xgbe_prv_data *pdata = filp->private_data;
176 	unsigned int value;
177 	ssize_t len;
178 
179 	len = xgbe_common_write(buffer, count, ppos, &value);
180 	if (len < 0)
181 		return len;
182 
183 	XMDIO_WRITE(pdata, pdata->debugfs_xpcs_mmd, pdata->debugfs_xpcs_reg,
184 		    value);
185 
186 	return len;
187 }
188 
189 static const struct file_operations xpcs_mmd_fops = {
190 	.owner = THIS_MODULE,
191 	.open = simple_open,
192 	.read =  xpcs_mmd_read,
193 	.write = xpcs_mmd_write,
194 };
195 
196 static const struct file_operations xpcs_reg_addr_fops = {
197 	.owner = THIS_MODULE,
198 	.open = simple_open,
199 	.read =  xpcs_reg_addr_read,
200 	.write = xpcs_reg_addr_write,
201 };
202 
203 static const struct file_operations xpcs_reg_value_fops = {
204 	.owner = THIS_MODULE,
205 	.open = simple_open,
206 	.read =  xpcs_reg_value_read,
207 	.write = xpcs_reg_value_write,
208 };
209 
210 static ssize_t xprop_reg_addr_read(struct file *filp, char __user *buffer,
211 				   size_t count, loff_t *ppos)
212 {
213 	struct xgbe_prv_data *pdata = filp->private_data;
214 
215 	return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xprop_reg);
216 }
217 
218 static ssize_t xprop_reg_addr_write(struct file *filp,
219 				    const char __user *buffer,
220 				    size_t count, loff_t *ppos)
221 {
222 	struct xgbe_prv_data *pdata = filp->private_data;
223 
224 	return xgbe_common_write(buffer, count, ppos,
225 				 &pdata->debugfs_xprop_reg);
226 }
227 
228 static ssize_t xprop_reg_value_read(struct file *filp, char __user *buffer,
229 				    size_t count, loff_t *ppos)
230 {
231 	struct xgbe_prv_data *pdata = filp->private_data;
232 	unsigned int value;
233 
234 	value = XP_IOREAD(pdata, pdata->debugfs_xprop_reg);
235 
236 	return xgbe_common_read(buffer, count, ppos, value);
237 }
238 
239 static ssize_t xprop_reg_value_write(struct file *filp,
240 				     const char __user *buffer,
241 				     size_t count, loff_t *ppos)
242 {
243 	struct xgbe_prv_data *pdata = filp->private_data;
244 	unsigned int value;
245 	ssize_t len;
246 
247 	len = xgbe_common_write(buffer, count, ppos, &value);
248 	if (len < 0)
249 		return len;
250 
251 	XP_IOWRITE(pdata, pdata->debugfs_xprop_reg, value);
252 
253 	return len;
254 }
255 
256 static const struct file_operations xprop_reg_addr_fops = {
257 	.owner = THIS_MODULE,
258 	.open = simple_open,
259 	.read =  xprop_reg_addr_read,
260 	.write = xprop_reg_addr_write,
261 };
262 
263 static const struct file_operations xprop_reg_value_fops = {
264 	.owner = THIS_MODULE,
265 	.open = simple_open,
266 	.read =  xprop_reg_value_read,
267 	.write = xprop_reg_value_write,
268 };
269 
270 static ssize_t xi2c_reg_addr_read(struct file *filp, char __user *buffer,
271 				  size_t count, loff_t *ppos)
272 {
273 	struct xgbe_prv_data *pdata = filp->private_data;
274 
275 	return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xi2c_reg);
276 }
277 
278 static ssize_t xi2c_reg_addr_write(struct file *filp,
279 				   const char __user *buffer,
280 				   size_t count, loff_t *ppos)
281 {
282 	struct xgbe_prv_data *pdata = filp->private_data;
283 
284 	return xgbe_common_write(buffer, count, ppos,
285 				 &pdata->debugfs_xi2c_reg);
286 }
287 
288 static ssize_t xi2c_reg_value_read(struct file *filp, char __user *buffer,
289 				   size_t count, loff_t *ppos)
290 {
291 	struct xgbe_prv_data *pdata = filp->private_data;
292 	unsigned int value;
293 
294 	value = XI2C_IOREAD(pdata, pdata->debugfs_xi2c_reg);
295 
296 	return xgbe_common_read(buffer, count, ppos, value);
297 }
298 
299 static ssize_t xi2c_reg_value_write(struct file *filp,
300 				    const char __user *buffer,
301 				    size_t count, loff_t *ppos)
302 {
303 	struct xgbe_prv_data *pdata = filp->private_data;
304 	unsigned int value;
305 	ssize_t len;
306 
307 	len = xgbe_common_write(buffer, count, ppos, &value);
308 	if (len < 0)
309 		return len;
310 
311 	XI2C_IOWRITE(pdata, pdata->debugfs_xi2c_reg, value);
312 
313 	return len;
314 }
315 
316 static const struct file_operations xi2c_reg_addr_fops = {
317 	.owner = THIS_MODULE,
318 	.open = simple_open,
319 	.read =  xi2c_reg_addr_read,
320 	.write = xi2c_reg_addr_write,
321 };
322 
323 static const struct file_operations xi2c_reg_value_fops = {
324 	.owner = THIS_MODULE,
325 	.open = simple_open,
326 	.read =  xi2c_reg_value_read,
327 	.write = xi2c_reg_value_write,
328 };
329 
330 void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
331 {
332 	char *buf;
333 
334 	/* Set defaults */
335 	pdata->debugfs_xgmac_reg = 0;
336 	pdata->debugfs_xpcs_mmd = 1;
337 	pdata->debugfs_xpcs_reg = 0;
338 
339 	buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
340 	if (!buf)
341 		return;
342 
343 	pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL);
344 
345 	debugfs_create_file("xgmac_register", 0600, pdata->xgbe_debugfs, pdata,
346 			    &xgmac_reg_addr_fops);
347 
348 	debugfs_create_file("xgmac_register_value", 0600, pdata->xgbe_debugfs,
349 			    pdata, &xgmac_reg_value_fops);
350 
351 	debugfs_create_file("xpcs_mmd", 0600, pdata->xgbe_debugfs, pdata,
352 			    &xpcs_mmd_fops);
353 
354 	debugfs_create_file("xpcs_register", 0600, pdata->xgbe_debugfs, pdata,
355 			    &xpcs_reg_addr_fops);
356 
357 	debugfs_create_file("xpcs_register_value", 0600, pdata->xgbe_debugfs,
358 			    pdata, &xpcs_reg_value_fops);
359 
360 	if (pdata->xprop_regs) {
361 		debugfs_create_file("xprop_register", 0600, pdata->xgbe_debugfs,
362 				    pdata, &xprop_reg_addr_fops);
363 
364 		debugfs_create_file("xprop_register_value", 0600,
365 				    pdata->xgbe_debugfs, pdata,
366 				    &xprop_reg_value_fops);
367 	}
368 
369 	if (pdata->xi2c_regs) {
370 		debugfs_create_file("xi2c_register", 0600, pdata->xgbe_debugfs,
371 				    pdata, &xi2c_reg_addr_fops);
372 
373 		debugfs_create_file("xi2c_register_value", 0600,
374 				    pdata->xgbe_debugfs, pdata,
375 				    &xi2c_reg_value_fops);
376 	}
377 
378 	if (pdata->vdata->an_cdr_workaround) {
379 		debugfs_create_bool("an_cdr_workaround", 0600,
380 				    pdata->xgbe_debugfs,
381 				    &pdata->debugfs_an_cdr_workaround);
382 
383 		debugfs_create_bool("an_cdr_track_early", 0600,
384 				    pdata->xgbe_debugfs,
385 				    &pdata->debugfs_an_cdr_track_early);
386 	}
387 
388 	kfree(buf);
389 }
390 
391 void xgbe_debugfs_exit(struct xgbe_prv_data *pdata)
392 {
393 	debugfs_remove_recursive(pdata->xgbe_debugfs);
394 	pdata->xgbe_debugfs = NULL;
395 }
396 
397 void xgbe_debugfs_rename(struct xgbe_prv_data *pdata)
398 {
399 	debugfs_change_name(pdata->xgbe_debugfs,
400 			    "amd-xgbe-%s", pdata->netdev->name);
401 }
402