17c1eadc1623823b1ef37a3a4ef0d26ec2c40587
[openwrt/openwrt.git] / target / linux / mvebu / patches-4.4 / 125-phy-provide-a-hook-for-link-up-link-down-events.patch
1 From d8b4e728f598d3c8a9b219d4679d5de350caa082 Mon Sep 17 00:00:00 2001
2 From: Russell King <rmk+kernel@arm.linux.org.uk>
3 Date: Fri, 18 Sep 2015 14:42:16 +0100
4 Subject: [PATCH 714/744] phy: provide a hook for link up/link down events
5
6 Sometimes, we need to do additional work between the PHY coming up and
7 marking the carrier present - for example, we may need to wait for the
8 PHY to MAC link to finish negotiation. This changes phylib to provide
9 a notification function pointer which avoids the built-in
10 netif_carrier_on() and netif_carrier_off() functions.
11
12 Standard ->adjust_link functionality is provided by hooking a helper
13 into the new ->phy_link_change method.
14
15 Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
16 Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
17 ---
18 drivers/net/phy/phy.c | 42 ++++++++++++++++++++++--------------------
19 drivers/net/phy/phy_device.c | 14 ++++++++++++++
20 include/linux/phy.h | 1 +
21 3 files changed, 37 insertions(+), 20 deletions(-)
22
23 --- a/drivers/net/phy/phy.c
24 +++ b/drivers/net/phy/phy.c
25 @@ -847,6 +847,16 @@ void phy_start(struct phy_device *phydev
26 }
27 EXPORT_SYMBOL(phy_start);
28
29 +static void phy_link_up(struct phy_device *phydev)
30 +{
31 + phydev->phy_link_change(phydev, true, true);
32 +}
33 +
34 +static void phy_link_down(struct phy_device *phydev, bool do_carrier)
35 +{
36 + phydev->phy_link_change(phydev, false, do_carrier);
37 +}
38 +
39 /**
40 * phy_state_machine - Handle the state machine
41 * @work: work_struct that describes the work to be done
42 @@ -888,8 +898,7 @@ void phy_state_machine(struct work_struc
43 /* If the link is down, give up on negotiation for now */
44 if (!phydev->link) {
45 phydev->state = PHY_NOLINK;
46 - netif_carrier_off(phydev->attached_dev);
47 - phydev->adjust_link(phydev->attached_dev);
48 + phy_link_down(phydev, true);
49 break;
50 }
51
52 @@ -901,9 +910,7 @@ void phy_state_machine(struct work_struc
53 /* If AN is done, we're running */
54 if (err > 0) {
55 phydev->state = PHY_RUNNING;
56 - netif_carrier_on(phydev->attached_dev);
57 - phydev->adjust_link(phydev->attached_dev);
58 -
59 + phy_link_up(phydev);
60 } else if (0 == phydev->link_timeout--)
61 needs_aneg = true;
62 break;
63 @@ -928,8 +935,7 @@ void phy_state_machine(struct work_struc
64 }
65 }
66 phydev->state = PHY_RUNNING;
67 - netif_carrier_on(phydev->attached_dev);
68 - phydev->adjust_link(phydev->attached_dev);
69 + phy_link_up(phydev);
70 }
71 break;
72 case PHY_FORCING:
73 @@ -939,13 +945,12 @@ void phy_state_machine(struct work_struc
74
75 if (phydev->link) {
76 phydev->state = PHY_RUNNING;
77 - netif_carrier_on(phydev->attached_dev);
78 + phy_link_up(phydev);
79 } else {
80 if (0 == phydev->link_timeout--)
81 needs_aneg = true;
82 + phy_link_down(phydev, false);
83 }
84 -
85 - phydev->adjust_link(phydev->attached_dev);
86 break;
87 case PHY_RUNNING:
88 /* Only register a CHANGE if we are polling or ignoring
89 @@ -968,14 +973,12 @@ void phy_state_machine(struct work_struc
90
91 if (phydev->link) {
92 phydev->state = PHY_RUNNING;
93 - netif_carrier_on(phydev->attached_dev);
94 + phy_link_up(phydev);
95 } else {
96 phydev->state = PHY_NOLINK;
97 - netif_carrier_off(phydev->attached_dev);
98 + phy_link_down(phydev, true);
99 }
100
101 - phydev->adjust_link(phydev->attached_dev);
102 -
103 if (phy_interrupt_is_valid(phydev))
104 err = phy_config_interrupt(phydev,
105 PHY_INTERRUPT_ENABLED);
106 @@ -983,8 +986,7 @@ void phy_state_machine(struct work_struc
107 case PHY_HALTED:
108 if (phydev->link) {
109 phydev->link = 0;
110 - netif_carrier_off(phydev->attached_dev);
111 - phydev->adjust_link(phydev->attached_dev);
112 + phy_link_down(phydev, true);
113 do_suspend = true;
114 }
115 break;
116 @@ -1004,11 +1006,11 @@ void phy_state_machine(struct work_struc
117
118 if (phydev->link) {
119 phydev->state = PHY_RUNNING;
120 - netif_carrier_on(phydev->attached_dev);
121 + phy_link_up(phydev);
122 } else {
123 phydev->state = PHY_NOLINK;
124 + phy_link_down(phydev, false);
125 }
126 - phydev->adjust_link(phydev->attached_dev);
127 } else {
128 phydev->state = PHY_AN;
129 phydev->link_timeout = PHY_AN_TIMEOUT;
130 @@ -1020,11 +1022,11 @@ void phy_state_machine(struct work_struc
131
132 if (phydev->link) {
133 phydev->state = PHY_RUNNING;
134 - netif_carrier_on(phydev->attached_dev);
135 + phy_link_up(phydev);
136 } else {
137 phydev->state = PHY_NOLINK;
138 + phy_link_down(phydev, false);
139 }
140 - phydev->adjust_link(phydev->attached_dev);
141 }
142 break;
143 }
144 --- a/drivers/net/phy/phy_device.c
145 +++ b/drivers/net/phy/phy_device.c
146 @@ -441,6 +441,19 @@ struct phy_device *phy_find_first(struct
147 }
148 EXPORT_SYMBOL(phy_find_first);
149
150 +static void phy_link_change(struct phy_device *phydev, bool up, bool do_carrier)
151 +{
152 + struct net_device *netdev = phydev->attached_dev;
153 +
154 + if (do_carrier) {
155 + if (up)
156 + netif_carrier_on(netdev);
157 + else
158 + netif_carrier_off(netdev);
159 + }
160 + phydev->adjust_link(netdev);
161 +}
162 +
163 /**
164 * phy_prepare_link - prepares the PHY layer to monitor link status
165 * @phydev: target phy_device struct
166 @@ -659,6 +672,7 @@ int phy_attach_direct(struct net_device
167 goto error;
168 }
169
170 + phydev->phy_link_change = phy_link_change;
171 phydev->attached_dev = dev;
172 dev->phydev = phydev;
173
174 --- a/include/linux/phy.h
175 +++ b/include/linux/phy.h
176 @@ -433,6 +433,7 @@ struct phy_device {
177
178 u8 mdix;
179
180 + void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier);
181 void (*adjust_link)(struct net_device *dev);
182 };
183 #define to_phy_device(d) container_of(d, struct phy_device, dev)