diff options
Diffstat (limited to 'drivers/net/ethernet/ti')
| -rw-r--r-- | drivers/net/ethernet/ti/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/Makefile | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/cpmac.c | 15 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/cpsw-phy-sel.c | 221 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 536 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/cpsw.h | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.c | 18 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.h | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/cpts.c | 24 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/cpts.h | 9 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/davinci_cpdma.c | 50 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/davinci_emac.c | 91 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/davinci_mdio.c | 52 | ||||
| -rw-r--r-- | drivers/net/ethernet/ti/tlan.c | 1 | 
14 files changed, 658 insertions, 372 deletions
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index de71b1ec462..53150c25a96 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -49,11 +49,19 @@ config TI_DAVINCI_CPDMA  	  To compile this driver as a module, choose M here: the module  	  will be called davinci_cpdma.  This is recommended. +config TI_CPSW_PHY_SEL +	boolean "TI CPSW Switch Phy sel Support" +	depends on TI_CPSW +	---help--- +	  This driver supports configuring of the phy mode connected to +	  the CPSW. +  config TI_CPSW  	tristate "TI CPSW Switch Support"  	depends on ARM && (ARCH_DAVINCI || SOC_AM33XX)  	select TI_DAVINCI_CPDMA  	select TI_DAVINCI_MDIO +	select TI_CPSW_PHY_SEL  	---help---  	  This driver supports TI's CPSW Ethernet Switch. diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index c65148e8aa1..9cfaab8152b 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -7,5 +7,6 @@ obj-$(CONFIG_CPMAC) += cpmac.o  obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o  obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o  obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o +obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o  obj-$(CONFIG_TI_CPSW) += ti_cpsw.o  ti_cpsw-y := cpsw_ale.o cpsw.o cpts.o diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index 2dc16b6efaf..7399a52f7c2 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -17,7 +17,6 @@   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/moduleparam.h> @@ -314,19 +313,6 @@ static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, };  static struct mii_bus *cpmac_mii; -static int cpmac_config(struct net_device *dev, struct ifmap *map) -{ -	if (dev->flags & IFF_UP) -		return -EBUSY; - -	/* Don't allow changing the I/O address */ -	if (map->base_addr != dev->base_addr) -		return -EOPNOTSUPP; - -	/* ignore other fields */ -	return 0; -} -  static void cpmac_set_multicast_list(struct net_device *dev)  {  	struct netdev_hw_addr *ha; @@ -1101,7 +1087,6 @@ static const struct net_device_ops cpmac_netdev_ops = {  	.ndo_tx_timeout		= cpmac_tx_timeout,  	.ndo_set_rx_mode	= cpmac_set_multicast_list,  	.ndo_do_ioctl		= cpmac_ioctl, -	.ndo_set_config		= cpmac_config,  	.ndo_change_mtu		= eth_change_mtu,  	.ndo_validate_addr	= eth_validate_addr,  	.ndo_set_mac_address	= eth_mac_addr, diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c new file mode 100644 index 00000000000..aa8bf45e53d --- /dev/null +++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c @@ -0,0 +1,221 @@ +/* Texas Instruments Ethernet Switch Driver + * + * Copyright (C) 2013 Texas Instruments + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/phy.h> +#include <linux/of.h> +#include <linux/of_device.h> + +#include "cpsw.h" + +/* AM33xx SoC specific definitions for the CONTROL port */ +#define AM33XX_GMII_SEL_MODE_MII	0 +#define AM33XX_GMII_SEL_MODE_RMII	1 +#define AM33XX_GMII_SEL_MODE_RGMII	2 + +#define AM33XX_GMII_SEL_RMII2_IO_CLK_EN	BIT(7) +#define AM33XX_GMII_SEL_RMII1_IO_CLK_EN	BIT(6) + +#define GMII_SEL_MODE_MASK		0x3 + +struct cpsw_phy_sel_priv { +	struct device	*dev; +	u32 __iomem	*gmii_sel; +	bool		rmii_clock_external; +	void (*cpsw_phy_sel)(struct cpsw_phy_sel_priv *priv, +			     phy_interface_t phy_mode, int slave); +}; + + +static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv, +				 phy_interface_t phy_mode, int slave) +{ +	u32 reg; +	u32 mask; +	u32 mode = 0; + +	reg = readl(priv->gmii_sel); + +	switch (phy_mode) { +	case PHY_INTERFACE_MODE_RMII: +		mode = AM33XX_GMII_SEL_MODE_RMII; +		break; + +	case PHY_INTERFACE_MODE_RGMII: +	case PHY_INTERFACE_MODE_RGMII_ID: +	case PHY_INTERFACE_MODE_RGMII_RXID: +	case PHY_INTERFACE_MODE_RGMII_TXID: +		mode = AM33XX_GMII_SEL_MODE_RGMII; +		break; + +	case PHY_INTERFACE_MODE_MII: +	default: +		mode = AM33XX_GMII_SEL_MODE_MII; +		break; +	}; + +	mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6); +	mode <<= slave * 2; + +	if (priv->rmii_clock_external) { +		if (slave == 0) +			mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN; +		else +			mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN; +	} + +	reg &= ~mask; +	reg |= mode; + +	writel(reg, priv->gmii_sel); +} + +static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv, +				 phy_interface_t phy_mode, int slave) +{ +	u32 reg; +	u32 mask; +	u32 mode = 0; + +	reg = readl(priv->gmii_sel); + +	switch (phy_mode) { +	case PHY_INTERFACE_MODE_RMII: +		mode = AM33XX_GMII_SEL_MODE_RMII; +		break; + +	case PHY_INTERFACE_MODE_RGMII: +	case PHY_INTERFACE_MODE_RGMII_ID: +	case PHY_INTERFACE_MODE_RGMII_RXID: +	case PHY_INTERFACE_MODE_RGMII_TXID: +		mode = AM33XX_GMII_SEL_MODE_RGMII; +		break; + +	case PHY_INTERFACE_MODE_MII: +	default: +		mode = AM33XX_GMII_SEL_MODE_MII; +		break; +	}; + +	switch (slave) { +	case 0: +		mask = GMII_SEL_MODE_MASK; +		break; +	case 1: +		mask = GMII_SEL_MODE_MASK << 4; +		mode <<= 4; +		break; +	default: +		dev_err(priv->dev, "invalid slave number...\n"); +		return; +	} + +	if (priv->rmii_clock_external) +		dev_err(priv->dev, "RMII External clock is not supported\n"); + +	reg &= ~mask; +	reg |= mode; + +	writel(reg, priv->gmii_sel); +} + +static struct platform_driver cpsw_phy_sel_driver; +static int match(struct device *dev, void *data) +{ +	struct device_node *node = (struct device_node *)data; +	return dev->of_node == node && +		dev->driver == &cpsw_phy_sel_driver.driver; +} + +void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave) +{ +	struct device_node *node; +	struct cpsw_phy_sel_priv *priv; + +	node = of_get_child_by_name(dev->of_node, "cpsw-phy-sel"); +	if (!node) { +		dev_err(dev, "Phy mode driver DT not found\n"); +		return; +	} + +	dev = bus_find_device(&platform_bus_type, NULL, node, match); +	priv = dev_get_drvdata(dev); + +	priv->cpsw_phy_sel(priv, phy_mode, slave); +} +EXPORT_SYMBOL_GPL(cpsw_phy_sel); + +static const struct of_device_id cpsw_phy_sel_id_table[] = { +	{ +		.compatible	= "ti,am3352-cpsw-phy-sel", +		.data		= &cpsw_gmii_sel_am3352, +	}, +	{ +		.compatible	= "ti,dra7xx-cpsw-phy-sel", +		.data		= &cpsw_gmii_sel_dra7xx, +	}, +	{ +		.compatible	= "ti,am43xx-cpsw-phy-sel", +		.data		= &cpsw_gmii_sel_am3352, +	}, +	{} +}; +MODULE_DEVICE_TABLE(of, cpsw_phy_sel_id_table); + +static int cpsw_phy_sel_probe(struct platform_device *pdev) +{ +	struct resource	*res; +	const struct of_device_id *of_id; +	struct cpsw_phy_sel_priv *priv; + +	of_id = of_match_node(cpsw_phy_sel_id_table, pdev->dev.of_node); +	if (!of_id) +		return -EINVAL; + +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) { +		dev_err(&pdev->dev, "unable to alloc memory for cpsw phy sel\n"); +		return -ENOMEM; +	} + +	priv->dev = &pdev->dev; +	priv->cpsw_phy_sel = of_id->data; + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gmii-sel"); +	priv->gmii_sel = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(priv->gmii_sel)) +		return PTR_ERR(priv->gmii_sel); + +	if (of_find_property(pdev->dev.of_node, "rmii-clock-ext", NULL)) +		priv->rmii_clock_external = true; + +	dev_set_drvdata(&pdev->dev, priv); + +	return 0; +} + +static struct platform_driver cpsw_phy_sel_driver = { +	.probe		= cpsw_phy_sel_probe, +	.driver		= { +		.name	= "cpsw-phy-sel", +		.owner	= THIS_MODULE, +		.of_match_table = cpsw_phy_sel_id_table, +	}, +}; + +module_platform_driver(cpsw_phy_sel_driver); +MODULE_AUTHOR("Mugunthan V N <mugunthanvnm@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 804846eb5fc..b988d16cd34 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -143,13 +143,13 @@ do {								\  		u32 i;		\  		for (i = 0; i < priv->num_irqs; i++) \  			enable_irq(priv->irqs_table[i]); \ -	} while (0); +	} while (0)  #define cpsw_disable_irq(priv)	\  	do {			\  		u32 i;		\  		for (i = 0; i < priv->num_irqs; i++) \  			disable_irq_nosync(priv->irqs_table[i]); \ -	} while (0); +	} while (0)  #define cpsw_slave_index(priv)				\  		((priv->data.dual_emac) ? priv->emac_port :	\ @@ -248,20 +248,31 @@ struct cpsw_ss_regs {  #define TS_131              (1<<11) /* Time Sync Dest IP Addr 131 enable */  #define TS_130              (1<<10) /* Time Sync Dest IP Addr 130 enable */  #define TS_129              (1<<9)  /* Time Sync Dest IP Addr 129 enable */ -#define TS_BIT8             (1<<8)  /* ts_ttl_nonzero? */ +#define TS_TTL_NONZERO      (1<<8)  /* Time Sync Time To Live Non-zero enable */ +#define TS_ANNEX_F_EN       (1<<6)  /* Time Sync Annex F enable */  #define TS_ANNEX_D_EN       (1<<4)  /* Time Sync Annex D enable */  #define TS_LTYPE2_EN        (1<<3)  /* Time Sync LTYPE 2 enable */  #define TS_LTYPE1_EN        (1<<2)  /* Time Sync LTYPE 1 enable */  #define TS_TX_EN            (1<<1)  /* Time Sync Transmit Enable */  #define TS_RX_EN            (1<<0)  /* Time Sync Receive Enable */ -#define CTRL_TS_BITS \ -	(TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 | TS_BIT8 | \ -	 TS_ANNEX_D_EN | TS_LTYPE1_EN) +#define CTRL_V2_TS_BITS \ +	(TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 |\ +	 TS_TTL_NONZERO  | TS_ANNEX_D_EN | TS_LTYPE1_EN) + +#define CTRL_V2_ALL_TS_MASK (CTRL_V2_TS_BITS | TS_TX_EN | TS_RX_EN) +#define CTRL_V2_TX_TS_BITS  (CTRL_V2_TS_BITS | TS_TX_EN) +#define CTRL_V2_RX_TS_BITS  (CTRL_V2_TS_BITS | TS_RX_EN) + + +#define CTRL_V3_TS_BITS \ +	(TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 |\ +	 TS_TTL_NONZERO | TS_ANNEX_F_EN | TS_ANNEX_D_EN |\ +	 TS_LTYPE1_EN) -#define CTRL_ALL_TS_MASK (CTRL_TS_BITS | TS_TX_EN | TS_RX_EN) -#define CTRL_TX_TS_BITS  (CTRL_TS_BITS | TS_TX_EN) -#define CTRL_RX_TS_BITS  (CTRL_TS_BITS | TS_RX_EN) +#define CTRL_V3_ALL_TS_MASK (CTRL_V3_TS_BITS | TS_TX_EN | TS_RX_EN) +#define CTRL_V3_TX_TS_BITS  (CTRL_V3_TS_BITS | TS_TX_EN) +#define CTRL_V3_RX_TS_BITS  (CTRL_V3_TS_BITS | TS_RX_EN)  /* Bit definitions for the CPSW2_TS_SEQ_MTYPE register */  #define TS_SEQ_ID_OFFSET_SHIFT   (16)    /* Time Sync Sequence ID Offset */ @@ -367,8 +378,6 @@ struct cpsw_priv {  	spinlock_t			lock;  	struct platform_device		*pdev;  	struct net_device		*ndev; -	struct resource			*cpsw_res; -	struct resource			*cpsw_wr_res;  	struct napi_struct		napi;  	struct device			*dev;  	struct cpsw_platform_data	data; @@ -380,7 +389,6 @@ struct cpsw_priv {  	u32				version;  	u32				coal_intvl;  	u32				bus_freq_mhz; -	struct net_device_stats		stats;  	int				rx_packet_max;  	int				host_port;  	struct clk			*clk; @@ -543,14 +551,93 @@ static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)  		return slave_num;  } +static void cpsw_set_promiscious(struct net_device *ndev, bool enable) +{ +	struct cpsw_priv *priv = netdev_priv(ndev); +	struct cpsw_ale *ale = priv->ale; +	int i; + +	if (priv->data.dual_emac) { +		bool flag = false; + +		/* Enabling promiscuous mode for one interface will be +		 * common for both the interface as the interface shares +		 * the same hardware resource. +		 */ +		for (i = 0; i < priv->data.slaves; i++) +			if (priv->slaves[i].ndev->flags & IFF_PROMISC) +				flag = true; + +		if (!enable && flag) { +			enable = true; +			dev_err(&ndev->dev, "promiscuity not disabled as the other interface is still in promiscuity mode\n"); +		} + +		if (enable) { +			/* Enable Bypass */ +			cpsw_ale_control_set(ale, 0, ALE_BYPASS, 1); + +			dev_dbg(&ndev->dev, "promiscuity enabled\n"); +		} else { +			/* Disable Bypass */ +			cpsw_ale_control_set(ale, 0, ALE_BYPASS, 0); +			dev_dbg(&ndev->dev, "promiscuity disabled\n"); +		} +	} else { +		if (enable) { +			unsigned long timeout = jiffies + HZ; + +			/* Disable Learn for all ports */ +			for (i = 0; i < priv->data.slaves; i++) { +				cpsw_ale_control_set(ale, i, +						     ALE_PORT_NOLEARN, 1); +				cpsw_ale_control_set(ale, i, +						     ALE_PORT_NO_SA_UPDATE, 1); +			} + +			/* Clear All Untouched entries */ +			cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1); +			do { +				cpu_relax(); +				if (cpsw_ale_control_get(ale, 0, ALE_AGEOUT)) +					break; +			} while (time_after(timeout, jiffies)); +			cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1); + +			/* Clear all mcast from ALE */ +			cpsw_ale_flush_multicast(ale, ALE_ALL_PORTS << +						 priv->host_port); + +			/* Flood All Unicast Packets to Host port */ +			cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1); +			dev_dbg(&ndev->dev, "promiscuity enabled\n"); +		} else { +			/* Flood All Unicast Packets to Host port */ +			cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 0); + +			/* Enable Learn for all ports */ +			for (i = 0; i < priv->data.slaves; i++) { +				cpsw_ale_control_set(ale, i, +						     ALE_PORT_NOLEARN, 0); +				cpsw_ale_control_set(ale, i, +						     ALE_PORT_NO_SA_UPDATE, 0); +			} +			dev_dbg(&ndev->dev, "promiscuity disabled\n"); +		} +	} +} +  static void cpsw_ndo_set_rx_mode(struct net_device *ndev)  {  	struct cpsw_priv *priv = netdev_priv(ndev);  	if (ndev->flags & IFF_PROMISC) {  		/* Enable promiscuous mode */ -		dev_err(priv->dev, "Ignoring Promiscuous mode\n"); +		cpsw_set_promiscious(ndev, true);  		return; +	} else { +		/* Disable promiscuous mode */ +		cpsw_set_promiscious(ndev, false);  	}  	/* Clear all mcast from ALE */ @@ -584,7 +671,7 @@ static void cpsw_intr_disable(struct cpsw_priv *priv)  	return;  } -void cpsw_tx_handler(void *token, int len, int status) +static void cpsw_tx_handler(void *token, int len, int status)  {  	struct sk_buff		*skb = token;  	struct net_device	*ndev = skb->dev; @@ -596,12 +683,12 @@ void cpsw_tx_handler(void *token, int len, int status)  	if (unlikely(netif_queue_stopped(ndev)))  		netif_wake_queue(ndev);  	cpts_tx_timestamp(priv->cpts, skb); -	priv->stats.tx_packets++; -	priv->stats.tx_bytes += len; +	ndev->stats.tx_packets++; +	ndev->stats.tx_bytes += len;  	dev_kfree_skb_any(skb);  } -void cpsw_rx_handler(void *token, int len, int status) +static void cpsw_rx_handler(void *token, int len, int status)  {  	struct sk_buff		*skb = token;  	struct sk_buff		*new_skb; @@ -611,7 +698,7 @@ void cpsw_rx_handler(void *token, int len, int status)  	cpsw_dual_emac_src_port_detect(status, priv, ndev, skb); -	if (unlikely(status < 0)) { +	if (unlikely(status < 0) || unlikely(!netif_running(ndev))) {  		/* the interface is going down, skbs are purged */  		dev_kfree_skb_any(skb);  		return; @@ -623,10 +710,10 @@ void cpsw_rx_handler(void *token, int len, int status)  		cpts_rx_timestamp(priv->cpts, skb);  		skb->protocol = eth_type_trans(skb, ndev);  		netif_receive_skb(skb); -		priv->stats.rx_bytes += len; -		priv->stats.rx_packets++; +		ndev->stats.rx_bytes += len; +		ndev->stats.rx_packets++;  	} else { -		priv->stats.rx_dropped++; +		ndev->stats.rx_dropped++;  		new_skb = skb;  	} @@ -639,13 +726,6 @@ void cpsw_rx_handler(void *token, int len, int status)  static irqreturn_t cpsw_interrupt(int irq, void *dev_id)  {  	struct cpsw_priv *priv = dev_id; -	u32 rx, tx, rx_thresh; - -	rx_thresh = __raw_readl(&priv->wr_regs->rx_thresh_stat); -	rx = __raw_readl(&priv->wr_regs->rx_stat); -	tx = __raw_readl(&priv->wr_regs->tx_stat); -	if (!rx_thresh && !rx && !tx) -		return IRQ_NONE;  	cpsw_intr_disable(priv);  	if (priv->irq_enabled == true) { @@ -749,6 +829,8 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave,  		/* set speed_in input in case RMII mode is used in 100Mbps */  		if (phy->speed == 100)  			mac_control |= BIT(15); +		else if (phy->speed == 10) +			mac_control |= BIT(18); /* In Band mode */  		*link = true;  	} else { @@ -976,14 +1058,19 @@ static inline void cpsw_add_dual_emac_def_ale_entries(  		priv->host_port, ALE_VLAN, slave->port_vlan);  } -static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) +static void soft_reset_slave(struct cpsw_slave *slave)  {  	char name[32]; -	u32 slave_port; - -	sprintf(name, "slave-%d", slave->slave_num); +	snprintf(name, sizeof(name), "slave-%d", slave->slave_num);  	soft_reset(name, &slave->sliver->soft_reset); +} + +static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) +{ +	u32 slave_port; + +	soft_reset_slave(slave);  	/* setup priority mapping */  	__raw_writel(RX_PRIORITY_MAPPING, &slave->sliver->rx_pri_map); @@ -1023,6 +1110,10 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)  		dev_info(priv->dev, "phy found : id is : 0x%x\n",  			 slave->phy->phy_id);  		phy_start(slave->phy); + +		/* Configure GMII_SEL register */ +		cpsw_phy_sel(&priv->pdev->dev, slave->phy->interface, +			     slave->slave_num);  	}  } @@ -1083,11 +1174,17 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)  static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)  { +	u32 slave_port; + +	slave_port = cpsw_get_slave_port(priv, slave->slave_num); +  	if (!slave->phy)  		return;  	phy_stop(slave->phy);  	phy_disconnect(slave->phy);  	slave->phy = NULL; +	cpsw_ale_control_set(priv->ale, slave_port, +			     ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);  }  static int cpsw_ndo_open(struct net_device *ndev) @@ -1117,6 +1214,10 @@ static int cpsw_ndo_open(struct net_device *ndev)  	/* Add default VLAN */  	if (!priv->data.dual_emac)  		cpsw_add_default_vlan(priv); +	else +		cpsw_ale_add_vlan(priv->ale, priv->data.default_vlan, +				  ALE_ALL_PORTS << priv->host_port, +				  ALE_ALL_PORTS << priv->host_port, 0, 0);  	if (!cpsw_common_res_usage_state(priv)) {  		/* setup tx dma to fixed prio and zero offset */ @@ -1151,6 +1252,12 @@ static int cpsw_ndo_open(struct net_device *ndev)  		 * receive descs  		 */  		cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i); + +		if (cpts_register(&priv->pdev->dev, priv->cpts, +				  priv->data.cpts_clock_mult, +				  priv->data.cpts_clock_shift)) +			dev_err(priv->dev, "error registering cpts device\n"); +  	}  	/* Enable Interrupt pacing if configured */ @@ -1161,6 +1268,12 @@ static int cpsw_ndo_open(struct net_device *ndev)  		cpsw_set_coalesce(ndev, &coal);  	} +	napi_enable(&priv->napi); +	cpdma_ctlr_start(priv->dma); +	cpsw_intr_enable(priv); +	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); +	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); +  	prim_cpsw = cpsw_get_slave_priv(priv, 0);  	if (prim_cpsw->irq_enabled == false) {  		if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) { @@ -1169,12 +1282,6 @@ static int cpsw_ndo_open(struct net_device *ndev)  		}  	} -	cpdma_ctlr_start(priv->dma); -	cpsw_intr_enable(priv); -	napi_enable(&priv->napi); -	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); -	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); -  	if (priv->data.dual_emac)  		priv->slaves[priv->emac_port].open_stat = true;  	return 0; @@ -1197,6 +1304,7 @@ static int cpsw_ndo_stop(struct net_device *ndev)  	netif_carrier_off(priv->ndev);  	if (cpsw_common_res_usage_state(priv) <= 1) { +		cpts_unregister(priv->cpts);  		cpsw_intr_disable(priv);  		cpdma_ctlr_int_ctrl(priv->dma, false);  		cpdma_ctlr_stop(priv->dma); @@ -1219,7 +1327,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,  	if (skb_padto(skb, CPSW_MIN_PACKET_SIZE)) {  		cpsw_err(priv, tx_err, "packet pad failed\n"); -		priv->stats.tx_dropped++; +		ndev->stats.tx_dropped++;  		return NETDEV_TX_OK;  	} @@ -1243,34 +1351,11 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,  	return NETDEV_TX_OK;  fail: -	priv->stats.tx_dropped++; +	ndev->stats.tx_dropped++;  	netif_stop_queue(ndev);  	return NETDEV_TX_BUSY;  } -static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags) -{ -	/* -	 * The switch cannot operate in promiscuous mode without substantial -	 * headache.  For promiscuous mode to work, we would need to put the -	 * ALE in bypass mode and route all traffic to the host port. -	 * Subsequently, the host will need to operate as a "bridge", learn, -	 * and flood as needed.  For now, we simply complain here and -	 * do nothing about it :-) -	 */ -	if ((flags & IFF_PROMISC) && (ndev->flags & IFF_PROMISC)) -		dev_err(&ndev->dev, "promiscuity ignored!\n"); - -	/* -	 * The switch cannot filter multicast traffic unless it is configured -	 * in "VLAN Aware" mode.  Unfortunately, VLAN awareness requires a -	 * whole bunch of additional logic that this driver does not implement -	 * at present. -	 */ -	if ((flags & IFF_ALLMULTI) && !(ndev->flags & IFF_ALLMULTI)) -		dev_err(&ndev->dev, "multicast traffic cannot be filtered!\n"); -} -  #ifdef CONFIG_TI_CPTS  static void cpsw_hwtstamp_v1(struct cpsw_priv *priv) @@ -1307,13 +1392,27 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)  		slave = &priv->slaves[priv->data.active_slave];  	ctrl = slave_read(slave, CPSW2_CONTROL); -	ctrl &= ~CTRL_ALL_TS_MASK; +	switch (priv->version) { +	case CPSW_VERSION_2: +		ctrl &= ~CTRL_V2_ALL_TS_MASK; -	if (priv->cpts->tx_enable) -		ctrl |= CTRL_TX_TS_BITS; +		if (priv->cpts->tx_enable) +			ctrl |= CTRL_V2_TX_TS_BITS; -	if (priv->cpts->rx_enable) -		ctrl |= CTRL_RX_TS_BITS; +		if (priv->cpts->rx_enable) +			ctrl |= CTRL_V2_RX_TS_BITS; +	break; +	case CPSW_VERSION_3: +	default: +		ctrl &= ~CTRL_V3_ALL_TS_MASK; + +		if (priv->cpts->tx_enable) +			ctrl |= CTRL_V3_TX_TS_BITS; + +		if (priv->cpts->rx_enable) +			ctrl |= CTRL_V3_RX_TS_BITS; +	break; +	}  	mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS; @@ -1322,12 +1421,17 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)  	__raw_writel(ETH_P_1588, &priv->regs->ts_ltype);  } -static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) +static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)  {  	struct cpsw_priv *priv = netdev_priv(dev);  	struct cpts *cpts = priv->cpts;  	struct hwtstamp_config cfg; +	if (priv->version != CPSW_VERSION_1 && +	    priv->version != CPSW_VERSION_2 && +	    priv->version != CPSW_VERSION_3) +		return -EOPNOTSUPP; +  	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))  		return -EFAULT; @@ -1335,16 +1439,8 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)  	if (cfg.flags)  		return -EINVAL; -	switch (cfg.tx_type) { -	case HWTSTAMP_TX_OFF: -		cpts->tx_enable = 0; -		break; -	case HWTSTAMP_TX_ON: -		cpts->tx_enable = 1; -		break; -	default: +	if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON)  		return -ERANGE; -	}  	switch (cfg.rx_filter) {  	case HWTSTAMP_FILTER_NONE: @@ -1371,26 +1467,47 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)  		return -ERANGE;  	} +	cpts->tx_enable = cfg.tx_type == HWTSTAMP_TX_ON; +  	switch (priv->version) {  	case CPSW_VERSION_1:  		cpsw_hwtstamp_v1(priv);  		break;  	case CPSW_VERSION_2: +	case CPSW_VERSION_3:  		cpsw_hwtstamp_v2(priv);  		break;  	default: -		return -ENOTSUPP; +		WARN_ON(1);  	}  	return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;  } +static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +{ +	struct cpsw_priv *priv = netdev_priv(dev); +	struct cpts *cpts = priv->cpts; +	struct hwtstamp_config cfg; + +	if (priv->version != CPSW_VERSION_1 && +	    priv->version != CPSW_VERSION_2 && +	    priv->version != CPSW_VERSION_3) +		return -EOPNOTSUPP; + +	cfg.flags = 0; +	cfg.tx_type = cpts->tx_enable ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; +	cfg.rx_filter = (cpts->rx_enable ? +			 HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE); + +	return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} +  #endif /*CONFIG_TI_CPTS*/  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)) @@ -1399,16 +1516,15 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)  	switch (cmd) {  #ifdef CONFIG_TI_CPTS  	case SIOCSHWTSTAMP: -		return cpsw_hwtstamp_ioctl(dev, req); +		return cpsw_hwtstamp_set(dev, req); +	case SIOCGHWTSTAMP: +		return cpsw_hwtstamp_get(dev, req);  #endif -	case SIOCGMIIPHY: -		data->phy_id = priv->slaves[slave_no].phy->addr; -		break; -	default: -		return -ENOTSUPP;  	} -	return 0; +	if (!priv->slaves[slave_no].phy) +		return -EOPNOTSUPP; +	return phy_mii_ioctl(priv->slaves[slave_no].phy, req, cmd);  }  static void cpsw_ndo_tx_timeout(struct net_device *ndev) @@ -1416,7 +1532,7 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)  	struct cpsw_priv *priv = netdev_priv(ndev);  	cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n"); -	priv->stats.tx_errors++; +	ndev->stats.tx_errors++;  	cpsw_intr_disable(priv);  	cpdma_ctlr_int_ctrl(priv->dma, false);  	cpdma_chan_stop(priv->txch); @@ -1455,12 +1571,6 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p)  	return 0;  } -static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev) -{ -	struct cpsw_priv *priv = netdev_priv(ndev); -	return &priv->stats; -} -  #ifdef CONFIG_NET_POLL_CONTROLLER  static void cpsw_ndo_poll_controller(struct net_device *ndev)  { @@ -1548,13 +1658,11 @@ static const struct net_device_ops cpsw_netdev_ops = {  	.ndo_open		= cpsw_ndo_open,  	.ndo_stop		= cpsw_ndo_stop,  	.ndo_start_xmit		= cpsw_ndo_start_xmit, -	.ndo_change_rx_flags	= cpsw_ndo_change_rx_flags,  	.ndo_set_mac_address	= cpsw_ndo_set_mac_address,  	.ndo_do_ioctl		= cpsw_ndo_ioctl,  	.ndo_validate_addr	= eth_validate_addr,  	.ndo_change_mtu		= eth_change_mtu,  	.ndo_tx_timeout		= cpsw_ndo_tx_timeout, -	.ndo_get_stats		= cpsw_ndo_get_stats,  	.ndo_set_rx_mode	= cpsw_ndo_set_rx_mode,  #ifdef CONFIG_NET_POLL_CONTROLLER  	.ndo_poll_controller	= cpsw_ndo_poll_controller, @@ -1705,69 +1813,62 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,  		return -EINVAL;  	if (of_property_read_u32(node, "slaves", &prop)) { -		pr_err("Missing slaves property in the DT.\n"); +		dev_err(&pdev->dev, "Missing slaves property in the DT.\n");  		return -EINVAL;  	}  	data->slaves = prop;  	if (of_property_read_u32(node, "active_slave", &prop)) { -		pr_err("Missing active_slave property in the DT.\n"); -		ret = -EINVAL; -		goto error_ret; +		dev_err(&pdev->dev, "Missing active_slave property in the DT.\n"); +		return -EINVAL;  	}  	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"); -		ret = -EINVAL; -		goto error_ret; +		dev_err(&pdev->dev, "Missing cpts_clock_mult property in the DT.\n"); +		return -EINVAL;  	}  	data->cpts_clock_mult = prop;  	if (of_property_read_u32(node, "cpts_clock_shift", &prop)) { -		pr_err("Missing cpts_clock_shift property in the DT.\n"); -		ret = -EINVAL; -		goto error_ret; +		dev_err(&pdev->dev, "Missing cpts_clock_shift property in the DT.\n"); +		return -EINVAL;  	}  	data->cpts_clock_shift = prop; -	data->slave_data = kcalloc(data->slaves, sizeof(struct cpsw_slave_data), -				   GFP_KERNEL); +	data->slave_data = devm_kzalloc(&pdev->dev, data->slaves +					* sizeof(struct cpsw_slave_data), +					GFP_KERNEL);  	if (!data->slave_data) -		return -EINVAL; +		return -ENOMEM;  	if (of_property_read_u32(node, "cpdma_channels", &prop)) { -		pr_err("Missing cpdma_channels property in the DT.\n"); -		ret = -EINVAL; -		goto error_ret; +		dev_err(&pdev->dev, "Missing cpdma_channels property in the DT.\n"); +		return -EINVAL;  	}  	data->channels = prop;  	if (of_property_read_u32(node, "ale_entries", &prop)) { -		pr_err("Missing ale_entries property in the DT.\n"); -		ret = -EINVAL; -		goto error_ret; +		dev_err(&pdev->dev, "Missing ale_entries property in the DT.\n"); +		return -EINVAL;  	}  	data->ale_entries = prop;  	if (of_property_read_u32(node, "bd_ram_size", &prop)) { -		pr_err("Missing bd_ram_size property in the DT.\n"); -		ret = -EINVAL; -		goto error_ret; +		dev_err(&pdev->dev, "Missing bd_ram_size property in the DT.\n"); +		return -EINVAL;  	}  	data->bd_ram_size = prop;  	if (of_property_read_u32(node, "rx_descs", &prop)) { -		pr_err("Missing rx_descs property in the DT.\n"); -		ret = -EINVAL; -		goto error_ret; +		dev_err(&pdev->dev, "Missing rx_descs property in the DT.\n"); +		return -EINVAL;  	}  	data->rx_descs = prop;  	if (of_property_read_u32(node, "mac_control", &prop)) { -		pr_err("Missing mac_control property in the DT.\n"); -		ret = -EINVAL; -		goto error_ret; +		dev_err(&pdev->dev, "Missing mac_control property in the DT.\n"); +		return -EINVAL;  	}  	data->mac_control = prop; @@ -1780,7 +1881,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,  	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);  	/* We do not want to force this, as in some cases may not have child */  	if (ret) -		pr_warn("Doesn't have any child node\n"); +		dev_warn(&pdev->dev, "Doesn't have any child node\n");  	for_each_child_of_node(node, slave_node) {  		struct cpsw_slave_data *slave_data = data->slave_data + i; @@ -1797,13 +1898,17 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,  		parp = of_get_property(slave_node, "phy_id", &lenp);  		if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) { -			pr_err("Missing slave[%d] phy_id property\n", i); -			ret = -EINVAL; -			goto error_ret; +			dev_err(&pdev->dev, "Missing slave[%d] phy_id property\n", i); +			return -EINVAL;  		}  		mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));  		phyid = be32_to_cpup(parp+1);  		mdio = of_find_device_by_node(mdio_node); +		of_node_put(mdio_node); +		if (!mdio) { +			pr_err("Missing mdio platform device\n"); +			return -EINVAL; +		}  		snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),  			 PHY_ID_FMT, mdio->name, phyid); @@ -1812,27 +1917,30 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,  			memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);  		slave_data->phy_if = of_get_phy_mode(slave_node); +		if (slave_data->phy_if < 0) { +			dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n", +				i); +			return slave_data->phy_if; +		}  		if (data->dual_emac) {  			if (of_property_read_u32(slave_node, "dual_emac_res_vlan",  						 &prop)) { -				pr_err("Missing dual_emac_res_vlan in DT.\n"); +				dev_err(&pdev->dev, "Missing dual_emac_res_vlan in DT.\n");  				slave_data->dual_emac_res_vlan = i+1; -				pr_err("Using %d as Reserved VLAN for %d slave\n", -				       slave_data->dual_emac_res_vlan, i); +				dev_err(&pdev->dev, "Using %d as Reserved VLAN for %d slave\n", +					slave_data->dual_emac_res_vlan, i);  			} else {  				slave_data->dual_emac_res_vlan = prop;  			}  		}  		i++; +		if (i == data->slaves) +			break;  	}  	return 0; - -error_ret: -	kfree(data->slave_data); -	return ret;  }  static int cpsw_probe_dual_emac(struct platform_device *pdev, @@ -1845,7 +1953,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,  	ndev = alloc_etherdev(sizeof(struct cpsw_priv));  	if (!ndev) { -		pr_err("cpsw: error allocating net_device\n"); +		dev_err(&pdev->dev, "cpsw: error allocating net_device\n");  		return -ENOMEM;  	} @@ -1861,10 +1969,10 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,  	if (is_valid_ether_addr(data->slave_data[1].mac_addr)) {  		memcpy(priv_sl2->mac_addr, data->slave_data[1].mac_addr,  			ETH_ALEN); -		pr_info("cpsw: Detected MACID = %pM\n", priv_sl2->mac_addr); +		dev_info(&pdev->dev, "cpsw: Detected MACID = %pM\n", priv_sl2->mac_addr);  	} else {  		random_ether_addr(priv_sl2->mac_addr); -		pr_info("cpsw: Random MACID = %pM\n", priv_sl2->mac_addr); +		dev_info(&pdev->dev, "cpsw: Random MACID = %pM\n", priv_sl2->mac_addr);  	}  	memcpy(ndev->dev_addr, priv_sl2->mac_addr, ETH_ALEN); @@ -1874,7 +1982,6 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,  	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;  	priv_sl2->host_port_regs = priv->host_port_regs; @@ -1896,14 +2003,14 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,  	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;  	ndev->netdev_ops = &cpsw_netdev_ops; -	SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops); +	ndev->ethtool_ops = &cpsw_ethtool_ops;  	netif_napi_add(ndev, &priv_sl2->napi, cpsw_poll, CPSW_POLL_WEIGHT);  	/* register the network device */  	SET_NETDEV_DEV(ndev, &pdev->dev);  	ret = register_netdev(ndev);  	if (ret) { -		pr_err("cpsw: error registering net device\n"); +		dev_err(&pdev->dev, "cpsw: error registering net device\n");  		free_netdev(ndev);  		ret = -ENODEV;  	} @@ -1918,14 +2025,14 @@ static int cpsw_probe(struct platform_device *pdev)  	struct cpsw_priv		*priv;  	struct cpdma_params		dma_params;  	struct cpsw_ale_params		ale_params; -	void __iomem			*ss_regs, *wr_regs; -	struct resource			*res; +	void __iomem			*ss_regs; +	struct resource			*res, *ss_res;  	u32 slave_offset, sliver_offset, slave_size;  	int ret = 0, i, k = 0;  	ndev = alloc_etherdev(sizeof(struct cpsw_priv));  	if (!ndev) { -		pr_err("error allocating net_device\n"); +		dev_err(&pdev->dev, "error allocating net_device\n");  		return -ENOMEM;  	} @@ -1940,7 +2047,7 @@ static int cpsw_probe(struct platform_device *pdev)  	priv->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL);  	priv->irq_enabled = true;  	if (!priv->cpts) { -		pr_err("error allocating cpts\n"); +		dev_err(&pdev->dev, "error allocating cpts\n");  		goto clean_ndev_ret;  	} @@ -1953,27 +2060,28 @@ static int cpsw_probe(struct platform_device *pdev)  	pinctrl_pm_select_default_state(&pdev->dev);  	if (cpsw_probe_dt(&priv->data, pdev)) { -		pr_err("cpsw: platform data missing\n"); +		dev_err(&pdev->dev, "cpsw: platform data missing\n");  		ret = -ENODEV; -		goto clean_ndev_ret; +		goto clean_runtime_disable_ret;  	}  	data = &priv->data;  	if (is_valid_ether_addr(data->slave_data[0].mac_addr)) {  		memcpy(priv->mac_addr, data->slave_data[0].mac_addr, ETH_ALEN); -		pr_info("Detected MACID = %pM\n", priv->mac_addr); +		dev_info(&pdev->dev, "Detected MACID = %pM\n", priv->mac_addr);  	} else {  		eth_random_addr(priv->mac_addr); -		pr_info("Random MACID = %pM\n", priv->mac_addr); +		dev_info(&pdev->dev, "Random MACID = %pM\n", priv->mac_addr);  	}  	memcpy(ndev->dev_addr, priv->mac_addr, ETH_ALEN); -	priv->slaves = kzalloc(sizeof(struct cpsw_slave) * data->slaves, -			       GFP_KERNEL); +	priv->slaves = devm_kzalloc(&pdev->dev, +				    sizeof(struct cpsw_slave) * data->slaves, +				    GFP_KERNEL);  	if (!priv->slaves) { -		ret = -EBUSY; -		goto clean_ndev_ret; +		ret = -ENOMEM; +		goto clean_runtime_disable_ret;  	}  	for (i = 0; i < data->slaves; i++)  		priv->slaves[i].slave_num = i; @@ -1981,55 +2089,37 @@ static int cpsw_probe(struct platform_device *pdev)  	priv->slaves[0].ndev = ndev;  	priv->emac_port = 0; -	priv->clk = clk_get(&pdev->dev, "fck"); +	priv->clk = devm_clk_get(&pdev->dev, "fck");  	if (IS_ERR(priv->clk)) { -		dev_err(&pdev->dev, "fck is not found\n"); +		dev_err(priv->dev, "fck is not found\n");  		ret = -ENODEV; -		goto clean_slave_ret; +		goto clean_runtime_disable_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) { -		dev_err(priv->dev, "error getting i/o resource\n"); -		ret = -ENOENT; -		goto clean_clk_ret; -	} -	if (!request_mem_region(priv->cpsw_res->start, -				resource_size(priv->cpsw_res), ndev->name)) { -		dev_err(priv->dev, "failed request i/o region\n"); -		ret = -ENXIO; -		goto clean_clk_ret; -	} -	ss_regs = ioremap(priv->cpsw_res->start, resource_size(priv->cpsw_res)); -	if (!ss_regs) { -		dev_err(priv->dev, "unable to map i/o region\n"); -		goto clean_cpsw_iores_ret; +	ss_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	ss_regs = devm_ioremap_resource(&pdev->dev, ss_res); +	if (IS_ERR(ss_regs)) { +		ret = PTR_ERR(ss_regs); +		goto clean_runtime_disable_ret;  	}  	priv->regs = ss_regs; -	priv->version = __raw_readl(&priv->regs->id_ver);  	priv->host_port = HOST_PORT_NUM; -	priv->cpsw_wr_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); -	if (!priv->cpsw_wr_res) { -		dev_err(priv->dev, "error getting i/o resource\n"); -		ret = -ENOENT; -		goto clean_iomap_ret; -	} -	if (!request_mem_region(priv->cpsw_wr_res->start, -			resource_size(priv->cpsw_wr_res), ndev->name)) { -		dev_err(priv->dev, "failed request i/o region\n"); -		ret = -ENXIO; -		goto clean_iomap_ret; -	} -	wr_regs = ioremap(priv->cpsw_wr_res->start, -				resource_size(priv->cpsw_wr_res)); -	if (!wr_regs) { -		dev_err(priv->dev, "unable to map i/o region\n"); -		goto clean_cpsw_wr_iores_ret; +	/* Need to enable clocks with runtime PM api to access module +	 * registers +	 */ +	pm_runtime_get_sync(&pdev->dev); +	priv->version = readl(&priv->regs->id_ver); +	pm_runtime_put_sync(&pdev->dev); + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1); +	priv->wr_regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(priv->wr_regs)) { +		ret = PTR_ERR(priv->wr_regs); +		goto clean_runtime_disable_ret;  	} -	priv->wr_regs = wr_regs;  	memset(&dma_params, 0, sizeof(dma_params));  	memset(&ale_params, 0, sizeof(ale_params)); @@ -2060,12 +2150,12 @@ static int cpsw_probe(struct platform_device *pdev)  		slave_size           = CPSW2_SLAVE_SIZE;  		sliver_offset        = CPSW2_SLIVER_OFFSET;  		dma_params.desc_mem_phys = -			(u32 __force) priv->cpsw_res->start + CPSW2_BD_OFFSET; +			(u32 __force) ss_res->start + CPSW2_BD_OFFSET;  		break;  	default:  		dev_err(priv->dev, "unknown version 0x%08x\n", priv->version);  		ret = -ENODEV; -		goto clean_cpsw_wr_iores_ret; +		goto clean_runtime_disable_ret;  	}  	for (i = 0; i < priv->data.slaves; i++) {  		struct cpsw_slave *slave = &priv->slaves[i]; @@ -2093,7 +2183,7 @@ static int cpsw_probe(struct platform_device *pdev)  	if (!priv->dma) {  		dev_err(priv->dev, "error initializing dma\n");  		ret = -ENOMEM; -		goto clean_wr_iomap_ret; +		goto clean_runtime_disable_ret;  	}  	priv->txch = cpdma_chan_create(priv->dma, tx_chan_num(0), @@ -2128,8 +2218,8 @@ static int cpsw_probe(struct platform_device *pdev)  	while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {  		for (i = res->start; i <= res->end; i++) { -			if (request_irq(i, cpsw_interrupt, 0, -					dev_name(&pdev->dev), priv)) { +			if (devm_request_irq(&pdev->dev, i, cpsw_interrupt, 0, +					     dev_name(&pdev->dev), priv)) {  				dev_err(priv->dev, "error attaching irq\n");  				goto clean_ale_ret;  			} @@ -2142,7 +2232,7 @@ static int cpsw_probe(struct platform_device *pdev)  	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;  	ndev->netdev_ops = &cpsw_netdev_ops; -	SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops); +	ndev->ethtool_ops = &cpsw_ethtool_ops;  	netif_napi_add(ndev, &priv->napi, cpsw_poll, CPSW_POLL_WEIGHT);  	/* register the network device */ @@ -2151,52 +2241,31 @@ static int cpsw_probe(struct platform_device *pdev)  	if (ret) {  		dev_err(priv->dev, "error registering net device\n");  		ret = -ENODEV; -		goto clean_irq_ret; +		goto clean_ale_ret;  	} -	if (cpts_register(&pdev->dev, priv->cpts, -			  data->cpts_clock_mult, data->cpts_clock_shift)) -		dev_err(priv->dev, "error registering cpts device\n"); - -	cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n", -		  priv->cpsw_res->start, ndev->irq); +	cpsw_notice(priv, probe, "initialized device (regs %pa, irq %d)\n", +		    &ss_res->start, ndev->irq);  	if (priv->data.dual_emac) {  		ret = cpsw_probe_dual_emac(pdev, priv);  		if (ret) {  			cpsw_err(priv, probe, "error probe slave 2 emac interface\n"); -			goto clean_irq_ret; +			goto clean_ale_ret;  		}  	}  	return 0; -clean_irq_ret: -	for (i = 0; i < priv->num_irqs; i++) -		free_irq(priv->irqs_table[i], priv);  clean_ale_ret:  	cpsw_ale_destroy(priv->ale);  clean_dma_ret:  	cpdma_chan_destroy(priv->txch);  	cpdma_chan_destroy(priv->rxch);  	cpdma_ctlr_destroy(priv->dma); -clean_wr_iomap_ret: -	iounmap(priv->wr_regs); -clean_cpsw_wr_iores_ret: -	release_mem_region(priv->cpsw_wr_res->start, -			   resource_size(priv->cpsw_wr_res)); -clean_iomap_ret: -	iounmap(priv->regs); -clean_cpsw_iores_ret: -	release_mem_region(priv->cpsw_res->start, -			   resource_size(priv->cpsw_res)); -clean_clk_ret: -	clk_put(priv->clk); -clean_slave_ret: +clean_runtime_disable_ret:  	pm_runtime_disable(&pdev->dev); -	kfree(priv->slaves);  clean_ndev_ret: -	kfree(priv->data.slave_data);  	free_netdev(priv->ndev);  	return ret;  } @@ -2205,30 +2274,16 @@ static int cpsw_remove(struct platform_device *pdev)  {  	struct net_device *ndev = platform_get_drvdata(pdev);  	struct cpsw_priv *priv = netdev_priv(ndev); -	int i;  	if (priv->data.dual_emac)  		unregister_netdev(cpsw_get_slave_ndev(priv, 1));  	unregister_netdev(ndev); -	cpts_unregister(priv->cpts); -	for (i = 0; i < priv->num_irqs; i++) -		free_irq(priv->irqs_table[i], priv); -  	cpsw_ale_destroy(priv->ale);  	cpdma_chan_destroy(priv->txch);  	cpdma_chan_destroy(priv->rxch);  	cpdma_ctlr_destroy(priv->dma); -	iounmap(priv->regs); -	release_mem_region(priv->cpsw_res->start, -			   resource_size(priv->cpsw_res)); -	iounmap(priv->wr_regs); -	release_mem_region(priv->cpsw_wr_res->start, -			   resource_size(priv->cpsw_wr_res));  	pm_runtime_disable(&pdev->dev); -	clk_put(priv->clk); -	kfree(priv->slaves); -	kfree(priv->data.slave_data);  	if (priv->data.dual_emac)  		free_netdev(cpsw_get_slave_ndev(priv, 1));  	free_netdev(ndev); @@ -2243,8 +2298,9 @@ static int cpsw_suspend(struct device *dev)  	if (netif_running(ndev))  		cpsw_ndo_stop(ndev); -	soft_reset("sliver 0", &priv->slaves[0].sliver->soft_reset); -	soft_reset("sliver 1", &priv->slaves[1].sliver->soft_reset); + +	for_each_slave(priv, soft_reset_slave); +  	pm_runtime_put_sync(&pdev->dev);  	/* Select sleep pin state */ @@ -2284,7 +2340,7 @@ static struct platform_driver cpsw_driver = {  		.name	 = "cpsw",  		.owner	 = THIS_MODULE,  		.pm	 = &cpsw_pm_ops, -		.of_match_table = of_match_ptr(cpsw_of_mtable), +		.of_match_table = cpsw_of_mtable,  	},  	.probe = cpsw_probe,  	.remove = cpsw_remove, diff --git a/drivers/net/ethernet/ti/cpsw.h b/drivers/net/ethernet/ti/cpsw.h index eb3e101ec04..574f49da693 100644 --- a/drivers/net/ethernet/ti/cpsw.h +++ b/drivers/net/ethernet/ti/cpsw.h @@ -39,4 +39,6 @@ struct cpsw_platform_data {  	bool	dual_emac;	/* Enable Dual EMAC mode */  }; +void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave); +  #endif /* __CPSW_H__ */ diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 7fa60d6092e..7f893069c41 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -163,7 +163,7 @@ int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)  		if (cpsw_ale_get_vlan_id(ale_entry) != vid)  			continue;  		cpsw_ale_get_addr(ale_entry, entry_addr); -		if (memcmp(entry_addr, addr, 6) == 0) +		if (ether_addr_equal(entry_addr, addr))  			return idx;  	}  	return -ENOENT; @@ -477,6 +477,14 @@ static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = {  		.port_shift	= 0,  		.bits		= 1,  	}, +	[ALE_P0_UNI_FLOOD]	= { +		.name		= "port0_unicast_flood", +		.offset		= ALE_CONTROL, +		.port_offset	= 0, +		.shift		= 8, +		.port_shift	= 0, +		.bits		= 1, +	},  	[ALE_VLAN_NOLEARN]	= {  		.name		= "vlan_nolearn",  		.offset		= ALE_CONTROL, @@ -573,6 +581,14 @@ static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = {  		.port_shift	= 0,  		.bits		= 1,  	}, +	[ALE_PORT_NO_SA_UPDATE]	= { +		.name		= "no_source_update", +		.offset		= ALE_PORTCTL, +		.port_offset	= 4, +		.shift		= 5, +		.port_shift	= 0, +		.bits		= 1, +	},  	[ALE_PORT_MCAST_LIMIT]	= {  		.name		= "mcast_limit",  		.offset		= ALE_PORTCTL, diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index 30daa1265f0..de409c33b25 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -34,6 +34,7 @@ enum cpsw_ale_control {  	ALE_ENABLE,  	ALE_CLEAR,  	ALE_AGEOUT, +	ALE_P0_UNI_FLOOD,  	ALE_VLAN_NOLEARN,  	ALE_NO_PORT_VLAN,  	ALE_OUI_DENY, @@ -47,6 +48,7 @@ enum cpsw_ale_control {  	ALE_PORT_DROP_UNTAGGED,  	ALE_PORT_DROP_UNKNOWN_VLAN,  	ALE_PORT_NOLEARN, +	ALE_PORT_NO_SA_UPDATE,  	ALE_PORT_UNKNOWN_VLAN_MEMBER,  	ALE_PORT_UNKNOWN_MCAST_FLOOD,  	ALE_PORT_UNKNOWN_REG_MCAST_FLOOD, diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c index 8c351f100ac..6b56f85951e 100644 --- a/drivers/net/ethernet/ti/cpts.c +++ b/drivers/net/ethernet/ti/cpts.c @@ -26,15 +26,13 @@  #include <linux/time.h>  #include <linux/uaccess.h>  #include <linux/workqueue.h> +#include <linux/if_ether.h> +#include <linux/if_vlan.h>  #include "cpts.h"  #ifdef CONFIG_TI_CPTS -static struct sock_filter ptp_filter[] = { -	PTP_FILTER -}; -  #define cpts_read32(c, r)	__raw_readl(&c->reg->r)  #define cpts_write32(c, v, r)	__raw_writel(v, &c->reg->r) @@ -217,6 +215,7 @@ static struct ptp_clock_info cpts_info = {  	.name		= "CTPS timer",  	.max_adj	= 1000000,  	.n_ext_ts	= 0, +	.n_pins		= 0,  	.pps		= 0,  	.adjfreq	= cpts_ptp_adjfreq,  	.adjtime	= cpts_ptp_adjtime, @@ -237,13 +236,11 @@ static void cpts_overflow_check(struct work_struct *work)  	schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);  } -#define CPTS_REF_CLOCK_NAME "cpsw_cpts_rft_clk" - -static void cpts_clk_init(struct cpts *cpts) +static void cpts_clk_init(struct device *dev, struct cpts *cpts)  { -	cpts->refclk = clk_get(NULL, CPTS_REF_CLOCK_NAME); +	cpts->refclk = devm_clk_get(dev, "cpts");  	if (IS_ERR(cpts->refclk)) { -		pr_err("Failed to clk_get %s\n", CPTS_REF_CLOCK_NAME); +		dev_err(dev, "Failed to get cpts refclk\n");  		cpts->refclk = NULL;  		return;  	} @@ -253,7 +250,6 @@ static void cpts_clk_init(struct cpts *cpts)  static void cpts_clk_release(struct cpts *cpts)  {  	clk_disable(cpts->refclk); -	clk_put(cpts->refclk);  }  static int cpts_match(struct sk_buff *skb, unsigned int ptp_class, @@ -300,7 +296,7 @@ static u64 cpts_find_ts(struct cpts *cpts, struct sk_buff *skb, int ev_type)  	u64 ns = 0;  	struct cpts_event *event;  	struct list_head *this, *next; -	unsigned int class = sk_run_filter(skb, ptp_filter); +	unsigned int class = ptp_classify_raw(skb);  	unsigned long flags;  	u16 seqid;  	u8 mtype; @@ -371,10 +367,6 @@ int cpts_register(struct device *dev, struct cpts *cpts,  	int err, i;  	unsigned long flags; -	if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) { -		pr_err("cpts: bad ptp filter\n"); -		return -EINVAL; -	}  	cpts->info = cpts_info;  	cpts->clock = ptp_clock_register(&cpts->info, dev);  	if (IS_ERR(cpts->clock)) { @@ -395,7 +387,7 @@ int cpts_register(struct device *dev, struct cpts *cpts,  	for (i = 0; i < CPTS_MAX_EVENTS; i++)  		list_add(&cpts->pool_data[i].list, &cpts->pool); -	cpts_clk_init(cpts); +	cpts_clk_init(dev, cpts);  	cpts_write32(cpts, CPTS_EN, control);  	cpts_write32(cpts, TS_PEND_EN, int_enable); diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h index fe993cdd7e2..1a581ef7eee 100644 --- a/drivers/net/ethernet/ti/cpts.h +++ b/drivers/net/ethernet/ti/cpts.h @@ -127,8 +127,8 @@ struct cpts {  };  #ifdef CONFIG_TI_CPTS -extern void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb); -extern void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb); +void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb); +void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);  #else  static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)  { @@ -138,8 +138,7 @@ static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)  }  #endif -extern int cpts_register(struct device *dev, struct cpts *cpts, -			 u32 mult, u32 shift); -extern void cpts_unregister(struct cpts *cpts); +int cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift); +void cpts_unregister(struct cpts *cpts);  #endif diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index 90a79462c86..4a000f6dd6f 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -81,7 +81,7 @@ struct cpdma_desc {  };  struct cpdma_desc_pool { -	u32			phys; +	phys_addr_t		phys;  	u32			hw_addr;  	void __iomem		*iomap;		/* ioremap map */  	void			*cpumap;	/* dma_alloc map */ @@ -158,9 +158,9 @@ cpdma_desc_pool_create(struct device *dev, u32 phys, u32 hw_addr,  	int bitmap_size;  	struct cpdma_desc_pool *pool; -	pool = kzalloc(sizeof(*pool), GFP_KERNEL); +	pool = devm_kzalloc(dev, sizeof(*pool), GFP_KERNEL);  	if (!pool) -		return NULL; +		goto fail;  	spin_lock_init(&pool->lock); @@ -170,7 +170,7 @@ cpdma_desc_pool_create(struct device *dev, u32 phys, u32 hw_addr,  	pool->num_desc	= size / pool->desc_size;  	bitmap_size  = (pool->num_desc / BITS_PER_LONG) * sizeof(long); -	pool->bitmap = kzalloc(bitmap_size, GFP_KERNEL); +	pool->bitmap = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);  	if (!pool->bitmap)  		goto fail; @@ -187,10 +187,7 @@ cpdma_desc_pool_create(struct device *dev, u32 phys, u32 hw_addr,  	if (pool->iomap)  		return pool; -  fail: -	kfree(pool->bitmap); -	kfree(pool);  	return NULL;  } @@ -203,7 +200,6 @@ static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool)  	spin_lock_irqsave(&pool->lock, flags);  	WARN_ON(pool->used_desc); -	kfree(pool->bitmap);  	if (pool->cpumap) {  		dma_free_coherent(pool->dev, pool->mem_size, pool->cpumap,  				  pool->phys); @@ -211,7 +207,6 @@ static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool)  		iounmap(pool->iomap);  	}  	spin_unlock_irqrestore(&pool->lock, flags); -	kfree(pool);  }  static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool, @@ -219,8 +214,7 @@ static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool,  {  	if (!desc)  		return 0; -	return pool->hw_addr + (__force dma_addr_t)desc - -			    (__force dma_addr_t)pool->iomap; +	return pool->hw_addr + (__force long)desc - (__force long)pool->iomap;  }  static inline struct cpdma_desc __iomem * @@ -277,7 +271,7 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params)  {  	struct cpdma_ctlr *ctlr; -	ctlr = kzalloc(sizeof(*ctlr), GFP_KERNEL); +	ctlr = devm_kzalloc(params->dev, sizeof(*ctlr), GFP_KERNEL);  	if (!ctlr)  		return NULL; @@ -291,10 +285,8 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params)  					    ctlr->params.desc_hw_addr,  					    ctlr->params.desc_mem_size,  					    ctlr->params.desc_align); -	if (!ctlr->pool) { -		kfree(ctlr); +	if (!ctlr->pool)  		return NULL; -	}  	if (WARN_ON(ctlr->num_chan > CPDMA_MAX_CHANNELS))  		ctlr->num_chan = CPDMA_MAX_CHANNELS; @@ -356,7 +348,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)  	int i;  	spin_lock_irqsave(&ctlr->lock, flags); -	if (ctlr->state != CPDMA_STATE_ACTIVE) { +	if (ctlr->state == CPDMA_STATE_TEARDOWN) {  		spin_unlock_irqrestore(&ctlr->lock, flags);  		return -EINVAL;  	} @@ -469,7 +461,6 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)  	cpdma_desc_pool_destroy(ctlr->pool);  	spin_unlock_irqrestore(&ctlr->lock, flags); -	kfree(ctlr);  	return ret;  }  EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy); @@ -508,21 +499,22 @@ struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,  				     cpdma_handler_fn handler)  {  	struct cpdma_chan *chan; -	int ret, offset = (chan_num % CPDMA_MAX_CHANNELS) * 4; +	int offset = (chan_num % CPDMA_MAX_CHANNELS) * 4;  	unsigned long flags;  	if (__chan_linear(chan_num) >= ctlr->num_chan)  		return NULL; -	ret = -ENOMEM; -	chan = kzalloc(sizeof(*chan), GFP_KERNEL); +	chan = devm_kzalloc(ctlr->dev, sizeof(*chan), GFP_KERNEL);  	if (!chan) -		goto err_chan_alloc; +		return ERR_PTR(-ENOMEM);  	spin_lock_irqsave(&ctlr->lock, flags); -	ret = -EBUSY; -	if (ctlr->channels[chan_num]) -		goto err_chan_busy; +	if (ctlr->channels[chan_num]) { +		spin_unlock_irqrestore(&ctlr->lock, flags); +		devm_kfree(ctlr->dev, chan); +		return ERR_PTR(-EBUSY); +	}  	chan->ctlr	= ctlr;  	chan->state	= CPDMA_STATE_IDLE; @@ -552,12 +544,6 @@ struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,  	ctlr->channels[chan_num] = chan;  	spin_unlock_irqrestore(&ctlr->lock, flags);  	return chan; - -err_chan_busy: -	spin_unlock_irqrestore(&ctlr->lock, flags); -	kfree(chan); -err_chan_alloc: -	return ERR_PTR(ret);  }  EXPORT_SYMBOL_GPL(cpdma_chan_create); @@ -892,7 +878,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)  	unsigned		timeout;  	spin_lock_irqsave(&chan->lock, flags); -	if (chan->state != CPDMA_STATE_ACTIVE) { +	if (chan->state == CPDMA_STATE_TEARDOWN) {  		spin_unlock_irqrestore(&chan->lock, flags);  		return -EINVAL;  	} @@ -972,7 +958,7 @@ struct cpdma_control_info {  #define ACCESS_RW	(ACCESS_RO | ACCESS_WO)  }; -struct cpdma_control_info controls[] = { +static struct cpdma_control_info controls[] = {  	[CPDMA_CMD_IDLE]	  = {CPDMA_DMACONTROL,	3,  1,      ACCESS_WO},  	[CPDMA_COPY_ERROR_FRAMES] = {CPDMA_DMACONTROL,	4,  1,      ACCESS_RW},  	[CPDMA_RX_OFF_LEN_UPDATE] = {CPDMA_DMACONTROL,	2,  1,      ACCESS_RW}, diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 67df09ea9d0..35a139e9a83 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -61,6 +61,7 @@  #include <linux/davinci_emac.h>  #include <linux/of.h>  #include <linux/of_address.h> +#include <linux/of_device.h>  #include <linux/of_irq.h>  #include <linux/of_net.h> @@ -876,8 +877,7 @@ static void emac_dev_mcast_set(struct net_device *ndev)  		    netdev_mc_count(ndev) > EMAC_DEF_MAX_MULTICAST_ADDRESSES) {  			mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST);  			emac_add_mcast(priv, EMAC_ALL_MULTI_SET, NULL); -		} -		if (!netdev_mc_empty(ndev)) { +		} else if (!netdev_mc_empty(ndev)) {  			struct netdev_hw_addr *ha;  			mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST); @@ -1532,9 +1532,9 @@ static int emac_dev_open(struct net_device *ndev)  	struct device *emac_dev = &ndev->dev;  	u32 cnt;  	struct resource *res; -	int ret; +	int q, m, ret; +	int res_num = 0, irq_num = 0;  	int i = 0; -	int k = 0;  	struct emac_priv *priv = netdev_priv(ndev);  	pm_runtime_get(&priv->pdev->dev); @@ -1564,15 +1564,23 @@ static int emac_dev_open(struct net_device *ndev)  	}  	/* Request IRQ */ +	while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, +					    res_num))) { +		for (irq_num = res->start; irq_num <= res->end; irq_num++) { +			if (request_irq(irq_num, emac_irq, 0, ndev->name, +					ndev)) { +				dev_err(emac_dev, +					"DaVinci EMAC: request_irq() failed\n"); +				ret = -EBUSY; -	while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { -		for (i = res->start; i <= res->end; i++) { -			if (devm_request_irq(&priv->pdev->dev, i, emac_irq, -					     0, ndev->name, ndev))  				goto rollback; +			}  		} -		k++; +		res_num++;  	} +	/* prepare counters for rollback in case of an error */ +	res_num--; +	irq_num--;  	/* Start/Enable EMAC hardware */  	emac_hw_enable(priv); @@ -1639,11 +1647,23 @@ static int emac_dev_open(struct net_device *ndev)  	return 0; -rollback: - -	dev_err(emac_dev, "DaVinci EMAC: devm_request_irq() failed"); -	ret = -EBUSY;  err: +	emac_int_disable(priv); +	napi_disable(&priv->napi); + +rollback: +	for (q = res_num; q >= 0; q--) { +		res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, q); +		/* at the first iteration, irq_num is already set to the +		 * right value +		 */ +		if (q != res_num) +			irq_num = res->end; + +		for (m = irq_num; m >= res->start; m--) +			free_irq(m, ndev); +	} +	cpdma_ctlr_stop(priv->dma);  	pm_runtime_put(&priv->pdev->dev);  	return ret;  } @@ -1659,6 +1679,9 @@ err:   */  static int emac_dev_stop(struct net_device *ndev)  { +	struct resource *res; +	int i = 0; +	int irq_num;  	struct emac_priv *priv = netdev_priv(ndev);  	struct device *emac_dev = &ndev->dev; @@ -1674,6 +1697,13 @@ static int emac_dev_stop(struct net_device *ndev)  	if (priv->phydev)  		phy_disconnect(priv->phydev); +	/* Free IRQ */ +	while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) { +		for (irq_num = res->start; irq_num <= res->end; irq_num++) +			free_irq(irq_num, priv->ndev); +		i++; +	} +  	if (netif_msg_drv(priv))  		dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name); @@ -1753,10 +1783,14 @@ static const struct net_device_ops emac_netdev_ops = {  #endif  }; +static const struct of_device_id davinci_emac_of_match[]; +  static struct emac_platform_data *  davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv)  {  	struct device_node *np; +	const struct of_device_id *match; +	const struct emac_platform_data *auxdata;  	struct emac_platform_data *pdata = NULL;  	const u8 *mac_addr; @@ -1794,7 +1828,20 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv)  	priv->phy_node = of_parse_phandle(np, "phy-handle", 0);  	if (!priv->phy_node) -		pdata->phy_id = ""; +		pdata->phy_id = NULL; + +	auxdata = pdev->dev.platform_data; +	if (auxdata) { +		pdata->interrupt_enable = auxdata->interrupt_enable; +		pdata->interrupt_disable = auxdata->interrupt_disable; +	} + +	match = of_match_device(davinci_emac_of_match, &pdev->dev); +	if (match && match->data) { +		auxdata = match->data; +		pdata->version = auxdata->version; +		pdata->hw_ram_addr = auxdata->hw_ram_addr; +	}  	pdev->dev.platform_data = pdata; @@ -1817,7 +1864,6 @@ static int davinci_emac_probe(struct platform_device *pdev)  	struct emac_priv *priv;  	unsigned long hw_ram_addr;  	struct emac_platform_data *pdata; -	struct device *emac_dev;  	struct cpdma_params dma_params;  	struct clk *emac_clk;  	unsigned long emac_bus_frequency; @@ -1853,7 +1899,7 @@ static int davinci_emac_probe(struct platform_device *pdev)  	}  	/* MAC addr and PHY mask , RMII enable info from platform_data */ -	memcpy(priv->mac_addr, pdata->mac_addr, 6); +	memcpy(priv->mac_addr, pdata->mac_addr, ETH_ALEN);  	priv->phy_id = pdata->phy_id;  	priv->rmii_en = pdata->rmii_en;  	priv->version = pdata->version; @@ -1863,7 +1909,6 @@ static int davinci_emac_probe(struct platform_device *pdev)  	priv->coal_intvl = 0;  	priv->bus_freq_mhz = (u32)(emac_bus_frequency / 1000000); -	emac_dev = &ndev->dev;  	/* Get EMAC platform data */  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	priv->emac_base_phys = res->start + pdata->ctrl_reg_offset; @@ -1882,7 +1927,7 @@ static int davinci_emac_probe(struct platform_device *pdev)  		hw_ram_addr = (u32 __force)res->start + pdata->ctrl_ram_offset;  	memset(&dma_params, 0, sizeof(dma_params)); -	dma_params.dev			= emac_dev; +	dma_params.dev			= &pdev->dev;  	dma_params.dmaregs		= priv->emac_base;  	dma_params.rxthresh		= priv->emac_base + 0x120;  	dma_params.rxfree		= priv->emac_base + 0x140; @@ -1932,7 +1977,7 @@ static int davinci_emac_probe(struct platform_device *pdev)  	}  	ndev->netdev_ops = &emac_netdev_ops; -	SET_ETHTOOL_OPS(ndev, ðtool_ops); +	ndev->ethtool_ops = ðtool_ops;  	netif_napi_add(ndev, &priv->napi, emac_poll, EMAC_POLL_WEIGHT);  	/* register the network device */ @@ -1946,7 +1991,7 @@ static int davinci_emac_probe(struct platform_device *pdev)  	if (netif_msg_probe(priv)) { -		dev_notice(emac_dev, "DaVinci EMAC Probe found device "\ +		dev_notice(&pdev->dev, "DaVinci EMAC Probe found device "  			   "(regs: %p, irq: %d)\n",  			   (void *)priv->emac_base_phys, ndev->irq);  	} @@ -2021,8 +2066,14 @@ static const struct dev_pm_ops davinci_emac_pm_ops = {  };  #if IS_ENABLED(CONFIG_OF) +static const struct emac_platform_data am3517_emac_data = { +	.version		= EMAC_VERSION_2, +	.hw_ram_addr		= 0x01e20000, +}; +  static const struct of_device_id davinci_emac_of_match[] = {  	{.compatible = "ti,davinci-dm6467-emac", }, +	{.compatible = "ti,am3517-emac", .data = &am3517_emac_data, },  	{},  };  MODULE_DEVICE_TABLE(of, davinci_emac_of_match); diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 4ec92659a10..735dc53d4b0 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -82,7 +82,7 @@ struct davinci_mdio_regs {  	}	user[0];  }; -struct mdio_platform_data default_pdata = { +static const struct mdio_platform_data default_pdata = {  	.bus_freq = DEF_OUT_FREQ,  }; @@ -303,7 +303,7 @@ static int davinci_mdio_probe_dt(struct mdio_platform_data *data,  		return -EINVAL;  	if (of_property_read_u32(node, "bus_freq", &prop)) { -		pr_err("Missing bus_freq property in the DT.\n"); +		dev_err(&pdev->dev, "Missing bus_freq property in the DT.\n");  		return -EINVAL;  	}  	data->bus_freq = prop; @@ -321,15 +321,14 @@ static int davinci_mdio_probe(struct platform_device *pdev)  	struct phy_device *phy;  	int ret, addr; -	data = kzalloc(sizeof(*data), GFP_KERNEL); +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);  	if (!data)  		return -ENOMEM; -	data->bus = mdiobus_alloc(); +	data->bus = devm_mdiobus_alloc(dev);  	if (!data->bus) {  		dev_err(dev, "failed to alloc mii bus\n"); -		ret = -ENOMEM; -		goto bail_out; +		return -ENOMEM;  	}  	if (dev->of_node) { @@ -349,12 +348,9 @@ static int davinci_mdio_probe(struct platform_device *pdev)  	data->bus->parent	= dev;  	data->bus->priv		= data; -	/* Select default pin state */ -	pinctrl_pm_select_default_state(&pdev->dev); -  	pm_runtime_enable(&pdev->dev);  	pm_runtime_get_sync(&pdev->dev); -	data->clk = clk_get(&pdev->dev, "fck"); +	data->clk = devm_clk_get(dev, "fck");  	if (IS_ERR(data->clk)) {  		dev_err(dev, "failed to get device clock\n");  		ret = PTR_ERR(data->clk); @@ -367,24 +363,9 @@ static int davinci_mdio_probe(struct platform_device *pdev)  	spin_lock_init(&data->lock);  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(dev, "could not find register map resource\n"); -		ret = -ENOENT; -		goto bail_out; -	} - -	res = devm_request_mem_region(dev, res->start, resource_size(res), -					    dev_name(dev)); -	if (!res) { -		dev_err(dev, "could not allocate register map resource\n"); -		ret = -ENXIO; -		goto bail_out; -	} - -	data->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); -	if (!data->regs) { -		dev_err(dev, "could not map mdio registers\n"); -		ret = -ENOMEM; +	data->regs = devm_ioremap_resource(dev, res); +	if (IS_ERR(data->regs)) { +		ret = PTR_ERR(data->regs);  		goto bail_out;  	} @@ -406,16 +387,9 @@ static int davinci_mdio_probe(struct platform_device *pdev)  	return 0;  bail_out: -	if (data->bus) -		mdiobus_free(data->bus); - -	if (data->clk) -		clk_put(data->clk);  	pm_runtime_put_sync(&pdev->dev);  	pm_runtime_disable(&pdev->dev); -	kfree(data); -  	return ret;  } @@ -423,18 +397,12 @@ static int davinci_mdio_remove(struct platform_device *pdev)  {  	struct davinci_mdio_data *data = platform_get_drvdata(pdev); -	if (data->bus) { +	if (data->bus)  		mdiobus_unregister(data->bus); -		mdiobus_free(data->bus); -	} -	if (data->clk) -		clk_put(data->clk);  	pm_runtime_put_sync(&pdev->dev);  	pm_runtime_disable(&pdev->dev); -	kfree(data); -  	return 0;  } diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 591437e59b9..62b19be5183 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -319,7 +319,6 @@ static void tlan_remove_one(struct pci_dev *pdev)  	free_netdev(dev); -	pci_set_drvdata(pdev, NULL);  	cancel_work_sync(&priv->tlan_tqueue);  }  | 
