net: phy: add phy_check_link_status

In few places in the state machine the state is set to PHY_RUNNING or
PHY_NOLINK after doing a phy_read_status(). So factor this out to
phy_check_link_status().

First use it in phy_start_aneg(): By setting the state to PHY_RUNNING
or PHY_NOLINK directly we can remove the code to handle the case that
we're using interrupts and aneg was finished already.

Definition of phy_link_up and phy_link_down needs to be moved because
they are called in the new function.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Heiner Kallweit 2018-11-07 20:45:58 +01:00 коммит произвёл David S. Miller
Родитель c96469f830
Коммит 74a992b359
1 изменённых файлов: 40 добавлений и 30 удалений

Просмотреть файл

@ -62,6 +62,17 @@ static const char *phy_state_to_str(enum phy_state st)
return NULL; return NULL;
} }
static void phy_link_up(struct phy_device *phydev)
{
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_print_status - Convenience function to print out the current phy status * phy_print_status - Convenience function to print out the current phy status
@ -493,6 +504,34 @@ static int phy_config_aneg(struct phy_device *phydev)
return genphy_config_aneg(phydev); return genphy_config_aneg(phydev);
} }
/**
* phy_check_link_status - check link status and set state accordingly
* @phydev: the phy_device struct
*
* Description: Check for link and whether autoneg was triggered / is running
* and set state accordingly
*/
static int phy_check_link_status(struct phy_device *phydev)
{
int err;
WARN_ON(!mutex_is_locked(&phydev->lock));
err = phy_read_status(phydev);
if (err)
return err;
if (phydev->link && phydev->state != PHY_RUNNING) {
phydev->state = PHY_RUNNING;
phy_link_up(phydev);
} else if (!phydev->link && phydev->state != PHY_NOLINK) {
phydev->state = PHY_NOLINK;
phy_link_down(phydev, true);
}
return 0;
}
/** /**
* phy_start_aneg - start auto-negotiation for this PHY device * phy_start_aneg - start auto-negotiation for this PHY device
* @phydev: the phy_device struct * @phydev: the phy_device struct
@ -504,7 +543,6 @@ static int phy_config_aneg(struct phy_device *phydev)
*/ */
int phy_start_aneg(struct phy_device *phydev) int phy_start_aneg(struct phy_device *phydev)
{ {
bool trigger = 0;
int err; int err;
if (!phydev->drv) if (!phydev->drv)
@ -524,32 +562,16 @@ int phy_start_aneg(struct phy_device *phydev)
if (phydev->state != PHY_HALTED) { if (phydev->state != PHY_HALTED) {
if (AUTONEG_ENABLE == phydev->autoneg) { if (AUTONEG_ENABLE == phydev->autoneg) {
phydev->state = PHY_AN; err = phy_check_link_status(phydev);
phydev->link_timeout = PHY_AN_TIMEOUT;
} else { } else {
phydev->state = PHY_FORCING; phydev->state = PHY_FORCING;
phydev->link_timeout = PHY_FORCE_TIMEOUT; phydev->link_timeout = PHY_FORCE_TIMEOUT;
} }
} }
/* Re-schedule a PHY state machine to check PHY status because
* negotiation may already be done and aneg interrupt may not be
* generated.
*/
if (!phy_polling_mode(phydev) && phydev->state == PHY_AN) {
err = phy_aneg_done(phydev);
if (err > 0) {
trigger = true;
err = 0;
}
}
out_unlock: out_unlock:
mutex_unlock(&phydev->lock); mutex_unlock(&phydev->lock);
if (trigger)
phy_trigger_machine(phydev);
return err; return err;
} }
EXPORT_SYMBOL(phy_start_aneg); EXPORT_SYMBOL(phy_start_aneg);
@ -893,18 +915,6 @@ void phy_start(struct phy_device *phydev)
} }
EXPORT_SYMBOL(phy_start); EXPORT_SYMBOL(phy_start);
static void phy_link_up(struct phy_device *phydev)
{
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_state_machine - Handle the state machine * phy_state_machine - Handle the state machine
* @work: work_struct that describes the work to be done * @work: work_struct that describes the work to be done