diff options
author | Madalin Bucur <madalin.bucur@freescale.com> | 2014-05-29 08:38:28 (GMT) |
---|---|---|
committer | Jose Rivera <German.Rivera@freescale.com> | 2014-06-03 17:46:02 (GMT) |
commit | cd24349709ec4b0e48e4de2b2024f50cf2a14862 (patch) | |
tree | 1762e6db7ffd6af27cc9b15d2c23bfb47300f33f /drivers/net/ethernet/freescale | |
parent | 043fa544a260d1884fccfaa908e588be8f1db1fc (diff) | |
download | linux-fsl-qoriq-cd24349709ec4b0e48e4de2b2024f50cf2a14862.tar.xz |
dpa_eth: add FSL_DPAA_DBG_LOOP debug option
Add debug option to divert traffic received on one DPAA interface
directly to another DPAA interface. By default this option is disabled.
When enabled special debugfs entries appear for each DPAA interface
that allow changing the divert state from disabled (-1) to enabled by
writing the Tx interface number in them.
Signed-off-by: Madalin Bucur <madalin.bucur@freescale.com>
Change-Id: I7c92d074980dadef55077e43616cb3caa2787838
Reviewed-on: http://git.am.freescale.net:8181/13043
Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com>
Reviewed-by: Cristian-Constantin Sovaiala <Cristian.Sovaiala@freescale.com>
Reviewed-by: Jose Rivera <German.Rivera@freescale.com>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r-- | drivers/net/ethernet/freescale/dpa/Kconfig | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/dpa/dpaa_debugfs.c | 106 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/dpa/dpaa_eth.c | 23 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/dpa/dpaa_eth.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/dpa/dpaa_eth_sg.c | 22 |
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 = |