diff options
Diffstat (limited to 'drivers/net/ethernet/ti')
| -rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 159 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/davinci_emac.c | 48 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/tlan.c | 4 | 
3 files changed, 170 insertions, 41 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index df32a090d08..7aebc0cb35e 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -126,6 +126,13 @@ do {								\  #define CPSW_FIFO_DUAL_MAC_MODE		(1 << 15)  #define CPSW_FIFO_RATE_LIMIT_MODE	(2 << 15) +#define CPSW_INTPACEEN		(0x3f << 16) +#define CPSW_INTPRESCALE_MASK	(0x7FF << 0) +#define CPSW_CMINTMAX_CNT	63 +#define CPSW_CMINTMIN_CNT	2 +#define CPSW_CMINTMAX_INTVL	(1000 / CPSW_CMINTMIN_CNT) +#define CPSW_CMINTMIN_INTVL	((1000 / CPSW_CMINTMAX_CNT) + 1) +  #define cpsw_enable_irq(priv)	\  	do {			\  		u32 i;		\ @@ -139,6 +146,10 @@ do {								\  			disable_irq_nosync(priv->irqs_table[i]); \  	} while (0); +#define cpsw_slave_index(priv)				\ +		((priv->data.dual_emac) ? priv->emac_port :	\ +		priv->data.active_slave) +  static int debug_level;  module_param(debug_level, int, 0);  MODULE_PARM_DESC(debug_level, "cpsw debug level (NETIF_MSG bits)"); @@ -160,6 +171,15 @@ struct cpsw_wr_regs {  	u32	rx_en;  	u32	tx_en;  	u32	misc_en; +	u32	mem_allign1[8]; +	u32	rx_thresh_stat; +	u32	rx_stat; +	u32	tx_stat; +	u32	misc_stat; +	u32	mem_allign2[8]; +	u32	rx_imax; +	u32	tx_imax; +  };  struct cpsw_ss_regs { @@ -314,6 +334,8 @@ struct cpsw_priv {  	struct cpsw_host_regs __iomem	*host_port_regs;  	u32				msg_enable;  	u32				version; +	u32				coal_intvl; +	u32				bus_freq_mhz;  	struct net_device_stats		stats;  	int				rx_packet_max;  	int				host_port; @@ -612,6 +634,77 @@ static void cpsw_adjust_link(struct net_device *ndev)  	}  } +static int cpsw_get_coalesce(struct net_device *ndev, +				struct ethtool_coalesce *coal) +{ +	struct cpsw_priv *priv = netdev_priv(ndev); + +	coal->rx_coalesce_usecs = priv->coal_intvl; +	return 0; +} + +static int cpsw_set_coalesce(struct net_device *ndev, +				struct ethtool_coalesce *coal) +{ +	struct cpsw_priv *priv = netdev_priv(ndev); +	u32 int_ctrl; +	u32 num_interrupts = 0; +	u32 prescale = 0; +	u32 addnl_dvdr = 1; +	u32 coal_intvl = 0; + +	if (!coal->rx_coalesce_usecs) +		return -EINVAL; + +	coal_intvl = coal->rx_coalesce_usecs; + +	int_ctrl =  readl(&priv->wr_regs->int_control); +	prescale = priv->bus_freq_mhz * 4; + +	if (coal_intvl < CPSW_CMINTMIN_INTVL) +		coal_intvl = CPSW_CMINTMIN_INTVL; + +	if (coal_intvl > CPSW_CMINTMAX_INTVL) { +		/* Interrupt pacer works with 4us Pulse, we can +		 * throttle further by dilating the 4us pulse. +		 */ +		addnl_dvdr = CPSW_INTPRESCALE_MASK / prescale; + +		if (addnl_dvdr > 1) { +			prescale *= addnl_dvdr; +			if (coal_intvl > (CPSW_CMINTMAX_INTVL * addnl_dvdr)) +				coal_intvl = (CPSW_CMINTMAX_INTVL +						* addnl_dvdr); +		} else { +			addnl_dvdr = 1; +			coal_intvl = CPSW_CMINTMAX_INTVL; +		} +	} + +	num_interrupts = (1000 * addnl_dvdr) / coal_intvl; +	writel(num_interrupts, &priv->wr_regs->rx_imax); +	writel(num_interrupts, &priv->wr_regs->tx_imax); + +	int_ctrl |= CPSW_INTPACEEN; +	int_ctrl &= (~CPSW_INTPRESCALE_MASK); +	int_ctrl |= (prescale & CPSW_INTPRESCALE_MASK); +	writel(int_ctrl, &priv->wr_regs->int_control); + +	cpsw_notice(priv, timer, "Set coalesce to %d usecs.\n", coal_intvl); +	if (priv->data.dual_emac) { +		int i; + +		for (i = 0; i < priv->data.slaves; i++) { +			priv = netdev_priv(priv->slaves[i].ndev); +			priv->coal_intvl = coal_intvl; +		} +	} else { +		priv->coal_intvl = coal_intvl; +	} + +	return 0; +} +  static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)  {  	static char *leader = "........................................"; @@ -834,6 +927,14 @@ static int cpsw_ndo_open(struct net_device *ndev)  		cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);  	} +	/* Enable Interrupt pacing if configured */ +	if (priv->coal_intvl != 0) { +		struct ethtool_coalesce coal; + +		coal.rx_coalesce_usecs = (priv->coal_intvl << 4); +		cpsw_set_coalesce(ndev, &coal); +	} +  	cpdma_ctlr_start(priv->dma);  	cpsw_intr_enable(priv);  	napi_enable(&priv->napi); @@ -942,7 +1043,7 @@ static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags)  static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)  { -	struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave]; +	struct cpsw_slave *slave = &priv->slaves[priv->data.active_slave];  	u32 ts_en, seq_id;  	if (!priv->cpts->tx_enable && !priv->cpts->rx_enable) { @@ -971,7 +1072,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)  	if (priv->data.dual_emac)  		slave = &priv->slaves[priv->emac_port];  	else -		slave = &priv->slaves[priv->data.cpts_active_slave]; +		slave = &priv->slaves[priv->data.active_slave];  	ctrl = slave_read(slave, CPSW2_CONTROL);  	ctrl &= ~CTRL_ALL_TS_MASK; @@ -1056,14 +1157,26 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)  static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)  { +	struct cpsw_priv *priv = netdev_priv(dev); +	struct mii_ioctl_data *data = if_mii(req); +	int slave_no = cpsw_slave_index(priv); +  	if (!netif_running(dev))  		return -EINVAL; +	switch (cmd) {  #ifdef CONFIG_TI_CPTS -	if (cmd == SIOCSHWTSTAMP) +	case SIOCSHWTSTAMP:  		return cpsw_hwtstamp_ioctl(dev, req);  #endif -	return -ENOTSUPP; +	case SIOCGMIIPHY: +		data->phy_id = priv->slaves[slave_no].phy->addr; +		break; +	default: +		return -ENOTSUPP; +	} + +	return 0;  }  static void cpsw_ndo_tx_timeout(struct net_device *ndev) @@ -1244,12 +1357,39 @@ static int cpsw_get_ts_info(struct net_device *ndev,  	return 0;  } +static int cpsw_get_settings(struct net_device *ndev, +			     struct ethtool_cmd *ecmd) +{ +	struct cpsw_priv *priv = netdev_priv(ndev); +	int slave_no = cpsw_slave_index(priv); + +	if (priv->slaves[slave_no].phy) +		return phy_ethtool_gset(priv->slaves[slave_no].phy, ecmd); +	else +		return -EOPNOTSUPP; +} + +static int cpsw_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) +{ +	struct cpsw_priv *priv = netdev_priv(ndev); +	int slave_no = cpsw_slave_index(priv); + +	if (priv->slaves[slave_no].phy) +		return phy_ethtool_sset(priv->slaves[slave_no].phy, ecmd); +	else +		return -EOPNOTSUPP; +} +  static const struct ethtool_ops cpsw_ethtool_ops = {  	.get_drvinfo	= cpsw_get_drvinfo,  	.get_msglevel	= cpsw_get_msglevel,  	.set_msglevel	= cpsw_set_msglevel,  	.get_link	= ethtool_op_get_link,  	.get_ts_info	= cpsw_get_ts_info, +	.get_settings	= cpsw_get_settings, +	.set_settings	= cpsw_set_settings, +	.get_coalesce	= cpsw_get_coalesce, +	.set_coalesce	= cpsw_set_coalesce,  };  static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, @@ -1282,12 +1422,12 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,  	}  	data->slaves = prop; -	if (of_property_read_u32(node, "cpts_active_slave", &prop)) { -		pr_err("Missing cpts_active_slave property in the DT.\n"); +	if (of_property_read_u32(node, "active_slave", &prop)) { +		pr_err("Missing active_slave property in the DT.\n");  		ret = -EINVAL;  		goto error_ret;  	} -	data->cpts_active_slave = prop; +	data->active_slave = prop;  	if (of_property_read_u32(node, "cpts_clock_mult", &prop)) {  		pr_err("Missing cpts_clock_mult property in the DT.\n"); @@ -1437,6 +1577,9 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,  	priv_sl2->slaves = priv->slaves;  	priv_sl2->clk = priv->clk; +	priv_sl2->coal_intvl = 0; +	priv_sl2->bus_freq_mhz = priv->bus_freq_mhz; +  	priv_sl2->cpsw_res = priv->cpsw_res;  	priv_sl2->regs = priv->regs;  	priv_sl2->host_port = priv->host_port; @@ -1546,6 +1689,8 @@ static int cpsw_probe(struct platform_device *pdev)  		ret = -ENODEV;  		goto clean_slave_ret;  	} +	priv->coal_intvl = 0; +	priv->bus_freq_mhz = clk_get_rate(priv->clk) / 1000000;  	priv->cpsw_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!priv->cpsw_res) { diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index ae1b77aa199..8121a3d5897 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1438,7 +1438,7 @@ static int emac_poll(struct napi_struct *napi, int budget)   * Polled functionality used by netconsole and others in non interrupt mode   *   */ -void emac_poll_controller(struct net_device *ndev) +static void emac_poll_controller(struct net_device *ndev)  {  	struct emac_priv *priv = netdev_priv(ndev); @@ -1865,21 +1865,18 @@ static int davinci_emac_probe(struct platform_device *pdev)  	/* obtain emac clock from kernel */ -	emac_clk = clk_get(&pdev->dev, NULL); +	emac_clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(emac_clk)) {  		dev_err(&pdev->dev, "failed to get EMAC clock\n");  		return -EBUSY;  	}  	emac_bus_frequency = clk_get_rate(emac_clk); -	clk_put(emac_clk);  	/* TODO: Probe PHY here if possible */  	ndev = alloc_etherdev(sizeof(struct emac_priv)); -	if (!ndev) { -		rc = -ENOMEM; -		goto no_ndev; -	} +	if (!ndev) +		return -ENOMEM;  	platform_set_drvdata(pdev, ndev);  	priv = netdev_priv(ndev); @@ -1893,7 +1890,7 @@ static int davinci_emac_probe(struct platform_device *pdev)  	if (!pdata) {  		dev_err(&pdev->dev, "no platform data\n");  		rc = -ENODEV; -		goto probe_quit; +		goto no_pdata;  	}  	/* MAC addr and PHY mask , RMII enable info from platform_data */ @@ -1913,23 +1910,23 @@ static int davinci_emac_probe(struct platform_device *pdev)  	if (!res) {  		dev_err(&pdev->dev,"error getting res\n");  		rc = -ENOENT; -		goto probe_quit; +		goto no_pdata;  	}  	priv->emac_base_phys = res->start + pdata->ctrl_reg_offset;  	size = resource_size(res); -	if (!request_mem_region(res->start, size, ndev->name)) { +	if (!devm_request_mem_region(&pdev->dev, res->start, +				     size, ndev->name)) {  		dev_err(&pdev->dev, "failed request_mem_region() for regs\n");  		rc = -ENXIO; -		goto probe_quit; +		goto no_pdata;  	} -	priv->remap_addr = ioremap(res->start, size); +	priv->remap_addr = devm_ioremap(&pdev->dev, res->start, size);  	if (!priv->remap_addr) {  		dev_err(&pdev->dev, "unable to map IO\n");  		rc = -ENOMEM; -		release_mem_region(res->start, size); -		goto probe_quit; +		goto no_pdata;  	}  	priv->emac_base = priv->remap_addr + pdata->ctrl_reg_offset;  	ndev->base_addr = (unsigned long)priv->remap_addr; @@ -1962,7 +1959,7 @@ static int davinci_emac_probe(struct platform_device *pdev)  	if (!priv->dma) {  		dev_err(&pdev->dev, "error initializing DMA\n");  		rc = -ENOMEM; -		goto no_dma; +		goto no_pdata;  	}  	priv->txchan = cpdma_chan_create(priv->dma, tx_chan_num(EMAC_DEF_TX_CH), @@ -1971,14 +1968,14 @@ static int davinci_emac_probe(struct platform_device *pdev)  				       emac_rx_handler);  	if (WARN_ON(!priv->txchan || !priv->rxchan)) {  		rc = -ENOMEM; -		goto no_irq_res; +		goto no_cpdma_chan;  	}  	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  	if (!res) {  		dev_err(&pdev->dev, "error getting irq res\n");  		rc = -ENOENT; -		goto no_irq_res; +		goto no_cpdma_chan;  	}  	ndev->irq = res->start; @@ -2000,7 +1997,7 @@ static int davinci_emac_probe(struct platform_device *pdev)  	if (rc) {  		dev_err(&pdev->dev, "error in register_netdev\n");  		rc = -ENODEV; -		goto no_irq_res; +		goto no_cpdma_chan;  	} @@ -2015,20 +2012,14 @@ static int davinci_emac_probe(struct platform_device *pdev)  	return 0; -no_irq_res: +no_cpdma_chan:  	if (priv->txchan)  		cpdma_chan_destroy(priv->txchan);  	if (priv->rxchan)  		cpdma_chan_destroy(priv->rxchan);  	cpdma_ctlr_destroy(priv->dma); -no_dma: -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	release_mem_region(res->start, resource_size(res)); -	iounmap(priv->remap_addr); - -probe_quit: +no_pdata:  	free_netdev(ndev); -no_ndev:  	return rc;  } @@ -2041,14 +2032,12 @@ no_ndev:   */  static int davinci_emac_remove(struct platform_device *pdev)  { -	struct resource *res;  	struct net_device *ndev = platform_get_drvdata(pdev);  	struct emac_priv *priv = netdev_priv(ndev);  	dev_notice(&ndev->dev, "DaVinci EMAC: davinci_emac_remove()\n");  	platform_set_drvdata(pdev, NULL); -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (priv->txchan)  		cpdma_chan_destroy(priv->txchan); @@ -2056,10 +2045,7 @@ static int davinci_emac_remove(struct platform_device *pdev)  		cpdma_chan_destroy(priv->rxchan);  	cpdma_ctlr_destroy(priv->dma); -	release_mem_region(res->start, resource_size(res)); -  	unregister_netdev(ndev); -	iounmap(priv->remap_addr);  	free_netdev(ndev);  	return 0; diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 22725386c5d..bdda36f8e54 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -1911,10 +1911,8 @@ static void tlan_reset_lists(struct net_device *dev)  		list->frame_size = TLAN_MAX_FRAME_SIZE;  		list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;  		skb = netdev_alloc_skb_ip_align(dev, TLAN_MAX_FRAME_SIZE + 5); -		if (!skb) { -			netdev_err(dev, "Out of memory for received data\n"); +		if (!skb)  			break; -		}  		list->buffer[0].address = pci_map_single(priv->pci_dev,  							 skb->data,  |