From 15e121ada53deb46da99d76f0417c728be436099 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Apr 2015 11:43:04 +0200 Subject: [PATCH 1/5] usb: musb: dsps: Do not use priv pointer Use container_of instead of dev->priv pointer. dev->priv is used by the musb core layer (which maybe should not be the case, but using container_of is good anyway). Signed-off-by: Sascha Hauer --- drivers/usb/musb/musb_dsps.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 36a316ab3..7bad1f813 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -129,14 +129,17 @@ struct dsps_glue { struct musb_hdrc_platform_data pdata; }; +static struct dsps_glue *to_dsps_glue(struct musb *musb) +{ + return container_of(musb, struct dsps_glue, musb); +} + /** * dsps_musb_enable - enable interrupts */ static void dsps_musb_enable(struct musb *musb) { - struct device_d *dev = musb->controller; - struct device_d *pdev = dev; - struct dsps_glue *glue = pdev->priv; + struct dsps_glue *glue = to_dsps_glue(musb); const struct dsps_musb_wrapper *wrp = glue->wrp; void __iomem *reg_base = musb->ctrl_base; u32 epmask, coremask; @@ -158,9 +161,7 @@ static void dsps_musb_enable(struct musb *musb) */ static void dsps_musb_disable(struct musb *musb) { - struct device_d *dev = musb->controller; - struct device_d *pdev = dev; - struct dsps_glue *glue = pdev->priv; + struct dsps_glue *glue = to_dsps_glue(musb); const struct dsps_musb_wrapper *wrp = glue->wrp; void __iomem *reg_base = musb->ctrl_base; @@ -173,8 +174,7 @@ static void dsps_musb_disable(struct musb *musb) static irqreturn_t dsps_interrupt(struct musb *musb) { void __iomem *reg_base = musb->ctrl_base; - struct device_d *dev = musb->controller; - struct dsps_glue *glue = dev->priv; + struct dsps_glue *glue = to_dsps_glue(musb); const struct dsps_musb_wrapper *wrp = glue->wrp; unsigned long flags; irqreturn_t ret = IRQ_NONE; @@ -213,8 +213,7 @@ out: static int dsps_musb_init(struct musb *musb) { - struct device_d *dev = musb->controller; - struct dsps_glue *glue = dev->priv; + struct dsps_glue *glue = to_dsps_glue(musb); const struct dsps_musb_wrapper *wrp = glue->wrp; u32 rev, val, mode; @@ -377,8 +376,6 @@ static int dsps_probe(struct device_d *dev) glue->dev = dev; glue->wrp = wrp; - dev->priv = glue; - pdata = &glue->pdata; glue->musb.mregs = dev_request_mem_region(dev, 0); From e8388cbb37e6aecb3e111169bc79e0e0eef2bfeb Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Apr 2015 11:46:54 +0200 Subject: [PATCH 2/5] usb: musb: set controller->priv pointer This is used by the detect callback but never initialized. Signed-off-by: Sascha Hauer --- drivers/usb/musb/musb_barebox.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/musb/musb_barebox.c b/drivers/usb/musb/musb_barebox.c index 6bc232b57..b1f38c35a 100644 --- a/drivers/usb/musb/musb_barebox.c +++ b/drivers/usb/musb/musb_barebox.c @@ -139,6 +139,7 @@ int musb_register(struct musb *musb) host->submit_control_msg = submit_control_msg; host->submit_bulk_msg = submit_bulk_msg; + musb->controller->priv = musb; musb->controller->detect = musb_detect; usb_register_host(host); From efe0fa9e927a699d1d0e09ad56e8ba9eb08a61e2 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Apr 2015 12:40:45 +0200 Subject: [PATCH 3/5] net: phy: Add missing phy_unregister_device The counterpart of phy_register_device is missing. Add it. Signed-off-by: Sascha Hauer --- drivers/net/phy/phy.c | 11 +++++++++++ include/linux/phy.h | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f3dffca46..edf5d03d9 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -272,6 +272,17 @@ int phy_register_device(struct phy_device *phydev) return ret; } +void phy_unregister_device(struct phy_device *phydev) +{ + if (!phydev->registered) + return; + + phydev->bus->phy_map[phydev->addr] = NULL; + + unregister_device(&phydev->dev); + phydev->registered = 0; +} + static struct phy_device *of_mdio_find_phy(struct eth_device *edev) { struct device_d *dev; diff --git a/include/linux/phy.h b/include/linux/phy.h index c0fd4ff19..9a451a62d 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -266,6 +266,7 @@ int phy_init(void); int phy_init_hw(struct phy_device *phydev); int phy_register_device(struct phy_device* dev); +void phy_unregister_device(struct phy_device *phydev); /** * phy_read - Convenience function for reading a given PHY register From acd1d67ea22dd0e140bf5d085e03243053c31935 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Apr 2015 12:41:43 +0200 Subject: [PATCH 4/5] eth: halt active ethernet device on unregister When an active ethernet device is unregistered it should be halted to quiesce the device. Signed-off-by: Sascha Hauer --- net/eth.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/eth.c b/net/eth.c index 89bddba07..0c1ff73e4 100644 --- a/net/eth.c +++ b/net/eth.c @@ -385,6 +385,9 @@ void eth_unregister(struct eth_device *edev) if (edev == eth_current) eth_current = NULL; + if (edev->active) + edev->halt(edev); + if (IS_ENABLED(CONFIG_OFDEVICE)) free(edev->nodepath); From 0706fd366faab8274d96662265ac8c14baf0762c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 28 Apr 2015 12:45:26 +0200 Subject: [PATCH 5/5] net: cpsw: unregister device on remove callback The CPSW uses DMA, so we should quiesce the device before leaving barebox. This patch unregisters the CPSW properly on the device remove callback. To do this we have to fix the error path in cpsw_slave_setup, since this function can fail and we need a known slave status in the remove function. Signed-off-by: Sascha Hauer --- drivers/net/cpsw.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index 76872546f..c0db96bb5 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -916,20 +916,22 @@ static int cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, struct phy_device *phy; phy = mdiobus_scan(&priv->miibus, priv->slaves[slave_num].phy_id); - if (IS_ERR(phy)) - return PTR_ERR(phy); + if (IS_ERR(phy)) { + ret = PTR_ERR(phy); + goto err_out; + } phy->dev.device_node = priv->slaves[slave_num].dev.device_node; ret = phy_register_device(phy); if (ret) - return ret; + goto err_out; sprintf(dev->name, "cpsw-slave"); dev->id = slave->slave_num; dev->parent = priv->dev; ret = register_device(dev); if (ret) - return ret; + goto err_register_dev; dev_dbg(&slave->dev, "* %s\n", __func__); @@ -948,7 +950,20 @@ static int cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, edev->set_ethaddr = cpsw_set_hwaddr; edev->parent = dev; - return eth_register(edev); + ret = eth_register(edev); + if (ret) + goto err_register_edev; + + return 0; + +err_register_dev: + phy_unregister_device(phy); +err_register_edev: + unregister_device(dev); +err_out: + slave->slave_num = -1; + + return ret; } struct cpsw_data { @@ -1219,6 +1234,8 @@ int cpsw_probe(struct device_d *dev) } } + dev->priv = priv; + return 0; out: free(priv->slaves); @@ -1227,6 +1244,22 @@ out: return ret; } +static void cpsw_remove(struct device_d *dev) +{ + struct cpsw_priv *priv = dev->priv; + int i; + + for (i = 0; i < priv->num_slaves; i++) { + struct cpsw_slave *slave = &priv->slaves[i]; + if (slave->slave_num < 0) + continue; + + eth_unregister(&slave->edev); + } + + mdiobus_unregister(&priv->miibus); +} + static __maybe_unused struct of_device_id cpsw_dt_ids[] = { { .compatible = "ti,cpsw", @@ -1238,6 +1271,7 @@ static __maybe_unused struct of_device_id cpsw_dt_ids[] = { static struct driver_d cpsw_driver = { .name = "cpsw", .probe = cpsw_probe, + .remove = cpsw_remove, .of_compatible = DRV_OF_COMPAT(cpsw_dt_ids), }; device_platform_driver(cpsw_driver);