diff options
Diffstat (limited to 'drivers/net/ethernet/cadence/macb_main.c')
| -rw-r--r-- | drivers/net/ethernet/cadence/macb_main.c | 161 | 
1 files changed, 102 insertions, 59 deletions
| diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 67933079aeea..2213e6ab8151 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -2558,7 +2558,7 @@ static int macb_open(struct net_device *dev)  	err = macb_phylink_connect(bp);  	if (err) -		goto napi_exit; +		goto reset_hw;  	netif_tx_start_all_queues(dev); @@ -2567,9 +2567,11 @@ static int macb_open(struct net_device *dev)  	return 0; -napi_exit: +reset_hw: +	macb_reset_hw(bp);  	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)  		napi_disable(&queue->napi); +	macb_free_consistent(bp);  pm_exit:  	pm_runtime_put_sync(&bp->pdev->dev);  	return err; @@ -2819,11 +2821,13 @@ static void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)  {  	struct macb *bp = netdev_priv(netdev); -	wol->supported = 0; -	wol->wolopts = 0; - -	if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) +	if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) {  		phylink_ethtool_get_wol(bp->phylink, wol); +		wol->supported |= WAKE_MAGIC; + +		if (bp->wol & MACB_WOL_ENABLED) +			wol->wolopts |= WAKE_MAGIC; +	}  }  static int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) @@ -2831,9 +2835,13 @@ static int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)  	struct macb *bp = netdev_priv(netdev);  	int ret; +	/* Pass the order to phylink layer */  	ret = phylink_ethtool_set_wol(bp->phylink, wol); -	if (!ret) -		return 0; +	/* Don't manage WoL on MAC if handled by the PHY +	 * or if there's a failure in talking to the PHY +	 */ +	if (!ret || ret != -EOPNOTSUPP) +		return ret;  	if (!(bp->wol & MACB_WOL_HAS_MAGIC_PACKET) ||  	    (wol->wolopts & ~WAKE_MAGIC)) @@ -3728,7 +3736,7 @@ static int macb_init(struct platform_device *pdev)  	if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) {  		val = 0; -		if (bp->phy_interface == PHY_INTERFACE_MODE_RGMII) +		if (phy_interface_mode_is_rgmii(bp->phy_interface))  			val = GEM_BIT(RGMII);  		else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII &&  			 (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII)) @@ -3760,15 +3768,9 @@ static int macb_init(struct platform_device *pdev)  static struct sifive_fu540_macb_mgmt *mgmt; -/* Initialize and start the Receiver and Transmit subsystems */ -static int at91ether_start(struct net_device *dev) +static int at91ether_alloc_coherent(struct macb *lp)  { -	struct macb *lp = netdev_priv(dev);  	struct macb_queue *q = &lp->queues[0]; -	struct macb_dma_desc *desc; -	dma_addr_t addr; -	u32 ctl; -	int i;  	q->rx_ring = dma_alloc_coherent(&lp->pdev->dev,  					 (AT91ETHER_MAX_RX_DESCR * @@ -3790,6 +3792,43 @@ static int at91ether_start(struct net_device *dev)  		return -ENOMEM;  	} +	return 0; +} + +static void at91ether_free_coherent(struct macb *lp) +{ +	struct macb_queue *q = &lp->queues[0]; + +	if (q->rx_ring) { +		dma_free_coherent(&lp->pdev->dev, +				  AT91ETHER_MAX_RX_DESCR * +				  macb_dma_desc_get_size(lp), +				  q->rx_ring, q->rx_ring_dma); +		q->rx_ring = NULL; +	} + +	if (q->rx_buffers) { +		dma_free_coherent(&lp->pdev->dev, +				  AT91ETHER_MAX_RX_DESCR * +				  AT91ETHER_MAX_RBUFF_SZ, +				  q->rx_buffers, q->rx_buffers_dma); +		q->rx_buffers = NULL; +	} +} + +/* Initialize and start the Receiver and Transmit subsystems */ +static int at91ether_start(struct macb *lp) +{ +	struct macb_queue *q = &lp->queues[0]; +	struct macb_dma_desc *desc; +	dma_addr_t addr; +	u32 ctl; +	int i, ret; + +	ret = at91ether_alloc_coherent(lp); +	if (ret) +		return ret; +  	addr = q->rx_buffers_dma;  	for (i = 0; i < AT91ETHER_MAX_RX_DESCR; i++) {  		desc = macb_rx_desc(q, i); @@ -3811,9 +3850,39 @@ static int at91ether_start(struct net_device *dev)  	ctl = macb_readl(lp, NCR);  	macb_writel(lp, NCR, ctl | MACB_BIT(RE) | MACB_BIT(TE)); +	/* Enable MAC interrupts */ +	macb_writel(lp, IER, MACB_BIT(RCOMP)	| +			     MACB_BIT(RXUBR)	| +			     MACB_BIT(ISR_TUND)	| +			     MACB_BIT(ISR_RLE)	| +			     MACB_BIT(TCOMP)	| +			     MACB_BIT(ISR_ROVR)	| +			     MACB_BIT(HRESP)); +  	return 0;  } +static void at91ether_stop(struct macb *lp) +{ +	u32 ctl; + +	/* Disable MAC interrupts */ +	macb_writel(lp, IDR, MACB_BIT(RCOMP)	| +			     MACB_BIT(RXUBR)	| +			     MACB_BIT(ISR_TUND)	| +			     MACB_BIT(ISR_RLE)	| +			     MACB_BIT(TCOMP)	| +			     MACB_BIT(ISR_ROVR) | +			     MACB_BIT(HRESP)); + +	/* Disable Receiver and Transmitter */ +	ctl = macb_readl(lp, NCR); +	macb_writel(lp, NCR, ctl & ~(MACB_BIT(TE) | MACB_BIT(RE))); + +	/* Free resources. */ +	at91ether_free_coherent(lp); +} +  /* Open the ethernet interface */  static int at91ether_open(struct net_device *dev)  { @@ -3833,63 +3902,36 @@ static int at91ether_open(struct net_device *dev)  	macb_set_hwaddr(lp); -	ret = at91ether_start(dev); +	ret = at91ether_start(lp);  	if (ret) -		return ret; - -	/* Enable MAC interrupts */ -	macb_writel(lp, IER, MACB_BIT(RCOMP)	| -			     MACB_BIT(RXUBR)	| -			     MACB_BIT(ISR_TUND)	| -			     MACB_BIT(ISR_RLE)	| -			     MACB_BIT(TCOMP)	| -			     MACB_BIT(ISR_ROVR)	| -			     MACB_BIT(HRESP)); +		goto pm_exit;  	ret = macb_phylink_connect(lp);  	if (ret) -		return ret; +		goto stop;  	netif_start_queue(dev);  	return 0; + +stop: +	at91ether_stop(lp); +pm_exit: +	pm_runtime_put_sync(&lp->pdev->dev); +	return ret;  }  /* Close the interface */  static int at91ether_close(struct net_device *dev)  {  	struct macb *lp = netdev_priv(dev); -	struct macb_queue *q = &lp->queues[0]; -	u32 ctl; - -	/* Disable Receiver and Transmitter */ -	ctl = macb_readl(lp, NCR); -	macb_writel(lp, NCR, ctl & ~(MACB_BIT(TE) | MACB_BIT(RE))); - -	/* Disable MAC interrupts */ -	macb_writel(lp, IDR, MACB_BIT(RCOMP)	| -			     MACB_BIT(RXUBR)	| -			     MACB_BIT(ISR_TUND)	| -			     MACB_BIT(ISR_RLE)	| -			     MACB_BIT(TCOMP)	| -			     MACB_BIT(ISR_ROVR) | -			     MACB_BIT(HRESP));  	netif_stop_queue(dev);  	phylink_stop(lp->phylink);  	phylink_disconnect_phy(lp->phylink); -	dma_free_coherent(&lp->pdev->dev, -			  AT91ETHER_MAX_RX_DESCR * -			  macb_dma_desc_get_size(lp), -			  q->rx_ring, q->rx_ring_dma); -	q->rx_ring = NULL; - -	dma_free_coherent(&lp->pdev->dev, -			  AT91ETHER_MAX_RX_DESCR * AT91ETHER_MAX_RBUFF_SZ, -			  q->rx_buffers, q->rx_buffers_dma); -	q->rx_buffers = NULL; +	at91ether_stop(lp);  	return pm_runtime_put(&lp->pdev->dev);  } @@ -4386,7 +4428,7 @@ static int macb_probe(struct platform_device *pdev)  	bp->wol = 0;  	if (of_get_property(np, "magic-packet", NULL))  		bp->wol |= MACB_WOL_HAS_MAGIC_PACKET; -	device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET); +	device_set_wakeup_capable(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET);  	spin_lock_init(&bp->lock); @@ -4562,10 +4604,10 @@ static int __maybe_unused macb_suspend(struct device *dev)  			bp->pm_data.scrt2 = gem_readl_n(bp, ETHT, SCRT2_ETHT);  	} -	netif_carrier_off(netdev);  	if (bp->ptp_info)  		bp->ptp_info->ptp_remove(netdev); -	pm_runtime_force_suspend(dev); +	if (!device_may_wakeup(dev)) +		pm_runtime_force_suspend(dev);  	return 0;  } @@ -4580,7 +4622,8 @@ static int __maybe_unused macb_resume(struct device *dev)  	if (!netif_running(netdev))  		return 0; -	pm_runtime_force_resume(dev); +	if (!device_may_wakeup(dev)) +		pm_runtime_force_resume(dev);  	if (bp->wol & MACB_WOL_ENABLED) {  		macb_writel(bp, IDR, MACB_BIT(WOL)); @@ -4618,7 +4661,7 @@ static int __maybe_unused macb_runtime_suspend(struct device *dev)  	struct net_device *netdev = dev_get_drvdata(dev);  	struct macb *bp = netdev_priv(netdev); -	if (!(device_may_wakeup(&bp->dev->dev))) { +	if (!(device_may_wakeup(dev))) {  		clk_disable_unprepare(bp->tx_clk);  		clk_disable_unprepare(bp->hclk);  		clk_disable_unprepare(bp->pclk); @@ -4634,7 +4677,7 @@ static int __maybe_unused macb_runtime_resume(struct device *dev)  	struct net_device *netdev = dev_get_drvdata(dev);  	struct macb *bp = netdev_priv(netdev); -	if (!(device_may_wakeup(&bp->dev->dev))) { +	if (!(device_may_wakeup(dev))) {  		clk_prepare_enable(bp->pclk);  		clk_prepare_enable(bp->hclk);  		clk_prepare_enable(bp->tx_clk); |