]>
Commit | Line | Data |
---|---|---|
a2443fd1 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2f53e904 | 2 | /* Framework for configuring and reading PHY devices |
00db8189 AF |
3 | * Based on code in sungem_phy.c and gianfar_phy.c |
4 | * | |
5 | * Author: Andy Fleming | |
6 | * | |
7 | * Copyright (c) 2004 Freescale Semiconductor, Inc. | |
0ac49527 | 8 | * Copyright (c) 2006, 2007 Maciej W. Rozycki |
00db8189 | 9 | */ |
8d242488 | 10 | |
00db8189 | 11 | #include <linux/kernel.h> |
00db8189 AF |
12 | #include <linux/string.h> |
13 | #include <linux/errno.h> | |
14 | #include <linux/unistd.h> | |
00db8189 | 15 | #include <linux/interrupt.h> |
00db8189 AF |
16 | #include <linux/delay.h> |
17 | #include <linux/netdevice.h> | |
18 | #include <linux/etherdevice.h> | |
19 | #include <linux/skbuff.h> | |
00db8189 AF |
20 | #include <linux/mm.h> |
21 | #include <linux/module.h> | |
00db8189 AF |
22 | #include <linux/mii.h> |
23 | #include <linux/ethtool.h> | |
24 | #include <linux/phy.h> | |
d6f8cfa3 | 25 | #include <linux/phy_led_triggers.h> |
3c3070d7 | 26 | #include <linux/workqueue.h> |
a59a4d19 | 27 | #include <linux/mdio.h> |
2f53e904 SS |
28 | #include <linux/io.h> |
29 | #include <linux/uaccess.h> | |
60063497 | 30 | #include <linux/atomic.h> |
2f53e904 | 31 | |
97b33bdf HK |
32 | #define PHY_STATE_TIME HZ |
33 | ||
3e2186e0 FF |
34 | #define PHY_STATE_STR(_state) \ |
35 | case PHY_##_state: \ | |
36 | return __stringify(_state); \ | |
37 | ||
38 | static const char *phy_state_to_str(enum phy_state st) | |
39 | { | |
40 | switch (st) { | |
41 | PHY_STATE_STR(DOWN) | |
3e2186e0 | 42 | PHY_STATE_STR(READY) |
3e2186e0 | 43 | PHY_STATE_STR(UP) |
3e2186e0 FF |
44 | PHY_STATE_STR(RUNNING) |
45 | PHY_STATE_STR(NOLINK) | |
3e2186e0 | 46 | PHY_STATE_STR(HALTED) |
3e2186e0 FF |
47 | } |
48 | ||
49 | return NULL; | |
50 | } | |
51 | ||
74a992b3 HK |
52 | static void phy_link_up(struct phy_device *phydev) |
53 | { | |
54 | phydev->phy_link_change(phydev, true, true); | |
55 | phy_led_trigger_change_speed(phydev); | |
56 | } | |
57 | ||
58 | static void phy_link_down(struct phy_device *phydev, bool do_carrier) | |
59 | { | |
60 | phydev->phy_link_change(phydev, false, do_carrier); | |
61 | phy_led_trigger_change_speed(phydev); | |
62 | } | |
3e2186e0 | 63 | |
23bfaa59 HK |
64 | static const char *phy_pause_str(struct phy_device *phydev) |
65 | { | |
66 | bool local_pause, local_asym_pause; | |
67 | ||
68 | if (phydev->autoneg == AUTONEG_DISABLE) | |
69 | goto no_pause; | |
70 | ||
71 | local_pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, | |
72 | phydev->advertising); | |
73 | local_asym_pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, | |
74 | phydev->advertising); | |
75 | ||
76 | if (local_pause && phydev->pause) | |
77 | return "rx/tx"; | |
78 | ||
79 | if (local_asym_pause && phydev->asym_pause) { | |
80 | if (local_pause) | |
81 | return "rx"; | |
82 | if (phydev->pause) | |
83 | return "tx"; | |
84 | } | |
85 | ||
86 | no_pause: | |
87 | return "off"; | |
88 | } | |
89 | ||
b3df0da8 RD |
90 | /** |
91 | * phy_print_status - Convenience function to print out the current phy status | |
92 | * @phydev: the phy_device struct | |
e1393456 AF |
93 | */ |
94 | void phy_print_status(struct phy_device *phydev) | |
95 | { | |
2f53e904 | 96 | if (phydev->link) { |
df40cc88 | 97 | netdev_info(phydev->attached_dev, |
766d1d38 FF |
98 | "Link is Up - %s/%s - flow control %s\n", |
99 | phy_speed_to_str(phydev->speed), | |
da4625ac | 100 | phy_duplex_to_str(phydev->duplex), |
23bfaa59 | 101 | phy_pause_str(phydev)); |
2f53e904 | 102 | } else { |
43b6329f | 103 | netdev_info(phydev->attached_dev, "Link is Down\n"); |
2f53e904 | 104 | } |
e1393456 AF |
105 | } |
106 | EXPORT_SYMBOL(phy_print_status); | |
00db8189 | 107 | |
b3df0da8 RD |
108 | /** |
109 | * phy_clear_interrupt - Ack the phy device's interrupt | |
110 | * @phydev: the phy_device struct | |
111 | * | |
112 | * If the @phydev driver has an ack_interrupt function, call it to | |
113 | * ack and clear the phy device's interrupt. | |
114 | * | |
ad033506 | 115 | * Returns 0 on success or < 0 on error. |
b3df0da8 | 116 | */ |
89ff05ec | 117 | static int phy_clear_interrupt(struct phy_device *phydev) |
00db8189 | 118 | { |
00db8189 | 119 | if (phydev->drv->ack_interrupt) |
e62a768f | 120 | return phydev->drv->ack_interrupt(phydev); |
00db8189 | 121 | |
e62a768f | 122 | return 0; |
00db8189 AF |
123 | } |
124 | ||
b3df0da8 RD |
125 | /** |
126 | * phy_config_interrupt - configure the PHY device for the requested interrupts | |
127 | * @phydev: the phy_device struct | |
128 | * @interrupts: interrupt flags to configure for this @phydev | |
129 | * | |
ad033506 | 130 | * Returns 0 on success or < 0 on error. |
b3df0da8 | 131 | */ |
695bce8f | 132 | static int phy_config_interrupt(struct phy_device *phydev, bool interrupts) |
00db8189 | 133 | { |
695bce8f | 134 | phydev->interrupts = interrupts ? 1 : 0; |
00db8189 | 135 | if (phydev->drv->config_intr) |
e62a768f | 136 | return phydev->drv->config_intr(phydev); |
00db8189 | 137 | |
e62a768f | 138 | return 0; |
00db8189 AF |
139 | } |
140 | ||
002ba705 RK |
141 | /** |
142 | * phy_restart_aneg - restart auto-negotiation | |
143 | * @phydev: target phy_device struct | |
144 | * | |
145 | * Restart the autonegotiation on @phydev. Returns >= 0 on success or | |
146 | * negative errno on error. | |
147 | */ | |
148 | int phy_restart_aneg(struct phy_device *phydev) | |
149 | { | |
150 | int ret; | |
151 | ||
152 | if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) | |
153 | ret = genphy_c45_restart_aneg(phydev); | |
154 | else | |
155 | ret = genphy_restart_aneg(phydev); | |
156 | ||
157 | return ret; | |
158 | } | |
159 | EXPORT_SYMBOL_GPL(phy_restart_aneg); | |
00db8189 | 160 | |
b3df0da8 RD |
161 | /** |
162 | * phy_aneg_done - return auto-negotiation status | |
163 | * @phydev: target phy_device struct | |
00db8189 | 164 | * |
76a423a3 FF |
165 | * Description: Return the auto-negotiation status from this @phydev |
166 | * Returns > 0 on success or < 0 on error. 0 means that auto-negotiation | |
167 | * is still pending. | |
00db8189 | 168 | */ |
372788f9 | 169 | int phy_aneg_done(struct phy_device *phydev) |
00db8189 | 170 | { |
65f2767a | 171 | if (phydev->drv && phydev->drv->aneg_done) |
76a423a3 | 172 | return phydev->drv->aneg_done(phydev); |
d7bed825 HK |
173 | else if (phydev->is_c45) |
174 | return genphy_c45_aneg_done(phydev); | |
175 | else | |
176 | return genphy_aneg_done(phydev); | |
00db8189 | 177 | } |
372788f9 | 178 | EXPORT_SYMBOL(phy_aneg_done); |
00db8189 | 179 | |
b3df0da8 | 180 | /** |
d0613037 RK |
181 | * phy_find_valid - find a PHY setting that matches the requested parameters |
182 | * @speed: desired speed | |
183 | * @duplex: desired duplex | |
184 | * @supported: mask of supported link modes | |
00db8189 | 185 | * |
d0613037 RK |
186 | * Locate a supported phy setting that is, in priority order: |
187 | * - an exact match for the specified speed and duplex mode | |
188 | * - a match for the specified speed, or slower speed | |
189 | * - the slowest supported speed | |
190 | * Returns the matched phy_setting entry, or %NULL if no supported phy | |
191 | * settings were found. | |
00db8189 | 192 | */ |
d0613037 | 193 | static const struct phy_setting * |
3c1bcc86 | 194 | phy_find_valid(int speed, int duplex, unsigned long *supported) |
00db8189 | 195 | { |
3c1bcc86 | 196 | return phy_lookup_setting(speed, duplex, supported, false); |
00db8189 AF |
197 | } |
198 | ||
1f9127ca ZB |
199 | /** |
200 | * phy_supported_speeds - return all speeds currently supported by a phy device | |
201 | * @phy: The phy device to return supported speeds of. | |
202 | * @speeds: buffer to store supported speeds in. | |
203 | * @size: size of speeds buffer. | |
204 | * | |
205 | * Description: Returns the number of supported speeds, and fills the speeds | |
206 | * buffer with the supported speeds. If speeds buffer is too small to contain | |
207 | * all currently supported speeds, will return as many speeds as can fit. | |
208 | */ | |
209 | unsigned int phy_supported_speeds(struct phy_device *phy, | |
210 | unsigned int *speeds, | |
211 | unsigned int size) | |
212 | { | |
3c1bcc86 | 213 | return phy_speeds(speeds, size, phy->supported); |
1f9127ca ZB |
214 | } |
215 | ||
54da5a8b GR |
216 | /** |
217 | * phy_check_valid - check if there is a valid PHY setting which matches | |
218 | * speed, duplex, and feature mask | |
219 | * @speed: speed to match | |
220 | * @duplex: duplex to match | |
221 | * @features: A mask of the valid settings | |
222 | * | |
223 | * Description: Returns true if there is a valid setting, false otherwise. | |
224 | */ | |
3c1bcc86 AL |
225 | static inline bool phy_check_valid(int speed, int duplex, |
226 | unsigned long *features) | |
54da5a8b | 227 | { |
3c1bcc86 | 228 | return !!phy_lookup_setting(speed, duplex, features, true); |
54da5a8b GR |
229 | } |
230 | ||
b3df0da8 RD |
231 | /** |
232 | * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex | |
233 | * @phydev: the target phy_device struct | |
00db8189 | 234 | * |
b3df0da8 | 235 | * Description: Make sure the PHY is set to supported speeds and |
00db8189 | 236 | * duplexes. Drop down by one in this order: 1000/FULL, |
b3df0da8 | 237 | * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF. |
00db8189 | 238 | */ |
89ff05ec | 239 | static void phy_sanitize_settings(struct phy_device *phydev) |
00db8189 | 240 | { |
d0613037 | 241 | const struct phy_setting *setting; |
00db8189 | 242 | |
3c1bcc86 AL |
243 | setting = phy_find_valid(phydev->speed, phydev->duplex, |
244 | phydev->supported); | |
d0613037 RK |
245 | if (setting) { |
246 | phydev->speed = setting->speed; | |
247 | phydev->duplex = setting->duplex; | |
248 | } else { | |
249 | /* We failed to find anything (no supported speeds?) */ | |
250 | phydev->speed = SPEED_UNKNOWN; | |
251 | phydev->duplex = DUPLEX_UNKNOWN; | |
252 | } | |
00db8189 | 253 | } |
00db8189 | 254 | |
b3df0da8 RD |
255 | /** |
256 | * phy_ethtool_sset - generic ethtool sset function, handles all the details | |
257 | * @phydev: target phy_device struct | |
258 | * @cmd: ethtool_cmd | |
00db8189 AF |
259 | * |
260 | * A few notes about parameter checking: | |
d651983d | 261 | * |
00db8189 AF |
262 | * - We don't set port or transceiver, so we don't care what they |
263 | * were set to. | |
264 | * - phy_start_aneg() will make sure forced settings are sane, and | |
265 | * choose the next best ones from the ones selected, so we don't | |
b3df0da8 | 266 | * care if ethtool tries to give us bad values. |
00db8189 AF |
267 | */ |
268 | int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) | |
269 | { | |
3c1bcc86 | 270 | __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); |
25db0338 DD |
271 | u32 speed = ethtool_cmd_speed(cmd); |
272 | ||
e5a03bfd | 273 | if (cmd->phy_address != phydev->mdio.addr) |
00db8189 AF |
274 | return -EINVAL; |
275 | ||
2f53e904 | 276 | /* We make sure that we don't pass unsupported values in to the PHY */ |
3c1bcc86 AL |
277 | ethtool_convert_legacy_u32_to_link_mode(advertising, cmd->advertising); |
278 | linkmode_and(advertising, advertising, phydev->supported); | |
00db8189 AF |
279 | |
280 | /* Verify the settings we care about. */ | |
281 | if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) | |
282 | return -EINVAL; | |
283 | ||
284 | if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) | |
285 | return -EINVAL; | |
286 | ||
8e95a202 | 287 | if (cmd->autoneg == AUTONEG_DISABLE && |
25db0338 DD |
288 | ((speed != SPEED_1000 && |
289 | speed != SPEED_100 && | |
290 | speed != SPEED_10) || | |
8e95a202 JP |
291 | (cmd->duplex != DUPLEX_HALF && |
292 | cmd->duplex != DUPLEX_FULL))) | |
00db8189 AF |
293 | return -EINVAL; |
294 | ||
295 | phydev->autoneg = cmd->autoneg; | |
296 | ||
25db0338 | 297 | phydev->speed = speed; |
00db8189 | 298 | |
3c1bcc86 | 299 | linkmode_copy(phydev->advertising, advertising); |
00db8189 | 300 | |
ccf355e5 FH |
301 | linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, |
302 | phydev->advertising, AUTONEG_ENABLE == cmd->autoneg); | |
00db8189 AF |
303 | |
304 | phydev->duplex = cmd->duplex; | |
305 | ||
1004ee61 | 306 | phydev->mdix_ctrl = cmd->eth_tp_mdix_ctrl; |
634ec36c | 307 | |
00db8189 AF |
308 | /* Restart the PHY */ |
309 | phy_start_aneg(phydev); | |
310 | ||
311 | return 0; | |
312 | } | |
9f6d55d0 | 313 | EXPORT_SYMBOL(phy_ethtool_sset); |
00db8189 | 314 | |
2d55173e PR |
315 | int phy_ethtool_ksettings_set(struct phy_device *phydev, |
316 | const struct ethtool_link_ksettings *cmd) | |
317 | { | |
3c1bcc86 | 318 | __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); |
2d55173e PR |
319 | u8 autoneg = cmd->base.autoneg; |
320 | u8 duplex = cmd->base.duplex; | |
321 | u32 speed = cmd->base.speed; | |
2d55173e PR |
322 | |
323 | if (cmd->base.phy_address != phydev->mdio.addr) | |
324 | return -EINVAL; | |
325 | ||
3c1bcc86 | 326 | linkmode_copy(advertising, cmd->link_modes.advertising); |
2d55173e PR |
327 | |
328 | /* We make sure that we don't pass unsupported values in to the PHY */ | |
3c1bcc86 | 329 | linkmode_and(advertising, advertising, phydev->supported); |
2d55173e PR |
330 | |
331 | /* Verify the settings we care about. */ | |
332 | if (autoneg != AUTONEG_ENABLE && autoneg != AUTONEG_DISABLE) | |
333 | return -EINVAL; | |
334 | ||
3e536cff | 335 | if (autoneg == AUTONEG_ENABLE && linkmode_empty(advertising)) |
2d55173e PR |
336 | return -EINVAL; |
337 | ||
338 | if (autoneg == AUTONEG_DISABLE && | |
339 | ((speed != SPEED_1000 && | |
340 | speed != SPEED_100 && | |
341 | speed != SPEED_10) || | |
342 | (duplex != DUPLEX_HALF && | |
343 | duplex != DUPLEX_FULL))) | |
344 | return -EINVAL; | |
345 | ||
346 | phydev->autoneg = autoneg; | |
347 | ||
805edd48 GH |
348 | if (autoneg == AUTONEG_DISABLE) { |
349 | phydev->speed = speed; | |
350 | phydev->duplex = duplex; | |
351 | } | |
2d55173e | 352 | |
3c1bcc86 | 353 | linkmode_copy(phydev->advertising, advertising); |
2d55173e | 354 | |
ccf355e5 FH |
355 | linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, |
356 | phydev->advertising, autoneg == AUTONEG_ENABLE); | |
2d55173e | 357 | |
1004ee61 | 358 | phydev->mdix_ctrl = cmd->base.eth_tp_mdix_ctrl; |
2d55173e PR |
359 | |
360 | /* Restart the PHY */ | |
361 | phy_start_aneg(phydev); | |
362 | ||
363 | return 0; | |
364 | } | |
365 | EXPORT_SYMBOL(phy_ethtool_ksettings_set); | |
366 | ||
5514174f | 367 | void phy_ethtool_ksettings_get(struct phy_device *phydev, |
368 | struct ethtool_link_ksettings *cmd) | |
2d55173e | 369 | { |
5333f507 | 370 | mutex_lock(&phydev->lock); |
3c1bcc86 AL |
371 | linkmode_copy(cmd->link_modes.supported, phydev->supported); |
372 | linkmode_copy(cmd->link_modes.advertising, phydev->advertising); | |
c0ec3c27 | 373 | linkmode_copy(cmd->link_modes.lp_advertising, phydev->lp_advertising); |
2d55173e PR |
374 | |
375 | cmd->base.speed = phydev->speed; | |
376 | cmd->base.duplex = phydev->duplex; | |
377 | if (phydev->interface == PHY_INTERFACE_MODE_MOCA) | |
378 | cmd->base.port = PORT_BNC; | |
379 | else | |
380 | cmd->base.port = PORT_MII; | |
ceb62813 FF |
381 | cmd->base.transceiver = phy_is_internal(phydev) ? |
382 | XCVR_INTERNAL : XCVR_EXTERNAL; | |
2d55173e PR |
383 | cmd->base.phy_address = phydev->mdio.addr; |
384 | cmd->base.autoneg = phydev->autoneg; | |
1004ee61 RL |
385 | cmd->base.eth_tp_mdix_ctrl = phydev->mdix_ctrl; |
386 | cmd->base.eth_tp_mdix = phydev->mdix; | |
5333f507 | 387 | mutex_unlock(&phydev->lock); |
2d55173e PR |
388 | } |
389 | EXPORT_SYMBOL(phy_ethtool_ksettings_get); | |
00db8189 | 390 | |
b3df0da8 RD |
391 | /** |
392 | * phy_mii_ioctl - generic PHY MII ioctl interface | |
393 | * @phydev: the phy_device struct | |
00c7d920 | 394 | * @ifr: &struct ifreq for socket ioctl's |
b3df0da8 RD |
395 | * @cmd: ioctl cmd to execute |
396 | * | |
397 | * Note that this function is currently incompatible with the | |
00db8189 | 398 | * PHYCONTROL layer. It changes registers without regard to |
b3df0da8 | 399 | * current state. Use at own risk. |
00db8189 | 400 | */ |
2f53e904 | 401 | int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd) |
00db8189 | 402 | { |
28b04113 | 403 | struct mii_ioctl_data *mii_data = if_mii(ifr); |
00db8189 | 404 | u16 val = mii_data->val_in; |
79ce0477 | 405 | bool change_autoneg = false; |
cdea04c2 | 406 | int prtad, devad; |
00db8189 AF |
407 | |
408 | switch (cmd) { | |
409 | case SIOCGMIIPHY: | |
e5a03bfd | 410 | mii_data->phy_id = phydev->mdio.addr; |
c6d6a511 LB |
411 | /* fall through */ |
412 | ||
00db8189 | 413 | case SIOCGMIIREG: |
cdea04c2 RK |
414 | if (mdio_phy_id_is_c45(mii_data->phy_id)) { |
415 | prtad = mdio_phy_id_prtad(mii_data->phy_id); | |
416 | devad = mdio_phy_id_devad(mii_data->phy_id); | |
417 | devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num; | |
418 | } else { | |
419 | prtad = mii_data->phy_id; | |
420 | devad = mii_data->reg_num; | |
421 | } | |
422 | mii_data->val_out = mdiobus_read(phydev->mdio.bus, prtad, | |
423 | devad); | |
e62a768f | 424 | return 0; |
00db8189 AF |
425 | |
426 | case SIOCSMIIREG: | |
cdea04c2 RK |
427 | if (mdio_phy_id_is_c45(mii_data->phy_id)) { |
428 | prtad = mdio_phy_id_prtad(mii_data->phy_id); | |
429 | devad = mdio_phy_id_devad(mii_data->phy_id); | |
430 | devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num; | |
431 | } else { | |
432 | prtad = mii_data->phy_id; | |
433 | devad = mii_data->reg_num; | |
434 | } | |
435 | if (prtad == phydev->mdio.addr) { | |
436 | switch (devad) { | |
00db8189 | 437 | case MII_BMCR: |
79ce0477 BH |
438 | if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) { |
439 | if (phydev->autoneg == AUTONEG_ENABLE) | |
440 | change_autoneg = true; | |
00db8189 | 441 | phydev->autoneg = AUTONEG_DISABLE; |
79ce0477 BH |
442 | if (val & BMCR_FULLDPLX) |
443 | phydev->duplex = DUPLEX_FULL; | |
444 | else | |
445 | phydev->duplex = DUPLEX_HALF; | |
446 | if (val & BMCR_SPEED1000) | |
447 | phydev->speed = SPEED_1000; | |
448 | else if (val & BMCR_SPEED100) | |
449 | phydev->speed = SPEED_100; | |
450 | else phydev->speed = SPEED_10; | |
451 | } | |
452 | else { | |
453 | if (phydev->autoneg == AUTONEG_DISABLE) | |
454 | change_autoneg = true; | |
00db8189 | 455 | phydev->autoneg = AUTONEG_ENABLE; |
79ce0477 | 456 | } |
00db8189 AF |
457 | break; |
458 | case MII_ADVERTISE: | |
9db299c7 AL |
459 | mii_adv_mod_linkmode_adv_t(phydev->advertising, |
460 | val); | |
79ce0477 | 461 | change_autoneg = true; |
00db8189 | 462 | break; |
4cf6c57e RK |
463 | case MII_CTRL1000: |
464 | mii_ctrl1000_mod_linkmode_adv_t(phydev->advertising, | |
465 | val); | |
466 | change_autoneg = true; | |
467 | break; | |
00db8189 AF |
468 | default: |
469 | /* do nothing */ | |
470 | break; | |
471 | } | |
472 | } | |
473 | ||
cdea04c2 | 474 | mdiobus_write(phydev->mdio.bus, prtad, devad, val); |
af1dc13e | 475 | |
cdea04c2 RK |
476 | if (prtad == phydev->mdio.addr && |
477 | devad == MII_BMCR && | |
2613f95f | 478 | val & BMCR_RESET) |
e62a768f | 479 | return phy_init_hw(phydev); |
79ce0477 BH |
480 | |
481 | if (change_autoneg) | |
482 | return phy_start_aneg(phydev); | |
483 | ||
e62a768f | 484 | return 0; |
dda93b48 | 485 | |
c1f19b51 | 486 | case SIOCSHWTSTAMP: |
25149ef9 | 487 | if (phydev->drv && phydev->drv->hwtstamp) |
c1f19b51 RC |
488 | return phydev->drv->hwtstamp(phydev, ifr); |
489 | /* fall through */ | |
490 | ||
dda93b48 | 491 | default: |
c6d6a511 | 492 | return -EOPNOTSUPP; |
00db8189 | 493 | } |
00db8189 | 494 | } |
680e9fe9 | 495 | EXPORT_SYMBOL(phy_mii_ioctl); |
00db8189 | 496 | |
97b33bdf | 497 | void phy_queue_state_machine(struct phy_device *phydev, unsigned long jiffies) |
a3320bcf HK |
498 | { |
499 | mod_delayed_work(system_power_efficient_wq, &phydev->state_queue, | |
97b33bdf | 500 | jiffies); |
a3320bcf | 501 | } |
97b33bdf | 502 | EXPORT_SYMBOL(phy_queue_state_machine); |
a3320bcf HK |
503 | |
504 | static void phy_trigger_machine(struct phy_device *phydev) | |
505 | { | |
506 | phy_queue_state_machine(phydev, 0); | |
507 | } | |
508 | ||
76299580 HK |
509 | static int phy_config_aneg(struct phy_device *phydev) |
510 | { | |
511 | if (phydev->drv->config_aneg) | |
512 | return phydev->drv->config_aneg(phydev); | |
34786005 CG |
513 | |
514 | /* Clause 45 PHYs that don't implement Clause 22 registers are not | |
515 | * allowed to call genphy_config_aneg() | |
516 | */ | |
517 | if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) | |
94acaeb5 | 518 | return genphy_c45_config_aneg(phydev); |
34786005 CG |
519 | |
520 | return genphy_config_aneg(phydev); | |
76299580 HK |
521 | } |
522 | ||
74a992b3 HK |
523 | /** |
524 | * phy_check_link_status - check link status and set state accordingly | |
525 | * @phydev: the phy_device struct | |
526 | * | |
527 | * Description: Check for link and whether autoneg was triggered / is running | |
528 | * and set state accordingly | |
529 | */ | |
530 | static int phy_check_link_status(struct phy_device *phydev) | |
531 | { | |
532 | int err; | |
533 | ||
534 | WARN_ON(!mutex_is_locked(&phydev->lock)); | |
535 | ||
fe4a7a41 JA |
536 | /* Keep previous state if loopback is enabled because some PHYs |
537 | * report that Link is Down when loopback is enabled. | |
538 | */ | |
539 | if (phydev->loopback_enabled) | |
540 | return 0; | |
541 | ||
74a992b3 HK |
542 | err = phy_read_status(phydev); |
543 | if (err) | |
544 | return err; | |
545 | ||
546 | if (phydev->link && phydev->state != PHY_RUNNING) { | |
547 | phydev->state = PHY_RUNNING; | |
548 | phy_link_up(phydev); | |
549 | } else if (!phydev->link && phydev->state != PHY_NOLINK) { | |
550 | phydev->state = PHY_NOLINK; | |
551 | phy_link_down(phydev, true); | |
552 | } | |
553 | ||
554 | return 0; | |
555 | } | |
556 | ||
b3df0da8 | 557 | /** |
921e1e0e | 558 | * _phy_start_aneg - start auto-negotiation for this PHY device |
b3df0da8 | 559 | * @phydev: the phy_device struct |
e1393456 | 560 | * |
b3df0da8 RD |
561 | * Description: Sanitizes the settings (if we're not autonegotiating |
562 | * them), and then calls the driver's config_aneg function. | |
563 | * If the PHYCONTROL Layer is operating, we change the state to | |
564 | * reflect the beginning of Auto-negotiation or forcing. | |
e1393456 | 565 | */ |
921e1e0e | 566 | static int _phy_start_aneg(struct phy_device *phydev) |
e1393456 AF |
567 | { |
568 | int err; | |
569 | ||
921e1e0e AL |
570 | lockdep_assert_held(&phydev->lock); |
571 | ||
25149ef9 FF |
572 | if (!phydev->drv) |
573 | return -EIO; | |
574 | ||
e1393456 AF |
575 | if (AUTONEG_DISABLE == phydev->autoneg) |
576 | phy_sanitize_settings(phydev); | |
577 | ||
76299580 | 578 | err = phy_config_aneg(phydev); |
e1393456 | 579 | if (err < 0) |
921e1e0e | 580 | return err; |
e1393456 | 581 | |
2bd229df HK |
582 | if (phy_is_started(phydev)) |
583 | err = phy_check_link_status(phydev); | |
921e1e0e AL |
584 | |
585 | return err; | |
586 | } | |
587 | ||
588 | /** | |
589 | * phy_start_aneg - start auto-negotiation for this PHY device | |
590 | * @phydev: the phy_device struct | |
591 | * | |
592 | * Description: Sanitizes the settings (if we're not autonegotiating | |
593 | * them), and then calls the driver's config_aneg function. | |
594 | * If the PHYCONTROL Layer is operating, we change the state to | |
595 | * reflect the beginning of Auto-negotiation or forcing. | |
596 | */ | |
597 | int phy_start_aneg(struct phy_device *phydev) | |
598 | { | |
599 | int err; | |
600 | ||
601 | mutex_lock(&phydev->lock); | |
602 | err = _phy_start_aneg(phydev); | |
35b5f6b1 | 603 | mutex_unlock(&phydev->lock); |
f555f34f | 604 | |
e1393456 AF |
605 | return err; |
606 | } | |
607 | EXPORT_SYMBOL(phy_start_aneg); | |
608 | ||
2b9672dd HK |
609 | static int phy_poll_aneg_done(struct phy_device *phydev) |
610 | { | |
611 | unsigned int retries = 100; | |
612 | int ret; | |
613 | ||
614 | do { | |
615 | msleep(100); | |
616 | ret = phy_aneg_done(phydev); | |
617 | } while (!ret && --retries); | |
618 | ||
619 | if (!ret) | |
620 | return -ETIMEDOUT; | |
621 | ||
622 | return ret < 0 ? ret : 0; | |
623 | } | |
624 | ||
625 | /** | |
626 | * phy_speed_down - set speed to lowest speed supported by both link partners | |
627 | * @phydev: the phy_device struct | |
628 | * @sync: perform action synchronously | |
629 | * | |
630 | * Description: Typically used to save energy when waiting for a WoL packet | |
631 | * | |
632 | * WARNING: Setting sync to false may cause the system being unable to suspend | |
633 | * in case the PHY generates an interrupt when finishing the autonegotiation. | |
634 | * This interrupt may wake up the system immediately after suspend. | |
635 | * Therefore use sync = false only if you're sure it's safe with the respective | |
636 | * network chip. | |
637 | */ | |
638 | int phy_speed_down(struct phy_device *phydev, bool sync) | |
639 | { | |
65b27995 | 640 | __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_tmp); |
2b9672dd HK |
641 | int ret; |
642 | ||
643 | if (phydev->autoneg != AUTONEG_ENABLE) | |
644 | return 0; | |
645 | ||
65b27995 HK |
646 | linkmode_copy(adv_tmp, phydev->advertising); |
647 | ||
648 | ret = phy_speed_down_core(phydev); | |
649 | if (ret) | |
650 | return ret; | |
2b9672dd | 651 | |
65b27995 HK |
652 | linkmode_copy(phydev->adv_old, adv_tmp); |
653 | ||
654 | if (linkmode_equal(phydev->advertising, adv_tmp)) | |
2b9672dd HK |
655 | return 0; |
656 | ||
657 | ret = phy_config_aneg(phydev); | |
658 | if (ret) | |
659 | return ret; | |
660 | ||
661 | return sync ? phy_poll_aneg_done(phydev) : 0; | |
662 | } | |
663 | EXPORT_SYMBOL_GPL(phy_speed_down); | |
664 | ||
665 | /** | |
666 | * phy_speed_up - (re)set advertised speeds to all supported speeds | |
667 | * @phydev: the phy_device struct | |
668 | * | |
669 | * Description: Used to revert the effect of phy_speed_down | |
670 | */ | |
671 | int phy_speed_up(struct phy_device *phydev) | |
672 | { | |
65b27995 | 673 | __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_tmp); |
2b9672dd HK |
674 | |
675 | if (phydev->autoneg != AUTONEG_ENABLE) | |
676 | return 0; | |
677 | ||
65b27995 HK |
678 | if (linkmode_empty(phydev->adv_old)) |
679 | return 0; | |
2b9672dd | 680 | |
65b27995 HK |
681 | linkmode_copy(adv_tmp, phydev->advertising); |
682 | linkmode_copy(phydev->advertising, phydev->adv_old); | |
683 | linkmode_zero(phydev->adv_old); | |
3c1bcc86 | 684 | |
65b27995 | 685 | if (linkmode_equal(phydev->advertising, adv_tmp)) |
2b9672dd HK |
686 | return 0; |
687 | ||
688 | return phy_config_aneg(phydev); | |
689 | } | |
690 | EXPORT_SYMBOL_GPL(phy_speed_up); | |
691 | ||
b3df0da8 RD |
692 | /** |
693 | * phy_start_machine - start PHY state machine tracking | |
694 | * @phydev: the phy_device struct | |
00db8189 | 695 | * |
b3df0da8 | 696 | * Description: The PHY infrastructure can run a state machine |
00db8189 | 697 | * which tracks whether the PHY is starting up, negotiating, |
fb5e7606 FF |
698 | * etc. This function starts the delayed workqueue which tracks |
699 | * the state of the PHY. If you want to maintain your own state machine, | |
29935aeb | 700 | * do not call this function. |
b3df0da8 | 701 | */ |
29935aeb | 702 | void phy_start_machine(struct phy_device *phydev) |
00db8189 | 703 | { |
6384e483 | 704 | phy_trigger_machine(phydev); |
00db8189 | 705 | } |
5e5758d9 | 706 | EXPORT_SYMBOL_GPL(phy_start_machine); |
00db8189 | 707 | |
b3df0da8 RD |
708 | /** |
709 | * phy_stop_machine - stop the PHY state machine tracking | |
710 | * @phydev: target phy_device struct | |
00db8189 | 711 | * |
fb5e7606 FF |
712 | * Description: Stops the state machine delayed workqueue, sets the |
713 | * state to UP (unless it wasn't up yet). This function must be | |
714 | * called BEFORE phy_detach. | |
00db8189 AF |
715 | */ |
716 | void phy_stop_machine(struct phy_device *phydev) | |
717 | { | |
a390d1f3 | 718 | cancel_delayed_work_sync(&phydev->state_queue); |
00db8189 | 719 | |
35b5f6b1 | 720 | mutex_lock(&phydev->lock); |
a2fc9d7e | 721 | if (phy_is_started(phydev)) |
00db8189 | 722 | phydev->state = PHY_UP; |
35b5f6b1 | 723 | mutex_unlock(&phydev->lock); |
00db8189 AF |
724 | } |
725 | ||
b3df0da8 RD |
726 | /** |
727 | * phy_error - enter HALTED state for this PHY device | |
728 | * @phydev: target phy_device struct | |
00db8189 AF |
729 | * |
730 | * Moves the PHY to the HALTED state in response to a read | |
731 | * or write error, and tells the controller the link is down. | |
732 | * Must not be called from interrupt context, or while the | |
733 | * phydev->lock is held. | |
734 | */ | |
9b9a8bfc | 735 | static void phy_error(struct phy_device *phydev) |
00db8189 | 736 | { |
fa7b28c1 HK |
737 | WARN_ON(1); |
738 | ||
35b5f6b1 | 739 | mutex_lock(&phydev->lock); |
00db8189 | 740 | phydev->state = PHY_HALTED; |
35b5f6b1 | 741 | mutex_unlock(&phydev->lock); |
3c293f4e | 742 | |
9f2959b6 | 743 | phy_trigger_machine(phydev); |
00db8189 AF |
744 | } |
745 | ||
a2c054a8 BM |
746 | /** |
747 | * phy_disable_interrupts - Disable the PHY interrupts from the PHY side | |
748 | * @phydev: target phy_device struct | |
749 | */ | |
750 | static int phy_disable_interrupts(struct phy_device *phydev) | |
751 | { | |
752 | int err; | |
753 | ||
754 | /* Disable PHY interrupts */ | |
755 | err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); | |
756 | if (err) | |
03fe2deb | 757 | return err; |
a2c054a8 BM |
758 | |
759 | /* Clear the interrupt */ | |
03fe2deb | 760 | return phy_clear_interrupt(phydev); |
a2c054a8 BM |
761 | } |
762 | ||
763 | /** | |
34d884e3 HK |
764 | * phy_interrupt - PHY interrupt handler |
765 | * @irq: interrupt line | |
766 | * @phy_dat: phy_device pointer | |
767 | * | |
768 | * Description: Handle PHY interrupt | |
a2c054a8 | 769 | */ |
34d884e3 | 770 | static irqreturn_t phy_interrupt(int irq, void *phy_dat) |
a2c054a8 | 771 | { |
34d884e3 | 772 | struct phy_device *phydev = phy_dat; |
a2c054a8 | 773 | |
34d884e3 HK |
774 | if (phydev->drv->did_interrupt && !phydev->drv->did_interrupt(phydev)) |
775 | return IRQ_NONE; | |
a2c054a8 | 776 | |
49644e68 HK |
777 | if (phydev->drv->handle_interrupt) { |
778 | if (phydev->drv->handle_interrupt(phydev)) | |
779 | goto phy_err; | |
780 | } else { | |
781 | /* reschedule state queue work to run as soon as possible */ | |
782 | phy_trigger_machine(phydev); | |
783 | } | |
a2c054a8 | 784 | |
d884814a HK |
785 | /* did_interrupt() may have cleared the interrupt already */ |
786 | if (!phydev->drv->did_interrupt && phy_clear_interrupt(phydev)) | |
a2c054a8 BM |
787 | goto phy_err; |
788 | return IRQ_HANDLED; | |
789 | ||
790 | phy_err: | |
791 | phy_error(phydev); | |
792 | return IRQ_NONE; | |
793 | } | |
794 | ||
b3df0da8 RD |
795 | /** |
796 | * phy_enable_interrupts - Enable the interrupts from the PHY side | |
797 | * @phydev: target phy_device struct | |
798 | */ | |
89ff05ec | 799 | static int phy_enable_interrupts(struct phy_device *phydev) |
00db8189 | 800 | { |
553fe92b | 801 | int err = phy_clear_interrupt(phydev); |
00db8189 | 802 | |
e1393456 AF |
803 | if (err < 0) |
804 | return err; | |
00db8189 | 805 | |
553fe92b | 806 | return phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); |
00db8189 | 807 | } |
00db8189 | 808 | |
b3df0da8 | 809 | /** |
07b09289 | 810 | * phy_request_interrupt - request and enable interrupt for a PHY device |
b3df0da8 | 811 | * @phydev: target phy_device struct |
e1393456 | 812 | * |
07b09289 | 813 | * Description: Request and enable the interrupt for the given PHY. |
b3df0da8 | 814 | * If this fails, then we set irq to PHY_POLL. |
e1393456 AF |
815 | * This should only be called with a valid IRQ number. |
816 | */ | |
434a4315 | 817 | void phy_request_interrupt(struct phy_device *phydev) |
e1393456 | 818 | { |
434a4315 HK |
819 | int err; |
820 | ||
821 | err = request_threaded_irq(phydev->irq, NULL, phy_interrupt, | |
822 | IRQF_ONESHOT | IRQF_SHARED, | |
823 | phydev_name(phydev), phydev); | |
824 | if (err) { | |
825 | phydev_warn(phydev, "Error %d requesting IRQ %d, falling back to polling\n", | |
826 | err, phydev->irq); | |
e1393456 | 827 | phydev->irq = PHY_POLL; |
07b09289 HK |
828 | } else { |
829 | if (phy_enable_interrupts(phydev)) { | |
830 | phydev_warn(phydev, "Can't enable interrupt, falling back to polling\n"); | |
831 | phy_free_interrupt(phydev); | |
832 | phydev->irq = PHY_POLL; | |
833 | } | |
e1393456 | 834 | } |
e1393456 | 835 | } |
434a4315 | 836 | EXPORT_SYMBOL(phy_request_interrupt); |
e1393456 | 837 | |
07b09289 HK |
838 | /** |
839 | * phy_free_interrupt - disable and free interrupt for a PHY device | |
840 | * @phydev: target phy_device struct | |
841 | * | |
842 | * Description: Disable and free the interrupt for the given PHY. | |
843 | * This should only be called with a valid IRQ number. | |
844 | */ | |
845 | void phy_free_interrupt(struct phy_device *phydev) | |
846 | { | |
847 | phy_disable_interrupts(phydev); | |
848 | free_irq(phydev->irq, phydev); | |
849 | } | |
850 | EXPORT_SYMBOL(phy_free_interrupt); | |
851 | ||
b3df0da8 RD |
852 | /** |
853 | * phy_stop - Bring down the PHY link, and stop checking the status | |
854 | * @phydev: target phy_device struct | |
855 | */ | |
e1393456 AF |
856 | void phy_stop(struct phy_device *phydev) |
857 | { | |
f802ca1f | 858 | if (!phy_is_started(phydev) && phydev->state != PHY_DOWN) { |
2b3e88ea HK |
859 | WARN(1, "called from state %s\n", |
860 | phy_state_to_str(phydev->state)); | |
2b3e88ea HK |
861 | return; |
862 | } | |
e1393456 | 863 | |
a2fc9d7e HK |
864 | mutex_lock(&phydev->lock); |
865 | ||
6daf6531 MR |
866 | phydev->state = PHY_HALTED; |
867 | ||
35b5f6b1 | 868 | mutex_unlock(&phydev->lock); |
3c3070d7 | 869 | |
e8cfd9d6 | 870 | phy_state_machine(&phydev->state_queue.work); |
cbfd12b3 | 871 | phy_stop_machine(phydev); |
e8cfd9d6 | 872 | |
2f53e904 | 873 | /* Cannot call flush_scheduled_work() here as desired because |
34d884e3 | 874 | * of rtnl_lock(), but PHY_HALTED shall guarantee irq handler |
3c3070d7 MR |
875 | * will not reenable interrupts. |
876 | */ | |
e1393456 | 877 | } |
2f53e904 | 878 | EXPORT_SYMBOL(phy_stop); |
e1393456 | 879 | |
b3df0da8 RD |
880 | /** |
881 | * phy_start - start or restart a PHY device | |
882 | * @phydev: target phy_device struct | |
e1393456 | 883 | * |
b3df0da8 | 884 | * Description: Indicates the attached device's readiness to |
e1393456 AF |
885 | * handle PHY-related work. Used during startup to start the |
886 | * PHY, and after a call to phy_stop() to resume operation. | |
887 | * Also used to indicate the MDIO bus has cleared an error | |
888 | * condition. | |
889 | */ | |
890 | void phy_start(struct phy_device *phydev) | |
891 | { | |
35b5f6b1 | 892 | mutex_lock(&phydev->lock); |
e1393456 | 893 | |
21796261 HK |
894 | if (phydev->state != PHY_READY && phydev->state != PHY_HALTED) { |
895 | WARN(1, "called from state %s\n", | |
896 | phy_state_to_str(phydev->state)); | |
897 | goto out; | |
898 | } | |
899 | ||
9e573cfc HK |
900 | /* if phy was suspended, bring the physical link up again */ |
901 | __phy_resume(phydev); | |
c15e10e7 | 902 | |
f24098f8 | 903 | phydev->state = PHY_UP; |
9e573cfc HK |
904 | |
905 | phy_start_machine(phydev); | |
21796261 | 906 | out: |
35b5f6b1 | 907 | mutex_unlock(&phydev->lock); |
e1393456 | 908 | } |
e1393456 | 909 | EXPORT_SYMBOL(phy_start); |
67c4f3fa | 910 | |
35b5f6b1 NC |
911 | /** |
912 | * phy_state_machine - Handle the state machine | |
913 | * @work: work_struct that describes the work to be done | |
35b5f6b1 | 914 | */ |
4f9c85a1 | 915 | void phy_state_machine(struct work_struct *work) |
00db8189 | 916 | { |
bf6aede7 | 917 | struct delayed_work *dwork = to_delayed_work(work); |
35b5f6b1 | 918 | struct phy_device *phydev = |
a390d1f3 | 919 | container_of(dwork, struct phy_device, state_queue); |
c15e10e7 | 920 | bool needs_aneg = false, do_suspend = false; |
3e2186e0 | 921 | enum phy_state old_state; |
00db8189 AF |
922 | int err = 0; |
923 | ||
35b5f6b1 | 924 | mutex_lock(&phydev->lock); |
00db8189 | 925 | |
3e2186e0 FF |
926 | old_state = phydev->state; |
927 | ||
e109374f FF |
928 | switch (phydev->state) { |
929 | case PHY_DOWN: | |
e109374f | 930 | case PHY_READY: |
e109374f FF |
931 | break; |
932 | case PHY_UP: | |
6e14a5ee | 933 | needs_aneg = true; |
00db8189 | 934 | |
e109374f FF |
935 | break; |
936 | case PHY_NOLINK: | |
c8e977ba | 937 | case PHY_RUNNING: |
c8e977ba | 938 | err = phy_check_link_status(phydev); |
e109374f | 939 | break; |
e109374f FF |
940 | case PHY_HALTED: |
941 | if (phydev->link) { | |
942 | phydev->link = 0; | |
a81497be | 943 | phy_link_down(phydev, true); |
e109374f | 944 | } |
95fb8bb3 | 945 | do_suspend = true; |
e109374f | 946 | break; |
00db8189 AF |
947 | } |
948 | ||
35b5f6b1 | 949 | mutex_unlock(&phydev->lock); |
00db8189 AF |
950 | |
951 | if (needs_aneg) | |
c45d7150 | 952 | err = phy_start_aneg(phydev); |
6e14a5ee | 953 | else if (do_suspend) |
be9dad1f SH |
954 | phy_suspend(phydev); |
955 | ||
00db8189 AF |
956 | if (err < 0) |
957 | phy_error(phydev); | |
958 | ||
5c5f626b | 959 | if (old_state != phydev->state) { |
6a95befc MG |
960 | phydev_dbg(phydev, "PHY state change %s -> %s\n", |
961 | phy_state_to_str(old_state), | |
962 | phy_state_to_str(phydev->state)); | |
5c5f626b HK |
963 | if (phydev->drv && phydev->drv->link_change_notify) |
964 | phydev->drv->link_change_notify(phydev); | |
965 | } | |
3e2186e0 | 966 | |
d5c3d846 FF |
967 | /* Only re-schedule a PHY state machine change if we are polling the |
968 | * PHY, if PHY_IGNORE_INTERRUPT is set, then we will be moving | |
075ddebc HK |
969 | * between states from phy_mac_interrupt(). |
970 | * | |
971 | * In state PHY_HALTED the PHY gets suspended, so rescheduling the | |
972 | * state machine would be pointless and possibly error prone when | |
973 | * called from phy_disconnect() synchronously. | |
d5c3d846 | 974 | */ |
a2004907 | 975 | mutex_lock(&phydev->lock); |
2b3e88ea | 976 | if (phy_polling_mode(phydev) && phy_is_started(phydev)) |
9f2959b6 | 977 | phy_queue_state_machine(phydev, PHY_STATE_TIME); |
a2004907 | 978 | mutex_unlock(&phydev->lock); |
35b5f6b1 | 979 | } |
a59a4d19 | 980 | |
664fcf12 AL |
981 | /** |
982 | * phy_mac_interrupt - MAC says the link has changed | |
983 | * @phydev: phy_device struct with changed link | |
664fcf12 | 984 | * |
28b2e0d2 HK |
985 | * The MAC layer is able to indicate there has been a change in the PHY link |
986 | * status. Trigger the state machine and work a work queue. | |
664fcf12 | 987 | */ |
28b2e0d2 | 988 | void phy_mac_interrupt(struct phy_device *phydev) |
5ea94e76 | 989 | { |
deccd16f | 990 | /* Trigger a state machine change */ |
d73a2156 | 991 | phy_trigger_machine(phydev); |
5ea94e76 FF |
992 | } |
993 | EXPORT_SYMBOL(phy_mac_interrupt); | |
994 | ||
3c1bcc86 AL |
995 | static void mmd_eee_adv_to_linkmode(unsigned long *advertising, u16 eee_adv) |
996 | { | |
997 | linkmode_zero(advertising); | |
998 | ||
999 | if (eee_adv & MDIO_EEE_100TX) | |
1000 | linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, | |
1001 | advertising); | |
1002 | if (eee_adv & MDIO_EEE_1000T) | |
1003 | linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, | |
1004 | advertising); | |
1005 | if (eee_adv & MDIO_EEE_10GT) | |
1006 | linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, | |
1007 | advertising); | |
1008 | if (eee_adv & MDIO_EEE_1000KX) | |
1009 | linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, | |
1010 | advertising); | |
1011 | if (eee_adv & MDIO_EEE_10GKX4) | |
1012 | linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, | |
1013 | advertising); | |
1014 | if (eee_adv & MDIO_EEE_10GKR) | |
1015 | linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, | |
1016 | advertising); | |
1017 | } | |
1018 | ||
a59a4d19 GC |
1019 | /** |
1020 | * phy_init_eee - init and check the EEE feature | |
1021 | * @phydev: target phy_device struct | |
1022 | * @clk_stop_enable: PHY may stop the clock during LPI | |
1023 | * | |
1024 | * Description: it checks if the Energy-Efficient Ethernet (EEE) | |
1025 | * is supported by looking at the MMD registers 3.20 and 7.60/61 | |
1026 | * and it programs the MMD register 3.0 setting the "Clock stop enable" | |
1027 | * bit if required. | |
1028 | */ | |
1029 | int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) | |
1030 | { | |
25149ef9 FF |
1031 | if (!phydev->drv) |
1032 | return -EIO; | |
1033 | ||
a59a4d19 | 1034 | /* According to 802.3az,the EEE is supported only in full duplex-mode. |
a59a4d19 | 1035 | */ |
32d75141 | 1036 | if (phydev->duplex == DUPLEX_FULL) { |
3c1bcc86 AL |
1037 | __ETHTOOL_DECLARE_LINK_MODE_MASK(common); |
1038 | __ETHTOOL_DECLARE_LINK_MODE_MASK(lp); | |
1039 | __ETHTOOL_DECLARE_LINK_MODE_MASK(adv); | |
a59a4d19 | 1040 | int eee_lp, eee_cap, eee_adv; |
4ae6e50c | 1041 | int status; |
3c1bcc86 | 1042 | u32 cap; |
a59a4d19 GC |
1043 | |
1044 | /* Read phy status to properly get the right settings */ | |
1045 | status = phy_read_status(phydev); | |
1046 | if (status) | |
1047 | return status; | |
1048 | ||
1049 | /* First check if the EEE ability is supported */ | |
a6d99fcd | 1050 | eee_cap = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); |
7a4cecf7 GC |
1051 | if (eee_cap <= 0) |
1052 | goto eee_exit_err; | |
a59a4d19 | 1053 | |
b32607dd | 1054 | cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap); |
a59a4d19 | 1055 | if (!cap) |
7a4cecf7 | 1056 | goto eee_exit_err; |
a59a4d19 GC |
1057 | |
1058 | /* Check which link settings negotiated and verify it in | |
1059 | * the EEE advertising registers. | |
1060 | */ | |
a6d99fcd | 1061 | eee_lp = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE); |
7a4cecf7 GC |
1062 | if (eee_lp <= 0) |
1063 | goto eee_exit_err; | |
a59a4d19 | 1064 | |
a6d99fcd | 1065 | eee_adv = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV); |
7a4cecf7 GC |
1066 | if (eee_adv <= 0) |
1067 | goto eee_exit_err; | |
a59a4d19 | 1068 | |
3c1bcc86 AL |
1069 | mmd_eee_adv_to_linkmode(adv, eee_adv); |
1070 | mmd_eee_adv_to_linkmode(lp, eee_lp); | |
1071 | linkmode_and(common, adv, lp); | |
1072 | ||
1073 | if (!phy_check_valid(phydev->speed, phydev->duplex, common)) | |
7a4cecf7 | 1074 | goto eee_exit_err; |
a59a4d19 | 1075 | |
b52c018d | 1076 | if (clk_stop_enable) |
a59a4d19 GC |
1077 | /* Configure the PHY to stop receiving xMII |
1078 | * clock while it is signaling LPI. | |
1079 | */ | |
b52c018d HK |
1080 | phy_set_bits_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, |
1081 | MDIO_PCS_CTRL1_CLKSTOP_EN); | |
a59a4d19 | 1082 | |
e62a768f | 1083 | return 0; /* EEE supported */ |
a59a4d19 | 1084 | } |
7a4cecf7 | 1085 | eee_exit_err: |
e62a768f | 1086 | return -EPROTONOSUPPORT; |
a59a4d19 GC |
1087 | } |
1088 | EXPORT_SYMBOL(phy_init_eee); | |
1089 | ||
1090 | /** | |
1091 | * phy_get_eee_err - report the EEE wake error count | |
1092 | * @phydev: target phy_device struct | |
1093 | * | |
1094 | * Description: it is to report the number of time where the PHY | |
1095 | * failed to complete its normal wake sequence. | |
1096 | */ | |
1097 | int phy_get_eee_err(struct phy_device *phydev) | |
1098 | { | |
25149ef9 FF |
1099 | if (!phydev->drv) |
1100 | return -EIO; | |
1101 | ||
a6d99fcd | 1102 | return phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_WK_ERR); |
a59a4d19 GC |
1103 | } |
1104 | EXPORT_SYMBOL(phy_get_eee_err); | |
1105 | ||
1106 | /** | |
1107 | * phy_ethtool_get_eee - get EEE supported and status | |
1108 | * @phydev: target phy_device struct | |
1109 | * @data: ethtool_eee data | |
1110 | * | |
1111 | * Description: it reportes the Supported/Advertisement/LP Advertisement | |
1112 | * capabilities. | |
1113 | */ | |
1114 | int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data) | |
1115 | { | |
1116 | int val; | |
1117 | ||
25149ef9 FF |
1118 | if (!phydev->drv) |
1119 | return -EIO; | |
1120 | ||
a59a4d19 | 1121 | /* Get Supported EEE */ |
a6d99fcd | 1122 | val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); |
a59a4d19 GC |
1123 | if (val < 0) |
1124 | return val; | |
b32607dd | 1125 | data->supported = mmd_eee_cap_to_ethtool_sup_t(val); |
a59a4d19 GC |
1126 | |
1127 | /* Get advertisement EEE */ | |
a6d99fcd | 1128 | val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV); |
a59a4d19 GC |
1129 | if (val < 0) |
1130 | return val; | |
b32607dd | 1131 | data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); |
d1420bb9 | 1132 | data->eee_enabled = !!data->advertised; |
a59a4d19 GC |
1133 | |
1134 | /* Get LP advertisement EEE */ | |
a6d99fcd | 1135 | val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE); |
a59a4d19 GC |
1136 | if (val < 0) |
1137 | return val; | |
b32607dd | 1138 | data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val); |
a59a4d19 | 1139 | |
d1420bb9 HK |
1140 | data->eee_active = !!(data->advertised & data->lp_advertised); |
1141 | ||
a59a4d19 GC |
1142 | return 0; |
1143 | } | |
1144 | EXPORT_SYMBOL(phy_ethtool_get_eee); | |
1145 | ||
1146 | /** | |
1147 | * phy_ethtool_set_eee - set EEE supported and status | |
1148 | * @phydev: target phy_device struct | |
1149 | * @data: ethtool_eee data | |
1150 | * | |
1151 | * Description: it is to program the Advertisement EEE register. | |
1152 | */ | |
1153 | int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) | |
1154 | { | |
d1420bb9 | 1155 | int cap, old_adv, adv = 0, ret; |
a59a4d19 | 1156 | |
25149ef9 FF |
1157 | if (!phydev->drv) |
1158 | return -EIO; | |
1159 | ||
83ea067f RK |
1160 | /* Get Supported EEE */ |
1161 | cap = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); | |
1162 | if (cap < 0) | |
1163 | return cap; | |
d853d145 | 1164 | |
f75abeb8 RK |
1165 | old_adv = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV); |
1166 | if (old_adv < 0) | |
1167 | return old_adv; | |
1168 | ||
d1420bb9 HK |
1169 | if (data->eee_enabled) { |
1170 | adv = !data->advertised ? cap : | |
1171 | ethtool_adv_to_mmd_eee_adv_t(data->advertised) & cap; | |
1172 | /* Mask prohibited EEE modes */ | |
1173 | adv &= ~phydev->eee_broken_modes; | |
1174 | } | |
83ea067f | 1175 | |
f75abeb8 RK |
1176 | if (old_adv != adv) { |
1177 | ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv); | |
1178 | if (ret < 0) | |
1179 | return ret; | |
1180 | ||
1181 | /* Restart autonegotiation so the new modes get sent to the | |
1182 | * link partner. | |
1183 | */ | |
e34f79e7 HK |
1184 | if (phydev->autoneg == AUTONEG_ENABLE) { |
1185 | ret = phy_restart_aneg(phydev); | |
1186 | if (ret < 0) | |
1187 | return ret; | |
1188 | } | |
f75abeb8 RK |
1189 | } |
1190 | ||
1191 | return 0; | |
a59a4d19 GC |
1192 | } |
1193 | EXPORT_SYMBOL(phy_ethtool_set_eee); | |
42e836eb MS |
1194 | |
1195 | int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) | |
1196 | { | |
25149ef9 | 1197 | if (phydev->drv && phydev->drv->set_wol) |
42e836eb MS |
1198 | return phydev->drv->set_wol(phydev, wol); |
1199 | ||
1200 | return -EOPNOTSUPP; | |
1201 | } | |
1202 | EXPORT_SYMBOL(phy_ethtool_set_wol); | |
1203 | ||
1204 | void phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) | |
1205 | { | |
25149ef9 | 1206 | if (phydev->drv && phydev->drv->get_wol) |
42e836eb MS |
1207 | phydev->drv->get_wol(phydev, wol); |
1208 | } | |
1209 | EXPORT_SYMBOL(phy_ethtool_get_wol); | |
9d9a77ce PR |
1210 | |
1211 | int phy_ethtool_get_link_ksettings(struct net_device *ndev, | |
1212 | struct ethtool_link_ksettings *cmd) | |
1213 | { | |
1214 | struct phy_device *phydev = ndev->phydev; | |
1215 | ||
1216 | if (!phydev) | |
1217 | return -ENODEV; | |
1218 | ||
5514174f | 1219 | phy_ethtool_ksettings_get(phydev, cmd); |
1220 | ||
1221 | return 0; | |
9d9a77ce PR |
1222 | } |
1223 | EXPORT_SYMBOL(phy_ethtool_get_link_ksettings); | |
1224 | ||
1225 | int phy_ethtool_set_link_ksettings(struct net_device *ndev, | |
1226 | const struct ethtool_link_ksettings *cmd) | |
1227 | { | |
1228 | struct phy_device *phydev = ndev->phydev; | |
1229 | ||
1230 | if (!phydev) | |
1231 | return -ENODEV; | |
1232 | ||
1233 | return phy_ethtool_ksettings_set(phydev, cmd); | |
1234 | } | |
1235 | EXPORT_SYMBOL(phy_ethtool_set_link_ksettings); | |
e86a8987 FF |
1236 | |
1237 | int phy_ethtool_nway_reset(struct net_device *ndev) | |
1238 | { | |
1239 | struct phy_device *phydev = ndev->phydev; | |
1240 | ||
1241 | if (!phydev) | |
1242 | return -ENODEV; | |
1243 | ||
25149ef9 FF |
1244 | if (!phydev->drv) |
1245 | return -EIO; | |
1246 | ||
002ba705 | 1247 | return phy_restart_aneg(phydev); |
e86a8987 FF |
1248 | } |
1249 | EXPORT_SYMBOL(phy_ethtool_nway_reset); |