staticconstchar *phylink_pcs_mode_str(unsignedint mode)
{ if (!mode) return"none";
if (mode & PHYLINK_PCS_NEG_OUTBAND) return"outband";
if (mode & PHYLINK_PCS_NEG_INBAND) { if (mode & PHYLINK_PCS_NEG_ENABLED) return"inband,an-enabled"; else return"inband,an-disabled";
}
return"unknown";
}
staticunsignedint phylink_interface_signal_rate(phy_interface_t interface)
{ switch (interface) { case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_1000BASEX: /* 1.25Mbd */ return1250; case PHY_INTERFACE_MODE_2500BASEX: /* 3.125Mbd */ return3125; case PHY_INTERFACE_MODE_5GBASER: /* 5.15625Mbd */ return5156; case PHY_INTERFACE_MODE_10GBASER: /* 10.3125Mbd */ return10313; default: return0;
}
}
/** *phylink_interface_max_speed()-getthemaximumspeedofaphyinterface *@interface:phyinterfacemodedefinedby&typedefphy_interface_t * *Determinethemaximumspeedofaphyinterface.Thisisintendedtohelp *determinethecorrectspeedtopasstotheMACwhenthephyisperforming *ratematching. * *Return:Themaximumspeedof@interface
*/ staticint phylink_interface_max_speed(phy_interface_t interface)
{ switch (interface) { case PHY_INTERFACE_MODE_100BASEX: case PHY_INTERFACE_MODE_REVRMII: case PHY_INTERFACE_MODE_RMII: case PHY_INTERFACE_MODE_SMII: case PHY_INTERFACE_MODE_REVMII: case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_MIILITE: return SPEED_100;
case PHY_INTERFACE_MODE_TBI: case PHY_INTERFACE_MODE_MOCA: case PHY_INTERFACE_MODE_RTBI: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_1000BASEKX: case PHY_INTERFACE_MODE_TRGMII: case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_PSGMII: case PHY_INTERFACE_MODE_QSGMII: case PHY_INTERFACE_MODE_QUSGMII: case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_GMII: return SPEED_1000;
case PHY_INTERFACE_MODE_2500BASEX: case PHY_INTERFACE_MODE_10G_QXGMII: return SPEED_2500;
case PHY_INTERFACE_MODE_5GBASER: return SPEED_5000;
case PHY_INTERFACE_MODE_XGMII: case PHY_INTERFACE_MODE_RXAUI: case PHY_INTERFACE_MODE_XAUI: case PHY_INTERFACE_MODE_10GBASER: case PHY_INTERFACE_MODE_10GKR: case PHY_INTERFACE_MODE_USXGMII: return SPEED_10000;
case PHY_INTERFACE_MODE_25GBASER: return SPEED_25000;
case PHY_INTERFACE_MODE_XLGMII: return SPEED_40000;
case PHY_INTERFACE_MODE_50GBASER: case PHY_INTERFACE_MODE_LAUI: return SPEED_50000;
case PHY_INTERFACE_MODE_100GBASEP: return SPEED_100000;
case PHY_INTERFACE_MODE_INTERNAL: case PHY_INTERFACE_MODE_NA: case PHY_INTERFACE_MODE_MAX: /* No idea! Garbage in, unknown out */ return SPEED_UNKNOWN;
}
/* If we get here, someone forgot to add an interface mode above */
WARN_ON_ONCE(1); return SPEED_UNKNOWN;
}
for (i = 0; i < ARRAY_SIZE(phylink_caps_params); i++) { if (speed == phylink_caps_params[i].speed &&
duplex == phylink_caps_params[i].duplex) return phylink_caps_params[i].mask;
}
switch (rate_matching) { case RATE_MATCH_OPEN_LOOP: /* TODO */
fallthrough; case RATE_MATCH_NONE:
matched_caps = 0; break; case RATE_MATCH_PAUSE: { /* The MAC must support asymmetric pause towards the local *deviceforthis.Wecouldallowjustsymmetricpause,but *thenwemighthavetorenegotiateifthelinkpartner *doesn'tsupportpause.Thisisbecausethere'snowayto *acceptpauseframeswithouttransmittingthemifweonly *supportsymmetricpause.
*/ if (!(mac_capabilities & MAC_SYM_PAUSE) ||
!(mac_capabilities & MAC_ASYM_PAUSE)) break;
/* We can't adapt if the MAC doesn't support the interface's *maxspeedatfullduplex.
*/ if (mac_capabilities &
phylink_cap_from_speed_duplex(max_speed, DUPLEX_FULL))
matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD)); break;
} case RATE_MATCH_CRS: /* The MAC must support half duplex at the interface's max *speed.
*/ if (mac_capabilities &
phylink_cap_from_speed_duplex(max_speed, DUPLEX_HALF)) {
matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD));
matched_caps &= mac_capabilities;
} break;
}
/* Get the PCS for this interface mode */ if (pl->mac_ops->mac_select_pcs) {
pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); if (IS_ERR(pcs)) return PTR_ERR(pcs);
}
if (pcs) { /* The PCS, if present, must be setup before phylink_create() *hasbeencalled.Iftheopsisnotinitialised,printan *errorandbacktraceratherthanoopsingthekernel.
*/ if (!pcs->ops) {
phylink_err(pl, "interface %s: uninitialised PCS\n",
phy_modes(state->interface));
dump_stack(); return -EINVAL;
}
/* Ensure that this PCS supports the interface which the MAC *returneditfor.ItisanerrorfortheMACtoreturnaPCS *thatdoesnotsupporttheinterfacemode.
*/ if (!phy_interface_empty(pcs->supported_interfaces) &&
!test_bit(state->interface, pcs->supported_interfaces)) {
phylink_err(pl, "MAC returned PCS which does not support %s\n",
phy_modes(state->interface)); return -EINVAL;
}
/* Validate the link parameters with the PCS */ if (pcs->ops->pcs_validate) {
ret = pcs->ops->pcs_validate(pcs, supported, state); if (ret < 0 || phylink_is_empty_linkmode(supported)) return -EINVAL;
/* Ensure the advertising mask is a subset of the *supportedmask.
*/
linkmode_and(state->advertising, state->advertising,
supported);
}
}
/* Then validate the link parameters with the MAC */ if (pl->mac_ops->mac_get_caps)
capabilities = pl->mac_ops->mac_get_caps(pl->config,
state->interface); else
capabilities = pl->config->mac_capabilities;
if (fwnode_property_read_bool(fixed_node, "full-duplex"))
pl->link_config.duplex = DUPLEX_FULL;
/* We treat the "pause" and "asym-pause" terminology as *definingthelinkpartner'sability.
*/ if (fwnode_property_read_bool(fixed_node, "pause"))
__set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
pl->link_config.lp_advertising); if (fwnode_property_read_bool(fixed_node, "asym-pause"))
__set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
pl->link_config.lp_advertising);
switch (pl->link_config.interface) { case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_PSGMII: case PHY_INTERFACE_MODE_QSGMII: case PHY_INTERFACE_MODE_QUSGMII: case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_RTBI: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: case PHY_INTERFACE_MODE_5GBASER: case PHY_INTERFACE_MODE_25GBASER: case PHY_INTERFACE_MODE_USXGMII: case PHY_INTERFACE_MODE_10G_QXGMII: case PHY_INTERFACE_MODE_10GKR: case PHY_INTERFACE_MODE_10GBASER: case PHY_INTERFACE_MODE_XLGMII: case PHY_INTERFACE_MODE_50GBASER: case PHY_INTERFACE_MODE_LAUI: case PHY_INTERFACE_MODE_100GBASEP:
caps = ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE);
caps = phylink_get_capabilities(pl->link_config.interface, caps,
RATE_MATCH_NONE);
phylink_caps_to_linkmodes(pl->supported, caps); break;
default:
phylink_err(pl, "incorrect link mode %s for in-band status\n",
phy_modes(pl->link_config.interface)); return -EINVAL;
}
if (phylink_validate(pl, pl->supported, &pl->link_config)) {
phylink_err(pl, "failed to validate link configuration for in-band status\n"); return -EINVAL;
}
}
return0;
}
staticvoid phylink_apply_manual_flow(struct phylink *pl, struct phylink_link_state *state)
{ /* If autoneg is disabled, pause AN is also disabled */ if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
state->advertising))
state->pause &= ~MLO_PAUSE_AN;
/* Manual configuration of pause modes */ if (!(pl->link_config.pause & MLO_PAUSE_AN))
state->pause = pl->link_config.pause;
}
/* Query inband for a specific interface mode, asking the MAC for the *PCSwhichwillbeusedtohandletheinterfacemode.
*/ staticunsignedint phylink_inband_caps(struct phylink *pl,
phy_interface_t interface)
{ struct phylink_pcs *pcs;
if (!pl->mac_ops->mac_select_pcs) return0;
pcs = pl->mac_ops->mac_select_pcs(pl->config, interface); if (!pcs) return0;
staticenum inband_type phylink_get_inband_type(phy_interface_t interface)
{ switch (interface) { case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_QSGMII: case PHY_INTERFACE_MODE_QUSGMII: case PHY_INTERFACE_MODE_USXGMII: case PHY_INTERFACE_MODE_10G_QXGMII: /* These protocols are designed for use with a PHY which *communicatesitsnegotiationresultbacktotheMACvia *inbandcommunication.Note:thereexistPHYsthatrun *withSGMIIbutdonotsendtheinbanddata.
*/ return INBAND_CISCO_SGMII;
case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: /* 1000base-X is designed for use media-side for Fibre *connections,andthustheAutonegbitneedstobe *takenintoaccount.Wealsodothisfor2500base-X *aswell,butdriversmaynotsupportthis,somay *needtooverridethis.
*/ return INBAND_BASEX;
/* Modern PCS-based method; update the advert at the PCS, and *restartnegotiationifthepcs_config()helperindicatesthat *theprogrammedadvertisementhaschanged.
*/
ret = phylink_pcs_config(pl->pcs, pl->pcs_neg_mode, &pl->link_config,
!!(pl->link_config.pause & MLO_PAUSE_AN)); if (ret < 0) return ret;
staticvoid phylink_activate_lpi(struct phylink *pl)
{ int err;
if (!test_bit(pl->cur_interface, pl->config->lpi_interfaces)) {
phylink_dbg(pl, "MAC does not support LPI with %s\n",
phy_modes(pl->cur_interface)); return;
}
switch (link_state.rate_matching) { case RATE_MATCH_PAUSE: /* The PHY is doing rate matchion from the media rate (in *thelink_state)totheinterfacespeed,andwillsend *pauseframestotheMACtolimititstransmissionspeed.
*/
speed = phylink_interface_max_speed(link_state.interface);
duplex = DUPLEX_FULL;
rx_pause = true; break;
case RATE_MATCH_CRS: /* The PHY is doing rate matchion from the media rate (in *thelink_state)totheinterfacespeed,andwillcause *collisionstotheMACtolimititstransmissionspeed.
*/
speed = phylink_interface_max_speed(link_state.interface);
duplex = DUPLEX_HALF; break;
}
if (pl->mac_supports_eee && pl->phy_enable_tx_lpi)
phylink_activate_lpi(pl);
if (ndev)
netif_carrier_on(ndev);
phylink_info(pl, "Link is Up - %s/%s - flow control %s\n",
phy_speed_to_str(link_state.speed),
phy_duplex_to_str(link_state.duplex),
phylink_pause_to_str(link_state.pause));
}
/* The PCS may have a latching link-fail indicator. If the link *wasup,bringthelinkdownandre-triggertheresolve. *Otherwise,re-readthePCSstatetogetthecurrentstatus *ofthelink.
*/ if (!link_state.link) { if (cur_link_state)
retrigger = true; else
phylink_mac_pcs_get_state(pl, &link_state);
}
/* If we have a phy, the "up" state is the union of both the *PHYandtheMAC
*/ if (phy)
link_state.link &= pl->phy_state.link;
/* Only update if the PHY link is up */ if (phy && pl->phy_state.link) { /* If the interface has changed, force a link down *eventifthelinkisn'talreadydown,andre-resolve.
*/ if (link_state.interface != pl->phy_state.interface) {
retrigger = true;
link_state.link = false;
}
link_state.interface = pl->phy_state.interface;
/* If we are doing rate matching, then the link *speed/duplexcomesfromthePHY
*/ if (pl->phy_state.rate_matching) {
link_state.rate_matching =
pl->phy_state.rate_matching;
link_state.speed = pl->phy_state.speed;
link_state.duplex = pl->phy_state.duplex;
}
/* If we have a PHY, we need to update with the PHY *flowcontrolbits.
*/
link_state.pause = pl->phy_state.pause;
mac_config = true;
}
}
if (pl->act_link_an_mode != MLO_AN_FIXED)
phylink_apply_manual_flow(pl, &link_state);
if (mac_config) { if (link_state.interface != pl->link_config.interface) { /* The interface has changed, force the link down and *thenreconfigure.
*/ if (cur_link_state) {
phylink_link_down(pl);
cur_link_state = false;
}
phylink_major_config(pl, false, &link_state);
pl->link_config.interface = link_state.interface;
}
}
/* If configuration of the interface failed, force the link down *untilwegetasuccessfulconfiguration.
*/ if (pl->major_config_failed)
link_state.link = false;
if (link_state.link != cur_link_state) {
pl->old_link_state = link_state.link; if (!link_state.link)
phylink_link_down(pl); else
phylink_link_up(pl, link_state);
} if (!link_state.link && retrigger) {
pl->link_failed = false;
queue_work(system_power_efficient_wq, &pl->resolve);
}
mutex_unlock(&pl->state_mutex); if (phy)
mutex_unlock(&phy->lock);
mutex_unlock(&pl->phydev_mutex);
}
staticvoid phylink_run_resolve(struct phylink *pl)
{ if (!pl->phylink_disable_state)
queue_work(system_power_efficient_wq, &pl->resolve);
}
staticvoid phylink_run_resolve_and_disable(struct phylink *pl, int bit)
{ unsignedlong state = pl->phylink_disable_state;
/* Get the LPI state from phylib */
pl->phy_enable_tx_lpi = phydev->enable_tx_lpi;
pl->mac_tx_lpi_timer = phydev->eee_cfg.tx_lpi_timer;
mutex_unlock(&pl->state_mutex);
/* If the PHY provides a bitmap of the interfaces it will be using *dependingonthenegotiatedmediaspeeds,usethistovalidate *whichethtoollinkmodescanbeused.
*/ if (!phy_interface_empty(phy->possible_interfaces)) { /* We only care about the union of the PHY's interfaces and *thosewhichthehostsupports.
*/
phy_interface_and(interfaces, phy->possible_interfaces,
pl->config->supported_interfaces);
if (phy_interface_empty(interfaces)) {
phylink_err(pl, "PHY has no common interfaces\n"); return -EINVAL;
}
if (phy_on_sfp(phy)) { /* If the PHY is on a SFP, limit the interfaces to *thosethatcanbeusedwithaSFPmodule.
*/
phy_interface_and(interfaces, interfaces,
phylink_sfp_interfaces);
if (phy_interface_empty(interfaces)) {
phylink_err(pl, "SFP PHY's possible interfaces becomes empty\n"); return -EINVAL;
}
}
ret = phylink_validate_phy(pl, phy, supported, &config); if (ret) {
phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n",
phy_modes(config.interface),
__ETHTOOL_LINK_MODE_MASK_NBITS, phy->supported,
__ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising,
ERR_PTR(ret)); return ret;
}
/* Restrict the phy advertisement according to the MAC support. */
linkmode_copy(phy->advertising, config.advertising);
/* If the MAC supports phylink managed EEE, restrict the EEE *advertisementaccordingtotheMAC'sLPIcapabilities.
*/ if (pl->mac_supports_eee) { /* If EEE is enabled, then we need to call phy_support_eee() *toensurethattheadvertisingmaskisappropriatelyset. *ThisalsoenablesEEEatthePHY.
*/ if (pl->eee_cfg.eee_enabled)
phy_support_eee(phy);
if (pl->config->mac_managed_pm)
phy->mac_managed_pm = true;
/* Allow the MAC to stop its clock if the PHY has the capability */
pl->mac_tx_clk_stop = phy_eee_tx_clock_stop_capable(phy) > 0;
if (pl->mac_supports_eee_ops) { /* Explicitly configure whether the PHY is allowed to stop it's *receiveclock.
*/
ret = phy_eee_rx_clock_stop(phy,
pl->config->eee_rx_clk_stop_enable); if (ret == -EOPNOTSUPP)
ret = 0;
}
if (ret == 0 && phy_interrupt_is_valid(phy))
phy_request_interrupt(phy);
/* Fixed links and 802.3z are handled without needing a PHY */ if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
(pl->cfg_link_an_mode == MLO_AN_INBAND &&
phy_interface_mode_is_8023z(pl->link_interface))) return0;
phy_fwnode = fwnode_get_phy_node(fwnode); if (IS_ERR(phy_fwnode)) { if (pl->cfg_link_an_mode == MLO_AN_PHY) return -ENODEV; return0;
}
phy_dev = fwnode_phy_find_device(phy_fwnode); /* We're done with the phy_node handle */
fwnode_handle_put(phy_fwnode); if (!phy_dev) return -ENODEV;
/* Use PHY device/driver interface */ if (pl->link_interface == PHY_INTERFACE_MODE_NA) {
pl->link_interface = phy_dev->interface;
pl->link_config.interface = pl->link_interface;
}
if (pl->config->mac_requires_rxc)
flags |= PHY_F_RXC_ALWAYS_ON;
ret = phy_attach_direct(pl->netdev, phy_dev, flags,
pl->link_interface);
phy_device_free(phy_dev); if (ret) return ret;
ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface); if (ret)
phy_detach(phy_dev);
phylink_info(pl, "configuring for %s/%s link mode\n",
phylink_an_mode_str(pl->req_link_an_mode),
phy_modes(pl->link_config.interface));
/* Always set the carrier off */ if (pl->netdev)
netif_carrier_off(pl->netdev);
pl->pcs_state = PCS_STATE_STARTING;
/* Apply the link configuration to the MAC when starting. This allows *afixed-linktostartwiththecorrectparameters,andalso *ensuresthatwesettheappropriateadvertisementforSerdeslinks. * *Restartautonegotiationifusing802.3ztoensurethatthelink *parametersareproperlynegotiated.ThisisnecessaryforDSA *switchesusing802.3znegotiationtoensuretheyseeourmodes.
*/
phylink_mac_initial_config(pl, true);
if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) { int irq = gpiod_to_irq(pl->link_gpio);
if (irq > 0) { if (!request_irq(irq, phylink_link_handler,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING, "netdev link", pl))
pl->link_irq = irq; else
irq = 0;
} if (irq <= 0)
poll = true;
}
if (pl->cfg_link_an_mode == MLO_AN_FIXED)
poll |= pl->config->poll_fixed_state;
if (poll)
mod_timer(&pl->link_poll, jiffies + HZ); if (pl->phydev)
phy_start(pl->phydev); if (pl->sfp_bus)
sfp_upstream_start(pl->sfp_bus);
}
EXPORT_SYMBOL_GPL(phylink_start);
if (pl->mac_rx_clk_stop_blocked == U8_MAX) {
phylink_warn(pl, "%s called too many times - ignoring\n",
__func__);
dump_stack(); return;
}
/* Disable PHY receive clock stop if this is the first time this *functionhasbeencalledandclock-stopwaspreviouslyenabled.
*/ if (pl->mac_rx_clk_stop_blocked++ == 0 &&
pl->mac_supports_eee_ops && pl->phydev &&
pl->config->eee_rx_clk_stop_enable)
phy_eee_rx_clock_stop(pl->phydev, false);
}
EXPORT_SYMBOL_GPL(phylink_rx_clk_stop_block);
if (mac_wol && (!pl->netdev || pl->netdev->ethtool->wol_enabled)) { /* Wake-on-Lan enabled, MAC handling */
mutex_lock(&pl->state_mutex);
/* Stop the resolver bringing the link up */
__set_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state);
pl->suspend_link_up = phylink_link_is_up(pl); if (pl->suspend_link_up) { /* Disable the carrier, to prevent transmit timeouts, *butonewouldhopeallpacketshavebeensent.This *alsomeansphylink_resolve()willdonothing.
*/ if (pl->netdev)
netif_carrier_off(pl->netdev);
pl->old_link_state = false;
}
/* We do not call mac_link_down() here as we want the *linktoremainuptoreceivetheWoLpackets.
*/
mutex_unlock(&pl->state_mutex);
} else {
phylink_stop(pl);
}
}
EXPORT_SYMBOL_GPL(phylink_suspend);
if (test_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state)) { /* Wake-on-Lan enabled, MAC handling */
if (pl->suspend_link_up) { /* Call mac_link_down() so we keep the overall state *balanced.Dothisunderthestate_mutexlockfor *consistency.Thiswillcausea"LinkDown"message *tobeprintedduringresume,whichisharmless- *thetruelinkstatewillbeprintedwhenweruna *resolve.
*/
mutex_lock(&pl->state_mutex);
phylink_link_down(pl);
mutex_unlock(&pl->state_mutex);
}
/* Re-apply the link parameters so that all the settings get *restoredtotheMAC.
*/
phylink_mac_initial_config(pl, true);
/* Re-enable and re-resolve the link parameters */
phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_MAC_WOL);
} else {
phylink_start(pl);
}
}
EXPORT_SYMBOL_GPL(phylink_resume);
for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) {
interface = phylink_sfp_interface_preference[i]; if (!test_bit(interface, pl->sfp_interfaces)) continue;
/* The logic here is: if speed == max_speed, then we've found *thebestinterface.Otherwisewefindtheinterfacethat *canjustsupporttherequestedspeed.
*/ if (max_speed >= speed)
best_interface = interface;
if (max_speed <= speed) break;
}
if (best_interface == PHY_INTERFACE_MODE_NA)
phylink_err(pl, "selection of interface failed, speed %u\n",
speed);
switch (pl->act_link_an_mode) { case MLO_AN_FIXED: /* We are using fixed settings. Report these as the *currentlinksettings-andnotethatthesealso *representthesupportedspeeds/duplex/pausemodes.
*/
phylink_get_fixed_state(pl, &link_state);
phylink_get_ksettings(&link_state, kset); break;
case MLO_AN_INBAND: /* If there is a phy attached, then use the reported *settingsfromthephywithnomodification.
*/ if (pl->phydev) break;
phylink_mac_pcs_get_state(pl, &link_state);
/* The MAC is reporting the link results from its own PCS *layerviain-bandstatus.Reporttheseasthecurrent *linksettings.
*/
phylink_get_ksettings(&link_state, kset); break;
}
/* We can rely on phylib for this update; we also do not need *toupdatethepl->link_configsettings: *-theconfigurationreturnedviaksettings_get()willcome *fromphylibwheneveraPHYispresent. *-link_config.interfacewillbeupdatedbythePHYcalling *backviaphylink_phy_change()andasubsequentresolve. *-initiallinkconfigurationforPHYmodecomesfromthe *lastphystateupdatedviaphylink_phy_change(). *-otherconfigurationchanges(e.g.pausemodes)are *performeddirectlyviaphylib. *-ifinin-bandmodewithaPHY,thelinkconfiguration *ispassedonthelinkfromthePHY,andallof *link_config.{speed,duplex,an_enabled,pause}arenotused. *-theonlypossibleusewouldbelink_config.advertising *pausemodeswhenin1000base-XmodewithaPHY,butin *thepresenceofaPHY,thisshouldnotbechangedasthat *shouldbedeterminedfromthemediasideadvertisement.
*/ return phy_ethtool_ksettings_set(pl->phydev, &phy_kset);
}
/* FIXME: should we reject autoneg if phy/mac does not support it? */ switch (kset->base.autoneg) { case AUTONEG_DISABLE: /* Autonegotiation disabled, select a suitable speed and *duplex.
*/
c = phy_caps_lookup(kset->base.speed, kset->base.duplex,
pl->supported, false); if (!c) return -EINVAL;
/* If we have a fixed link, refuse to change link parameters. *Ifthelinkparametersmatch,acceptthembutdonothing.
*/ if (pl->req_link_an_mode == MLO_AN_FIXED) { if (c->speed != pl->link_config.speed ||
c->duplex != pl->link_config.duplex) return -EINVAL; return0;
}
case AUTONEG_ENABLE: /* If we have a fixed link, allow autonegotiation (since that *isourdefaultcase)butdonotallowtheadvertisementto *bechanged.Iftheadvertisementmatches,simplyreturn.
*/ if (pl->req_link_an_mode == MLO_AN_FIXED) { if (!linkmode_equal(config.advertising,
pl->link_config.advertising)) return -EINVAL; return0;
}
/* We have ruled out the case with a PHY attached, and the *fixed-linkcases.Allthatisleftarein-bandlinks.
*/
linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising,
kset->base.autoneg == AUTONEG_ENABLE);
/* If this link is with an SFP, ensure that changes to advertised modes *alsocausetheassociatedinterfacetobeselectedsuchthatthe *linkcanbeconfiguredcorrectly.
*/ if (pl->sfp_bus) { if (kset->base.autoneg == AUTONEG_ENABLE)
config.interface =
phylink_sfp_select_interface(pl,
config.advertising); else
config.interface =
phylink_sfp_select_interface_speed(pl,
config.speed); if (config.interface == PHY_INTERFACE_MODE_NA) return -EINVAL;
/* Revalidate with the selected interface */
linkmode_copy(support, pl->supported); if (phylink_validate(pl, support, &config)) {
phylink_err(pl, "validation of %s/%s with support %*pb failed\n",
phylink_an_mode_str(pl->req_link_an_mode),
phy_modes(config.interface),
__ETHTOOL_LINK_MODE_MASK_NBITS, support); return -EINVAL;
}
} else { /* Validate without changing the current supported mask. */
linkmode_copy(support, pl->supported); if (phylink_validate(pl, support, &config)) return -EINVAL;
}
/* If autonegotiation is enabled, we must have an advertisement */ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
config.advertising) &&
phylink_is_empty_linkmode(config.advertising)) return -EINVAL;
/* Validate the autonegotiation state. We don't have a PHY in this *situation,sothePCSisthemedia-facingentity.
*/ if (!phylink_validate_pcs_inband_autoneg(pl, config.interface,
config.advertising)) return -EINVAL;
if (pl->link_config.interface != config.interface) { /* The interface changed, e.g. 1000base-X <-> 2500base-X */ /* We need to force the link down, then change the interface */ if (pl->old_link_state) {
phylink_link_down(pl);
pl->old_link_state = false;
} if (!test_bit(PHYLINK_DISABLE_STOPPED,
&pl->phylink_disable_state))
phylink_major_config(pl, false, &config);
pl->link_config.interface = config.interface;
linkmode_copy(pl->link_config.advertising, config.advertising);
} elseif (!linkmode_equal(pl->link_config.advertising,
config.advertising)) {
linkmode_copy(pl->link_config.advertising, config.advertising);
phylink_change_inband_advert(pl);
}
mutex_unlock(&pl->state_mutex);
/* Update our in-band advertisement, triggering a renegotiation if *theadvertisementchanged.
*/ if (!pl->phydev)
phylink_change_inband_advert(pl);
mutex_unlock(&pl->state_mutex);
/* If we have a PHY, a change of the pause frame advertisement will *causephylibtorenegotiate(ifANisenabled)whichwillinturn *callourphylink_phy_change()andtriggeraresolve.Notethat *wecan'tholdourstatemutexwhilecallingphy_set_asym_pause().
*/ if (pl->phydev)
phy_set_asym_pause(pl->phydev, pause->rx_pause,
pause->tx_pause);
/* If the manual pause settings changed, make sure we trigger a *resolvetoupdatetheirstate;wecannotguaranteethatthe *linkwillcycle.
*/ if (manual_changed) {
pl->link_failed = true;
phylink_run_resolve(pl);
}
/* This emulates MII registers for a fixed-mode phy operating as per the *passedinstate."aneg"definesifwereportnegotiationispossible. * *FIXME:shoulddealwithnegotiationstatetoo.
*/ staticint phylink_mii_emul_read(unsignedint reg, struct phylink_link_state *state)
{ struct fixed_phy_status fs; unsignedlong *lpa = state->lp_advertising; int val;
interface = PHY_INTERFACE_MODE_NA; for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) if (test_bit(phylink_sfp_interface_preference[i], intf)) {
interface = phylink_sfp_interface_preference[i]; break;
}
phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
phylink_an_mode_str(mode), phy_modes(state->interface),
__ETHTOOL_LINK_MODE_MASK_NBITS, supported);
if (!linkmode_equal(pl->supported, supported)) {
linkmode_copy(pl->supported, supported);
changed = true;
}
if (!linkmode_equal(pl->link_config.advertising, state->advertising)) {
linkmode_copy(pl->link_config.advertising, state->advertising);
changed = true;
}
/* Ignore errors if we're expecting a PHY to attach later */
ret = phylink_validate(pl, support, &config); if (ret) {
phylink_err(pl, "validation with support %*pb failed: %pe\n",
__ETHTOOL_LINK_MODE_MASK_NBITS, support,
ERR_PTR(ret)); return ret;
}
config.interface = phylink_sfp_select_interface(pl, config.advertising); if (config.interface == PHY_INTERFACE_MODE_NA) return -EINVAL;
/* Attach the PHY so that the PHY is present when we do the major *configurationstep.
*/
ret = phylink_attach_phy(pl, phy, config.interface); if (ret < 0) return ret;
/* This will validate the configuration for us. */
ret = phylink_bringup_phy(pl, phy, config.interface); if (ret < 0) {
phy_detach(phy); return ret;
}
/* Find the union of the supported interfaces by the PCS/MAC and *theSFPmodule.
*/
phy_interface_and(pl->sfp_interfaces, pl->config->supported_interfaces,
pl->sfp_interfaces); if (phy_interface_empty(pl->sfp_interfaces)) {
phylink_err(pl, "unsupported SFP module: no common interface modes\n"); return -EINVAL;
}
/* For all the interfaces that are supported, reduce the sfp_support *masktoonlythoselinkmodesthatcanbesupported.
*/
ret = phylink_validate_mask(pl, NULL, pl->sfp_support, &config,
pl->sfp_interfaces); if (ret) {
phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n",
__ETHTOOL_LINK_MODE_MASK_NBITS, support); return ret;
}
interface = phylink_choose_sfp_interface(pl, pl->sfp_interfaces); if (interface == PHY_INTERFACE_MODE_NA) {
phylink_err(pl, "failed to select SFP interface\n"); return -EINVAL;
}
inband_type = phylink_get_inband_type(interface); if (inband_type == INBAND_NONE) { /* If this is the sole interface, and there is no inband *support,cleartheadvertisingmaskandAutonegbitin *thesupportmask.Otherwise,justcleartheAutonegbit *intheadvertisingmask.
*/ if (phy_interface_weight(pl->sfp_interfaces) == 1) {
linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
pl->sfp_support);
linkmode_zero(config.advertising);
} else {
linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
config.advertising);
}
}
if (!phylink_validate_pcs_inband_autoneg(pl, interface,
config.advertising)) {
phylink_err(pl, "autoneg setting not compatible with PCS"); return -EINVAL;
}
config.interface = interface;
/* Ignore errors if we're expecting a PHY to attach later */
ret = phylink_validate(pl, support, &config); if (ret) {
phylink_err(pl, "validation with support %*pb failed: %pe\n",
__ETHTOOL_LINK_MODE_MASK_NBITS, support,
ERR_PTR(ret)); return ret;
}
/* If this module may have a PHY connecting later, defer until later */
pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id); if (pl->sfp_may_have_phy) return0;
if (!phy->drv) {
phylink_err(pl, "PHY %s (id 0x%.8lx) has no driver loaded\n",
phydev_name(phy), (unsignedlong)phy->phy_id);
phylink_err(pl, "Drivers which handle known common cases: CONFIG_BCM84881_PHY, CONFIG_MARVELL_PHY\n"); return -EINVAL;
}
void phylink_resolve_c73(struct phylink_link_state *state)
{ int i;
for (i = 0; i < ARRAY_SIZE(phylink_c73_priority_resolution); i++) { int bit = phylink_c73_priority_resolution[i].bit; if (linkmode_test_bit(bit, state->advertising) &&
linkmode_test_bit(bit, state->lp_advertising)) break;
}
case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_QSGMII: if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
phylink_decode_sgmii_word(state, lpa); break;
case PHY_INTERFACE_MODE_QUSGMII: if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
phylink_decode_usgmii_word(state, lpa); break;
switch (interface) { case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX:
adv = ADVERTISE_1000XFULL; if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
advertising))
adv |= ADVERTISE_1000XPAUSE; if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
advertising))
adv |= ADVERTISE_1000XPSE_ASYM; return adv; case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_QSGMII: return0x0001; default: /* Nothing to do for other modes */ return -EINVAL;
}
}
EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement);
/* Configure the inband state. Ensure ISOLATE bit is disabled */
ret = mdiodev_modify(pcs, MII_BMCR, BMCR_ANENABLE | BMCR_ISOLATE, bmcr); if (ret < 0) return ret;
staticint __init phylink_init(void)
{ for (int i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); ++i)
__set_bit(phylink_sfp_interface_preference[i],
phylink_sfp_interfaces);
return0;
}
module_init(phylink_init);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("phylink models the MAC to optional PHY connection");
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.302Angebot
(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.