| From ef0cc7d01f3eeca37c6bf864903af1c0cf0a792d Mon Sep 17 00:00:00 2001 | 
 | From: Ioana Radulescu <ruxandra.radulescu@nxp.com> | 
 | Date: Fri, 5 May 2017 18:11:08 +0300 | 
 | Subject: [PATCH] dpaa2-eth: Add Tx shaping support | 
 |  | 
 | Add support in sysfs for controlling DPNI Tx shaping | 
 | parameters: rate limit (in Mbps) and max burst size (in bytes). | 
 | The settings are per port. | 
 |  | 
 | TODO: See how to integrate Tx shaping support using | 
 | standard Linux tools (ethtool) | 
 |  | 
 | Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com> | 
 | Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com> | 
 | --- | 
 |  drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 80 ++++++++++++++++++++++++ | 
 |  drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h |  4 ++ | 
 |  2 files changed, 84 insertions(+) | 
 |  | 
 | --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 
 | +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 
 | @@ -3778,6 +3778,83 @@ const struct dcbnl_rtnl_ops dpaa2_eth_dc | 
 |  }; | 
 |  #endif | 
 |   | 
 | +/* SysFS support */ | 
 | +static ssize_t dpaa2_eth_show_tx_shaping(struct device *dev, | 
 | +					 struct device_attribute *attr, | 
 | +					 char *buf) | 
 | +{ | 
 | +	struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); | 
 | +	/* No MC API for getting the shaping config. We're stateful. */ | 
 | +	struct dpni_tx_shaping_cfg *scfg = &priv->shaping_cfg; | 
 | + | 
 | +	return sprintf(buf, "%u %hu\n", scfg->rate_limit, scfg->max_burst_size); | 
 | +} | 
 | + | 
 | +static ssize_t dpaa2_eth_write_tx_shaping(struct device *dev, | 
 | +					  struct device_attribute *attr, | 
 | +					  const char *buf, | 
 | +					  size_t count) | 
 | +{ | 
 | +	int err, items; | 
 | +	struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); | 
 | +	struct dpni_tx_shaping_cfg scfg; | 
 | + | 
 | +	items = sscanf(buf, "%u %hu", &scfg.rate_limit, &scfg.max_burst_size); | 
 | +	if (items != 2) { | 
 | +		pr_err("Expected format: \"rate_limit(Mbps) max_burst_size(bytes)\"\n"); | 
 | +		return -EINVAL; | 
 | +	} | 
 | +	/* Size restriction as per MC API documentation */ | 
 | +	if (scfg.max_burst_size > DPAA2_ETH_MAX_BURST_SIZE) { | 
 | +		pr_err("max_burst_size must be <= %d\n", | 
 | +		       DPAA2_ETH_MAX_BURST_SIZE); | 
 | +		return -EINVAL; | 
 | +	} | 
 | + | 
 | +	err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, &scfg); | 
 | +	if (err) { | 
 | +		dev_err(dev, "dpni_set_tx_shaping() failed\n"); | 
 | +		return -EPERM; | 
 | +	} | 
 | +	/* If successful, save the current configuration for future inquiries */ | 
 | +	priv->shaping_cfg = scfg; | 
 | + | 
 | +	return count; | 
 | +} | 
 | + | 
 | +static struct device_attribute dpaa2_eth_attrs[] = { | 
 | +	__ATTR(tx_shaping, | 
 | +	       0600, | 
 | +	       dpaa2_eth_show_tx_shaping, | 
 | +	       dpaa2_eth_write_tx_shaping), | 
 | +}; | 
 | + | 
 | +static void dpaa2_eth_sysfs_init(struct device *dev) | 
 | +{ | 
 | +	int i, err; | 
 | + | 
 | +	for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++) { | 
 | +		err = device_create_file(dev, &dpaa2_eth_attrs[i]); | 
 | +		if (err) { | 
 | +			dev_err(dev, "ERROR creating sysfs file\n"); | 
 | +			goto undo; | 
 | +		} | 
 | +	} | 
 | +	return; | 
 | + | 
 | +undo: | 
 | +	while (i > 0) | 
 | +		device_remove_file(dev, &dpaa2_eth_attrs[--i]); | 
 | +} | 
 | + | 
 | +static void dpaa2_eth_sysfs_remove(struct device *dev) | 
 | +{ | 
 | +	int i; | 
 | + | 
 | +	for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++) | 
 | +		device_remove_file(dev, &dpaa2_eth_attrs[i]); | 
 | +} | 
 | + | 
 |  static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) | 
 |  { | 
 |  	struct device *dev; | 
 | @@ -3897,6 +3974,7 @@ static int dpaa2_eth_probe(struct fsl_mc | 
 |  #ifdef CONFIG_DEBUG_FS | 
 |  	dpaa2_dbg_add(priv); | 
 |  #endif | 
 | +	dpaa2_eth_sysfs_init(&net_dev->dev); | 
 |   | 
 |  	dev_info(dev, "Probed interface %s\n", net_dev->name); | 
 |  	return 0; | 
 | @@ -3944,6 +4022,8 @@ static int dpaa2_eth_remove(struct fsl_m | 
 |  #ifdef CONFIG_DEBUG_FS | 
 |  	dpaa2_dbg_remove(priv); | 
 |  #endif | 
 | +	dpaa2_eth_sysfs_remove(&net_dev->dev); | 
 | + | 
 |  	unregister_netdev(net_dev); | 
 |   | 
 |  	if (priv->do_link_poll) | 
 | --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 
 | +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 
 | @@ -42,6 +42,9 @@ | 
 |   */ | 
 |  #define DPAA2_ETH_FQ_TAILDROP_THRESH	(1024 * 1024) | 
 |   | 
 | +/* Maximum burst size value for Tx shaping */ | 
 | +#define DPAA2_ETH_MAX_BURST_SIZE	0xF7FF | 
 | + | 
 |  /* Maximum number of Tx confirmation frames to be processed | 
 |   * in a single NAPI call | 
 |   */ | 
 | @@ -445,6 +448,7 @@ struct dpaa2_eth_priv { | 
 |  #ifdef CONFIG_DEBUG_FS | 
 |  	struct dpaa2_debugfs dbg; | 
 |  #endif | 
 | +	struct dpni_tx_shaping_cfg shaping_cfg; | 
 |  }; | 
 |   | 
 |  #define DPAA2_RXH_SUPPORTED	(RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \ |