Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+20 −22
Original line number Diff line number Diff line
@@ -865,9 +865,15 @@ void phy_start(struct phy_device *phydev)
}
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);
}

@@ -912,8 +918,7 @@ void phy_state_machine(struct work_struct *work)
		/* If the link is down, give up on negotiation for now */
		if (!phydev->link) {
			phydev->state = PHY_NOLINK;
			netif_carrier_off(phydev->attached_dev);
			phy_adjust_link(phydev);
			phy_link_down(phydev, true);
			break;
		}

@@ -925,9 +930,7 @@ void phy_state_machine(struct work_struct *work)
		/* If AN is done, we're running */
		if (err > 0) {
			phydev->state = PHY_RUNNING;
			netif_carrier_on(phydev->attached_dev);
			phy_adjust_link(phydev);

			phy_link_up(phydev);
		} else if (0 == phydev->link_timeout--)
			needs_aneg = true;
		break;
@@ -952,8 +955,7 @@ void phy_state_machine(struct work_struct *work)
				}
			}
			phydev->state = PHY_RUNNING;
			netif_carrier_on(phydev->attached_dev);
			phy_adjust_link(phydev);
			phy_link_up(phydev);
		}
		break;
	case PHY_FORCING:
@@ -963,13 +965,12 @@ void phy_state_machine(struct work_struct *work)

		if (phydev->link) {
			phydev->state = PHY_RUNNING;
			netif_carrier_on(phydev->attached_dev);
			phy_link_up(phydev);
		} else {
			if (0 == phydev->link_timeout--)
				needs_aneg = true;
			phy_link_down(phydev, false);
		}

		phy_adjust_link(phydev);
		break;
	case PHY_RUNNING:
		/* Only register a CHANGE if we are polling and link changed
@@ -1001,14 +1002,12 @@ void phy_state_machine(struct work_struct *work)

		if (phydev->link) {
			phydev->state = PHY_RUNNING;
			netif_carrier_on(phydev->attached_dev);
			phy_link_up(phydev);
		} else {
			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))
			err = phy_config_interrupt(phydev,
						   PHY_INTERRUPT_ENABLED);
@@ -1016,8 +1015,7 @@ void phy_state_machine(struct work_struct *work)
	case PHY_HALTED:
		if (phydev->link) {
			phydev->link = 0;
			netif_carrier_off(phydev->attached_dev);
			phy_adjust_link(phydev);
			phy_link_down(phydev, true);
			do_suspend = true;
		}
		break;
@@ -1037,11 +1035,11 @@ void phy_state_machine(struct work_struct *work)

				if (phydev->link) {
					phydev->state = PHY_RUNNING;
					netif_carrier_on(phydev->attached_dev);
					phy_link_up(phydev);
				} else	{
					phydev->state = PHY_NOLINK;
					phy_link_down(phydev, false);
				}
				phy_adjust_link(phydev);
			} else {
				phydev->state = PHY_AN;
				phydev->link_timeout = PHY_AN_TIMEOUT;
@@ -1053,11 +1051,11 @@ void phy_state_machine(struct work_struct *work)

			if (phydev->link) {
				phydev->state = PHY_RUNNING;
				netif_carrier_on(phydev->attached_dev);
				phy_link_up(phydev);
			} else	{
				phydev->state = PHY_NOLINK;
				phy_link_down(phydev, false);
			}
			phy_adjust_link(phydev);
		}
		break;
	}
+14 −0
Original line number Diff line number Diff line
@@ -688,6 +688,19 @@ struct phy_device *phy_find_first(struct mii_bus *bus)
}
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
 * @phydev: target phy_device struct
@@ -951,6 +964,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
		goto error;
	}

	phydev->phy_link_change = phy_link_change;
	phydev->attached_dev = dev;
	dev->phydev = phydev;

+1 −0
Original line number Diff line number Diff line
@@ -474,6 +474,7 @@ struct phy_device {
	u8 mdix;
	u8 mdix_ctrl;

	void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier);
	void (*adjust_link)(struct net_device *dev);
};
#define to_phy_device(d) container_of(to_mdio_device(d), \