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

Commit 122e9b71 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'cpsw-fixes'

Grygorii Strashko says:

====================
drivers: net: cpsw: fix driver loading/unloading

This series fixes set of isssues observed when CPSW driver module is unloaded/loaded:
1) rmmod: deadlock in cpdma_ctlr_destroy
2) rmmod: L3 back-trace and crash if all net interfaces are down, because CPSW
can be powerred down by PM runtime in this case.
3) insmod: mdio device is not recreated on next insmod
 - need to use of_platform_depopulate() in cpsw_remove().
4) rmmod: system crash on omap_device removal

Tested on: am437x-idk, am57xx-beagle-x15

Changes in v2:
- build warning fixed
- added fix for correct omap_device removal

Link on v1:
 https://lkml.org/lkml/2016/7/22/240


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c882219a 213fa10d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -194,7 +194,7 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
	int err;

	switch (event) {
	case BUS_NOTIFY_DEL_DEVICE:
	case BUS_NOTIFY_REMOVED_DEVICE:
		if (pdev->archdata.od)
			omap_device_delete(pdev->archdata.od);
		break;
+9 −10
Original line number Diff line number Diff line
@@ -2564,19 +2564,17 @@ static int cpsw_probe(struct platform_device *pdev)
	return ret;
}

static int cpsw_remove_child_device(struct device *dev, void *c)
{
	struct platform_device *pdev = to_platform_device(dev);

	of_device_unregister(pdev);

	return 0;
}

static int cpsw_remove(struct platform_device *pdev)
{
	struct net_device *ndev = platform_get_drvdata(pdev);
	struct cpsw_priv *priv = netdev_priv(ndev);
	int ret;

	ret = pm_runtime_get_sync(&pdev->dev);
	if (ret < 0) {
		pm_runtime_put_noidle(&pdev->dev);
		return ret;
	}

	if (priv->data.dual_emac)
		unregister_netdev(cpsw_get_slave_ndev(priv, 1));
@@ -2584,8 +2582,9 @@ static int cpsw_remove(struct platform_device *pdev)

	cpsw_ale_destroy(priv->ale);
	cpdma_ctlr_destroy(priv->dma);
	of_platform_depopulate(&pdev->dev);
	pm_runtime_put_sync(&pdev->dev);
	pm_runtime_disable(&pdev->dev);
	device_for_each_child(&pdev->dev, NULL, cpsw_remove_child_device);
	if (priv->data.dual_emac)
		free_netdev(cpsw_get_slave_ndev(priv, 1));
	free_netdev(ndev);
+0 −3
Original line number Diff line number Diff line
@@ -357,13 +357,11 @@ EXPORT_SYMBOL_GPL(cpdma_ctlr_stop);

int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
{
	unsigned long flags;
	int ret = 0, i;

	if (!ctlr)
		return -EINVAL;

	spin_lock_irqsave(&ctlr->lock, flags);
	if (ctlr->state != CPDMA_STATE_IDLE)
		cpdma_ctlr_stop(ctlr);

@@ -371,7 +369,6 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
		cpdma_chan_destroy(ctlr->channels[i]);

	cpdma_desc_pool_destroy(ctlr->pool);
	spin_unlock_irqrestore(&ctlr->lock, flags);
	return ret;
}
EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy);