Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e2d1af3 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'cpsw-fixes'



Johan Hovold says:

====================
net: cpsw: fix leaks and probe deferral

This series fixes as number of leaks and issues in the cpsw probe-error
and driver-unbind paths, some which specifically prevented deferred
probing.

v2
 - Keep platform device runtime-resumed throughout probe instead of
   resuming in the probe error path as suggested by Grygorii (patch
   1/7).

 - Runtime-resume platform device before registering any children in
   order to make sure it is synchronously suspended after deregistering
   children in the error path (patch 3/7).
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 06ba3b21 23a09873
Loading
Loading
Loading
Loading
+74 −21
Original line number Diff line number Diff line
@@ -2375,8 +2375,11 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
			 * to the PHY is the Ethernet MAC DT node.
			 */
			ret = of_phy_register_fixed_link(slave_node);
			if (ret)
			if (ret) {
				if (ret != -EPROBE_DEFER)
					dev_err(&pdev->dev, "failed to register fixed-link phy: %d\n", ret);
				return ret;
			}
			slave_data->phy_node = of_node_get(slave_node);
		} else if (parp) {
			u32 phyid;
@@ -2397,6 +2400,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
			}
			snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
				 PHY_ID_FMT, mdio->name, phyid);
			put_device(&mdio->dev);
		} else {
			dev_err(&pdev->dev,
				"No slave[%d] phy_id, phy-handle, or fixed-link property\n",
@@ -2440,6 +2444,46 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
	return 0;
}

static void cpsw_remove_dt(struct platform_device *pdev)
{
	struct net_device *ndev = platform_get_drvdata(pdev);
	struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
	struct cpsw_platform_data *data = &cpsw->data;
	struct device_node *node = pdev->dev.of_node;
	struct device_node *slave_node;
	int i = 0;

	for_each_available_child_of_node(node, slave_node) {
		struct cpsw_slave_data *slave_data = &data->slave_data[i];

		if (strcmp(slave_node->name, "slave"))
			continue;

		if (of_phy_is_fixed_link(slave_node)) {
			struct phy_device *phydev;

			phydev = of_phy_find_device(slave_node);
			if (phydev) {
				fixed_phy_unregister(phydev);
				/* Put references taken by
				 * of_phy_find_device() and
				 * of_phy_register_fixed_link().
				 */
				phy_device_free(phydev);
				phy_device_free(phydev);
			}
		}

		of_node_put(slave_data->phy_node);

		i++;
		if (i == data->slaves)
			break;
	}

	of_platform_depopulate(&pdev->dev);
}

static int cpsw_probe_dual_emac(struct cpsw_priv *priv)
{
	struct cpsw_common		*cpsw = priv->cpsw;
@@ -2547,6 +2591,9 @@ static int cpsw_probe(struct platform_device *pdev)
	int irq;

	cpsw = devm_kzalloc(&pdev->dev, sizeof(struct cpsw_common), GFP_KERNEL);
	if (!cpsw)
		return -ENOMEM;

	cpsw->dev = &pdev->dev;

	ndev = alloc_etherdev_mq(sizeof(struct cpsw_priv), CPSW_MAX_QUEUES);
@@ -2584,11 +2631,19 @@ static int cpsw_probe(struct platform_device *pdev)
	/* Select default pin state */
	pinctrl_pm_select_default_state(&pdev->dev);

	if (cpsw_probe_dt(&cpsw->data, pdev)) {
		dev_err(&pdev->dev, "cpsw: platform data missing\n");
		ret = -ENODEV;
	/* Need to enable clocks with runtime PM api to access module
	 * registers
	 */
	ret = pm_runtime_get_sync(&pdev->dev);
	if (ret < 0) {
		pm_runtime_put_noidle(&pdev->dev);
		goto clean_runtime_disable_ret;
	}

	ret = cpsw_probe_dt(&cpsw->data, pdev);
	if (ret)
		goto clean_dt_ret;

	data = &cpsw->data;
	cpsw->rx_ch_num = 1;
	cpsw->tx_ch_num = 1;
@@ -2608,7 +2663,7 @@ static int cpsw_probe(struct platform_device *pdev)
				    GFP_KERNEL);
	if (!cpsw->slaves) {
		ret = -ENOMEM;
		goto clean_runtime_disable_ret;
		goto clean_dt_ret;
	}
	for (i = 0; i < data->slaves; i++)
		cpsw->slaves[i].slave_num = i;
@@ -2620,7 +2675,7 @@ static int cpsw_probe(struct platform_device *pdev)
	if (IS_ERR(clk)) {
		dev_err(priv->dev, "fck is not found\n");
		ret = -ENODEV;
		goto clean_runtime_disable_ret;
		goto clean_dt_ret;
	}
	cpsw->bus_freq_mhz = clk_get_rate(clk) / 1000000;

@@ -2628,26 +2683,17 @@ static int cpsw_probe(struct platform_device *pdev)
	ss_regs = devm_ioremap_resource(&pdev->dev, ss_res);
	if (IS_ERR(ss_regs)) {
		ret = PTR_ERR(ss_regs);
		goto clean_runtime_disable_ret;
		goto clean_dt_ret;
	}
	cpsw->regs = ss_regs;

	/* Need to enable clocks with runtime PM api to access module
	 * registers
	 */
	ret = pm_runtime_get_sync(&pdev->dev);
	if (ret < 0) {
		pm_runtime_put_noidle(&pdev->dev);
		goto clean_runtime_disable_ret;
	}
	cpsw->version = readl(&cpsw->regs->id_ver);
	pm_runtime_put_sync(&pdev->dev);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	cpsw->wr_regs = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(cpsw->wr_regs)) {
		ret = PTR_ERR(cpsw->wr_regs);
		goto clean_runtime_disable_ret;
		goto clean_dt_ret;
	}

	memset(&dma_params, 0, sizeof(dma_params));
@@ -2684,7 +2730,7 @@ static int cpsw_probe(struct platform_device *pdev)
	default:
		dev_err(priv->dev, "unknown version 0x%08x\n", cpsw->version);
		ret = -ENODEV;
		goto clean_runtime_disable_ret;
		goto clean_dt_ret;
	}
	for (i = 0; i < cpsw->data.slaves; i++) {
		struct cpsw_slave *slave = &cpsw->slaves[i];
@@ -2713,7 +2759,7 @@ static int cpsw_probe(struct platform_device *pdev)
	if (!cpsw->dma) {
		dev_err(priv->dev, "error initializing dma\n");
		ret = -ENOMEM;
		goto clean_runtime_disable_ret;
		goto clean_dt_ret;
	}

	cpsw->txch[0] = cpdma_chan_create(cpsw->dma, 0, cpsw_tx_handler, 0);
@@ -2811,16 +2857,23 @@ static int cpsw_probe(struct platform_device *pdev)
		ret = cpsw_probe_dual_emac(priv);
		if (ret) {
			cpsw_err(priv, probe, "error probe slave 2 emac interface\n");
			goto clean_ale_ret;
			goto clean_unregister_netdev_ret;
		}
	}

	pm_runtime_put(&pdev->dev);

	return 0;

clean_unregister_netdev_ret:
	unregister_netdev(ndev);
clean_ale_ret:
	cpsw_ale_destroy(cpsw->ale);
clean_dma_ret:
	cpdma_ctlr_destroy(cpsw->dma);
clean_dt_ret:
	cpsw_remove_dt(pdev);
	pm_runtime_put_sync(&pdev->dev);
clean_runtime_disable_ret:
	pm_runtime_disable(&pdev->dev);
clean_ndev_ret:
@@ -2846,7 +2899,7 @@ static int cpsw_remove(struct platform_device *pdev)

	cpsw_ale_destroy(cpsw->ale);
	cpdma_ctlr_destroy(cpsw->dma);
	of_platform_depopulate(&pdev->dev);
	cpsw_remove_dt(pdev);
	pm_runtime_put_sync(&pdev->dev);
	pm_runtime_disable(&pdev->dev);
	if (cpsw->data.dual_emac)