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
15static 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, fmt: "0x%08x\n", value);
25 if (!buf)
26 return -ENOMEM;
27
28 if (count < strlen(buf)) {
29 kfree(objp: buf);
30 return -ENOSPC;
31 }
32
33 len = simple_read_from_buffer(to: buffer, count, ppos, from: buf, strlen(buf));
34 kfree(objp: buf);
35
36 return len;
37}
38
39static 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(to: workarea, available: sizeof(workarea) - 1, ppos,
53 from: buffer, count);
54 if (len < 0)
55 return len;
56
57 workarea[len] = '\0';
58 ret = kstrtouint(s: workarea, base: 16, res: value);
59 if (ret)
60 return -EIO;
61
62 return len;
63}
64
65static 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, value: pdata->debugfs_xgmac_reg);
71}
72
73static 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 value: &pdata->debugfs_xgmac_reg);
81}
82
83static 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
94static 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: &value);
103 if (len < 0)
104 return len;
105
106 XGMAC_IOWRITE(pdata, pdata->debugfs_xgmac_reg, value);
107
108 return len;
109}
110
111static 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
118static 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
125static 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, value: pdata->debugfs_xpcs_mmd);
131}
132
133static 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 value: &pdata->debugfs_xpcs_mmd);
140}
141
142static 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, value: pdata->debugfs_xpcs_reg);
148}
149
150static 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 value: &pdata->debugfs_xpcs_reg);
157}
158
159static 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
171static 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: &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
189static 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
196static 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
203static 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
210static 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, value: pdata->debugfs_xprop_reg);
216}
217
218static 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 value: &pdata->debugfs_xprop_reg);
226}
227
228static 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
239static 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: &value);
248 if (len < 0)
249 return len;
250
251 XP_IOWRITE(pdata, pdata->debugfs_xprop_reg, value);
252
253 return len;
254}
255
256static 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
263static 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
270static 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, value: pdata->debugfs_xi2c_reg);
276}
277
278static 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 value: &pdata->debugfs_xi2c_reg);
286}
287
288static 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
299static 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: &value);
308 if (len < 0)
309 return len;
310
311 XI2C_IOWRITE(pdata, pdata->debugfs_xi2c_reg, value);
312
313 return len;
314}
315
316static 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
323static 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
330void 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, fmt: "amd-xgbe-%s", pdata->netdev->name);
340 if (!buf)
341 return;
342
343 pdata->xgbe_debugfs = debugfs_create_dir(name: 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(name: "an_cdr_workaround", mode: 0600,
380 parent: pdata->xgbe_debugfs,
381 value: &pdata->debugfs_an_cdr_workaround);
382
383 debugfs_create_bool(name: "an_cdr_track_early", mode: 0600,
384 parent: pdata->xgbe_debugfs,
385 value: &pdata->debugfs_an_cdr_track_early);
386 }
387
388 kfree(objp: buf);
389}
390
391void xgbe_debugfs_exit(struct xgbe_prv_data *pdata)
392{
393 debugfs_remove_recursive(dentry: pdata->xgbe_debugfs);
394 pdata->xgbe_debugfs = NULL;
395}
396
397void xgbe_debugfs_rename(struct xgbe_prv_data *pdata)
398{
399 debugfs_change_name(dentry: pdata->xgbe_debugfs,
400 fmt: "amd-xgbe-%s", pdata->netdev->name);
401}
402

source code of linux/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c