summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/freescale/dpa/Kconfig16
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_debugfs.c106
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth.c23
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth.h12
-rw-r--r--drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c22
5 files changed, 179 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/dpa/Kconfig b/drivers/net/ethernet/freescale/dpa/Kconfig
index b91a3ff..0f27792 100644
--- a/drivers/net/ethernet/freescale/dpa/Kconfig
+++ b/drivers/net/ethernet/freescale/dpa/Kconfig
@@ -133,4 +133,20 @@ config FSL_DPAA_ETH_DEBUG
---help---
This option compiles debug code for the DPAA Ethernet driver.
+config FSL_DPAA_DBG_LOOP
+ bool "DPAA Ethernet Debug loopback"
+ depends on FSL_DPAA_ETH_DEBUGFS && FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE
+ default n
+ ---help---
+ This option allows to divert all received traffic on a certain interface A towards a
+ selected interface B. This option is used to benchmark the HW + Ethernet driver in
+ isolation from the Linux networking stack. The loops are controlled by debugfs entries,
+ one for each interface. By default all loops are disabled (target value is -1). I.e. to
+ change the loop setting for interface 4 and divert all received traffic to interface 5
+ write Tx interface number in the receive interface debugfs file:
+ # cat /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop
+ 4->-1
+ # echo 5 > /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop
+ # cat /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop
+ 4->5
endif # FSL_DPAA_ETH
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_debugfs.c b/drivers/net/ethernet/freescale/dpa/dpaa_debugfs.c
index 0c884a5..a5665ac 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_debugfs.c
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_debugfs.c
@@ -41,6 +41,12 @@
static int __cold dpa_debugfs_open(struct inode *inode, struct file *file);
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+static int __cold dpa_debugfs_loop_open(struct inode *inode, struct file *file);
+static ssize_t dpa_loop_write(struct file *f,
+ const char __user *buf, size_t count, loff_t *off);
+#endif
+
static struct dentry *dpa_debugfs_root;
static const struct file_operations dpa_debugfs_fops = {
.open = dpa_debugfs_open,
@@ -49,6 +55,16 @@ static const struct file_operations dpa_debugfs_fops = {
.release = single_release,
};
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+static const struct file_operations dpa_debugfs_lp_fops = {
+ .open = dpa_debugfs_loop_open,
+ .write = dpa_loop_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
static int dpa_debugfs_show(struct seq_file *file, void *offset)
{
int i;
@@ -200,6 +216,74 @@ static int dpa_debugfs_show(struct seq_file *file, void *offset)
return 0;
}
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+static int dpa_debugfs_loop_show(struct seq_file *file, void *offset)
+{
+ struct dpa_priv_s *priv;
+
+ BUG_ON(offset == NULL);
+
+ priv = netdev_priv((struct net_device *)file->private);
+ seq_printf(file, "%d->%d\n", priv->loop_id, priv->loop_to);
+
+ return 0;
+}
+
+static int user_input_convert(const char __user *user_buf, size_t count,
+ long *val)
+{
+ char buf[12];
+
+ if (count > sizeof(buf) - 1)
+ return -EINVAL;
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+ buf[count] = '\0';
+ if (kstrtol(buf, 0, val))
+ return -EINVAL;
+ return 0;
+}
+
+static ssize_t dpa_loop_write(struct file *f,
+ const char __user *buf, size_t count, loff_t *off)
+{
+ struct dpa_priv_s *priv;
+ struct net_device *netdev;
+ struct seq_file *sf;
+ int ret;
+ long val;
+
+ ret = user_input_convert(buf, count, &val);
+ if (ret)
+ return ret;
+
+ sf = (struct seq_file *)f->private_data;
+ netdev = (struct net_device *)sf->private;
+ priv = netdev_priv(netdev);
+
+ priv->loop_to = ((val < 0) || (val > 20)) ? -1 : val;
+
+ return count;
+}
+
+static int __cold dpa_debugfs_loop_open(struct inode *inode, struct file *file)
+{
+ int _errno;
+ const struct net_device *net_dev;
+
+ _errno = single_open(file, dpa_debugfs_loop_show, inode->i_private);
+ if (unlikely(_errno < 0)) {
+ net_dev = (struct net_device *)inode->i_private;
+
+ if (netif_msg_drv((struct dpa_priv_s *)netdev_priv(net_dev)))
+ netdev_err(net_dev, "single_open() = %d\n",
+ _errno);
+ }
+
+ return _errno;
+}
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
+
static int __cold dpa_debugfs_open(struct inode *inode, struct file *file)
{
int _errno;
@@ -219,6 +303,9 @@ static int __cold dpa_debugfs_open(struct inode *inode, struct file *file)
int dpa_netdev_debugfs_create(struct net_device *net_dev)
{
struct dpa_priv_s *priv = netdev_priv(net_dev);
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ char loop_file_name[100];
+#endif
if (unlikely(dpa_debugfs_root == NULL)) {
pr_err(KBUILD_MODNAME ": %s:%hu:%s(): \t%s\n",
@@ -241,6 +328,22 @@ int dpa_netdev_debugfs_create(struct net_device *net_dev)
return -ENOMEM;
}
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ sprintf(loop_file_name, "%s_loop", net_dev->name);
+ priv->debugfs_loop_file = debugfs_create_file(loop_file_name,
+ S_IRUGO,
+ dpa_debugfs_root,
+ net_dev,
+ &dpa_debugfs_lp_fops);
+ if (unlikely(priv->debugfs_loop_file == NULL)) {
+ netdev_err(net_dev, "debugfs_create_file(%s/%s/%s)",
+ powerpc_debugfs_root->d_iname,
+ dpa_debugfs_root->d_iname,
+ loop_file_name);
+
+ return -ENOMEM;
+ }
+#endif
return 0;
}
@@ -249,6 +352,9 @@ void dpa_netdev_debugfs_remove(struct net_device *net_dev)
struct dpa_priv_s *priv = netdev_priv(net_dev);
debugfs_remove(priv->debugfs_file);
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ debugfs_remove(priv->debugfs_loop_file);
+#endif
}
static int __init dpa_debugfs_module_init(void)
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpa/dpaa_eth.c
index e6f50a5..1568e20 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth.c
@@ -108,6 +108,10 @@ static const char rtx[][3] = {
static uint8_t dpa_priv_common_bpid;
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+struct net_device *dpa_loop_netdevs[20];
+#endif
+
#ifdef CONFIG_PM
static int dpaa_suspend_noirq(struct device *dev)
@@ -855,6 +859,15 @@ static int dpa_priv_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
static const struct of_device_id dpa_match[];
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+static int dpa_new_loop_id(void)
+{
+ static int if_id;
+
+ return if_id++;
+}
+#endif
+
static int
dpaa_eth_priv_probe(struct platform_device *_of_dev)
{
@@ -906,6 +919,12 @@ dpaa_eth_priv_probe(struct platform_device *_of_dev)
priv->msg_enable = netif_msg_init(debug, -1);
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ priv->loop_id = dpa_new_loop_id();
+ priv->loop_to = -1; /* disabled by default */
+ dpa_loop_netdevs[priv->loop_id] = net_dev;
+#endif
+
mac_dev = dpa_mac_probe(_of_dev);
if (IS_ERR(mac_dev) || !mac_dev) {
err = PTR_ERR(mac_dev);
@@ -1119,6 +1138,10 @@ static int __init __cold dpa_load(void)
dpa_max_frm = fm_get_max_frm();
dpa_num_cpus = num_possible_cpus();
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ memset(dpa_loop_netdevs, 0, sizeof(dpa_loop_netdevs));
+#endif
+
_errno = platform_driver_register(&dpa_driver);
if (unlikely(_errno < 0)) {
pr_err(KBUILD_MODNAME
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth.h b/drivers/net/ethernet/freescale/dpa/dpaa_eth.h
index 8511826..ca5ad85 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth.h
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth.h
@@ -343,6 +343,9 @@ struct dpa_priv_s {
#ifdef CONFIG_FSL_DPAA_ETH_DEBUGFS
struct dentry *debugfs_file;
#endif /* CONFIG_FSL_DPAA_ETH_DEBUGFS */
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ struct dentry *debugfs_loop_file;
+#endif
uint32_t msg_enable; /* net_device message level */
#ifdef CONFIG_FSL_DPAA_1588
@@ -388,6 +391,10 @@ struct dpa_priv_s {
#ifdef CONFIG_PM
u32 wol;
#endif
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ int loop_id;
+ int loop_to;
+#endif
};
struct fm_port_fqs {
@@ -397,6 +404,11 @@ struct fm_port_fqs {
struct dpa_fq *rx_errq;
};
+
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+extern struct net_device *dpa_loop_netdevs[20];
+#endif
+
/* functions with different implementation for SG and non-SG: */
int dpa_bp_priv_seed(struct dpa_bp *dpa_bp);
int dpaa_eth_refill_bpools(struct dpa_bp *dpa_bp, int *count_ptr);
diff --git a/drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c b/drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c
index 91be76f..2b49ab0 100644
--- a/drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c
+++ b/drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c
@@ -519,6 +519,20 @@ static struct sk_buff *__hot sg_fd_to_skb(const struct dpa_priv_s *priv,
return skb;
}
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+static inline int dpa_skb_loop(const struct dpa_priv_s *priv,
+ struct sk_buff *skb)
+{
+ if (unlikely(priv->loop_to < 0))
+ return 0; /* loop disabled by default */
+
+ skb_push(skb, ETH_HLEN); /* compensate for eth_type_trans */
+ dpa_tx(skb, dpa_loop_netdevs[priv->loop_to]);
+
+ return 1; /* Frame Tx on the selected interface */
+}
+#endif
+
void __hot _dpa_rx(struct net_device *net_dev,
struct qman_portal *portal,
const struct dpa_priv_s *priv,
@@ -583,6 +597,14 @@ void __hot _dpa_rx(struct net_device *net_dev,
skb_len = skb->len;
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
+ if (dpa_skb_loop(priv, skb)) {
+ percpu_stats->rx_packets++;
+ percpu_stats->rx_bytes += skb_len;
+ return;
+ }
+#endif
+
if (use_gro) {
gro_result_t gro_result;
const struct qman_portal_config *pc =