diff options
author | Philippe Reynes <tremyfr@gmail.com> | 2016-04-14 18:35:00 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-18 14:45:08 -0400 |
commit | 2d55173e71b06c5a369489852d972304e14189fd (patch) | |
tree | c02c71e55e4d63e9fb54c5cc6bcb721689435132 | |
parent | 6d62b4d5fac620ee0ca65dc6d99b0306d96bc541 (diff) |
phy: add generic function to support ksetting support
The old ethtool api (get_setting and set_setting) has
generic phy functions phy_ethtool_sset and phy_ethtool_gset.
To supprt the new ethtool api (get_link_ksettings and
set_link_ksettings), we add generic phy function
phy_ethtool_ksettings_get and phy_ethtool_ksettings_set.
Signed-off-by: Philippe Reynes <tremyfr@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/phy/phy.c | 81 | ||||
-rw-r--r-- | include/linux/phy.h | 4 |
2 files changed, 85 insertions, 0 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 5590b9c182c9..6f221c8c2a7f 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -362,6 +362,60 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) | |||
362 | } | 362 | } |
363 | EXPORT_SYMBOL(phy_ethtool_sset); | 363 | EXPORT_SYMBOL(phy_ethtool_sset); |
364 | 364 | ||
365 | int phy_ethtool_ksettings_set(struct phy_device *phydev, | ||
366 | const struct ethtool_link_ksettings *cmd) | ||
367 | { | ||
368 | u8 autoneg = cmd->base.autoneg; | ||
369 | u8 duplex = cmd->base.duplex; | ||
370 | u32 speed = cmd->base.speed; | ||
371 | u32 advertising; | ||
372 | |||
373 | if (cmd->base.phy_address != phydev->mdio.addr) | ||
374 | return -EINVAL; | ||
375 | |||
376 | ethtool_convert_link_mode_to_legacy_u32(&advertising, | ||
377 | cmd->link_modes.advertising); | ||
378 | |||
379 | /* We make sure that we don't pass unsupported values in to the PHY */ | ||
380 | advertising &= phydev->supported; | ||
381 | |||
382 | /* Verify the settings we care about. */ | ||
383 | if (autoneg != AUTONEG_ENABLE && autoneg != AUTONEG_DISABLE) | ||
384 | return -EINVAL; | ||
385 | |||
386 | if (autoneg == AUTONEG_ENABLE && advertising == 0) | ||
387 | return -EINVAL; | ||
388 | |||
389 | if (autoneg == AUTONEG_DISABLE && | ||
390 | ((speed != SPEED_1000 && | ||
391 | speed != SPEED_100 && | ||
392 | speed != SPEED_10) || | ||
393 | (duplex != DUPLEX_HALF && | ||
394 | duplex != DUPLEX_FULL))) | ||
395 | return -EINVAL; | ||
396 | |||
397 | phydev->autoneg = autoneg; | ||
398 | |||
399 | phydev->speed = speed; | ||
400 | |||
401 | phydev->advertising = advertising; | ||
402 | |||
403 | if (autoneg == AUTONEG_ENABLE) | ||
404 | phydev->advertising |= ADVERTISED_Autoneg; | ||
405 | else | ||
406 | phydev->advertising &= ~ADVERTISED_Autoneg; | ||
407 | |||
408 | phydev->duplex = duplex; | ||
409 | |||
410 | phydev->mdix = cmd->base.eth_tp_mdix_ctrl; | ||
411 | |||
412 | /* Restart the PHY */ | ||
413 | phy_start_aneg(phydev); | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | EXPORT_SYMBOL(phy_ethtool_ksettings_set); | ||
418 | |||
365 | int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) | 419 | int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) |
366 | { | 420 | { |
367 | cmd->supported = phydev->supported; | 421 | cmd->supported = phydev->supported; |
@@ -385,6 +439,33 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) | |||
385 | } | 439 | } |
386 | EXPORT_SYMBOL(phy_ethtool_gset); | 440 | EXPORT_SYMBOL(phy_ethtool_gset); |
387 | 441 | ||
442 | int phy_ethtool_ksettings_get(struct phy_device *phydev, | ||
443 | struct ethtool_link_ksettings *cmd) | ||
444 | { | ||
445 | ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, | ||
446 | phydev->supported); | ||
447 | |||
448 | ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, | ||
449 | phydev->advertising); | ||
450 | |||
451 | ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, | ||
452 | phydev->lp_advertising); | ||
453 | |||
454 | cmd->base.speed = phydev->speed; | ||
455 | cmd->base.duplex = phydev->duplex; | ||
456 | if (phydev->interface == PHY_INTERFACE_MODE_MOCA) | ||
457 | cmd->base.port = PORT_BNC; | ||
458 | else | ||
459 | cmd->base.port = PORT_MII; | ||
460 | |||
461 | cmd->base.phy_address = phydev->mdio.addr; | ||
462 | cmd->base.autoneg = phydev->autoneg; | ||
463 | cmd->base.eth_tp_mdix_ctrl = phydev->mdix; | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | EXPORT_SYMBOL(phy_ethtool_ksettings_get); | ||
468 | |||
388 | /** | 469 | /** |
389 | * phy_mii_ioctl - generic PHY MII ioctl interface | 470 | * phy_mii_ioctl - generic PHY MII ioctl interface |
390 | * @phydev: the phy_device struct | 471 | * @phydev: the phy_device struct |
diff --git a/include/linux/phy.h b/include/linux/phy.h index 2abd7918f64f..be3f83bbdc0b 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h | |||
@@ -805,6 +805,10 @@ void phy_start_machine(struct phy_device *phydev); | |||
805 | void phy_stop_machine(struct phy_device *phydev); | 805 | void phy_stop_machine(struct phy_device *phydev); |
806 | int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); | 806 | int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); |
807 | int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); | 807 | int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); |
808 | int phy_ethtool_ksettings_get(struct phy_device *phydev, | ||
809 | struct ethtool_link_ksettings *cmd); | ||
810 | int phy_ethtool_ksettings_set(struct phy_device *phydev, | ||
811 | const struct ethtool_link_ksettings *cmd); | ||
808 | int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); | 812 | int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); |
809 | int phy_start_interrupts(struct phy_device *phydev); | 813 | int phy_start_interrupts(struct phy_device *phydev); |
810 | void phy_print_status(struct phy_device *phydev); | 814 | void phy_print_status(struct phy_device *phydev); |