diff options
Diffstat (limited to 'drivers/net/phy/phy.c')
-rw-r--r-- | drivers/net/phy/phy.c | 84 |
1 files changed, 59 insertions, 25 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 76d96b9ebcd..3bc079a67a3 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -38,6 +38,26 @@ #include <asm/irq.h> +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 @@ -45,12 +65,13 @@ void phy_print_status(struct phy_device *phydev) { if (phydev->link) { - pr_info("%s - Link is Up - %d/%s\n", - dev_name(&phydev->dev), - phydev->speed, - DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); + netdev_info(phydev->attached_dev, + "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 { - 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); @@ -62,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) { @@ -77,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) { @@ -93,15 +114,16 @@ 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) { - int retval = phy_read(phydev, MII_BMSR); + if (phydev->drv->aneg_done) + return phydev->drv->aneg_done(phydev); - return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); + return genphy_aneg_done(phydev); } /* A structure for mapping a particular speed and duplex @@ -283,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; @@ -690,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); @@ -702,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; @@ -731,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--) { - needs_aneg = 1; - /* If we have the magic_aneg bit, we try again */ - if (phydev->drv->flags & PHY_HAS_MAGICANEG) - break; - } + } else if (0 == phydev->link_timeout--) + needs_aneg = true; break; case PHY_NOLINK: err = phy_read_status(phydev); @@ -744,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); @@ -759,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); @@ -795,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: @@ -844,6 +876,7 @@ void phy_state_machine(struct work_struct *work) } phydev->adjust_link(phydev->attached_dev); } + do_resume = true; break; } @@ -851,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); |