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
xgbe_common_read(char __user * buffer,size_t count,loff_t * ppos,unsigned int value)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
xgbe_common_write(const char __user * buffer,size_t count,loff_t * ppos,unsigned int * value)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
xgmac_reg_addr_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)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
xgmac_reg_addr_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)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
xgmac_reg_value_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)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
xgmac_reg_value_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)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
xpcs_mmd_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)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
xpcs_mmd_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)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
xpcs_reg_addr_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)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
xpcs_reg_addr_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)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
xpcs_reg_value_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)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
xpcs_reg_value_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)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
xprop_reg_addr_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)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
xprop_reg_addr_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)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
xprop_reg_value_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)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
xprop_reg_value_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)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
xi2c_reg_addr_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)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
xi2c_reg_addr_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)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
xi2c_reg_value_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)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
xi2c_reg_value_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)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
xgbe_debugfs_init(struct xgbe_prv_data * pdata)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
xgbe_debugfs_exit(struct xgbe_prv_data * pdata)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
xgbe_debugfs_rename(struct xgbe_prv_data * pdata)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