From 43b6329f982092d8fe5c953940609ca8ee3055df Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 11 Feb 2014 17:27:33 -0800 Subject: net: phy: use network device in phy_print_status phy_print_status() currently uses dev_name(&phydev->dev) which will usually result in printing something along those lines for Device Tree aware drivers: libphy: f0b60000.etherne:0a - Link is Down libphy: f0ba0000.etherne:00 - Link is Up - 1000/Full This is not terribly useful for network administrators or users since we expect a network interface name to be able to correlate link events with interfaces. Update phy_print_status() to use netdev_info() with phydev->attached_dev which is the backing network device for our PHY device. The leading dash is removed since netdev_info() prefixes the messages with ": " already. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 19c9eca0ef26..c35b2e73168a 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -45,12 +45,11 @@ void phy_print_status(struct phy_device *phydev) { if (phydev->link) { - pr_info("%s - Link is Up - %d/%s\n", - dev_name(&phydev->dev), + netdev_info(phydev->attached_dev, "Link is Up - %d/%s\n", phydev->speed, DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); } else { - pr_info("%s - Link is Down\n", dev_name(&phydev->dev)); + netdev_info(phydev->attached_dev, "Link is Down\n"); } } EXPORT_SYMBOL(phy_print_status); -- cgit v1.2.3 From df40cc887924f64810e2dc8bd810aec5b37061c9 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 11 Feb 2014 17:27:34 -0800 Subject: net: phy: update phy_print_status to show pause settings Update phy_print_status() to also display the PHY device pause settings (rx/tx or off). Suggested-by: Joe Perches Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index c35b2e73168a..8ae22603b1b1 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -45,9 +45,11 @@ void phy_print_status(struct phy_device *phydev) { if (phydev->link) { - netdev_info(phydev->attached_dev, "Link is Up - %d/%s\n", + netdev_info(phydev->attached_dev, + "Link is Up - %d/%s - flow control %s\n", phydev->speed, - DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); + DUPLEX_FULL == phydev->duplex ? "Full" : "Half", + phydev->pause ? "rx/tx" : "off"); } else { netdev_info(phydev->attached_dev, "Link is Down\n"); } -- cgit v1.2.3 From 766d1d388e6e6bfda99a00d68ac9247a1c25a0d9 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 11 Feb 2014 17:27:35 -0800 Subject: net: phy: display human readable PHY speed settings Use a convenience function: phy_speed_to_str() which will display human readable speeds. Suggested-by: Joe Perches Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 8ae22603b1b1..36fc6e16b569 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -38,6 +38,26 @@ #include +static const char *phy_speed_to_str(int speed) +{ + switch (speed) { + case SPEED_10: + return "10Mbps"; + case SPEED_100: + return "100Mbps"; + case SPEED_1000: + return "1Gbps"; + case SPEED_2500: + return "2.5Gbps"; + case SPEED_10000: + return "10Gbps"; + case SPEED_UNKNOWN: + return "Unknown"; + default: + return "Unsupported (update phy.c)"; + } +} + /** * phy_print_status - Convenience function to print out the current phy status * @phydev: the phy_device struct @@ -46,8 +66,8 @@ void phy_print_status(struct phy_device *phydev) { if (phydev->link) { netdev_info(phydev->attached_dev, - "Link is Up - %d/%s - flow control %s\n", - phydev->speed, + "Link is Up - %s/%s - flow control %s\n", + phy_speed_to_str(phydev->speed), DUPLEX_FULL == phydev->duplex ? "Full" : "Half", phydev->pause ? "rx/tx" : "off"); } else { -- cgit v1.2.3 From a9fa6e6ac29709e7a623b60695c172da675df045 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 11 Feb 2014 17:27:36 -0800 Subject: net: phy: add genphy_aneg_done() In preparation for allowing PHY drivers to potentially override their auto-negotiation done callback, move the contents of phy_aneg_done() to genphy_aneg_done() since that function really is the generic implementation based on the BMSR_ANEGCOMPLETE status. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 4 +--- drivers/net/phy/phy_device.c | 16 ++++++++++++++++ include/linux/phy.h | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 36fc6e16b569..db9c543bd2af 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -120,9 +120,7 @@ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) */ static inline int phy_aneg_done(struct phy_device *phydev) { - int retval = phy_read(phydev, MII_BMSR); - - return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); + return genphy_aneg_done(phydev); } /* A structure for mapping a particular speed and duplex diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 82514e72b3d8..4e7db726028f 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -865,6 +865,22 @@ int genphy_config_aneg(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_config_aneg); +/** + * genphy_aneg_done - return auto-negotiation status + * @phydev: target phy_device struct + * + * Description: Reads the status register and returns 0 either if + * auto-negotiation is incomplete, or if there was an error. + * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. + */ +int genphy_aneg_done(struct phy_device *phydev) +{ + int retval = phy_read(phydev, MII_BMSR); + + return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); +} +EXPORT_SYMBOL(genphy_aneg_done); + static int gen10g_config_aneg(struct phy_device *phydev) { return 0; diff --git a/include/linux/phy.h b/include/linux/phy.h index 565188ca328f..c572842c9029 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -612,6 +612,7 @@ static inline int phy_read_status(struct phy_device *phydev) int genphy_setup_forced(struct phy_device *phydev); int genphy_restart_aneg(struct phy_device *phydev); int genphy_config_aneg(struct phy_device *phydev); +int genphy_aneg_done(struct phy_device *phydev); int genphy_update_link(struct phy_device *phydev); int genphy_read_status(struct phy_device *phydev); int genphy_suspend(struct phy_device *phydev); -- cgit v1.2.3 From 76a423a3f8f16bfc7fb86360a620be18c775b94d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 11 Feb 2014 17:27:37 -0800 Subject: net: phy: allow driver to implement their own aneg_done Some PHYs out there can be very quirky with respect to how they would report the auto-negotiation is completed. Allow drivers to override the generic aneg_done() implementation by providing their own. Since not all drivers have been updated yet to use genphy_aneg_done() as aneg_done() callback, we explicitely check that this callback is valid before calling into it. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 9 ++++++--- drivers/net/phy/phy_device.c | 1 + include/linux/phy.h | 3 +++ 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index db9c543bd2af..2fa4611709a4 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -114,12 +114,15 @@ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) * phy_aneg_done - return auto-negotiation status * @phydev: target phy_device struct * - * Description: Reads the status register and returns 0 either if - * auto-negotiation is incomplete, or if there was an error. - * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. + * Description: Return the auto-negotiation status from this @phydev + * Returns > 0 on success or < 0 on error. 0 means that auto-negotiation + * is still pending. */ static inline int phy_aneg_done(struct phy_device *phydev) { + if (phydev->drv->aneg_done) + return phydev->drv->aneg_done(phydev); + return genphy_aneg_done(phydev); } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 4e7db726028f..7c184208ed4d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1267,6 +1267,7 @@ static struct phy_driver genphy_driver[] = { .config_init = genphy_config_init, .features = 0, .config_aneg = genphy_config_aneg, + .aneg_done = genphy_aneg_done, .read_status = genphy_read_status, .suspend = genphy_suspend, .resume = genphy_resume, diff --git a/include/linux/phy.h b/include/linux/phy.h index c572842c9029..eede6579cae7 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -417,6 +417,9 @@ struct phy_driver { */ int (*config_aneg)(struct phy_device *phydev); + /* Determines the auto negotiation result */ + int (*aneg_done)(struct phy_device *phydev); + /* Determines the negotiated speed and duplex */ int (*read_status)(struct phy_device *phydev); -- cgit v1.2.3 From ad033506f5061db818bab1cc07b2c3d8d477cf12 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 11 Feb 2014 17:27:38 -0800 Subject: net: phy: fix phy_{clear,config}_interrupt comment typos The comments above phy_{clear,config}_interrupt used the word "on" instead of "or", when talking about the return values of the functions, fix these two typos. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 2fa4611709a4..fc918b63dc65 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -83,7 +83,7 @@ EXPORT_SYMBOL(phy_print_status); * If the @phydev driver has an ack_interrupt function, call it to * ack and clear the phy device's interrupt. * - * Returns 0 on success on < 0 on error. + * Returns 0 on success or < 0 on error. */ static int phy_clear_interrupt(struct phy_device *phydev) { @@ -98,7 +98,7 @@ static int phy_clear_interrupt(struct phy_device *phydev) * @phydev: the phy_device struct * @interrupts: interrupt flags to configure for this @phydev * - * Returns 0 on success on < 0 on error. + * Returns 0 on success or < 0 on error. */ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) { -- cgit v1.2.3 From c88838ce89515331ac835a470dc51ddf574770b1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 13 Feb 2014 16:08:43 -0800 Subject: net: phy: update port type for MoCA PHYs MoCA PHYs are using coaxial (BNC-like) connectors, update the transceiver port type when replying to ethtool. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index fc918b63dc65..643b5d665f41 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -305,7 +305,10 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) ethtool_cmd_speed_set(cmd, phydev->speed); cmd->duplex = phydev->duplex; - cmd->port = PORT_MII; + if (phydev->interface == PHY_INTERFACE_MODE_MOCA) + cmd->port = PORT_BNC; + else + cmd->port = PORT_MII; cmd->phy_address = phydev->addr; cmd->transceiver = phy_is_internal(phydev) ? XCVR_INTERNAL : XCVR_EXTERNAL; -- cgit v1.2.3 From fa8cddaf903c0e010ff2de210ea4974fa30603ef Mon Sep 17 00:00:00 2001 From: Balakumaran Kannan Date: Wed, 9 Apr 2014 09:03:45 +0530 Subject: net phylib: Remove unnecessary condition check in phy This condition check makes no difference in the code flow since 3.10 Signed-off-by: Balakumaran Kannan Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 1d788f19135b..1b6d09aef427 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -756,12 +756,8 @@ void phy_state_machine(struct work_struct *work) netif_carrier_on(phydev->attached_dev); phydev->adjust_link(phydev->attached_dev); - } else if (0 == phydev->link_timeout--) { + } else if (0 == phydev->link_timeout--) needs_aneg = 1; - /* If we have the magic_aneg bit, we try again */ - if (phydev->drv->flags & PHY_HAS_MAGICANEG) - break; - } break; case PHY_NOLINK: err = phy_read_status(phydev); -- cgit v1.2.3 From e46e08b843d8ff8c46ad8d7b0b95acaacc4e6195 Mon Sep 17 00:00:00 2001 From: Balakumaran Kannan Date: Thu, 24 Apr 2014 08:22:47 +0530 Subject: net phy: Check for aneg completion before setting state to PHY_RUNNING phy_state_machine should check whether auto-negotiatin is completed before changing phydev->state from PHY_NOLINK to PHY_RUNNING. If auto-negotiation is not completed phydev->state should be set to PHY_AN. Signed-off-by: Balakumaran Kannan Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 1b6d09aef427..a972056b2249 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -765,6 +765,17 @@ void phy_state_machine(struct work_struct *work) break; if (phydev->link) { + if (AUTONEG_ENABLE == phydev->autoneg) { + err = phy_aneg_done(phydev); + if (err < 0) + break; + + if (!err) { + phydev->state = PHY_AN; + phydev->link_timeout = PHY_AN_TIMEOUT; + break; + } + } phydev->state = PHY_RUNNING; netif_carrier_on(phydev->attached_dev); phydev->adjust_link(phydev->attached_dev); -- cgit v1.2.3 From 6e14a5eeb158215881ef4507833a3574d0dbad19 Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Thu, 15 May 2014 13:35:34 +0800 Subject: net: phy: resume phydev when going to RESUMING With commit be9dad1f9f26604fb ("net: phy: suspend phydev when going to HALTED"), an unused PHY device will be put in a low-power mode using BMCR_PDOWN. Some Ethernet drivers might be calling phy_start() and phy_stop() from ndo_open and ndo_close() respectively, while calling phy_connect() and phy_disconnect() from probe and remove. In such a case, the PHY will be powered down during the phy_stop() call, but will fail to be powered up in phy_start(). This patch fixes this scenario. Signed-off-by: Jiancheng Xue Signed-off-by: Zhangfei Gao Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/net/phy/phy.c') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index a972056b2249..3bc079a67a3d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -715,7 +715,7 @@ void phy_state_machine(struct work_struct *work) struct delayed_work *dwork = to_delayed_work(work); struct phy_device *phydev = container_of(dwork, struct phy_device, state_queue); - int needs_aneg = 0, do_suspend = 0; + bool needs_aneg = false, do_suspend = false, do_resume = false; int err = 0; mutex_lock(&phydev->lock); @@ -727,7 +727,7 @@ void phy_state_machine(struct work_struct *work) case PHY_PENDING: break; case PHY_UP: - needs_aneg = 1; + needs_aneg = true; phydev->link_timeout = PHY_AN_TIMEOUT; @@ -757,7 +757,7 @@ void phy_state_machine(struct work_struct *work) phydev->adjust_link(phydev->attached_dev); } else if (0 == phydev->link_timeout--) - needs_aneg = 1; + needs_aneg = true; break; case PHY_NOLINK: err = phy_read_status(phydev); @@ -791,7 +791,7 @@ void phy_state_machine(struct work_struct *work) netif_carrier_on(phydev->attached_dev); } else { if (0 == phydev->link_timeout--) - needs_aneg = 1; + needs_aneg = true; } phydev->adjust_link(phydev->attached_dev); @@ -827,7 +827,7 @@ void phy_state_machine(struct work_struct *work) phydev->link = 0; netif_carrier_off(phydev->attached_dev); phydev->adjust_link(phydev->attached_dev); - do_suspend = 1; + do_suspend = true; } break; case PHY_RESUMING: @@ -876,6 +876,7 @@ void phy_state_machine(struct work_struct *work) } phydev->adjust_link(phydev->attached_dev); } + do_resume = true; break; } @@ -883,9 +884,10 @@ void phy_state_machine(struct work_struct *work) if (needs_aneg) err = phy_start_aneg(phydev); - - if (do_suspend) + else if (do_suspend) phy_suspend(phydev); + else if (do_resume) + phy_resume(phydev); if (err < 0) phy_error(phydev); -- cgit v1.2.3