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 124static ssize_t xgbe_common_read(char __user *buffer, size_t count, 125 loff_t *ppos, unsigned int value) 126{ 127 char *buf; 128 ssize_t len; 129 130 if (*ppos != 0) 131 return 0; 132 133 buf = kasprintf(GFP_KERNEL, "0x%08x\n", value); 134 if (!buf) 135 return -ENOMEM; 136 137 if (count < strlen(buf)) { 138 kfree(buf); 139 return -ENOSPC; 140 } 141 142 len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); 143 kfree(buf); 144 145 return len; 146} 147 148static ssize_t xgbe_common_write(const char __user *buffer, size_t count, 149 loff_t *ppos, unsigned int *value) 150{ 151 char workarea[32]; 152 ssize_t len; 153 int ret; 154 155 if (*ppos != 0) 156 return 0; 157 158 if (count >= sizeof(workarea)) 159 return -ENOSPC; 160 161 len = simple_write_to_buffer(workarea, sizeof(workarea) - 1, ppos, 162 buffer, count); 163 if (len < 0) 164 return len; 165 166 workarea[len] = '\0'; 167 ret = kstrtouint(workarea, 16, value); 168 if (ret) 169 return -EIO; 170 171 return len; 172} 173 174static ssize_t xgmac_reg_addr_read(struct file *filp, char __user *buffer, 175 size_t count, loff_t *ppos) 176{ 177 struct xgbe_prv_data *pdata = filp->private_data; 178 179 return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xgmac_reg); 180} 181 182static ssize_t xgmac_reg_addr_write(struct file *filp, 183 const char __user *buffer, 184 size_t count, loff_t *ppos) 185{ 186 struct xgbe_prv_data *pdata = filp->private_data; 187 188 return xgbe_common_write(buffer, count, ppos, 189 &pdata->debugfs_xgmac_reg); 190} 191 192static ssize_t xgmac_reg_value_read(struct file *filp, char __user *buffer, 193 size_t count, loff_t *ppos) 194{ 195 struct xgbe_prv_data *pdata = filp->private_data; 196 unsigned int value; 197 198 value = XGMAC_IOREAD(pdata, pdata->debugfs_xgmac_reg); 199 200 return xgbe_common_read(buffer, count, ppos, value); 201} 202 203static ssize_t xgmac_reg_value_write(struct file *filp, 204 const char __user *buffer, 205 size_t count, loff_t *ppos) 206{ 207 struct xgbe_prv_data *pdata = filp->private_data; 208 unsigned int value; 209 ssize_t len; 210 211 len = xgbe_common_write(buffer, count, ppos, &value); 212 if (len < 0) 213 return len; 214 215 XGMAC_IOWRITE(pdata, pdata->debugfs_xgmac_reg, value); 216 217 return len; 218} 219 220static const struct file_operations xgmac_reg_addr_fops = { 221 .owner = THIS_MODULE, 222 .open = simple_open, 223 .read = xgmac_reg_addr_read, 224 .write = xgmac_reg_addr_write, 225}; 226 227static const struct file_operations xgmac_reg_value_fops = { 228 .owner = THIS_MODULE, 229 .open = simple_open, 230 .read = xgmac_reg_value_read, 231 .write = xgmac_reg_value_write, 232}; 233 234static ssize_t xpcs_mmd_read(struct file *filp, char __user *buffer, 235 size_t count, loff_t *ppos) 236{ 237 struct xgbe_prv_data *pdata = filp->private_data; 238 239 return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_mmd); 240} 241 242static ssize_t xpcs_mmd_write(struct file *filp, const char __user *buffer, 243 size_t count, loff_t *ppos) 244{ 245 struct xgbe_prv_data *pdata = filp->private_data; 246 247 return xgbe_common_write(buffer, count, ppos, 248 &pdata->debugfs_xpcs_mmd); 249} 250 251static ssize_t xpcs_reg_addr_read(struct file *filp, char __user *buffer, 252 size_t count, loff_t *ppos) 253{ 254 struct xgbe_prv_data *pdata = filp->private_data; 255 256 return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_reg); 257} 258 259static ssize_t xpcs_reg_addr_write(struct file *filp, const char __user *buffer, 260 size_t count, loff_t *ppos) 261{ 262 struct xgbe_prv_data *pdata = filp->private_data; 263 264 return xgbe_common_write(buffer, count, ppos, 265 &pdata->debugfs_xpcs_reg); 266} 267 268static ssize_t xpcs_reg_value_read(struct file *filp, char __user *buffer, 269 size_t count, loff_t *ppos) 270{ 271 struct xgbe_prv_data *pdata = filp->private_data; 272 unsigned int value; 273 274 value = XMDIO_READ(pdata, pdata->debugfs_xpcs_mmd, 275 pdata->debugfs_xpcs_reg); 276 277 return xgbe_common_read(buffer, count, ppos, value); 278} 279 280static ssize_t xpcs_reg_value_write(struct file *filp, 281 const char __user *buffer, 282 size_t count, loff_t *ppos) 283{ 284 struct xgbe_prv_data *pdata = filp->private_data; 285 unsigned int value; 286 ssize_t len; 287 288 len = xgbe_common_write(buffer, count, ppos, &value); 289 if (len < 0) 290 return len; 291 292 XMDIO_WRITE(pdata, pdata->debugfs_xpcs_mmd, pdata->debugfs_xpcs_reg, 293 value); 294 295 return len; 296} 297 298static const struct file_operations xpcs_mmd_fops = { 299 .owner = THIS_MODULE, 300 .open = simple_open, 301 .read = xpcs_mmd_read, 302 .write = xpcs_mmd_write, 303}; 304 305static const struct file_operations xpcs_reg_addr_fops = { 306 .owner = THIS_MODULE, 307 .open = simple_open, 308 .read = xpcs_reg_addr_read, 309 .write = xpcs_reg_addr_write, 310}; 311 312static const struct file_operations xpcs_reg_value_fops = { 313 .owner = THIS_MODULE, 314 .open = simple_open, 315 .read = xpcs_reg_value_read, 316 .write = xpcs_reg_value_write, 317}; 318 319void xgbe_debugfs_init(struct xgbe_prv_data *pdata) 320{ 321 struct dentry *pfile; 322 char *buf; 323 324 /* Set defaults */ 325 pdata->debugfs_xgmac_reg = 0; 326 pdata->debugfs_xpcs_mmd = 1; 327 pdata->debugfs_xpcs_reg = 0; 328 329 buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name); 330 if (!buf) 331 return; 332 333 pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL); 334 if (!pdata->xgbe_debugfs) { 335 netdev_err(pdata->netdev, "debugfs_create_dir failed\n"); 336 kfree(buf); 337 return; 338 } 339 340 pfile = debugfs_create_file("xgmac_register", 0600, 341 pdata->xgbe_debugfs, pdata, 342 &xgmac_reg_addr_fops); 343 if (!pfile) 344 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 345 346 pfile = debugfs_create_file("xgmac_register_value", 0600, 347 pdata->xgbe_debugfs, pdata, 348 &xgmac_reg_value_fops); 349 if (!pfile) 350 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 351 352 pfile = debugfs_create_file("xpcs_mmd", 0600, 353 pdata->xgbe_debugfs, pdata, 354 &xpcs_mmd_fops); 355 if (!pfile) 356 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 357 358 pfile = debugfs_create_file("xpcs_register", 0600, 359 pdata->xgbe_debugfs, pdata, 360 &xpcs_reg_addr_fops); 361 if (!pfile) 362 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 363 364 pfile = debugfs_create_file("xpcs_register_value", 0600, 365 pdata->xgbe_debugfs, pdata, 366 &xpcs_reg_value_fops); 367 if (!pfile) 368 netdev_err(pdata->netdev, "debugfs_create_file failed\n"); 369 370 kfree(buf); 371} 372 373void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) 374{ 375 debugfs_remove_recursive(pdata->xgbe_debugfs); 376 pdata->xgbe_debugfs = NULL; 377} 378