1 /* 2 * AMD 10Gb Ethernet driver 3 * 4 * This file is available to you under your choice of the following two 5 * licenses: 6 * 7 * License 1: GPLv2 8 * 9 * Copyright (c) 2014 Advanced Micro Devices, Inc. 10 * 11 * This file is free software; you may copy, redistribute and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation, either version 2 of the License, or (at 14 * your option) any later version. 15 * 16 * This file is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program. If not, see <http://www.gnu.org/licenses/>. 23 * 24 * This file incorporates work covered by the following copyright and 25 * permission notice: 26 * The Synopsys DWC ETHER XGMAC Software Driver and documentation 27 * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 28 * Inc. unless otherwise expressly agreed to in writing between Synopsys 29 * and you. 30 * 31 * The Software IS NOT an item of Licensed Software or Licensed Product 32 * under any End User Software License Agreement or Agreement for Licensed 33 * Product with Synopsys or any supplement thereto. Permission is hereby 34 * granted, free of charge, to any person obtaining a copy of this software 35 * annotated with this license and the Software, to deal in the Software 36 * without restriction, including without limitation the rights to use, 37 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 38 * of the Software, and to permit persons to whom the Software is furnished 39 * to do so, subject to the following conditions: 40 * 41 * The above copyright notice and this permission notice shall be included 42 * in all copies or substantial portions of the Software. 43 * 44 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 45 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 54 * THE POSSIBILITY OF SUCH DAMAGE. 55 * 56 * 57 * License 2: Modified BSD 58 * 59 * Copyright (c) 2014 Advanced Micro Devices, Inc. 60 * All rights reserved. 61 * 62 * Redistribution and use in source and binary forms, with or without 63 * modification, are permitted provided that the following conditions are met: 64 * * Redistributions of source code must retain the above copyright 65 * notice, this list of conditions and the following disclaimer. 66 * * Redistributions in binary form must reproduce the above copyright 67 * notice, this list of conditions and the following disclaimer in the 68 * documentation and/or other materials provided with the distribution. 69 * * Neither the name of Advanced Micro Devices, Inc. nor the 70 * names of its contributors may be used to endorse or promote products 71 * derived from this software without specific prior written permission. 72 * 73 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 74 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 76 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 77 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 78 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 79 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 80 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 81 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 82 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 83 * 84 * This file incorporates work covered by the following copyright and 85 * permission notice: 86 * The Synopsys DWC ETHER XGMAC Software Driver and documentation 87 * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 88 * Inc. unless otherwise expressly agreed to in writing between Synopsys 89 * and you. 90 * 91 * The Software IS NOT an item of Licensed Software or Licensed Product 92 * under any End User Software License Agreement or Agreement for Licensed 93 * Product with Synopsys or any supplement thereto. Permission is hereby 94 * granted, free of charge, to any person obtaining a copy of this software 95 * annotated with this license and the Software, to deal in the Software 96 * without restriction, including without limitation the rights to use, 97 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 98 * of the Software, and to permit persons to whom the Software is furnished 99 * to do so, subject to the following conditions: 100 * 101 * The above copyright notice and this permission notice shall be included 102 * in all copies or substantial portions of the Software. 103 * 104 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 105 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 106 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 107 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 108 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 109 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 110 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 111 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 112 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 113 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 114 * THE POSSIBILITY OF SUCH DAMAGE. 115 */ 116 117 #include <linux/debugfs.h> 118 #include <linux/module.h> 119 #include <linux/slab.h> 120 121 #include "xgbe.h" 122 #include "xgbe-common.h" 123 124 125 static ssize_t xgbe_common_read(char __user *buffer, size_t count, 126 loff_t *ppos, unsigned int value) 127 { 128 char *buf; 129 ssize_t len; 130 131 if (*ppos != 0) 132 return 0; 133 134 buf = kasprintf(GFP_KERNEL, "0x%08x\n", value); 135 if (!buf) 136 return -ENOMEM; 137 138 if (count < strlen(buf)) { 139 kfree(buf); 140 return -ENOSPC; 141 } 142 143 len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); 144 kfree(buf); 145 146 return len; 147 } 148 149 static ssize_t xgbe_common_write(const char __user *buffer, size_t count, 150 loff_t *ppos, unsigned int *value) 151 { 152 char workarea[32]; 153 ssize_t len; 154 unsigned int scan_value; 155 156 if (*ppos != 0) 157 return 0; 158 159 if (count >= sizeof(workarea)) 160 return -ENOSPC; 161 162 len = simple_write_to_buffer(workarea, sizeof(workarea) - 1, ppos, 163 buffer, count); 164 if (len < 0) 165 return len; 166 167 workarea[len] = '\0'; 168 if (sscanf(workarea, "%x", &scan_value) == 1) 169 *value = scan_value; 170 else 171 return -EIO; 172 173 return len; 174 } 175 176 static ssize_t xgmac_reg_addr_read(struct file *filp, char __user *buffer, 177 size_t count, loff_t *ppos) 178 { 179 struct xgbe_prv_data *pdata = filp->private_data; 180 181 return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xgmac_reg); 182 } 183 184 static ssize_t xgmac_reg_addr_write(struct file *filp, 185 const char __user *buffer, 186 size_t count, loff_t *ppos) 187 { 188 struct xgbe_prv_data *pdata = filp->private_data; 189 190 return xgbe_common_write(buffer, count, ppos, 191 &pdata->debugfs_xgmac_reg); 192 } 193 194 static ssize_t xgmac_reg_value_read(struct file *filp, char __user *buffer, 195 size_t count, loff_t *ppos) 196 { 197 struct xgbe_prv_data *pdata = filp->private_data; 198 unsigned int value; 199 200 value = XGMAC_IOREAD(pdata, pdata->debugfs_xgmac_reg); 201 202 return xgbe_common_read(buffer, count, ppos, value); 203 } 204 205 static ssize_t xgmac_reg_value_write(struct file *filp, 206 const char __user *buffer, 207 size_t count, loff_t *ppos) 208 { 209 struct xgbe_prv_data *pdata = filp->private_data; 210 unsigned int value; 211 ssize_t len; 212 213 len = xgbe_common_write(buffer, count, ppos, &value); 214 if (len < 0) 215 return len; 216 217 XGMAC_IOWRITE(pdata, pdata->debugfs_xgmac_reg, value); 218 219 return len; 220 } 221 222 static const struct file_operations xgmac_reg_addr_fops = { 223 .owner = THIS_MODULE, 224 .open = simple_open, 225 .read = xgmac_reg_addr_read, 226 .write = xgmac_reg_addr_write, 227 }; 228 229 static const struct file_operations xgmac_reg_value_fops = { 230 .owner = THIS_MODULE, 231 .open = simple_open, 232 .read = xgmac_reg_value_read, 233 .write = xgmac_reg_value_write, 234 }; 235 236 static ssize_t xpcs_mmd_read(struct file *filp, char __user *buffer, 237 size_t count, loff_t *ppos) 238 { 239 struct xgbe_prv_data *pdata = filp->private_data; 240 241 return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_mmd); 242 } 243 244 static ssize_t xpcs_mmd_write(struct file *filp, const char __user *buffer, 245 size_t count, loff_t *ppos) 246 { 247 struct xgbe_prv_data *pdata = filp->private_data; 248 249 return xgbe_common_write(buffer, count, ppos, 250 &pdata->debugfs_xpcs_mmd); 251 } 252 253 static ssize_t xpcs_reg_addr_read(struct file *filp, char __user *buffer, 254 size_t count, loff_t *ppos) 255 { 256 struct xgbe_prv_data *pdata = filp->private_data; 257 258 return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_reg); 259 } 260 261 static ssize_t xpcs_reg_addr_write(struct file *filp, const char __user *buffer, 262 size_t count, loff_t *ppos) 263 { 264 struct xgbe_prv_data *pdata = filp->private_data; 265 266 return xgbe_common_write(buffer, count, ppos, 267 &pdata->debugfs_xpcs_reg); 268 } 269 270 static ssize_t xpcs_reg_value_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 unsigned int value; 275 276 value = pdata->hw_if.read_mmd_regs(pdata, pdata->debugfs_xpcs_mmd, 277 pdata->debugfs_xpcs_reg); 278 279 return xgbe_common_read(buffer, count, ppos, value); 280 } 281 282 static ssize_t xpcs_reg_value_write(struct file *filp, 283 const char __user *buffer, 284 size_t count, loff_t *ppos) 285 { 286 struct xgbe_prv_data *pdata = filp->private_data; 287 unsigned int value; 288 ssize_t len; 289 290 len = xgbe_common_write(buffer, count, ppos, &value); 291 if (len < 0) 292 return len; 293 294 pdata->hw_if.write_mmd_regs(pdata, pdata->debugfs_xpcs_mmd, 295 pdata->debugfs_xpcs_reg, value); 296 297 return len; 298 } 299 300 static const struct file_operations xpcs_mmd_fops = { 301 .owner = THIS_MODULE, 302 .open = simple_open, 303 .read = xpcs_mmd_read, 304 .write = xpcs_mmd_write, 305 }; 306 307 static const struct file_operations xpcs_reg_addr_fops = { 308 .owner = THIS_MODULE, 309 .open = simple_open, 310 .read = xpcs_reg_addr_read, 311 .write = xpcs_reg_addr_write, 312 }; 313 314 static const struct file_operations xpcs_reg_value_fops = { 315 .owner = THIS_MODULE, 316 .open = simple_open, 317 .read = xpcs_reg_value_read, 318 .write = xpcs_reg_value_write, 319 }; 320 321 void xgbe_debugfs_init(struct xgbe_prv_data *pdata) 322 { 323 struct dentry *pfile; 324 char *buf; 325 326 /* Set defaults */ 327 pdata->debugfs_xgmac_reg = 0; 328 pdata->debugfs_xpcs_mmd = 1; 329 pdata->debugfs_xpcs_reg = 0; 330 331 buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name); 332 pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL); 333 if (pdata->xgbe_debugfs == NULL) { 334 netdev_err(pdata->netdev, "debugfs_create_dir failed\n"); 335 return; 336 } 337 338 pfile = debugfs_create_file("xgmac_register", 0600, 339 pdata->xgbe_debugfs, pdata, 340 &xgmac_reg_addr_fops); 341 if (!pfile) 342 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 343 344 pfile = debugfs_create_file("xgmac_register_value", 0600, 345 pdata->xgbe_debugfs, pdata, 346 &xgmac_reg_value_fops); 347 if (!pfile) 348 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 349 350 pfile = debugfs_create_file("xpcs_mmd", 0600, 351 pdata->xgbe_debugfs, pdata, 352 &xpcs_mmd_fops); 353 if (!pfile) 354 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 355 356 pfile = debugfs_create_file("xpcs_register", 0600, 357 pdata->xgbe_debugfs, pdata, 358 &xpcs_reg_addr_fops); 359 if (!pfile) 360 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 361 362 pfile = debugfs_create_file("xpcs_register_value", 0600, 363 pdata->xgbe_debugfs, pdata, 364 &xpcs_reg_value_fops); 365 if (!pfile) 366 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 367 368 kfree(buf); 369 } 370 371 void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) 372 { 373 debugfs_remove_recursive(pdata->xgbe_debugfs); 374 pdata->xgbe_debugfs = NULL; 375 } 376