diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/at803x.c | 4 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 4 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 1 | ||||
-rw-r--r-- | drivers/net/phy/meson-gxl.c | 74 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 9 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 10 |
6 files changed, 87 insertions, 15 deletions
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 5f93e6add563..e911e4990b20 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c | |||
@@ -239,14 +239,10 @@ static int at803x_resume(struct phy_device *phydev) | |||
239 | { | 239 | { |
240 | int value; | 240 | int value; |
241 | 241 | ||
242 | mutex_lock(&phydev->lock); | ||
243 | |||
244 | value = phy_read(phydev, MII_BMCR); | 242 | value = phy_read(phydev, MII_BMCR); |
245 | value &= ~(BMCR_PDOWN | BMCR_ISOLATE); | 243 | value &= ~(BMCR_PDOWN | BMCR_ISOLATE); |
246 | phy_write(phydev, MII_BMCR, value); | 244 | phy_write(phydev, MII_BMCR, value); |
247 | 245 | ||
248 | mutex_unlock(&phydev->lock); | ||
249 | |||
250 | return 0; | 246 | return 0; |
251 | } | 247 | } |
252 | 248 | ||
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 4d02b27df044..b5a8f750e433 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c | |||
@@ -637,6 +637,10 @@ static int m88e1510_config_aneg(struct phy_device *phydev) | |||
637 | if (err < 0) | 637 | if (err < 0) |
638 | goto error; | 638 | goto error; |
639 | 639 | ||
640 | /* Do not touch the fiber page if we're in copper->sgmii mode */ | ||
641 | if (phydev->interface == PHY_INTERFACE_MODE_SGMII) | ||
642 | return 0; | ||
643 | |||
640 | /* Then the fiber link */ | 644 | /* Then the fiber link */ |
641 | err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); | 645 | err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); |
642 | if (err < 0) | 646 | if (err < 0) |
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 2df7b62c1a36..54d00a1d2bef 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -270,6 +270,7 @@ static void of_mdiobus_link_mdiodev(struct mii_bus *bus, | |||
270 | 270 | ||
271 | if (addr == mdiodev->addr) { | 271 | if (addr == mdiodev->addr) { |
272 | dev->of_node = child; | 272 | dev->of_node = child; |
273 | dev->fwnode = of_fwnode_handle(child); | ||
273 | return; | 274 | return; |
274 | } | 275 | } |
275 | } | 276 | } |
diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c index 1ea69b7585d9..842eb871a6e3 100644 --- a/drivers/net/phy/meson-gxl.c +++ b/drivers/net/phy/meson-gxl.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/ethtool.h> | 22 | #include <linux/ethtool.h> |
23 | #include <linux/phy.h> | 23 | #include <linux/phy.h> |
24 | #include <linux/netdevice.h> | 24 | #include <linux/netdevice.h> |
25 | #include <linux/bitfield.h> | ||
25 | 26 | ||
26 | static int meson_gxl_config_init(struct phy_device *phydev) | 27 | static int meson_gxl_config_init(struct phy_device *phydev) |
27 | { | 28 | { |
@@ -50,6 +51,77 @@ static int meson_gxl_config_init(struct phy_device *phydev) | |||
50 | return 0; | 51 | return 0; |
51 | } | 52 | } |
52 | 53 | ||
54 | /* This function is provided to cope with the possible failures of this phy | ||
55 | * during aneg process. When aneg fails, the PHY reports that aneg is done | ||
56 | * but the value found in MII_LPA is wrong: | ||
57 | * - Early failures: MII_LPA is just 0x0001. if MII_EXPANSION reports that | ||
58 | * the link partner (LP) supports aneg but the LP never acked our base | ||
59 | * code word, it is likely that we never sent it to begin with. | ||
60 | * - Late failures: MII_LPA is filled with a value which seems to make sense | ||
61 | * but it actually is not what the LP is advertising. It seems that we | ||
62 | * can detect this using a magic bit in the WOL bank (reg 12 - bit 12). | ||
63 | * If this particular bit is not set when aneg is reported being done, | ||
64 | * it means MII_LPA is likely to be wrong. | ||
65 | * | ||
66 | * In both case, forcing a restart of the aneg process solve the problem. | ||
67 | * When this failure happens, the first retry is usually successful but, | ||
68 | * in some cases, it may take up to 6 retries to get a decent result | ||
69 | */ | ||
70 | static int meson_gxl_read_status(struct phy_device *phydev) | ||
71 | { | ||
72 | int ret, wol, lpa, exp; | ||
73 | |||
74 | if (phydev->autoneg == AUTONEG_ENABLE) { | ||
75 | ret = genphy_aneg_done(phydev); | ||
76 | if (ret < 0) | ||
77 | return ret; | ||
78 | else if (!ret) | ||
79 | goto read_status_continue; | ||
80 | |||
81 | /* Need to access WOL bank, make sure the access is open */ | ||
82 | ret = phy_write(phydev, 0x14, 0x0000); | ||
83 | if (ret) | ||
84 | return ret; | ||
85 | ret = phy_write(phydev, 0x14, 0x0400); | ||
86 | if (ret) | ||
87 | return ret; | ||
88 | ret = phy_write(phydev, 0x14, 0x0000); | ||
89 | if (ret) | ||
90 | return ret; | ||
91 | ret = phy_write(phydev, 0x14, 0x0400); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | /* Request LPI_STATUS WOL register */ | ||
96 | ret = phy_write(phydev, 0x14, 0x8D80); | ||
97 | if (ret) | ||
98 | return ret; | ||
99 | |||
100 | /* Read LPI_STATUS value */ | ||
101 | wol = phy_read(phydev, 0x15); | ||
102 | if (wol < 0) | ||
103 | return wol; | ||
104 | |||
105 | lpa = phy_read(phydev, MII_LPA); | ||
106 | if (lpa < 0) | ||
107 | return lpa; | ||
108 | |||
109 | exp = phy_read(phydev, MII_EXPANSION); | ||
110 | if (exp < 0) | ||
111 | return exp; | ||
112 | |||
113 | if (!(wol & BIT(12)) || | ||
114 | ((exp & EXPANSION_NWAY) && !(lpa & LPA_LPACK))) { | ||
115 | /* Looks like aneg failed after all */ | ||
116 | phydev_dbg(phydev, "LPA corruption - aneg restart\n"); | ||
117 | return genphy_restart_aneg(phydev); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | read_status_continue: | ||
122 | return genphy_read_status(phydev); | ||
123 | } | ||
124 | |||
53 | static struct phy_driver meson_gxl_phy[] = { | 125 | static struct phy_driver meson_gxl_phy[] = { |
54 | { | 126 | { |
55 | .phy_id = 0x01814400, | 127 | .phy_id = 0x01814400, |
@@ -60,7 +132,7 @@ static struct phy_driver meson_gxl_phy[] = { | |||
60 | .config_init = meson_gxl_config_init, | 132 | .config_init = meson_gxl_config_init, |
61 | .config_aneg = genphy_config_aneg, | 133 | .config_aneg = genphy_config_aneg, |
62 | .aneg_done = genphy_aneg_done, | 134 | .aneg_done = genphy_aneg_done, |
63 | .read_status = genphy_read_status, | 135 | .read_status = meson_gxl_read_status, |
64 | .suspend = genphy_suspend, | 136 | .suspend = genphy_suspend, |
65 | .resume = genphy_resume, | 137 | .resume = genphy_resume, |
66 | }, | 138 | }, |
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 2b1e67bc1e73..ed10d1fc8f59 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -828,7 +828,6 @@ EXPORT_SYMBOL(phy_stop); | |||
828 | */ | 828 | */ |
829 | void phy_start(struct phy_device *phydev) | 829 | void phy_start(struct phy_device *phydev) |
830 | { | 830 | { |
831 | bool do_resume = false; | ||
832 | int err = 0; | 831 | int err = 0; |
833 | 832 | ||
834 | mutex_lock(&phydev->lock); | 833 | mutex_lock(&phydev->lock); |
@@ -841,6 +840,9 @@ void phy_start(struct phy_device *phydev) | |||
841 | phydev->state = PHY_UP; | 840 | phydev->state = PHY_UP; |
842 | break; | 841 | break; |
843 | case PHY_HALTED: | 842 | case PHY_HALTED: |
843 | /* if phy was suspended, bring the physical link up again */ | ||
844 | phy_resume(phydev); | ||
845 | |||
844 | /* make sure interrupts are re-enabled for the PHY */ | 846 | /* make sure interrupts are re-enabled for the PHY */ |
845 | if (phydev->irq != PHY_POLL) { | 847 | if (phydev->irq != PHY_POLL) { |
846 | err = phy_enable_interrupts(phydev); | 848 | err = phy_enable_interrupts(phydev); |
@@ -849,17 +851,12 @@ void phy_start(struct phy_device *phydev) | |||
849 | } | 851 | } |
850 | 852 | ||
851 | phydev->state = PHY_RESUMING; | 853 | phydev->state = PHY_RESUMING; |
852 | do_resume = true; | ||
853 | break; | 854 | break; |
854 | default: | 855 | default: |
855 | break; | 856 | break; |
856 | } | 857 | } |
857 | mutex_unlock(&phydev->lock); | 858 | mutex_unlock(&phydev->lock); |
858 | 859 | ||
859 | /* if phy was suspended, bring the physical link up again */ | ||
860 | if (do_resume) | ||
861 | phy_resume(phydev); | ||
862 | |||
863 | phy_trigger_machine(phydev, true); | 860 | phy_trigger_machine(phydev, true); |
864 | } | 861 | } |
865 | EXPORT_SYMBOL(phy_start); | 862 | EXPORT_SYMBOL(phy_start); |
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 67f25ac29025..b15b31ca2618 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -135,7 +135,9 @@ static int mdio_bus_phy_resume(struct device *dev) | |||
135 | if (!mdio_bus_phy_may_suspend(phydev)) | 135 | if (!mdio_bus_phy_may_suspend(phydev)) |
136 | goto no_resume; | 136 | goto no_resume; |
137 | 137 | ||
138 | mutex_lock(&phydev->lock); | ||
138 | ret = phy_resume(phydev); | 139 | ret = phy_resume(phydev); |
140 | mutex_unlock(&phydev->lock); | ||
139 | if (ret < 0) | 141 | if (ret < 0) |
140 | return ret; | 142 | return ret; |
141 | 143 | ||
@@ -1026,7 +1028,9 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, | |||
1026 | if (err) | 1028 | if (err) |
1027 | goto error; | 1029 | goto error; |
1028 | 1030 | ||
1031 | mutex_lock(&phydev->lock); | ||
1029 | phy_resume(phydev); | 1032 | phy_resume(phydev); |
1033 | mutex_unlock(&phydev->lock); | ||
1030 | phy_led_triggers_register(phydev); | 1034 | phy_led_triggers_register(phydev); |
1031 | 1035 | ||
1032 | return err; | 1036 | return err; |
@@ -1157,6 +1161,8 @@ int phy_resume(struct phy_device *phydev) | |||
1157 | struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver); | 1161 | struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver); |
1158 | int ret = 0; | 1162 | int ret = 0; |
1159 | 1163 | ||
1164 | WARN_ON(!mutex_is_locked(&phydev->lock)); | ||
1165 | |||
1160 | if (phydev->drv && phydrv->resume) | 1166 | if (phydev->drv && phydrv->resume) |
1161 | ret = phydrv->resume(phydev); | 1167 | ret = phydrv->resume(phydev); |
1162 | 1168 | ||
@@ -1639,13 +1645,9 @@ int genphy_resume(struct phy_device *phydev) | |||
1639 | { | 1645 | { |
1640 | int value; | 1646 | int value; |
1641 | 1647 | ||
1642 | mutex_lock(&phydev->lock); | ||
1643 | |||
1644 | value = phy_read(phydev, MII_BMCR); | 1648 | value = phy_read(phydev, MII_BMCR); |
1645 | phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); | 1649 | phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); |
1646 | 1650 | ||
1647 | mutex_unlock(&phydev->lock); | ||
1648 | |||
1649 | return 0; | 1651 | return 0; |
1650 | } | 1652 | } |
1651 | EXPORT_SYMBOL(genphy_resume); | 1653 | EXPORT_SYMBOL(genphy_resume); |