diff options
Diffstat (limited to 'drivers/net/ethernet/ti/cpsw.c')
| -rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 546 | 
1 files changed, 303 insertions, 243 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 79974e31187..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,74 +1813,67 @@ 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; -	if (!of_property_read_u32(node, "dual_emac", &prop)) -		data->dual_emac = prop; +	if (of_property_read_bool(node, "dual_emac")) +		data->dual_emac = 1;  	/*  	 * Populate all the child nodes here... @@ -1780,9 +1881,9 @@ 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_node_by_name(slave_node, "slave") { +	for_each_child_of_node(node, slave_node) {  		struct cpsw_slave_data *slave_data = data->slave_data + i;  		const void *mac_addr = NULL;  		u32 phyid; @@ -1791,15 +1892,23 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,  		struct device_node *mdio_node;  		struct platform_device *mdio; +		/* This is no slave child node, continue */ +		if (strcmp(slave_node->name, "slave")) +			continue; +  		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); @@ -1808,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, @@ -1841,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;  	} @@ -1857,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); @@ -1870,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; @@ -1892,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;  	} @@ -1914,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;  	} @@ -1936,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;  	} @@ -1949,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; @@ -1977,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)); @@ -2056,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]; @@ -2089,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), @@ -2124,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;  			} @@ -2138,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 */ @@ -2147,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;  } @@ -2201,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); @@ -2239,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 */ @@ -2280,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,  | 
