aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/mdio_bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/mdio_bus.c')
-rw-r--r--drivers/net/phy/mdio_bus.c72
1 files changed, 64 insertions, 8 deletions
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index bd4e8d72dc08..e17b70291bbc 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -264,6 +264,8 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
264 (phydev->phy_id & phydrv->phy_id_mask)); 264 (phydev->phy_id & phydrv->phy_id_mask));
265} 265}
266 266
267#ifdef CONFIG_PM
268
267static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) 269static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
268{ 270{
269 struct device_driver *drv = phydev->dev.driver; 271 struct device_driver *drv = phydev->dev.driver;
@@ -295,34 +297,88 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
295 return true; 297 return true;
296} 298}
297 299
298/* Suspend and resume. Copied from platform_suspend and 300static int mdio_bus_suspend(struct device *dev)
299 * platform_resume
300 */
301static int mdio_bus_suspend(struct device * dev, pm_message_t state)
302{ 301{
303 struct phy_driver *phydrv = to_phy_driver(dev->driver); 302 struct phy_driver *phydrv = to_phy_driver(dev->driver);
304 struct phy_device *phydev = to_phy_device(dev); 303 struct phy_device *phydev = to_phy_device(dev);
305 304
305 /*
306 * We must stop the state machine manually, otherwise it stops out of
307 * control, possibly with the phydev->lock held. Upon resume, netdev
308 * may call phy routines that try to grab the same lock, and that may
309 * lead to a deadlock.
310 */
311 if (phydev->attached_dev)
312 phy_stop_machine(phydev);
313
306 if (!mdio_bus_phy_may_suspend(phydev)) 314 if (!mdio_bus_phy_may_suspend(phydev))
307 return 0; 315 return 0;
316
308 return phydrv->suspend(phydev); 317 return phydrv->suspend(phydev);
309} 318}
310 319
311static int mdio_bus_resume(struct device * dev) 320static int mdio_bus_resume(struct device *dev)
312{ 321{
313 struct phy_driver *phydrv = to_phy_driver(dev->driver); 322 struct phy_driver *phydrv = to_phy_driver(dev->driver);
314 struct phy_device *phydev = to_phy_device(dev); 323 struct phy_device *phydev = to_phy_device(dev);
324 int ret;
315 325
316 if (!mdio_bus_phy_may_suspend(phydev)) 326 if (!mdio_bus_phy_may_suspend(phydev))
327 goto no_resume;
328
329 ret = phydrv->resume(phydev);
330 if (ret < 0)
331 return ret;
332
333no_resume:
334 if (phydev->attached_dev)
335 phy_start_machine(phydev, NULL);
336
337 return 0;
338}
339
340static int mdio_bus_restore(struct device *dev)
341{
342 struct phy_device *phydev = to_phy_device(dev);
343 struct net_device *netdev = phydev->attached_dev;
344 int ret;
345
346 if (!netdev)
317 return 0; 347 return 0;
318 return phydrv->resume(phydev); 348
349 ret = phy_init_hw(phydev);
350 if (ret < 0)
351 return ret;
352
353 /* The PHY needs to renegotiate. */
354 phydev->link = 0;
355 phydev->state = PHY_UP;
356
357 phy_start_machine(phydev, NULL);
358
359 return 0;
319} 360}
320 361
362static struct dev_pm_ops mdio_bus_pm_ops = {
363 .suspend = mdio_bus_suspend,
364 .resume = mdio_bus_resume,
365 .freeze = mdio_bus_suspend,
366 .thaw = mdio_bus_resume,
367 .restore = mdio_bus_restore,
368};
369
370#define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops)
371
372#else
373
374#define MDIO_BUS_PM_OPS NULL
375
376#endif /* CONFIG_PM */
377
321struct bus_type mdio_bus_type = { 378struct bus_type mdio_bus_type = {
322 .name = "mdio_bus", 379 .name = "mdio_bus",
323 .match = mdio_bus_match, 380 .match = mdio_bus_match,
324 .suspend = mdio_bus_suspend, 381 .pm = MDIO_BUS_PM_OPS,
325 .resume = mdio_bus_resume,
326}; 382};
327EXPORT_SYMBOL(mdio_bus_type); 383EXPORT_SYMBOL(mdio_bus_type);
328 384