diff options
-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 = |