diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
| -rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 33 | 
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 42ec6ca3bf03..38e5b5abe067 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3798,7 +3798,6 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep,  	entries_free = fec_enet_get_free_txdesc_num(txq);  	if (entries_free < MAX_SKB_FRAGS + 1) {  		netdev_err(fep->netdev, "NOT enough BD for SG!\n"); -		xdp_return_frame(frame);  		return NETDEV_TX_BUSY;  	} @@ -3835,6 +3834,11 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep,  	index = fec_enet_get_bd_index(last_bdp, &txq->bd);  	txq->tx_skbuff[index] = NULL; +	/* Make sure the updates to rest of the descriptor are performed before +	 * transferring ownership. +	 */ +	dma_wmb(); +  	/* Send it on its way.  Tell FEC it's ready, interrupt when done,  	 * it's the last BD of the frame, and to put the CRC on the end.  	 */ @@ -3844,8 +3848,14 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep,  	/* If this was the last BD in the ring, start at the beginning again. */  	bdp = fec_enet_get_nextdesc(last_bdp, &txq->bd); +	/* Make sure the update to bdp are performed before txq->bd.cur. */ +	dma_wmb(); +  	txq->bd.cur = bdp; +	/* Trigger transmission start */ +	writel(0, txq->bd.reg_desc_active); +  	return 0;  } @@ -3874,12 +3884,6 @@ static int fec_enet_xdp_xmit(struct net_device *dev,  		sent_frames++;  	} -	/* Make sure the update to bdp and tx_skbuff are performed. */ -	wmb(); - -	/* Trigger transmission start */ -	writel(0, txq->bd.reg_desc_active); -  	__netif_tx_unlock(nq);  	return sent_frames; @@ -4478,9 +4482,11 @@ fec_drv_remove(struct platform_device *pdev)  	struct device_node *np = pdev->dev.of_node;  	int ret; -	ret = pm_runtime_resume_and_get(&pdev->dev); +	ret = pm_runtime_get_sync(&pdev->dev);  	if (ret < 0) -		return ret; +		dev_err(&pdev->dev, +			"Failed to resume device in remove callback (%pe)\n", +			ERR_PTR(ret));  	cancel_work_sync(&fep->tx_timeout_work);  	fec_ptp_stop(pdev); @@ -4493,8 +4499,13 @@ fec_drv_remove(struct platform_device *pdev)  		of_phy_deregister_fixed_link(np);  	of_node_put(fep->phy_node); -	clk_disable_unprepare(fep->clk_ahb); -	clk_disable_unprepare(fep->clk_ipg); +	/* After pm_runtime_get_sync() failed, the clks are still off, so skip +	 * disabling them again. +	 */ +	if (ret >= 0) { +		clk_disable_unprepare(fep->clk_ahb); +		clk_disable_unprepare(fep->clk_ipg); +	}  	pm_runtime_put_noidle(&pdev->dev);  	pm_runtime_disable(&pdev->dev);  | 
