diff options
author | Andrew Lunn <andrew@lunn.ch> | 2016-01-06 14:11:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-01-07 14:31:27 -0500 |
commit | bc87922ff59d364a33e9bce0febdef21a7fbd2af (patch) | |
tree | c7179d7f4969f2006e81cd7512c5d0aac8392de2 | |
parent | 0071f56e46dadb88dc3ad1f8d9cf9c3ae014735d (diff) |
phy: Move PHY PM operations into phy_device
The MDIO PM operations are really PHY device PM operations. So move
them into phy_device. This will be needed when we support devices on
the mdio bus which are not PHYs.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 83 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 110 | ||||
-rw-r--r-- | include/linux/mdio.h | 2 |
3 files changed, 121 insertions, 74 deletions
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index e6dddb086265..65ff8199bd09 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -561,95 +561,32 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv) | |||
561 | } | 561 | } |
562 | 562 | ||
563 | #ifdef CONFIG_PM | 563 | #ifdef CONFIG_PM |
564 | |||
565 | static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) | ||
566 | { | ||
567 | struct device_driver *drv = phydev->mdio.dev.driver; | ||
568 | struct phy_driver *phydrv = to_phy_driver(drv); | ||
569 | struct net_device *netdev = phydev->attached_dev; | ||
570 | |||
571 | if (!drv || !phydrv->suspend) | ||
572 | return false; | ||
573 | |||
574 | /* PHY not attached? May suspend if the PHY has not already been | ||
575 | * suspended as part of a prior call to phy_disconnect() -> | ||
576 | * phy_detach() -> phy_suspend() because the parent netdev might be the | ||
577 | * MDIO bus driver and clock gated at this point. | ||
578 | */ | ||
579 | if (!netdev) | ||
580 | return !phydev->suspended; | ||
581 | |||
582 | /* Don't suspend PHY if the attched netdev parent may wakeup. | ||
583 | * The parent may point to a PCI device, as in tg3 driver. | ||
584 | */ | ||
585 | if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent)) | ||
586 | return false; | ||
587 | |||
588 | /* Also don't suspend PHY if the netdev itself may wakeup. This | ||
589 | * is the case for devices w/o underlaying pwr. mgmt. aware bus, | ||
590 | * e.g. SoC devices. | ||
591 | */ | ||
592 | if (device_may_wakeup(&netdev->dev)) | ||
593 | return false; | ||
594 | |||
595 | return true; | ||
596 | } | ||
597 | |||
598 | static int mdio_bus_suspend(struct device *dev) | 564 | static int mdio_bus_suspend(struct device *dev) |
599 | { | 565 | { |
600 | struct phy_device *phydev = to_phy_device(dev); | 566 | struct mdio_device *mdio = to_mdio_device(dev); |
601 | 567 | ||
602 | /* We must stop the state machine manually, otherwise it stops out of | 568 | if (mdio->pm_ops && mdio->pm_ops->suspend) |
603 | * control, possibly with the phydev->lock held. Upon resume, netdev | 569 | return mdio->pm_ops->suspend(dev); |
604 | * may call phy routines that try to grab the same lock, and that may | ||
605 | * lead to a deadlock. | ||
606 | */ | ||
607 | if (phydev->attached_dev && phydev->adjust_link) | ||
608 | phy_stop_machine(phydev); | ||
609 | |||
610 | if (!mdio_bus_phy_may_suspend(phydev)) | ||
611 | return 0; | ||
612 | 570 | ||
613 | return phy_suspend(phydev); | 571 | return 0; |
614 | } | 572 | } |
615 | 573 | ||
616 | static int mdio_bus_resume(struct device *dev) | 574 | static int mdio_bus_resume(struct device *dev) |
617 | { | 575 | { |
618 | struct phy_device *phydev = to_phy_device(dev); | 576 | struct mdio_device *mdio = to_mdio_device(dev); |
619 | int ret; | ||
620 | |||
621 | if (!mdio_bus_phy_may_suspend(phydev)) | ||
622 | goto no_resume; | ||
623 | 577 | ||
624 | ret = phy_resume(phydev); | 578 | if (mdio->pm_ops && mdio->pm_ops->resume) |
625 | if (ret < 0) | 579 | return mdio->pm_ops->resume(dev); |
626 | return ret; | ||
627 | |||
628 | no_resume: | ||
629 | if (phydev->attached_dev && phydev->adjust_link) | ||
630 | phy_start_machine(phydev); | ||
631 | 580 | ||
632 | return 0; | 581 | return 0; |
633 | } | 582 | } |
634 | 583 | ||
635 | static int mdio_bus_restore(struct device *dev) | 584 | static int mdio_bus_restore(struct device *dev) |
636 | { | 585 | { |
637 | struct phy_device *phydev = to_phy_device(dev); | 586 | struct mdio_device *mdio = to_mdio_device(dev); |
638 | struct net_device *netdev = phydev->attached_dev; | ||
639 | int ret; | ||
640 | |||
641 | if (!netdev) | ||
642 | return 0; | ||
643 | |||
644 | ret = phy_init_hw(phydev); | ||
645 | if (ret < 0) | ||
646 | return ret; | ||
647 | |||
648 | /* The PHY needs to renegotiate. */ | ||
649 | phydev->link = 0; | ||
650 | phydev->state = PHY_UP; | ||
651 | 587 | ||
652 | phy_start_machine(phydev); | 588 | if (mdio->pm_ops && mdio->pm_ops->restore) |
589 | return mdio->pm_ops->restore(dev); | ||
653 | 590 | ||
654 | return 0; | 591 | return 0; |
655 | } | 592 | } |
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 7a5222daff93..eb0b0ed32662 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -63,6 +63,115 @@ static struct phy_driver genphy_driver[GENPHY_DRV_MAX]; | |||
63 | static LIST_HEAD(phy_fixup_list); | 63 | static LIST_HEAD(phy_fixup_list); |
64 | static DEFINE_MUTEX(phy_fixup_lock); | 64 | static DEFINE_MUTEX(phy_fixup_lock); |
65 | 65 | ||
66 | #ifdef CONFIG_PM | ||
67 | static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) | ||
68 | { | ||
69 | struct device_driver *drv = phydev->mdio.dev.driver; | ||
70 | struct phy_driver *phydrv = to_phy_driver(drv); | ||
71 | struct net_device *netdev = phydev->attached_dev; | ||
72 | |||
73 | if (!drv || !phydrv->suspend) | ||
74 | return false; | ||
75 | |||
76 | /* PHY not attached? May suspend if the PHY has not already been | ||
77 | * suspended as part of a prior call to phy_disconnect() -> | ||
78 | * phy_detach() -> phy_suspend() because the parent netdev might be the | ||
79 | * MDIO bus driver and clock gated at this point. | ||
80 | */ | ||
81 | if (!netdev) | ||
82 | return !phydev->suspended; | ||
83 | |||
84 | /* Don't suspend PHY if the attached netdev parent may wakeup. | ||
85 | * The parent may point to a PCI device, as in tg3 driver. | ||
86 | */ | ||
87 | if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent)) | ||
88 | return false; | ||
89 | |||
90 | /* Also don't suspend PHY if the netdev itself may wakeup. This | ||
91 | * is the case for devices w/o underlaying pwr. mgmt. aware bus, | ||
92 | * e.g. SoC devices. | ||
93 | */ | ||
94 | if (device_may_wakeup(&netdev->dev)) | ||
95 | return false; | ||
96 | |||
97 | return true; | ||
98 | } | ||
99 | |||
100 | static int mdio_bus_phy_suspend(struct device *dev) | ||
101 | { | ||
102 | struct phy_device *phydev = to_phy_device(dev); | ||
103 | |||
104 | /* We must stop the state machine manually, otherwise it stops out of | ||
105 | * control, possibly with the phydev->lock held. Upon resume, netdev | ||
106 | * may call phy routines that try to grab the same lock, and that may | ||
107 | * lead to a deadlock. | ||
108 | */ | ||
109 | if (phydev->attached_dev && phydev->adjust_link) | ||
110 | phy_stop_machine(phydev); | ||
111 | |||
112 | if (!mdio_bus_phy_may_suspend(phydev)) | ||
113 | return 0; | ||
114 | |||
115 | return phy_suspend(phydev); | ||
116 | } | ||
117 | |||
118 | static int mdio_bus_phy_resume(struct device *dev) | ||
119 | { | ||
120 | struct phy_device *phydev = to_phy_device(dev); | ||
121 | int ret; | ||
122 | |||
123 | if (!mdio_bus_phy_may_suspend(phydev)) | ||
124 | goto no_resume; | ||
125 | |||
126 | ret = phy_resume(phydev); | ||
127 | if (ret < 0) | ||
128 | return ret; | ||
129 | |||
130 | no_resume: | ||
131 | if (phydev->attached_dev && phydev->adjust_link) | ||
132 | phy_start_machine(phydev); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int mdio_bus_phy_restore(struct device *dev) | ||
138 | { | ||
139 | struct phy_device *phydev = to_phy_device(dev); | ||
140 | struct net_device *netdev = phydev->attached_dev; | ||
141 | int ret; | ||
142 | |||
143 | if (!netdev) | ||
144 | return 0; | ||
145 | |||
146 | ret = phy_init_hw(phydev); | ||
147 | if (ret < 0) | ||
148 | return ret; | ||
149 | |||
150 | /* The PHY needs to renegotiate. */ | ||
151 | phydev->link = 0; | ||
152 | phydev->state = PHY_UP; | ||
153 | |||
154 | phy_start_machine(phydev); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static const struct dev_pm_ops mdio_bus_phy_pm_ops = { | ||
160 | .suspend = mdio_bus_phy_suspend, | ||
161 | .resume = mdio_bus_phy_resume, | ||
162 | .freeze = mdio_bus_phy_suspend, | ||
163 | .thaw = mdio_bus_phy_resume, | ||
164 | .restore = mdio_bus_phy_restore, | ||
165 | }; | ||
166 | |||
167 | #define MDIO_BUS_PHY_PM_OPS (&mdio_bus_phy_pm_ops) | ||
168 | |||
169 | #else | ||
170 | |||
171 | #define MDIO_BUS_PHY_PM_OPS NULL | ||
172 | |||
173 | #endif /* CONFIG_PM */ | ||
174 | |||
66 | /** | 175 | /** |
67 | * phy_register_fixup - creates a new phy_fixup and adds it to the list | 176 | * phy_register_fixup - creates a new phy_fixup and adds it to the list |
68 | * @bus_id: A string which matches phydev->mdio.dev.bus_id (or PHY_ANY_ID) | 177 | * @bus_id: A string which matches phydev->mdio.dev.bus_id (or PHY_ANY_ID) |
@@ -165,6 +274,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, | |||
165 | mdiodev->dev.parent = &bus->dev; | 274 | mdiodev->dev.parent = &bus->dev; |
166 | mdiodev->dev.bus = &mdio_bus_type; | 275 | mdiodev->dev.bus = &mdio_bus_type; |
167 | mdiodev->bus = bus; | 276 | mdiodev->bus = bus; |
277 | mdiodev->pm_ops = MDIO_BUS_PHY_PM_OPS; | ||
168 | mdiodev->addr = addr; | 278 | mdiodev->addr = addr; |
169 | mdiodev->flags = MDIO_DEVICE_FLAG_PHY; | 279 | mdiodev->flags = MDIO_DEVICE_FLAG_PHY; |
170 | 280 | ||
diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 8cd9579e18ea..9f844d372ed5 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h | |||
@@ -15,7 +15,7 @@ struct mii_bus; | |||
15 | 15 | ||
16 | struct mdio_device { | 16 | struct mdio_device { |
17 | struct device dev; | 17 | struct device dev; |
18 | 18 | const struct dev_pm_ops *pm_ops; | |
19 | struct mii_bus *bus; | 19 | struct mii_bus *bus; |
20 | /* Bus address of the MDIO device (0-31) */ | 20 | /* Bus address of the MDIO device (0-31) */ |
21 | int addr; | 21 | int addr; |