/* If the PHY on the mido bus is not attached but has WOL enabled *wecannotsuspendthePHY.
*/ if (!netdev && phy_drv_wol_enabled(phydev)) returnfalse;
/* PHY not attached? May suspend if the PHY has not already been *suspendedaspartofapriorcalltophy_disconnect()-> *phy_detach()->phy_suspend()becausetheparentnetdevmightbethe *MDIObusdriverandclockgatedatthispoint.
*/ if (!netdev) goto out;
if (netdev->ethtool->wol_enabled) returnfalse;
/* As long as not all affected network drivers support the *wol_enabledflag,let'scheckforhintsthatWoLisenabled. *Don'tsuspendPHYiftheattachednetdevparentmaywakeup. *TheparentmaypointtoaPCIdevice,asintg3driver.
*/ if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent)) returnfalse;
/* Also don't suspend PHY if the netdev itself may wakeup. This *isthecasefordevicesw/ounderlayingpwr.mgmt.awarebus, *e.g.SoCdevices.
*/ if (device_may_wakeup(&netdev->dev)) returnfalse;
/* Wakeup interrupts may occur during the system sleep transition when *thePHYisinaccessible.SetflagtopostponehandlinguntilthePHY *hasresumed.Waitforconcurrentinterrupthandlertocomplete.
*/ 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,possiblywiththephydev->lockheld.Uponresume,netdev *maycallphyroutinesthattrytograbthesamelock,andthatmay *leadtoadeadlock.
*/ if (phy_uses_state_machine(phydev))
phy_stop_machine(phydev);
if (!mdio_bus_phy_may_suspend(phydev)) return0;
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) return0;
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 *neitherPHY_HALTED,PHY_READYnorPHY_UP,thisisanindication *thatsomethingwentwrongandweshouldmostlikelybeusing *MACmanagedPM,butwearenot.
*/
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() *becausetheyoccurredduringthesystemsleeptransition.
*/ 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);
/* 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);
/* 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. *Fixupscanbesettomatchanyinoneormorefields.
*/ 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) return0;
if (!phy_id_compare(phydev->phy_id, fixup->phy_uid,
fixup->phy_uid_mask)) if (fixup->phy_uid != PHY_ANY_UID) return0;
return1;
}
/* 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);
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, *notwhetheraPHYdrivermoduleexistsforthePHYID. *Accept-ENOENTbecausethismayoccurincasenoinitramfsexists, *thenmodprobeisn'tavailable.
*/ 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;
}
return0;
}
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 *bothertryingtodosoonlyifitisn'talreadyloaded, *becausethatgetscomplicated.Ahotplugeventwouldhave *doneanunconditionalmodprobeanyway. *Wedon'tdonormalhotplugbecauseitwon'tworkforMDIO *--becauseitreliesonthedevicestayingaroundforlong *enoughforthedrivertogetloaded.WithMDIO,theNIC *driverwillgetboredandgiveupassoonasitfindsthat *there'snodriver_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:thetargetMIIbus *@prtad:PHYpackageaddressontheMIIbus *@devad:PHYdevice(MMD)address * *ReadtheMDIO_STAT2register,andcheckwhetheradeviceisresponding *atthisaddress. * *Returns:negativeerrornumberonbusaccesserror,zeroifnodevice *isresponding,orpositiveifadeviceispresent.
*/ staticint phy_c45_probe_present(struct mii_bus *bus, int prtad, int devad)
{ int stat2;
/* Find first non-zero Devices In package. Device zero is reserved *for802.3c45compliedPHYs,sodon'tprobeitatfirst.
*/ 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 *addressbeforereadingthedevices-in-package *registertoavoidreadinggarbagefromthePHY. *SomePHYs(88x3310)vendorspaceisnotIEEE802.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 *MMD0,assome10GPHYshavezeroDevicesInpackage, *e.g.CortinaCS4315/CS4340PHY.
*/
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 *toignoretheseiftheydonotcontainIEEE802.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);
/* 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;
return0;
}
/* 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;
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 *of0whenprobedusingget_phy_c22_id()withnoerror.Proceedto *probewithC45toseeifwe'reabletogetavalidPHYIDintheC45 *space,ifsuccessful,createtheC45PHYdevice.
*/ 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);
}
/* Search the list of PHY devices on the mdio bus for the *PHYwiththerequestedname
*/
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-SafelywaituntilaPHYresethasproperlycompleted *@phydev:ThePHYdevicetopoll * *Description:AccordingtoIEEE802.3,Section2,Subsection22.2.4.1.1,as *publishedin2008,aPHYresetmaytakeupto0.5seconds.TheMIIBMCR *registermustbepolleduntiltheBMCR_RESETbitclears. * *Furthermore,anyattemptstowritetoPHYregistersmayhavenoeffect *orevengenerateMDIObuserrorsuntilthisiscomplete. * *SomePHYs(suchastheMarvell88E1111)don'tentirelyconformtothe *standardanddonotfullyresetaftertheBMCR_RESETbitisset,andmay *even*REQUIRE*asoft-resettoproperlyrestartautonegotiation.Inan *efforttosupportsuchbrokenPHYs,thisfunctionisseparatefromthe *standardphy_init_hw()whichwillzeroalltheotherbitsintheBMCR *andreapplyalldriver-specificandboard-specificfixups.
*/ 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_RESETbitisclearedbeforetheyareusable.
*/
msleep(1); return0;
}
int phy_init_hw(struct phy_device *phydev)
{ int ret = 0;
/* Deassert the reset signal */
phy_device_reset(phydev, 0);
if (!phydev->drv) return0;
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 *withmorethenonephy
*/
}
/* For Ethernet device drivers that register their own MDIO bus, we *willhavebus->ownermatchndev_mod,sowedonotwanttoincrement *ourownmodule->refcnthere,otherwisewewouldnotbeableto *unloadlateron.
*/ 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,andweshouldusethegenphydriver.
*/ 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 *callingregister_netdevice()->netdev_register_kobject()and *doesthedev->dev.kobjinitialization.Hereweonlycheckfor *successwhichindicatesthatthenetworkdevicekobjectis *ready.Oncewedothatwestillneedtokeeptrackofwhether *linksweresuccessfullysetupornotforphy_detach()to *removethemaccordingly.
*/
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 *associatedinterruptline.Thiscouldbethecaseifthey *detectabrokeninterrupthandling.
*/ 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 *ittodifferentvaluedependingonthePHYconfiguration.Ifwehave *thegenericPHYdriverwecan'tfigureitout,thussettheold *legacyPORT_MIIvalue.
*/ 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 *wehavecertainkeyparameters *(dev_flagsandinterface)
*/
err = phy_init_hw(phydev); if (err) goto error;
phy_resume(phydev); if (!phydev->is_on_sfp_module)
phy_led_triggers_register(phydev);
/* Search the list of PHY devices on the mdio bus for the *PHYwiththerequestedname
*/
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);
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 *wasusingthegenericdriver),weunbindthedevice *fromthegenericdriversothatthere'sachancea *realdrivercouldbeloaded
*/ 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);
/* *Thephydevmightgoawayontheput_device()below,soavoid *ause-after-freebugbyreadingtheunderlyingbusfirst.
*/
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) return0;
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) return0;
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) return0;
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-performaPHYresetifneeded *@phydev:targetphy_devicestruct * *Description:SomePHYsareknowntoneedaresetaftertheirrefclkwas *enabled.Thisfunctionevaluatestheflagsandperformtheresetifit's *needed.Returns<0onerror,0ifthephywasn'tresetand1ifthephy *wasreset.
*/ int phy_reset_after_clk_enable(struct phy_device *phydev)
{ if (!phydev || !phydev->drv) return -ENODEV;
/* 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/seccapablePHYsshallhavetheBMSR_ESTATENbitsettoa *logical1.
*/ if (!(bmsr & BMSR_ESTATEN)) return changed;
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-EnableandRestartAutonegotiation *@phydev:targetphy_devicestruct
*/ 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-Enableandrestartauto-negotiation *@phydev:targetphy_devicestruct *@restart:whetheranegrestartisrequested * *Check,andrestartauto-negotiationifneeded.
*/ 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 *beginwith?Ormaybephywasisolated?
*/
ret = phy_read(phydev, MII_BMCR); if (ret < 0) return ret;
if (!changed) { /* Advertisement hasn't changed, but maybe aneg was never on to *beginwith?Ormaybephywasisolated?
*/ 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 *thanwewerebefore.
*/ if (changed > 0) return genphy_restart_aneg(phydev);
return0;
}
EXPORT_SYMBOL(genphy_c37_config_aneg);
/** *genphy_aneg_done-returnauto-negotiationstatus *@phydev:targetphy_devicestruct * *Description:Readsthestatusregisterandreturns0eitherif *auto-negotiationisincomplete,oriftherewasanerror. *ReturnsBMSR_ANEGCOMPLETEifauto-negotiationisdone.
*/ int genphy_aneg_done(struct phy_device *phydev)
{ int retval = phy_read(phydev, MII_BMSR);
/** *genphy_update_link-updatelinkstatusin@phydev *@phydev:targetphy_devicestruct * *Description:Updatethevalueinphydev->linktoreflectthe *currentlinkvalue.Inordertodothis,weneedtoread *thestatusregistertwice,keepingthesecondvalue.
*/ 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 *reportlinkasdown.
*/ if (bmcr & BMCR_ANRESTART) goto done;
/* The link state is latched low so that momentary link *dropscanbedetected.Donotdouble-readthestatus *inpollingmodetodetectsuchshortlinkdropsexcept *thelinkwasalreadydown.
*/ 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" *bithasbeenreset,but"linkup"bitnotyet.
*/ if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete)
phydev->link = 0;
return0;
}
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); return0;
}
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);
/** *genphy_soft_reset-softwareresetthePHYviaBMCR_RESETbit *@phydev:targetphy_devicestruct * *Description:PerformasoftwarePHYresetusingthestandard *BMCR_RESETbitandpollfortheresetbittobecleared. * *Returns:0onsuccess,<0onfailure
*/ int genphy_soft_reset(struct phy_device *phydev)
{
u16 res = BMCR_RESET; int ret;
if (phydev->autoneg == AUTONEG_ENABLE)
res |= BMCR_ANRESTART;
ret = phy_modify(phydev, MII_BMCR, BMCR_ISOLATE, res); if (ret < 0) return ret;
/* Clause 22 states that setting bit BMCR_RESET sets control registers *totheirdefaultvalue.ThereforethePOWERDOWNbitissupposedto *beclearedaftersoftreset.
*/
phydev->suspended = 0;
ret = phy_poll_reset(phydev); if (ret) return ret;
/* BMCR may be reset to defaults */ if (phydev->autoneg == AUTONEG_DISABLE)
ret = genphy_setup_forced(phydev);
return ret;
}
EXPORT_SYMBOL(genphy_soft_reset);
irqreturn_t genphy_handle_interrupt_no_ack(struct phy_device *phydev)
{ /* It seems there are cases where the interrupts are handled by another *entity(ieanIRQcontrollerembeddedinsidethePHY)anddonot *needanyotherinterractionfromphylib.Inthiscase,justtrigger *thestatemachinedirectly.
*/
phy_trigger_machine(phydev);
val = phy_read(phydev, MII_BMSR); if (val < 0) return val;
linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported,
val & BMSR_ANEGCAPABLE);
linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported,
val & BMSR_100FULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, phydev->supported,
val & BMSR_100HALF);
linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, phydev->supported,
val & BMSR_10FULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, phydev->supported,
val & BMSR_10HALF);
if (val & BMSR_ESTATEN) {
val = phy_read(phydev, MII_ESTATUS); if (val < 0) return val;
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
phydev->supported, val & ESTATUS_1000_TFULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
phydev->supported, val & ESTATUS_1000_THALF);
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
phydev->supported, val & ESTATUS_1000_XFULL);
}
/* This is optional functionality. If not supported, we may get an error *whichshouldbeignored.
*/
genphy_c45_read_eee_abilities(phydev);
return0;
}
EXPORT_SYMBOL(genphy_read_abilities);
/* This is used for the phy device which doesn't support the MMD extended *registeraccess,butitdoeshavesideeffectwhenwearetryingtoaccess *theMMDregisterviaindirectmethod.
*/ int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad, u16 regnum)
{ return -EOPNOTSUPP;
}
EXPORT_SYMBOL(genphy_read_mmd_unsupported);
int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum,
u16 regnum, u16 val)
{ return -EOPNOTSUPP;
}
EXPORT_SYMBOL(genphy_write_mmd_unsupported);
err = of_property_read_u32(led, "reg", &index); if (err) return err; if (index > U8_MAX) return -EINVAL;
if (of_property_read_bool(led, "active-high"))
set_bit(PHY_LED_ACTIVE_HIGH, &modes); if (of_property_read_bool(led, "active-low"))
set_bit(PHY_LED_ACTIVE_LOW, &modes); if (of_property_read_bool(led, "inactive-high-impedance"))
set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
if (WARN_ON(modes & BIT(PHY_LED_ACTIVE_LOW) &&
modes & BIT(PHY_LED_ACTIVE_HIGH))) return -EINVAL;
if (modes) { /* Return error if asked to set polarity modes but not supported */ if (!phydev->drv->led_polarity_set) return -EINVAL;
err = phydev->drv->led_polarity_set(phydev, index, modes); if (err) return err;
}
phyled->index = index; if (phydev->drv->led_brightness_set)
cdev->brightness_set_blocking = phy_led_set_brightness; if (phydev->drv->led_blink_set)
cdev->blink_set = phy_led_blink_set;
leds = of_get_child_by_name(node, "leds"); if (!leds) return0;
/* Check if the PHY driver have at least an OP to *settheLEDs.
*/ if (!(phydev->drv->led_brightness_set ||
phydev->drv->led_blink_set ||
phydev->drv->led_hw_control_set)) {
phydev_dbg(phydev, "ignoring leds node defined with no PHY driver support\n"); gotoexit;
}
/* Disable the interrupt if the PHY doesn't support it *buttheinterruptisstillavalidone
*/ if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev))
phydev->irq = PHY_POLL;
if (phydrv->flags & PHY_IS_INTERNAL)
phydev->is_internal = true;
/* Deassert the reset signal */
phy_device_reset(phydev, 0);
if (phydev->drv->probe) {
err = phydev->drv->probe(phydev); if (err) goto out;
}
/* Get PHY default EEE advertising modes and handle them as potentially *safeinitialconfiguration.
*/
err = genphy_c45_read_eee_adv(phydev, phydev->advertising_eee); if (err) goto out;
/* Get the EEE modes we want to prohibit. */
of_set_phy_eee_broken(phydev);
/* Some PHYs may advertise, by default, not support EEE modes. So, *weneedtocleanthem.InadditionremovealldisabledEEEmodes.
*/
linkmode_and(phydev->advertising_eee, phydev->supported_eee,
phydev->advertising_eee);
linkmode_andnot(phydev->advertising_eee, phydev->advertising_eee,
phydev->eee_disabled_modes);
/* There is no "enabled" flag. If PHY is advertising, assume it is *kindofenabled.
*/
phydev->eee_cfg.eee_enabled = !linkmode_empty(phydev->advertising_eee);
/* Get master/slave strap overrides */
of_set_phy_timing_role(phydev);
/* The Pause Frame bits indicate that the PHY can support passing *pauseframes.Duringautonegotiation,thePHYswilldetermineif *theyshouldallowpauseframestopass.TheMACdrivershouldthen *usethatresulttodeterminewhethertoenableflowcontrolvia *pauseframes. * *Normally,PHYdriversshouldnotsetthePausebits,andinstead *allowphylibtodothat.However,theremaybesomesituations *(e.g.hardwareerratum)wherethedriverwantstosetonlyone *ofthesebits.
*/ if (!test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported) &&
!test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported)) {
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
phydev->supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
phydev->supported);
}
/* Set the state to READY by default */
phydev->state = PHY_READY;
/* Get the LEDs from the device tree, and instantiate standard *LEDsforthem.
*/ if (IS_ENABLED(CONFIG_PHYLIB_LEDS) && !phy_driver_is_genphy(phydev))
err = of_phy_leds(phydev);
out: /* Re-assert the reset signal on error */ if (err)
phy_device_reset(phydev, 1);
if (phydev->drv && phydev->drv->remove)
phydev->drv->remove(phydev);
/* Assert the reset signal */
phy_device_reset(phydev, 1);
phydev->drv = NULL;
return0;
}
/** *phy_driver_register-registeraphy_driverwiththePHYlayer *@new_driver:newphy_drivertoregister *@owner:moduleowningthisPHY
*/ int phy_driver_register(struct phy_driver *new_driver, struct module *owner)
{ int retval;
/* Either the features are hard coded, or dynamically *determined.Itcannotbeboth.
*/ if (WARN_ON(new_driver->features && new_driver->get_features)) {
pr_err("%s: features and get_features must not both be set\n",
new_driver->name); return -EINVAL;
}
/* PHYLIB device drivers must not match using a DT compatible table *asthisbypassesourchecksthatthemdiodevthatisbeingmatched *isbackedbyastructphy_device.Ifsuchacasehappens,wewill *makeout-of-boundsaccessesandlockupinphydev->lock.
*/ if (WARN(new_driver->mdiodrv.driver.of_match_table, "%s: driver must not provide a DT match table\n",
new_driver->name)) return -EINVAL;
retval = driver_register(&new_driver->mdiodrv.driver); if (retval) {
pr_err("%s: Error %d in registering driver\n",
new_driver->name, retval);
return retval;
}
pr_debug("%s: Registered new driver\n", new_driver->name);
return0;
}
EXPORT_SYMBOL(phy_driver_register);
int phy_drivers_register(struct phy_driver *new_driver, int n, struct module *owner)
{ int i, ret = 0;
for (i = 0; i < n; i++) {
ret = phy_driver_register(new_driver + i, owner); if (ret) { while (i-- > 0)
phy_driver_unregister(new_driver + i); break;
}
} return ret;
}
EXPORT_SYMBOL(phy_drivers_register);
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.90Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤
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.