diff options
Diffstat (limited to 'drivers/net/ethernet/xilinx/xilinx_axienet_main.c')
| -rw-r--r-- | drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 97 | 
1 files changed, 65 insertions, 32 deletions
| diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 3a8775e0ca55..b508c9453f40 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1053,9 +1053,9 @@ static int axienet_open(struct net_device *ndev)  	 * including the MDIO. MDIO must be disabled before resetting.  	 * Hold MDIO bus lock to avoid MDIO accesses during the reset.  	 */ -	mutex_lock(&lp->mii_bus->mdio_lock); +	axienet_lock_mii(lp);  	ret = axienet_device_reset(ndev); -	mutex_unlock(&lp->mii_bus->mdio_lock); +	axienet_unlock_mii(lp);  	ret = phylink_of_phy_connect(lp->phylink, lp->dev->of_node, 0);  	if (ret) { @@ -1148,9 +1148,9 @@ static int axienet_stop(struct net_device *ndev)  	}  	/* Do a reset to ensure DMA is really stopped */ -	mutex_lock(&lp->mii_bus->mdio_lock); +	axienet_lock_mii(lp);  	__axienet_device_reset(lp); -	mutex_unlock(&lp->mii_bus->mdio_lock); +	axienet_unlock_mii(lp);  	cancel_work_sync(&lp->dma_err_task); @@ -1709,9 +1709,9 @@ static void axienet_dma_err_handler(struct work_struct *work)  	 * including the MDIO. MDIO must be disabled before resetting.  	 * Hold MDIO bus lock to avoid MDIO accesses during the reset.  	 */ -	mutex_lock(&lp->mii_bus->mdio_lock); +	axienet_lock_mii(lp);  	__axienet_device_reset(lp); -	mutex_unlock(&lp->mii_bus->mdio_lock); +	axienet_unlock_mii(lp);  	for (i = 0; i < lp->tx_bd_num; i++) {  		cur_p = &lp->tx_bd_v[i]; @@ -1835,8 +1835,8 @@ static int axienet_probe(struct platform_device *pdev)  	struct device_node *np;  	struct axienet_local *lp;  	struct net_device *ndev; -	const void *mac_addr;  	struct resource *ethres; +	u8 mac_addr[ETH_ALEN];  	int addr_width = 32;  	u32 value; @@ -1863,24 +1863,41 @@ static int axienet_probe(struct platform_device *pdev)  	lp->rx_bd_num = RX_BD_NUM_DEFAULT;  	lp->tx_bd_num = TX_BD_NUM_DEFAULT; -	lp->clk = devm_clk_get_optional(&pdev->dev, NULL); -	if (IS_ERR(lp->clk)) { -		ret = PTR_ERR(lp->clk); +	lp->axi_clk = devm_clk_get_optional(&pdev->dev, "s_axi_lite_clk"); +	if (!lp->axi_clk) { +		/* For backward compatibility, if named AXI clock is not present, +		 * treat the first clock specified as the AXI clock. +		 */ +		lp->axi_clk = devm_clk_get_optional(&pdev->dev, NULL); +	} +	if (IS_ERR(lp->axi_clk)) { +		ret = PTR_ERR(lp->axi_clk);  		goto free_netdev;  	} -	ret = clk_prepare_enable(lp->clk); +	ret = clk_prepare_enable(lp->axi_clk);  	if (ret) { -		dev_err(&pdev->dev, "Unable to enable clock: %d\n", ret); +		dev_err(&pdev->dev, "Unable to enable AXI clock: %d\n", ret);  		goto free_netdev;  	} +	lp->misc_clks[0].id = "axis_clk"; +	lp->misc_clks[1].id = "ref_clk"; +	lp->misc_clks[2].id = "mgt_clk"; + +	ret = devm_clk_bulk_get_optional(&pdev->dev, XAE_NUM_MISC_CLOCKS, lp->misc_clks); +	if (ret) +		goto cleanup_clk; + +	ret = clk_bulk_prepare_enable(XAE_NUM_MISC_CLOCKS, lp->misc_clks); +	if (ret) +		goto cleanup_clk; +  	/* Map device registers */  	ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	lp->regs = devm_ioremap_resource(&pdev->dev, ethres);  	if (IS_ERR(lp->regs)) { -		dev_err(&pdev->dev, "could not map Axi Ethernet regs.\n");  		ret = PTR_ERR(lp->regs); -		goto free_netdev; +		goto cleanup_clk;  	}  	lp->regs_start = ethres->start; @@ -1958,18 +1975,18 @@ static int axienet_probe(struct platform_device *pdev)  			break;  		default:  			ret = -EINVAL; -			goto free_netdev; +			goto cleanup_clk;  		}  	} else {  		ret = of_get_phy_mode(pdev->dev.of_node, &lp->phy_mode);  		if (ret) -			goto free_netdev; +			goto cleanup_clk;  	}  	if (lp->switch_x_sgmii && lp->phy_mode != PHY_INTERFACE_MODE_SGMII &&  	    lp->phy_mode != PHY_INTERFACE_MODE_1000BASEX) {  		dev_err(&pdev->dev, "xlnx,switch-x-sgmii only supported with SGMII or 1000BaseX\n");  		ret = -EINVAL; -		goto free_netdev; +		goto cleanup_clk;  	}  	/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ @@ -1982,7 +1999,7 @@ static int axienet_probe(struct platform_device *pdev)  			dev_err(&pdev->dev,  				"unable to get DMA resource\n");  			of_node_put(np); -			goto free_netdev; +			goto cleanup_clk;  		}  		lp->dma_regs = devm_ioremap_resource(&pdev->dev,  						     &dmares); @@ -2002,12 +2019,12 @@ static int axienet_probe(struct platform_device *pdev)  	if (IS_ERR(lp->dma_regs)) {  		dev_err(&pdev->dev, "could not map DMA regs\n");  		ret = PTR_ERR(lp->dma_regs); -		goto free_netdev; +		goto cleanup_clk;  	}  	if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) {  		dev_err(&pdev->dev, "could not determine irqs\n");  		ret = -ENOMEM; -		goto free_netdev; +		goto cleanup_clk;  	}  	/* Autodetect the need for 64-bit DMA pointers. @@ -2037,7 +2054,7 @@ static int axienet_probe(struct platform_device *pdev)  	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_width));  	if (ret) {  		dev_err(&pdev->dev, "No suitable DMA available\n"); -		goto free_netdev; +		goto cleanup_clk;  	}  	/* Check for Ethernet core IRQ (optional) */ @@ -2045,13 +2062,14 @@ static int axienet_probe(struct platform_device *pdev)  		dev_info(&pdev->dev, "Ethernet core IRQ not defined\n");  	/* Retrieve the MAC address */ -	mac_addr = of_get_mac_address(pdev->dev.of_node); -	if (IS_ERR(mac_addr)) { -		dev_warn(&pdev->dev, "could not find MAC address property: %ld\n", -			 PTR_ERR(mac_addr)); -		mac_addr = NULL; +	ret = of_get_mac_address(pdev->dev.of_node, mac_addr); +	if (!ret) { +		axienet_set_mac_address(ndev, mac_addr); +	} else { +		dev_warn(&pdev->dev, "could not find MAC address property: %d\n", +			 ret); +		axienet_set_mac_address(ndev, NULL);  	} -	axienet_set_mac_address(ndev, mac_addr);  	lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;  	lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD; @@ -2068,12 +2086,12 @@ static int axienet_probe(struct platform_device *pdev)  		if (!lp->phy_node) {  			dev_err(&pdev->dev, "phy-handle required for 1000BaseX/SGMII\n");  			ret = -EINVAL; -			goto free_netdev; +			goto cleanup_mdio;  		}  		lp->pcs_phy = of_mdio_find_device(lp->phy_node);  		if (!lp->pcs_phy) {  			ret = -EPROBE_DEFER; -			goto free_netdev; +			goto cleanup_mdio;  		}  		lp->phylink_config.pcs_poll = true;  	} @@ -2087,17 +2105,31 @@ static int axienet_probe(struct platform_device *pdev)  	if (IS_ERR(lp->phylink)) {  		ret = PTR_ERR(lp->phylink);  		dev_err(&pdev->dev, "phylink_create error (%i)\n", ret); -		goto free_netdev; +		goto cleanup_mdio;  	}  	ret = register_netdev(lp->ndev);  	if (ret) {  		dev_err(lp->dev, "register_netdev() error (%i)\n", ret); -		goto free_netdev; +		goto cleanup_phylink;  	}  	return 0; +cleanup_phylink: +	phylink_destroy(lp->phylink); + +cleanup_mdio: +	if (lp->pcs_phy) +		put_device(&lp->pcs_phy->dev); +	if (lp->mii_bus) +		axienet_mdio_teardown(lp); +	of_node_put(lp->phy_node); + +cleanup_clk: +	clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks); +	clk_disable_unprepare(lp->axi_clk); +  free_netdev:  	free_netdev(ndev); @@ -2119,7 +2151,8 @@ static int axienet_remove(struct platform_device *pdev)  	axienet_mdio_teardown(lp); -	clk_disable_unprepare(lp->clk); +	clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks); +	clk_disable_unprepare(lp->axi_clk);  	of_node_put(lp->phy_node);  	lp->phy_node = NULL; | 
