if (up)
netif_carrier_on(netdev); else
netif_carrier_off(netdev);
phydev->adjust_link(netdev); if (phydev->mii_ts && phydev->mii_ts->link_state)
phydev->mii_ts->link_state(phydev->mii_ts, phydev);
}
/** * phy_uses_state_machine - test whether consumer driver uses PAL state machine * @phydev: the target PHY device structure * * Ultimately, this aims to indirectly determine whether the PHY is attached * to a consumer which uses the state machine by calling phy_start() and * phy_stop(). * * When the PHY driver consumer uses phylib, it must have previously called * phy_connect_direct() or one of its derivatives, so that phy_prepare_link() * has set up a hook for monitoring state changes. * * When the PHY driver is used by the MAC driver consumer through phylink (the * only other provider of a phy_link_change() method), using the PHY state * machine is not optional. * * Return: true if consumer calls phy_start() and phy_stop(), false otherwise.
*/ staticbool phy_uses_state_machine(struct phy_device *phydev)
{ if (phydev->phy_link_change == phy_link_change) return phydev->attached_dev && phydev->adjust_link;
/* If the PHY on the mido bus is not attached but has WOL enabled * we cannot suspend the PHY.
*/ if (!netdev && phy_drv_wol_enabled(phydev)) returnfalse;
/* PHY not attached? May suspend if the PHY has not already been * suspended as part of a prior call to phy_disconnect() -> * phy_detach() -> phy_suspend() because the parent netdev might be the * MDIO bus driver and clock gated at this point.
*/ if (!netdev) goto out;
if (netdev->ethtool->wol_enabled) returnfalse;
/* As long as not all affected network drivers support the * wol_enabled flag, let's check for hints that WoL is enabled. * Don't suspend PHY if the attached netdev parent may wake up. * The parent may point to a PCI device, as in tg3 driver.
*/ if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent)) returnfalse;
/* Also don't suspend PHY if the netdev itself may wakeup. This * is the case for devices w/o underlaying pwr. mgmt. aware bus, * e.g. SoC devices.
*/ if (device_may_wakeup(&netdev->dev)) returnfalse;
/* Wakeup interrupts may occur during the system sleep transition when * the PHY is inaccessible. Set flag to postpone handling until the PHY * has resumed. Wait for concurrent interrupt handler to complete.
*/ if (phy_interrupt_is_valid(phydev)) {
phydev->irq_suspended = 1;
synchronize_irq(phydev->irq);
}
/* We must stop the state machine manually, otherwise it stops out of * control, possibly with the phydev->lock held. Upon resume, netdev * may call phy routines that try to grab the same lock, and that may * lead to a deadlock.
*/ if (phy_uses_state_machine(phydev))
phy_stop_machine(phydev);
if (!mdio_bus_phy_may_suspend(phydev)) return 0;
phydev->suspended_by_mdio_bus = 1;
return phy_suspend(phydev);
}
static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
{ struct phy_device *phydev = to_phy_device(dev); int ret;
if (phydev->mac_managed_pm) return 0;
if (!phydev->suspended_by_mdio_bus) goto no_resume;
phydev->suspended_by_mdio_bus = 0;
/* If we managed to get here with the PHY state machine in a state * neither PHY_HALTED, PHY_READY nor PHY_UP, this is an indication * that something went wrong and we should most likely be using * MAC managed PM, but we are not.
*/
WARN_ON(phydev->state != PHY_HALTED && phydev->state != PHY_READY &&
phydev->state != PHY_UP);
ret = phy_init_hw(phydev); if (ret < 0) return ret;
ret = phy_resume(phydev); if (ret < 0) return ret;
no_resume: if (phy_interrupt_is_valid(phydev)) {
phydev->irq_suspended = 0;
synchronize_irq(phydev->irq);
/* Rerun interrupts which were postponed by phy_interrupt() * because they occurred during the system sleep transition.
*/ if (phydev->irq_rerun) {
phydev->irq_rerun = 0;
enable_irq(phydev->irq);
irq_wake_thread(phydev->irq, phydev);
}
}
if (phy_uses_state_machine(phydev))
phy_start_machine(phydev);
/** * phy_register_fixup - creates a new phy_fixup and adds it to the list * @bus_id: A string which matches phydev->mdio.dev.bus_id (or PHY_ANY_ID) * @phy_uid: Used to match against phydev->phy_id (the UID of the PHY) * It can also be PHY_ANY_UID * @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before * comparison * @run: The actual code to be run when a matching PHY is found
*/ staticint phy_register_fixup(constchar *bus_id, u32 phy_uid, u32 phy_uid_mask, int (*run)(struct phy_device *))
{ struct phy_fixup *fixup = kzalloc(sizeof(*fixup), GFP_KERNEL);
/* Registers a fixup to be run on any PHY with the UID in phy_uid */ int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask, int (*run)(struct phy_device *))
{ return phy_register_fixup(PHY_ANY_ID, phy_uid, phy_uid_mask, run);
}
EXPORT_SYMBOL(phy_register_fixup_for_uid);
/* Registers a fixup to be run on the PHY with id string bus_id */ int phy_register_fixup_for_id(constchar *bus_id, int (*run)(struct phy_device *))
{ return phy_register_fixup(bus_id, PHY_ANY_UID, 0xffffffff, run);
}
EXPORT_SYMBOL(phy_register_fixup_for_id);
/** * phy_unregister_fixup - remove a phy_fixup from the list * @bus_id: A string matches fixup->bus_id (or PHY_ANY_ID) in phy_fixup_list * @phy_uid: A phy id matches fixup->phy_id (or PHY_ANY_UID) in phy_fixup_list * @phy_uid_mask: Applied to phy_uid and fixup->phy_uid before comparison
*/ int phy_unregister_fixup(constchar *bus_id, u32 phy_uid, u32 phy_uid_mask)
{ struct list_head *pos, *n; struct phy_fixup *fixup; int ret;
/* Unregisters a fixup of any PHY with the UID in phy_uid */ int phy_unregister_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask)
{ return phy_unregister_fixup(PHY_ANY_ID, phy_uid, phy_uid_mask);
}
EXPORT_SYMBOL(phy_unregister_fixup_for_uid);
/* Unregisters a fixup of the PHY with id string bus_id */ int phy_unregister_fixup_for_id(constchar *bus_id)
{ return phy_unregister_fixup(bus_id, PHY_ANY_UID, 0xffffffff);
}
EXPORT_SYMBOL(phy_unregister_fixup_for_id);
/* Returns 1 if fixup matches phydev in bus_id and phy_uid. * Fixups can be set to match any in one or more fields.
*/ staticint phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
{ if (strcmp(fixup->bus_id, phydev_name(phydev)) != 0) if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0) return 0;
if (!phy_id_compare(phydev->phy_id, fixup->phy_uid,
fixup->phy_uid_mask)) if (fixup->phy_uid != PHY_ANY_UID) return 0;
return 1;
}
/* Runs any matching fixups for this phydev */ staticint phy_scan_fixups(struct phy_device *phydev)
{ struct phy_fixup *fixup;
mutex_lock(&phy_fixup_lock);
list_for_each_entry(fixup, &phy_fixup_list, list) { if (phy_needs_fixup(phydev, fixup)) { int err = fixup->run(phydev);
/** * genphy_match_phy_device - match a PHY device with a PHY driver * @phydev: target phy_device struct * @phydrv: target phy_driver struct * * Description: Checks whether the given PHY device matches the specified * PHY driver. For Clause 45 PHYs, iterates over the available device * identifiers and compares them against the driver's expected PHY ID, * applying the provided mask. For Clause 22 PHYs, a direct ID comparison * is performed. * * Return: 1 if the PHY device matches the driver, 0 otherwise.
*/ int genphy_match_phy_device(struct phy_device *phydev, conststruct phy_driver *phydrv)
{ if (phydev->is_c45) { constint num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids); int i;
for (i = 1; i < num_ids; i++) { if (phydev->c45_ids.device_ids[i] == 0xffffffff) continue;
if (phy_id_compare(phydev->c45_ids.device_ids[i],
phydrv->phy_id, phydrv->phy_id_mask)) return 1;
}
staticint phy_request_driver_module(struct phy_device *dev, u32 phy_id)
{ int ret;
ret = request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT,
MDIO_ID_ARGS(phy_id)); /* We only check for failures in executing the usermode binary, * not whether a PHY driver module exists for the PHY ID. * Accept -ENOENT because this may occur in case no initramfs exists, * then modprobe isn't available.
*/ if (IS_ENABLED(CONFIG_MODULES) && ret < 0 && ret != -ENOENT) {
phydev_err(dev, "error %d loading PHY driver module for ID 0x%08lx\n",
ret, (unsignedlong)phy_id); return ret;
}
return 0;
}
struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id, bool is_c45, struct phy_c45_device_ids *c45_ids)
{ struct phy_device *dev; struct mdio_device *mdiodev; int ret = 0;
/* We allocate the device, and initialize the default values */
dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return ERR_PTR(-ENOMEM);
/* Request the appropriate module unconditionally; don't * bother trying to do so only if it isn't already loaded, * because that gets complicated. A hotplug event would have * done an unconditional modprobe anyway. * We don't do normal hotplug because it won't work for MDIO * -- because it relies on the device staying around for long * enough for the driver to get loaded. With MDIO, the NIC * driver will get bored and give up as soon as it finds that * there's no driver _already_ loaded.
*/ if (is_c45 && c45_ids) { constint num_ids = ARRAY_SIZE(c45_ids->device_ids); int i;
for (i = 1; i < num_ids; i++) { if (c45_ids->device_ids[i] == 0xffffffff) continue;
ret = phy_request_driver_module(dev,
c45_ids->device_ids[i]); if (ret) break;
}
} else {
ret = phy_request_driver_module(dev, phy_id);
}
if (ret) {
put_device(&mdiodev->dev);
dev = ERR_PTR(ret);
}
return dev;
}
EXPORT_SYMBOL(phy_device_create);
/* phy_c45_probe_present - checks to see if a MMD is present in the package * @bus: the target MII bus * @prtad: PHY package address on the MII bus * @devad: PHY device (MMD) address * * Read the MDIO_STAT2 register, and check whether a device is responding * at this address. * * Returns: negative error number on bus access error, zero if no device * is responding, or positive if a device is present.
*/ staticint phy_c45_probe_present(struct mii_bus *bus, int prtad, int devad)
{ int stat2;
/* get_phy_c45_devs_in_pkg - reads a MMD's devices in package registers. * @bus: the target MII bus * @addr: PHY address on the MII bus * @dev_addr: MMD address in the PHY. * @devices_in_package: where to store the devices in package information. * * Description: reads devices in package registers of a MMD at @dev_addr * from PHY at @addr on @bus. * * Returns: 0 on success, -EIO on failure.
*/ staticint get_phy_c45_devs_in_pkg(struct mii_bus *bus, int addr, int dev_addr,
u32 *devices_in_package)
{ int phy_reg;
/** * get_phy_c45_ids - reads the specified addr for its 802.3-c45 IDs. * @bus: the target MII bus * @addr: PHY address on the MII bus * @c45_ids: where to store the c45 ID information. * * Read the PHY "devices in package". If this appears to be valid, read * the PHY identifiers for each device. Return the "devices in package" * and identifiers in @c45_ids. * * Returns zero on success, %-EIO on bus access error, or %-ENODEV if * the "devices in package" is invalid or no device responds.
*/ staticint get_phy_c45_ids(struct mii_bus *bus, int addr, struct phy_c45_device_ids *c45_ids)
{ constint num_ids = ARRAY_SIZE(c45_ids->device_ids);
u32 devs_in_pkg = 0; int i, ret, phy_reg;
/* Find first non-zero Devices In package. Device zero is reserved * for 802.3 c45 complied PHYs, so don't probe it at first.
*/ for (i = 1; i < MDIO_MMD_NUM && (devs_in_pkg == 0 ||
(devs_in_pkg & 0x1fffffff) == 0x1fffffff); i++) { if (i == MDIO_MMD_VEND1 || i == MDIO_MMD_VEND2) { /* Check that there is a device present at this * address before reading the devices-in-package * register to avoid reading garbage from the PHY. * Some PHYs (88x3310) vendor space is not IEEE802.3 * compliant.
*/
ret = phy_c45_probe_present(bus, addr, i); if (ret < 0) /* returning -ENODEV doesn't stop bus * scanning
*/ return (phy_reg == -EIO ||
phy_reg == -ENODEV) ? -ENODEV : -EIO;
if (!ret) continue;
}
phy_reg = get_phy_c45_devs_in_pkg(bus, addr, i, &devs_in_pkg); if (phy_reg < 0) return -EIO;
}
if ((devs_in_pkg & 0x1fffffff) == 0x1fffffff) { /* If mostly Fs, there is no device there, then let's probe * MMD 0, as some 10G PHYs have zero Devices In package, * e.g. Cortina CS4315/CS4340 PHY.
*/
phy_reg = get_phy_c45_devs_in_pkg(bus, addr, 0, &devs_in_pkg); if (phy_reg < 0) return -EIO;
/* no device there, let's get out of here */ if ((devs_in_pkg & 0x1fffffff) == 0x1fffffff) return -ENODEV;
}
/* Now probe Device Identifiers for each device present. */ for (i = 1; i < num_ids; i++) { if (!(devs_in_pkg & (1 << i))) continue;
if (i == MDIO_MMD_VEND1 || i == MDIO_MMD_VEND2) { /* Probe the "Device Present" bits for the vendor MMDs * to ignore these if they do not contain IEEE 802.3 * registers.
*/
ret = phy_c45_probe_present(bus, addr, i); if (ret < 0) return ret;
if (!ret) continue;
}
phy_reg = mdiobus_c45_read(bus, addr, i, MII_PHYSID1); if (phy_reg < 0) return -EIO;
c45_ids->device_ids[i] = phy_reg << 16;
phy_reg = mdiobus_c45_read(bus, addr, i, MII_PHYSID2); if (phy_reg < 0) return -EIO;
c45_ids->device_ids[i] |= phy_reg;
}
c45_ids->devices_in_package = devs_in_pkg; /* Bit 0 doesn't represent a device, it indicates c22 regs presence */
c45_ids->mmds_present = devs_in_pkg & ~BIT(0);
return 0;
}
/** * get_phy_c22_id - reads the specified addr for its clause 22 ID. * @bus: the target MII bus * @addr: PHY address on the MII bus * @phy_id: where to store the ID retrieved. * * Read the 802.3 clause 22 PHY ID from the PHY at @addr on the @bus, * placing it in @phy_id. Return zero on successful read and the ID is * valid, %-EIO on bus access error, or %-ENODEV if no device responds * or invalid ID.
*/ staticint get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id)
{ int phy_reg;
/* Grab the bits from PHYIR1, and put them in the upper half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID1); if (phy_reg < 0) { /* returning -ENODEV doesn't stop bus scanning */ return (phy_reg == -EIO || phy_reg == -ENODEV) ? -ENODEV : -EIO;
}
*phy_id = phy_reg << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID2); if (phy_reg < 0) { /* returning -ENODEV doesn't stop bus scanning */ return (phy_reg == -EIO || phy_reg == -ENODEV) ? -ENODEV : -EIO;
}
*phy_id |= phy_reg;
/* If the phy_id is mostly Fs, there is no device there */ if ((*phy_id & 0x1fffffff) == 0x1fffffff) return -ENODEV;
return 0;
}
/* Extract the phy ID from the compatible string of the form * ethernet-phy-idAAAA.BBBB.
*/ int fwnode_get_phy_id(struct fwnode_handle *fwnode, u32 *phy_id)
{ unsignedint upper, lower; constchar *cp; int ret;
ret = fwnode_property_read_string(fwnode, "compatible", &cp); if (ret) return ret;
if (sscanf(cp, "ethernet-phy-id%4x.%4x", &upper, &lower) != 2) return -EINVAL;
/** * get_phy_device - reads the specified PHY device and returns its @phy_device * struct * @bus: the target MII bus * @addr: PHY address on the MII bus * @is_c45: If true the PHY uses the 802.3 clause 45 protocol * * Probe for a PHY at @addr on @bus. * * When probing for a clause 22 PHY, then read the ID registers. If we find * a valid ID, allocate and return a &struct phy_device. * * When probing for a clause 45 PHY, read the "devices in package" registers. * If the "devices in package" appears valid, read the ID registers for each * MMD, allocate and return a &struct phy_device. * * Returns an allocated &struct phy_device on success, %-ENODEV if there is * no PHY present, or %-EIO on bus access error.
*/ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
{ struct phy_c45_device_ids c45_ids;
u32 phy_id = 0; int r;
if (is_c45)
r = get_phy_c45_ids(bus, addr, &c45_ids); else
r = get_phy_c22_id(bus, addr, &phy_id);
if (r) return ERR_PTR(r);
/* PHY device such as the Marvell Alaska 88E2110 will return a PHY ID * of 0 when probed using get_phy_c22_id() with no error. Proceed to * probe with C45 to see if we're able to get a valid PHY ID in the C45 * space, if successful, create the C45 PHY device.
*/ if (!is_c45 && phy_id == 0 && bus->read_c45) {
r = get_phy_c45_ids(bus, addr, &c45_ids); if (!r) return phy_device_create(bus, addr, phy_id, true, &c45_ids);
}
/** * phy_device_register - Register the phy device on the MDIO bus * @phydev: phy_device structure to be added to the MDIO bus
*/ int phy_device_register(struct phy_device *phydev)
{ int err;
err = mdiobus_register_device(&phydev->mdio); if (err) return err;
/* Deassert the reset signal */
phy_device_reset(phydev, 0);
/* Run all of the fixups for this PHY */
err = phy_scan_fixups(phydev); if (err) {
phydev_err(phydev, "failed to initialize\n"); goto out;
}
err = device_add(&phydev->mdio.dev); if (err) {
phydev_err(phydev, "failed to add\n"); goto out;
}
return 0;
out: /* Assert the reset signal */
phy_device_reset(phydev, 1);
/** * phy_device_remove - Remove a previously registered phy device from the MDIO bus * @phydev: phy_device structure to remove * * This doesn't free the phy_device itself, it merely reverses the effects * of phy_device_register(). Use phy_device_free() to free the device * after calling this function.
*/ void phy_device_remove(struct phy_device *phydev)
{
unregister_mii_timestamper(phydev->mii_ts);
pse_control_put(phydev->psec);
device_del(&phydev->mdio.dev);
/* Assert the reset signal */
phy_device_reset(phydev, 1);
/** * phy_get_c45_ids - Read 802.3-c45 IDs for phy device. * @phydev: phy_device structure to read 802.3-c45 IDs * * Returns zero on success, %-EIO on bus access error, or %-ENODEV if * the "devices in package" is invalid.
*/ int phy_get_c45_ids(struct phy_device *phydev)
{ return get_phy_c45_ids(phydev->mdio.bus, phydev->mdio.addr,
&phydev->c45_ids);
}
EXPORT_SYMBOL(phy_get_c45_ids);
/** * phy_find_first - finds the first PHY device on the bus * @bus: the target MII bus
*/ struct phy_device *phy_find_first(struct mii_bus *bus)
{ struct phy_device *phydev; int addr;
/** * phy_prepare_link - prepares the PHY layer to monitor link status * @phydev: target phy_device struct * @handler: callback function for link status change notifications * * Description: Tells the PHY infrastructure to handle the * gory details on monitoring link status (whether through * polling or an interrupt), and to call back to the * connected device driver when the link status changes. * If you want to monitor your own link state, don't call * this function.
*/ staticvoid phy_prepare_link(struct phy_device *phydev, void (*handler)(struct net_device *))
{
phydev->adjust_link = handler;
}
/** * phy_connect_direct - connect an ethernet device to a specific phy_device * @dev: the network device to connect * @phydev: the pointer to the phy device * @handler: callback function for state change notifications * @interface: PHY device's interface
*/ int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, void (*handler)(struct net_device *),
phy_interface_t interface)
{ int rc;
if (!dev) return -EINVAL;
rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface); if (rc) return rc;
phy_prepare_link(phydev, handler); if (phy_interrupt_is_valid(phydev))
phy_request_interrupt(phydev);
return 0;
}
EXPORT_SYMBOL(phy_connect_direct);
/** * phy_connect - connect an ethernet device to a PHY device * @dev: the network device to connect * @bus_id: the id string of the PHY device to connect * @handler: callback function for state change notifications * @interface: PHY device's interface * * Description: Convenience function for connecting ethernet * devices to PHY devices. The default behavior is for * the PHY infrastructure to handle everything, and only notify * the connected driver when the link status changes. If you * don't want, or can't use the provided functionality, you may * choose to call only the subset of functions which provide * the desired functionality.
*/ struct phy_device *phy_connect(struct net_device *dev, constchar *bus_id, void (*handler)(struct net_device *),
phy_interface_t interface)
{ struct phy_device *phydev; struct device *d; int rc;
/* Search the list of PHY devices on the mdio bus for the * PHY with the requested name
*/
d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id); if (!d) {
pr_err("PHY %s not found\n", bus_id); return ERR_PTR(-ENODEV);
}
phydev = to_phy_device(d);
/** * phy_poll_reset - Safely wait until a PHY reset has properly completed * @phydev: The PHY device to poll * * Description: According to IEEE 802.3, Section 2, Subsection 22.2.4.1.1, as * published in 2008, a PHY reset may take up to 0.5 seconds. The MII BMCR * register must be polled until the BMCR_RESET bit clears. * * Furthermore, any attempts to write to PHY registers may have no effect * or even generate MDIO bus errors until this is complete. * * Some PHYs (such as the Marvell 88E1111) don't entirely conform to the * standard and do not fully reset after the BMCR_RESET bit is set, and may * even *REQUIRE* a soft-reset to properly restart autonegotiation. In an * effort to support such broken PHYs, this function is separate from the * standard phy_init_hw() which will zero all the other bits in the BMCR * and reapply all driver-specific and board-specific fixups.
*/ staticint phy_poll_reset(struct phy_device *phydev)
{ /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ int ret, val;
ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
50000, 600000, true); if (ret) return ret; /* Some chips (smsc911x) may still need up to another 1ms after the * BMCR_RESET bit is cleared before they are usable.
*/
msleep(1); return 0;
}
int phy_init_hw(struct phy_device *phydev)
{ int ret = 0;
/* Deassert the reset signal */
phy_device_reset(phydev, 0);
if (!phydev->drv) return 0;
if (phydev->drv->soft_reset) {
ret = phydev->drv->soft_reset(phydev); if (ret < 0) return ret;
/* see comment in genphy_soft_reset for an explanation */
phydev->suspended = 0;
}
ret = phy_scan_fixups(phydev); if (ret < 0) return ret;
phy_interface_zero(phydev->possible_interfaces);
if (phydev->drv->config_init) {
ret = phydev->drv->config_init(phydev); if (ret < 0) return ret;
}
if (phydev->drv->config_intr) {
ret = phydev->drv->config_intr(phydev); if (ret < 0) return ret;
}
err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj, "attached_dev"); if (err) return;
err = sysfs_create_link_nowarn(&dev->dev.kobj,
&phydev->mdio.dev.kobj, "phydev"); if (err) {
dev_err(&dev->dev, "could not add device link to %s err %d\n",
kobject_name(&phydev->mdio.dev.kobj),
err); /* non-fatal - some net drivers can use one netdevice * with more then one phy
*/
}
/** * phy_sfp_connect_phy - Connect the SFP module's PHY to the upstream PHY * @upstream: pointer to the upstream phy device * @phy: pointer to the SFP module's phy device * * This helper allows keeping track of PHY devices on the link. It adds the * SFP module's phy to the phy namespace of the upstream phy * * Return: 0 on success, otherwise a negative error code.
*/ int phy_sfp_connect_phy(void *upstream, struct phy_device *phy)
{ struct phy_device *phydev = upstream; struct net_device *dev = phydev->attached_dev;
if (dev) return phy_link_topo_add_phy(dev, phy, PHY_UPSTREAM_PHY, phydev);
return 0;
}
EXPORT_SYMBOL(phy_sfp_connect_phy);
/** * phy_sfp_disconnect_phy - Disconnect the SFP module's PHY from the upstream PHY * @upstream: pointer to the upstream phy device * @phy: pointer to the SFP module's phy device * * This helper allows keeping track of PHY devices on the link. It removes the * SFP module's phy to the phy namespace of the upstream phy. As the module phy * will be destroyed, re-inserting the same module will add a new phy with a * new index.
*/ void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy)
{ struct phy_device *phydev = upstream; struct net_device *dev = phydev->attached_dev;
if (dev)
phy_link_topo_del_phy(dev, phy);
}
EXPORT_SYMBOL(phy_sfp_disconnect_phy);
/** * phy_sfp_attach - attach the SFP bus to the PHY upstream network device * @upstream: pointer to the phy device * @bus: sfp bus representing cage being attached * * This is used to fill in the sfp_upstream_ops .attach member.
*/ void phy_sfp_attach(void *upstream, struct sfp_bus *bus)
{ struct phy_device *phydev = upstream;
if (phydev->attached_dev)
phydev->attached_dev->sfp_bus = bus;
phydev->sfp_bus_attached = true;
}
EXPORT_SYMBOL(phy_sfp_attach);
/** * phy_sfp_detach - detach the SFP bus from the PHY upstream network device * @upstream: pointer to the phy device * @bus: sfp bus representing cage being attached * * This is used to fill in the sfp_upstream_ops .detach member.
*/ void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
{ struct phy_device *phydev = upstream;
if (phydev->attached_dev)
phydev->attached_dev->sfp_bus = NULL;
phydev->sfp_bus_attached = false;
}
EXPORT_SYMBOL(phy_sfp_detach);
/** * phy_sfp_probe - probe for a SFP cage attached to this PHY device * @phydev: Pointer to phy_device * @ops: SFP's upstream operations
*/ int phy_sfp_probe(struct phy_device *phydev, conststruct sfp_upstream_ops *ops)
{ struct sfp_bus *bus; int ret = 0;
if (phydev->mdio.dev.fwnode) {
bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode); if (IS_ERR(bus)) return PTR_ERR(bus);
/** * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach * @phydev: Pointer to phy_device to attach * @flags: PHY device's dev_flags * @interface: PHY device's interface * * Description: Called by drivers to attach to a particular PHY * device. The phy_device is found, and properly hooked up * to the phy_driver. If no driver is attached, then a * generic driver is used. The phy_device is given a ptr to * the attaching device, and given a callback for link status * change. The phy_device is returned to the attaching driver. * This function takes a reference on the phy device.
*/ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{ struct mii_bus *bus = phydev->mdio.bus; struct device *d = &phydev->mdio.dev; struct module *ndev_owner = NULL; int err;
/* For Ethernet device drivers that register their own MDIO bus, we * will have bus->owner match ndev_mod, so we do not want to increment * our own module->refcnt here, otherwise we would not be able to * unload later on.
*/ if (dev)
ndev_owner = dev->dev.parent->driver->owner; if (ndev_owner != bus->owner && !try_module_get(bus->owner)) {
phydev_err(phydev, "failed to get the bus module\n"); return -EIO;
}
get_device(d);
/* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver.
*/ if (!d->driver) { if (phydev->is_c45)
d->driver = &genphy_c45_driver.mdiodrv.driver; else
d->driver = &genphy_driver.mdiodrv.driver;
phydev->is_genphy_driven = 1;
}
if (!try_module_get(d->driver->owner)) {
phydev_err(phydev, "failed to get the device driver module\n");
err = -EIO; goto error_put_device;
}
if (phydev->is_genphy_driven) {
err = d->driver->probe(d); if (err >= 0)
err = device_bind_driver(d);
/* Some Ethernet drivers try to connect to a PHY device before * calling register_netdevice() -> netdev_register_kobject() and * does the dev->dev.kobj initialization. Here we only check for * success which indicates that the network device kobject is * ready. Once we do that we still need to keep track of whether * links were successfully set up or not for phy_detach() to * remove them accordingly.
*/
phydev->sysfs_links = false;
phy_sysfs_create_links(phydev);
if (!phydev->attached_dev) {
err = sysfs_create_file(&phydev->mdio.dev.kobj,
&dev_attr_phy_standalone.attr); if (err)
phydev_err(phydev, "error creating 'phy_standalone' sysfs entry\n");
}
phydev->dev_flags |= flags;
phydev->interface = interface;
phydev->state = PHY_READY;
phydev->interrupts = PHY_INTERRUPT_DISABLED;
/* PHYs can request to use poll mode even though they have an * associated interrupt line. This could be the case if they * detect a broken interrupt handling.
*/ if (phydev->dev_flags & PHY_F_NO_IRQ)
phydev->irq = PHY_POLL;
if (!phy_drv_supports_irq(phydev->drv) && phy_interrupt_is_valid(phydev))
phydev->irq = PHY_POLL;
/* Port is set to PORT_TP by default and the actual PHY driver will set * it to different value depending on the PHY configuration. If we have * the generic PHY driver we can't figure it out, thus set the old * legacy PORT_MII value.
*/ if (phydev->is_genphy_driven)
phydev->port = PORT_MII;
/* Initial carrier state is off as the phy is about to be * (re)initialized.
*/ if (dev)
netif_carrier_off(phydev->attached_dev);
/* Do initial configuration here, now that * we have certain key parameters * (dev_flags and interface)
*/
err = phy_init_hw(phydev); if (err) goto error;
phy_resume(phydev); if (!phydev->is_on_sfp_module)
phy_led_triggers_register(phydev);
/** * If the external phy used by current mac interface is managed by * another mac interface, so we should create a device link between * phy dev and mac dev.
*/ if (dev && phydev->mdio.bus->parent && dev->dev.parent != phydev->mdio.bus->parent)
phydev->devlink = device_link_add(dev->dev.parent, &phydev->mdio.dev,
DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
return err;
error: /* phy_detach() does all of the cleanup below */
phy_detach(phydev); return err;
/** * phy_attach - attach a network device to a particular PHY device * @dev: network device to attach * @bus_id: Bus ID of PHY device to attach * @interface: PHY device's interface * * Description: Same as phy_attach_direct() except that a PHY bus_id * string is passed instead of a pointer to a struct phy_device.
*/ struct phy_device *phy_attach(struct net_device *dev, constchar *bus_id,
phy_interface_t interface)
{ struct phy_device *phydev; struct device *d; int rc;
if (!dev) return ERR_PTR(-EINVAL);
/* Search the list of PHY devices on the mdio bus for the * PHY with the requested name
*/
d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id); if (!d) {
pr_err("PHY %s not found\n", bus_id); return ERR_PTR(-ENODEV);
}
phydev = to_phy_device(d);
/** * phy_detach - detach a PHY device from its network device * @phydev: target phy_device struct * * This detaches the phy device from its network device and the phy * driver, and drops the reference count taken in phy_attach_direct().
*/ void phy_detach(struct phy_device *phydev)
{ struct net_device *dev = phydev->attached_dev; struct module *ndev_owner = NULL; struct mii_bus *bus;
if (phydev->devlink) {
device_link_del(phydev->devlink);
phydev->devlink = NULL;
}
if (phydev->sysfs_links) { if (dev)
sysfs_remove_link(&dev->dev.kobj, "phydev");
sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev");
}
if (!phydev->attached_dev)
sysfs_remove_file(&phydev->mdio.dev.kobj,
&dev_attr_phy_standalone.attr);
phy_suspend(phydev); if (dev) { struct hwtstamp_provider *hwprov;
hwprov = rtnl_dereference(dev->hwprov); /* Disable timestamp if it is the one selected */ if (hwprov && hwprov->phydev == phydev) {
rcu_assign_pointer(dev->hwprov, NULL);
kfree_rcu(hwprov, rcu_head);
}
if (!phydev->is_on_sfp_module)
phy_led_triggers_unregister(phydev);
if (phydev->mdio.dev.driver)
module_put(phydev->mdio.dev.driver->owner);
/* If the device had no specific driver before (i.e. - it * was using the generic driver), we unbind the device * from the generic driver so that there's a chance a * real driver could be loaded
*/ if (phydev->is_genphy_driven) {
device_release_driver(&phydev->mdio.dev);
phydev->is_genphy_driven = 0;
}
/* Assert the reset signal */
phy_device_reset(phydev, 1);
/* * The phydev might go away on the put_device() below, so avoid * a use-after-free bug by reading the underlying bus first.
*/
bus = phydev->mdio.bus;
put_device(&phydev->mdio.dev); if (dev)
ndev_owner = dev->dev.parent->driver->owner; if (ndev_owner != bus->owner)
module_put(bus->owner);
}
EXPORT_SYMBOL(phy_detach);
int phy_suspend(struct phy_device *phydev)
{ struct net_device *netdev = phydev->attached_dev; conststruct phy_driver *phydrv = phydev->drv; int ret;
if (phydev->suspended || !phydrv) return 0;
phydev->wol_enabled = phy_drv_wol_enabled(phydev) ||
(netdev && netdev->ethtool->wol_enabled); /* If the device has WOL enabled, we cannot suspend the PHY */ if (phydev->wol_enabled && !(phydrv->flags & PHY_ALWAYS_CALL_SUSPEND)) return -EBUSY;
if (!phydrv->suspend) return 0;
ret = phydrv->suspend(phydev); if (!ret)
phydev->suspended = true;
return ret;
}
EXPORT_SYMBOL(phy_suspend);
int __phy_resume(struct phy_device *phydev)
{ conststruct phy_driver *phydrv = phydev->drv; int ret;
lockdep_assert_held(&phydev->lock);
if (!phydrv || !phydrv->resume) return 0;
ret = phydrv->resume(phydev); if (!ret)
phydev->suspended = false;
return ret;
}
EXPORT_SYMBOL(__phy_resume);
int phy_resume(struct phy_device *phydev)
{ int ret;
mutex_lock(&phydev->lock);
ret = __phy_resume(phydev);
mutex_unlock(&phydev->lock);
return ret;
}
EXPORT_SYMBOL(phy_resume);
/** * phy_reset_after_clk_enable - perform a PHY reset if needed * @phydev: target phy_device struct * * Description: Some PHYs are known to need a reset after their refclk was * enabled. This function evaluates the flags and perform the reset if it's * needed. Returns < 0 on error, 0 if the phy wasn't reset and 1 if the phy * was reset.
*/ int phy_reset_after_clk_enable(struct phy_device *phydev)
{ if (!phydev || !phydev->drv) return -ENODEV;
/** * genphy_config_advert - sanitize and advertise auto-negotiation parameters * @phydev: target phy_device struct * @advert: auto-negotiation parameters to advertise * * Description: Writes MII_ADVERTISE with the appropriate values, * after sanitizing the values to make sure we only advertise * what is supported. Returns < 0 on error, 0 if the PHY's advertisement * hasn't changed, and > 0 if it has changed.
*/ staticint genphy_config_advert(struct phy_device *phydev, constunsignedlong *advert)
{ int err, bmsr, changed = 0;
u32 adv;
adv = linkmode_adv_to_mii_adv_t(advert);
/* Setup standard advertisement */
err = phy_modify_changed(phydev, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_100BASE4 |
ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
adv); if (err < 0) return err; if (err > 0)
changed = 1;
bmsr = phy_read(phydev, MII_BMSR); if (bmsr < 0) return bmsr;
/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a * logical 1.
*/ if (!(bmsr & BMSR_ESTATEN)) return changed;
/** * genphy_c37_config_advert - sanitize and advertise auto-negotiation parameters * @phydev: target phy_device struct * * Description: Writes MII_ADVERTISE with the appropriate values, * after sanitizing the values to make sure we only advertise * what is supported. Returns < 0 on error, 0 if the PHY's advertisement * hasn't changed, and > 0 if it has changed. This function is intended * for Clause 37 1000Base-X mode.
*/ staticint genphy_c37_config_advert(struct phy_device *phydev)
{
u16 adv = 0;
/* Only allow advertising what this PHY supports */
linkmode_and(phydev->advertising, phydev->advertising,
phydev->supported);
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
phydev->advertising))
adv |= ADVERTISE_1000XFULL; if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
phydev->advertising))
adv |= ADVERTISE_1000XPAUSE; if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
phydev->advertising))
adv |= ADVERTISE_1000XPSE_ASYM;
/** * genphy_setup_forced - configures/forces speed/duplex from @phydev * @phydev: target phy_device struct * * Description: Configures MII_BMCR to force speed/duplex * to the values in phydev. Assumes that the values are valid. * Please see phy_sanitize_settings().
*/ int genphy_setup_forced(struct phy_device *phydev)
{
u16 ctl;
val = phy_read(phydev, MII_STAT1000); if (val < 0) return val;
if (val & LPA_1000MSFAIL) {
state = MASTER_SLAVE_STATE_ERR;
} elseif (phydev->link) { /* this bits are valid only for active link */ if (val & LPA_1000MSRES)
state = MASTER_SLAVE_STATE_MASTER; else
state = MASTER_SLAVE_STATE_SLAVE;
} else {
state = MASTER_SLAVE_STATE_UNKNOWN;
}
/** * genphy_restart_aneg - Enable and Restart Autonegotiation * @phydev: target phy_device struct
*/ int genphy_restart_aneg(struct phy_device *phydev)
{ /* Don't isolate the PHY if we're negotiating */ return phy_modify(phydev, MII_BMCR, BMCR_ISOLATE,
BMCR_ANENABLE | BMCR_ANRESTART);
}
EXPORT_SYMBOL(genphy_restart_aneg);
/** * genphy_check_and_restart_aneg - Enable and restart auto-negotiation * @phydev: target phy_device struct * @restart: whether aneg restart is requested * * Check, and restart auto-negotiation if needed.
*/ int genphy_check_and_restart_aneg(struct phy_device *phydev, bool restart)
{ int ret;
if (!restart) { /* Advertisement hasn't changed, but maybe aneg was never on to * begin with? Or maybe phy was isolated?
*/
ret = phy_read(phydev, MII_BMCR); if (ret < 0) return ret;
/** * __genphy_config_aneg - restart auto-negotiation or write BMCR * @phydev: target phy_device struct * @changed: whether autoneg is requested * * Description: If auto-negotiation is enabled, we configure the * advertising, and then restart auto-negotiation. If it is not * enabled, then we write the BMCR.
*/ int __genphy_config_aneg(struct phy_device *phydev, bool changed)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(fixed_advert); conststruct link_capabilities *c; unsignedlong *advert; int err;
/** * genphy_c37_config_aneg - restart auto-negotiation or write BMCR * @phydev: target phy_device struct * * Description: If auto-negotiation is enabled, we configure the * advertising, and then restart auto-negotiation. If it is not * enabled, then we write the BMCR. This function is intended * for use with Clause 37 1000Base-X mode.
*/ int genphy_c37_config_aneg(struct phy_device *phydev)
{ int err, changed;
if (phydev->autoneg != AUTONEG_ENABLE) return genphy_setup_forced(phydev);
if (!changed) { /* Advertisement hasn't changed, but maybe aneg was never on to * begin with? Or maybe phy was isolated?
*/ int ctl = phy_read(phydev, MII_BMCR);
if (ctl < 0) return ctl;
if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
changed = 1; /* do restart aneg */
}
/* Only restart aneg if we are advertising something different * than we were before.
*/ if (changed > 0) return genphy_restart_aneg(phydev);
/** * 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);
/** * genphy_update_link - update link status in @phydev * @phydev: target phy_device struct * * Description: Update the value in phydev->link to reflect the * current link value. In order to do this, we need to read * the status register twice, keeping the second value.
*/ int genphy_update_link(struct phy_device *phydev)
{ int status = 0, bmcr;
bmcr = phy_read(phydev, MII_BMCR); if (bmcr < 0) return bmcr;
/* Autoneg is being started, therefore disregard BMSR value and * report link as down.
*/ if (bmcr & BMCR_ANRESTART) goto done;
/* The link state is latched low so that momentary link * drops can be detected. Do not double-read the status * in polling mode to detect such short link drops except * the link was already down.
*/ if (!phy_polling_mode(phydev) || !phydev->link) {
status = phy_read(phydev, MII_BMSR); if (status < 0) return status; elseif (status & BMSR_LSTATUS) goto done;
}
/* Read link and autonegotiation status */
status = phy_read(phydev, MII_BMSR); if (status < 0) return status;
done:
phydev->link = status & BMSR_LSTATUS ? 1 : 0;
phydev->autoneg_complete = status & BMSR_ANEGCOMPLETE ? 1 : 0;
/* Consider the case that autoneg was started and "aneg complete" * bit has been reset, but "link up" bit not yet.
*/ if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete)
phydev->link = 0;
return 0;
}
EXPORT_SYMBOL(genphy_update_link);
int genphy_read_lpa(struct phy_device *phydev)
{ int lpa, lpagb;
if (phydev->autoneg == AUTONEG_ENABLE) { if (!phydev->autoneg_complete) {
mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
0);
mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, 0); return 0;
}
if (phydev->is_gigabit_capable) {
lpagb = phy_read(phydev, MII_STAT1000); if (lpagb < 0) return lpagb;
if (lpagb & LPA_1000MSFAIL) { int adv = phy_read(phydev, MII_CTRL1000);
if (adv < 0) return adv;
if (adv & CTL1000_ENABLE_MASTER)
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.