526 lines · c
1/*2 * AMD 10Gb Ethernet driver3 *4 * This file is available to you under your choice of the following two5 * licenses:6 *7 * License 1: GPLv28 *9 * Copyright (c) 2014 Advanced Micro Devices, Inc.10 *11 * This file is free software; you may copy, redistribute and/or modify12 * it under the terms of the GNU General Public License as published by13 * the Free Software Foundation, either version 2 of the License, or (at14 * your option) any later version.15 *16 * This file is distributed in the hope that it will be useful, but17 * WITHOUT ANY WARRANTY; without even the implied warranty of18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU19 * General Public License for more details.20 *21 * You should have received a copy of the GNU General Public License22 * along with this program. If not, see <http://www.gnu.org/licenses/>.23 *24 * This file incorporates work covered by the following copyright and25 * permission notice:26 * The Synopsys DWC ETHER XGMAC Software Driver and documentation27 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,28 * Inc. unless otherwise expressly agreed to in writing between Synopsys29 * and you.30 *31 * The Software IS NOT an item of Licensed Software or Licensed Product32 * under any End User Software License Agreement or Agreement for Licensed33 * Product with Synopsys or any supplement thereto. Permission is hereby34 * granted, free of charge, to any person obtaining a copy of this software35 * annotated with this license and the Software, to deal in the Software36 * without restriction, including without limitation the rights to use,37 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies38 * of the Software, and to permit persons to whom the Software is furnished39 * to do so, subject to the following conditions:40 *41 * The above copyright notice and this permission notice shall be included42 * 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 LIMITED46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A47 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF54 * THE POSSIBILITY OF SUCH DAMAGE.55 *56 *57 * License 2: Modified BSD58 *59 * Copyright (c) 2014 Advanced Micro Devices, Inc.60 * All rights reserved.61 *62 * Redistribution and use in source and binary forms, with or without63 * modification, are permitted provided that the following conditions are met:64 * * Redistributions of source code must retain the above copyright65 * notice, this list of conditions and the following disclaimer.66 * * Redistributions in binary form must reproduce the above copyright67 * notice, this list of conditions and the following disclaimer in the68 * documentation and/or other materials provided with the distribution.69 * * Neither the name of Advanced Micro Devices, Inc. nor the70 * names of its contributors may be used to endorse or promote products71 * 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, THE75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE76 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY77 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES78 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;79 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND80 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT81 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF82 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.83 *84 * This file incorporates work covered by the following copyright and85 * permission notice:86 * The Synopsys DWC ETHER XGMAC Software Driver and documentation87 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,88 * Inc. unless otherwise expressly agreed to in writing between Synopsys89 * and you.90 *91 * The Software IS NOT an item of Licensed Software or Licensed Product92 * under any End User Software License Agreement or Agreement for Licensed93 * Product with Synopsys or any supplement thereto. Permission is hereby94 * granted, free of charge, to any person obtaining a copy of this software95 * annotated with this license and the Software, to deal in the Software96 * without restriction, including without limitation the rights to use,97 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies98 * of the Software, and to permit persons to whom the Software is furnished99 * to do so, subject to the following conditions:100 *101 * The above copyright notice and this permission notice shall be included102 * 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 LIMITED106 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A107 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS108 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR109 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF110 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS111 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN112 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)113 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF114 * 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 -EINVAL;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 319static ssize_t xprop_reg_addr_read(struct file *filp, char __user *buffer,320 size_t count, loff_t *ppos)321{322 struct xgbe_prv_data *pdata = filp->private_data;323 324 return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xprop_reg);325}326 327static ssize_t xprop_reg_addr_write(struct file *filp,328 const char __user *buffer,329 size_t count, loff_t *ppos)330{331 struct xgbe_prv_data *pdata = filp->private_data;332 333 return xgbe_common_write(buffer, count, ppos,334 &pdata->debugfs_xprop_reg);335}336 337static ssize_t xprop_reg_value_read(struct file *filp, char __user *buffer,338 size_t count, loff_t *ppos)339{340 struct xgbe_prv_data *pdata = filp->private_data;341 unsigned int value;342 343 value = XP_IOREAD(pdata, pdata->debugfs_xprop_reg);344 345 return xgbe_common_read(buffer, count, ppos, value);346}347 348static ssize_t xprop_reg_value_write(struct file *filp,349 const char __user *buffer,350 size_t count, loff_t *ppos)351{352 struct xgbe_prv_data *pdata = filp->private_data;353 unsigned int value;354 ssize_t len;355 356 len = xgbe_common_write(buffer, count, ppos, &value);357 if (len < 0)358 return len;359 360 XP_IOWRITE(pdata, pdata->debugfs_xprop_reg, value);361 362 return len;363}364 365static const struct file_operations xprop_reg_addr_fops = {366 .owner = THIS_MODULE,367 .open = simple_open,368 .read = xprop_reg_addr_read,369 .write = xprop_reg_addr_write,370};371 372static const struct file_operations xprop_reg_value_fops = {373 .owner = THIS_MODULE,374 .open = simple_open,375 .read = xprop_reg_value_read,376 .write = xprop_reg_value_write,377};378 379static ssize_t xi2c_reg_addr_read(struct file *filp, char __user *buffer,380 size_t count, loff_t *ppos)381{382 struct xgbe_prv_data *pdata = filp->private_data;383 384 return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xi2c_reg);385}386 387static ssize_t xi2c_reg_addr_write(struct file *filp,388 const char __user *buffer,389 size_t count, loff_t *ppos)390{391 struct xgbe_prv_data *pdata = filp->private_data;392 393 return xgbe_common_write(buffer, count, ppos,394 &pdata->debugfs_xi2c_reg);395}396 397static ssize_t xi2c_reg_value_read(struct file *filp, char __user *buffer,398 size_t count, loff_t *ppos)399{400 struct xgbe_prv_data *pdata = filp->private_data;401 unsigned int value;402 403 value = XI2C_IOREAD(pdata, pdata->debugfs_xi2c_reg);404 405 return xgbe_common_read(buffer, count, ppos, value);406}407 408static ssize_t xi2c_reg_value_write(struct file *filp,409 const char __user *buffer,410 size_t count, loff_t *ppos)411{412 struct xgbe_prv_data *pdata = filp->private_data;413 unsigned int value;414 ssize_t len;415 416 len = xgbe_common_write(buffer, count, ppos, &value);417 if (len < 0)418 return len;419 420 XI2C_IOWRITE(pdata, pdata->debugfs_xi2c_reg, value);421 422 return len;423}424 425static const struct file_operations xi2c_reg_addr_fops = {426 .owner = THIS_MODULE,427 .open = simple_open,428 .read = xi2c_reg_addr_read,429 .write = xi2c_reg_addr_write,430};431 432static const struct file_operations xi2c_reg_value_fops = {433 .owner = THIS_MODULE,434 .open = simple_open,435 .read = xi2c_reg_value_read,436 .write = xi2c_reg_value_write,437};438 439void xgbe_debugfs_init(struct xgbe_prv_data *pdata)440{441 char *buf;442 443 /* Set defaults */444 pdata->debugfs_xgmac_reg = 0;445 pdata->debugfs_xpcs_mmd = 1;446 pdata->debugfs_xpcs_reg = 0;447 448 buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);449 if (!buf)450 return;451 452 pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL);453 454 debugfs_create_file("xgmac_register", 0600, pdata->xgbe_debugfs, pdata,455 &xgmac_reg_addr_fops);456 457 debugfs_create_file("xgmac_register_value", 0600, pdata->xgbe_debugfs,458 pdata, &xgmac_reg_value_fops);459 460 debugfs_create_file("xpcs_mmd", 0600, pdata->xgbe_debugfs, pdata,461 &xpcs_mmd_fops);462 463 debugfs_create_file("xpcs_register", 0600, pdata->xgbe_debugfs, pdata,464 &xpcs_reg_addr_fops);465 466 debugfs_create_file("xpcs_register_value", 0600, pdata->xgbe_debugfs,467 pdata, &xpcs_reg_value_fops);468 469 if (pdata->xprop_regs) {470 debugfs_create_file("xprop_register", 0600, pdata->xgbe_debugfs,471 pdata, &xprop_reg_addr_fops);472 473 debugfs_create_file("xprop_register_value", 0600,474 pdata->xgbe_debugfs, pdata,475 &xprop_reg_value_fops);476 }477 478 if (pdata->xi2c_regs) {479 debugfs_create_file("xi2c_register", 0600, pdata->xgbe_debugfs,480 pdata, &xi2c_reg_addr_fops);481 482 debugfs_create_file("xi2c_register_value", 0600,483 pdata->xgbe_debugfs, pdata,484 &xi2c_reg_value_fops);485 }486 487 if (pdata->vdata->an_cdr_workaround) {488 debugfs_create_bool("an_cdr_workaround", 0600,489 pdata->xgbe_debugfs,490 &pdata->debugfs_an_cdr_workaround);491 492 debugfs_create_bool("an_cdr_track_early", 0600,493 pdata->xgbe_debugfs,494 &pdata->debugfs_an_cdr_track_early);495 }496 497 kfree(buf);498}499 500void xgbe_debugfs_exit(struct xgbe_prv_data *pdata)501{502 debugfs_remove_recursive(pdata->xgbe_debugfs);503 pdata->xgbe_debugfs = NULL;504}505 506void xgbe_debugfs_rename(struct xgbe_prv_data *pdata)507{508 char *buf;509 510 if (!pdata->xgbe_debugfs)511 return;512 513 buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);514 if (!buf)515 return;516 517 if (!strcmp(pdata->xgbe_debugfs->d_name.name, buf))518 goto out;519 520 debugfs_rename(pdata->xgbe_debugfs->d_parent, pdata->xgbe_debugfs,521 pdata->xgbe_debugfs->d_parent, buf);522 523out:524 kfree(buf);525}526