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