Commit a81497be authored by Russell King's avatar Russell King Committed by David S. Miller

net: phy: provide a hook for link up/link down events

Sometimes, we need to do additional work between the PHY coming up and
marking the carrier present - for example, we may need to wait for the
PHY to MAC link to finish negotiation.  This changes phylib to provide
a notification function pointer which avoids the built-in
netif_carrier_on() and netif_carrier_off() functions.

Standard ->adjust_link functionality is provided by hooking a helper
into the new ->phy_link_change method.
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1f3645bb
...@@ -865,9 +865,15 @@ void phy_start(struct phy_device *phydev) ...@@ -865,9 +865,15 @@ void phy_start(struct phy_device *phydev)
} }
EXPORT_SYMBOL(phy_start); EXPORT_SYMBOL(phy_start);
static void phy_adjust_link(struct phy_device *phydev) static void phy_link_up(struct phy_device *phydev)
{ {
phydev->adjust_link(phydev->attached_dev); phydev->phy_link_change(phydev, true, true);
phy_led_trigger_change_speed(phydev);
}
static void phy_link_down(struct phy_device *phydev, bool do_carrier)
{
phydev->phy_link_change(phydev, false, do_carrier);
phy_led_trigger_change_speed(phydev); phy_led_trigger_change_speed(phydev);
} }
...@@ -912,8 +918,7 @@ void phy_state_machine(struct work_struct *work) ...@@ -912,8 +918,7 @@ void phy_state_machine(struct work_struct *work)
/* If the link is down, give up on negotiation for now */ /* If the link is down, give up on negotiation for now */
if (!phydev->link) { if (!phydev->link) {
phydev->state = PHY_NOLINK; phydev->state = PHY_NOLINK;
netif_carrier_off(phydev->attached_dev); phy_link_down(phydev, true);
phy_adjust_link(phydev);
break; break;
} }
...@@ -925,9 +930,7 @@ void phy_state_machine(struct work_struct *work) ...@@ -925,9 +930,7 @@ void phy_state_machine(struct work_struct *work)
/* If AN is done, we're running */ /* If AN is done, we're running */
if (err > 0) { if (err > 0) {
phydev->state = PHY_RUNNING; phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev); phy_link_up(phydev);
phy_adjust_link(phydev);
} else if (0 == phydev->link_timeout--) } else if (0 == phydev->link_timeout--)
needs_aneg = true; needs_aneg = true;
break; break;
...@@ -952,8 +955,7 @@ void phy_state_machine(struct work_struct *work) ...@@ -952,8 +955,7 @@ void phy_state_machine(struct work_struct *work)
} }
} }
phydev->state = PHY_RUNNING; phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev); phy_link_up(phydev);
phy_adjust_link(phydev);
} }
break; break;
case PHY_FORCING: case PHY_FORCING:
...@@ -963,13 +965,12 @@ void phy_state_machine(struct work_struct *work) ...@@ -963,13 +965,12 @@ void phy_state_machine(struct work_struct *work)
if (phydev->link) { if (phydev->link) {
phydev->state = PHY_RUNNING; phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev); phy_link_up(phydev);
} else { } else {
if (0 == phydev->link_timeout--) if (0 == phydev->link_timeout--)
needs_aneg = true; needs_aneg = true;
phy_link_down(phydev, false);
} }
phy_adjust_link(phydev);
break; break;
case PHY_RUNNING: case PHY_RUNNING:
/* Only register a CHANGE if we are polling and link changed /* Only register a CHANGE if we are polling and link changed
...@@ -1001,14 +1002,12 @@ void phy_state_machine(struct work_struct *work) ...@@ -1001,14 +1002,12 @@ void phy_state_machine(struct work_struct *work)
if (phydev->link) { if (phydev->link) {
phydev->state = PHY_RUNNING; phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev); phy_link_up(phydev);
} else { } else {
phydev->state = PHY_NOLINK; phydev->state = PHY_NOLINK;
netif_carrier_off(phydev->attached_dev); phy_link_down(phydev, true);
} }
phy_adjust_link(phydev);
if (phy_interrupt_is_valid(phydev)) if (phy_interrupt_is_valid(phydev))
err = phy_config_interrupt(phydev, err = phy_config_interrupt(phydev,
PHY_INTERRUPT_ENABLED); PHY_INTERRUPT_ENABLED);
...@@ -1016,8 +1015,7 @@ void phy_state_machine(struct work_struct *work) ...@@ -1016,8 +1015,7 @@ void phy_state_machine(struct work_struct *work)
case PHY_HALTED: case PHY_HALTED:
if (phydev->link) { if (phydev->link) {
phydev->link = 0; phydev->link = 0;
netif_carrier_off(phydev->attached_dev); phy_link_down(phydev, true);
phy_adjust_link(phydev);
do_suspend = true; do_suspend = true;
} }
break; break;
...@@ -1037,11 +1035,11 @@ void phy_state_machine(struct work_struct *work) ...@@ -1037,11 +1035,11 @@ void phy_state_machine(struct work_struct *work)
if (phydev->link) { if (phydev->link) {
phydev->state = PHY_RUNNING; phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev); phy_link_up(phydev);
} else { } else {
phydev->state = PHY_NOLINK; phydev->state = PHY_NOLINK;
phy_link_down(phydev, false);
} }
phy_adjust_link(phydev);
} else { } else {
phydev->state = PHY_AN; phydev->state = PHY_AN;
phydev->link_timeout = PHY_AN_TIMEOUT; phydev->link_timeout = PHY_AN_TIMEOUT;
...@@ -1053,11 +1051,11 @@ void phy_state_machine(struct work_struct *work) ...@@ -1053,11 +1051,11 @@ void phy_state_machine(struct work_struct *work)
if (phydev->link) { if (phydev->link) {
phydev->state = PHY_RUNNING; phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev); phy_link_up(phydev);
} else { } else {
phydev->state = PHY_NOLINK; phydev->state = PHY_NOLINK;
phy_link_down(phydev, false);
} }
phy_adjust_link(phydev);
} }
break; break;
} }
......
...@@ -688,6 +688,19 @@ struct phy_device *phy_find_first(struct mii_bus *bus) ...@@ -688,6 +688,19 @@ struct phy_device *phy_find_first(struct mii_bus *bus)
} }
EXPORT_SYMBOL(phy_find_first); EXPORT_SYMBOL(phy_find_first);
static void phy_link_change(struct phy_device *phydev, bool up, bool do_carrier)
{
struct net_device *netdev = phydev->attached_dev;
if (do_carrier) {
if (up)
netif_carrier_on(netdev);
else
netif_carrier_off(netdev);
}
phydev->adjust_link(netdev);
}
/** /**
* phy_prepare_link - prepares the PHY layer to monitor link status * phy_prepare_link - prepares the PHY layer to monitor link status
* @phydev: target phy_device struct * @phydev: target phy_device struct
...@@ -951,6 +964,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, ...@@ -951,6 +964,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
goto error; goto error;
} }
phydev->phy_link_change = phy_link_change;
phydev->attached_dev = dev; phydev->attached_dev = dev;
dev->phydev = phydev; dev->phydev = phydev;
......
...@@ -474,6 +474,7 @@ struct phy_device { ...@@ -474,6 +474,7 @@ struct phy_device {
u8 mdix; u8 mdix;
u8 mdix_ctrl; u8 mdix_ctrl;
void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier);
void (*adjust_link)(struct net_device *dev); void (*adjust_link)(struct net_device *dev);
}; };
#define to_phy_device(d) container_of(to_mdio_device(d), \ #define to_phy_device(d) container_of(to_mdio_device(d), \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment