summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/freescale/gianfar_debugfs.c
diff options
context:
space:
mode:
authorClaudiu Manoil <claudiu.manoil@freescale.com>2014-08-13 08:13:53 (GMT)
committerMatthew Weigel <Matthew.Weigel@freescale.com>2014-12-11 18:39:24 (GMT)
commit30e0b7dd208bcc1fa5728d6de84030f4a3c13651 (patch)
tree8244c42d560010ec9941e7ba3826466a3a694346 /drivers/net/ethernet/freescale/gianfar_debugfs.c
parent7ac42ef158796c13dac8ff493fca8c98195bdbf3 (diff)
downloadlinux-fsl-qoriq-30e0b7dd208bcc1fa5728d6de84030f4a3c13651.tar.xz
gianfar: Add debugfs packet forwarding loopback
Add the GFAR_DBG_LOOP config option and debugfs support to be able to configure packet forwarding loops in the Gianfar driver. This config option is disabled by default and should be used only for debugging/ benchmarking purposes. For details on how to configure a packet forwarding debug loop refer to the help section of CONFIG_GFAR_DBG_LOOP. Change-Id: I24d440edc4c7d63a055205e022b743e30f58409b Signed-off-by: Claudiu Manoil <claudiu.manoil@freescale.com> Reviewed-on: http://git.am.freescale.net:8181/22861 Reviewed-by: Richard Schmitt <richard.schmitt@freescale.com> Tested-by: Richard Schmitt <richard.schmitt@freescale.com>
Diffstat (limited to 'drivers/net/ethernet/freescale/gianfar_debugfs.c')
-rw-r--r--drivers/net/ethernet/freescale/gianfar_debugfs.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar_debugfs.c b/drivers/net/ethernet/freescale/gianfar_debugfs.c
new file mode 100644
index 0000000..b8f5e4c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/gianfar_debugfs.c
@@ -0,0 +1,157 @@
+/* Copyright 2013 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/debugfs.h>
+
+#include "gianfar.h"
+
+static struct dentry *gfar_dbg_root;
+LIST_HEAD(gfar_dbg_ndevs);
+
+static ssize_t gfar_dbg_ndev_loopbk_read(struct file *f,
+ char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct gfar_private *priv = f->private_data;
+ const char *name = NULL;
+ const char *b;
+ int len;
+
+ if (*ppos != 0)
+ return 0;
+
+ if (priv->dbg_ndev_loopbk_tgt)
+ name = priv->dbg_ndev_loopbk_tgt->name;
+
+ b = kasprintf(GFP_KERNEL, "%s\n", name ? name : "off");
+
+ if (!b)
+ return -ENOMEM;
+
+ if (count < strlen(b)) {
+ kfree(b);
+ return -ENOSPC;
+ }
+
+ len = simple_read_from_buffer(buf, count, ppos, b, strlen(b));
+
+ kfree(b);
+
+ return len;
+}
+
+static ssize_t gfar_dbg_ndev_loopbk_write(struct file *f,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct gfar_private *priv = f->private_data;
+ struct gfar_private *gfar_dbg_priv = NULL;
+ int found = 0;
+
+ if (*ppos != 0)
+ return 0;
+
+ if (!strncmp("off", buf, count - 1) || !strncmp("0", buf, count - 1))
+ goto update;
+
+ list_for_each_entry(gfar_dbg_priv, &gfar_dbg_ndevs, dbg_ndev_node) {
+ const char *name = gfar_dbg_priv->ndev->name;
+ if ((strlen(name) == count - 1) &&
+ !strncmp(buf, name, count - 1)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("Invalid loopback target device name!\n");
+ return count;
+ }
+
+update:
+ priv->dbg_ndev_loopbk_tgt = NULL;
+ if (gfar_dbg_priv)
+ priv->dbg_ndev_loopbk_tgt = gfar_dbg_priv->ndev;
+
+ return count;
+}
+
+static const struct file_operations gfar_dbg_ndev_loopbk_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = gfar_dbg_ndev_loopbk_read,
+ .write = gfar_dbg_ndev_loopbk_write
+};
+
+void gfar_dbg_ndev_init(struct gfar_private *priv)
+{
+ const char *name = priv->ndev->name;
+ struct dentry *f;
+
+ priv->dbg_ndev_dir = debugfs_create_dir(name, gfar_dbg_root);
+ if (!priv->dbg_ndev_dir) {
+ pr_err("debugfs init failed for %s\n", name);
+ return;
+ }
+
+ f = debugfs_create_file("lo", 0600, priv->dbg_ndev_dir,
+ priv, &gfar_dbg_ndev_loopbk_fops);
+ if (!f) {
+ pr_err("debugfs failed to init loopback for %s\n", name);
+ return;
+ }
+
+ list_add(&priv->dbg_ndev_node, &gfar_dbg_ndevs);
+}
+
+void gfar_dbg_ndev_exit(struct gfar_private *priv)
+{
+ if (!priv->dbg_ndev_dir)
+ return;
+
+ list_del(&priv->dbg_ndev_node);
+
+ debugfs_remove_recursive(priv->dbg_ndev_dir);
+ priv->dbg_ndev_dir = NULL;
+ priv->dbg_ndev_loopbk_tgt = NULL;
+}
+
+void gfar_dbg_init(void)
+{
+ gfar_dbg_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (!gfar_dbg_root)
+ pr_err("debugfs init failed\n");
+}
+
+void gfar_dbg_exit(void)
+{
+ debugfs_remove_recursive(gfar_dbg_root);
+}