| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Clause 45 PHY support
- */
- #include <linux/ethtool.h>
- #include <linux/export.h>
- #include <linux/mdio.h>
- #include <linux/mii.h>
- #include <linux/phy.h>
- #include <linux/ethtool_netlink.h>
- #include "mdio-open-alliance.h"
- #include "phylib-internal.h"
- /**
- * genphy_c45_baset1_able - checks if the PMA has BASE-T1 extended abilities
- * @phydev: target phy_device struct
- */
- static bool genphy_c45_baset1_able(struct phy_device *phydev)
- {
- int val;
- if (phydev->pma_extable == -ENODATA) {
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
- if (val < 0)
- return false;
- phydev->pma_extable = val;
- }
- return !!(phydev->pma_extable & MDIO_PMA_EXTABLE_BT1);
- }
- /**
- * genphy_c45_pma_can_sleep - checks if the PMA have sleep support
- * @phydev: target phy_device struct
- */
- static bool genphy_c45_pma_can_sleep(struct phy_device *phydev)
- {
- int stat1;
- stat1 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT1);
- if (stat1 < 0)
- return false;
- return !!(stat1 & MDIO_STAT1_LPOWERABLE);
- }
- /**
- * genphy_c45_pma_resume - wakes up the PMA module
- * @phydev: target phy_device struct
- */
- int genphy_c45_pma_resume(struct phy_device *phydev)
- {
- if (!genphy_c45_pma_can_sleep(phydev))
- return -EOPNOTSUPP;
- return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
- MDIO_CTRL1_LPOWER);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_pma_resume);
- /**
- * genphy_c45_pma_suspend - suspends the PMA module
- * @phydev: target phy_device struct
- */
- int genphy_c45_pma_suspend(struct phy_device *phydev)
- {
- if (!genphy_c45_pma_can_sleep(phydev))
- return -EOPNOTSUPP;
- return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
- MDIO_CTRL1_LPOWER);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_pma_suspend);
- /**
- * genphy_c45_pma_baset1_setup_master_slave - configures forced master/slave
- * role of BaseT1 devices.
- * @phydev: target phy_device struct
- */
- int genphy_c45_pma_baset1_setup_master_slave(struct phy_device *phydev)
- {
- int ctl = 0;
- switch (phydev->master_slave_set) {
- case MASTER_SLAVE_CFG_MASTER_PREFERRED:
- case MASTER_SLAVE_CFG_MASTER_FORCE:
- ctl = MDIO_PMA_PMD_BT1_CTRL_CFG_MST;
- break;
- case MASTER_SLAVE_CFG_SLAVE_FORCE:
- case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
- break;
- case MASTER_SLAVE_CFG_UNKNOWN:
- case MASTER_SLAVE_CFG_UNSUPPORTED:
- return 0;
- default:
- phydev_warn(phydev, "Unsupported Master/Slave mode\n");
- return -EOPNOTSUPP;
- }
- return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL,
- MDIO_PMA_PMD_BT1_CTRL_CFG_MST, ctl);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_setup_master_slave);
- /**
- * genphy_c45_pma_setup_forced - configures a forced speed
- * @phydev: target phy_device struct
- */
- int genphy_c45_pma_setup_forced(struct phy_device *phydev)
- {
- int bt1_ctrl, ctrl1, ctrl2, ret;
- /* Half duplex is not supported */
- if (phydev->duplex != DUPLEX_FULL)
- return -EINVAL;
- ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
- if (ctrl1 < 0)
- return ctrl1;
- ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2);
- if (ctrl2 < 0)
- return ctrl2;
- ctrl1 &= ~MDIO_CTRL1_SPEEDSEL;
- /*
- * PMA/PMD type selection is 1.7.5:0 not 1.7.3:0. See 45.2.1.6.1
- * in 802.3-2012 and 802.3-2015.
- */
- ctrl2 &= ~(MDIO_PMA_CTRL2_TYPE | 0x30);
- switch (phydev->speed) {
- case SPEED_10:
- if (genphy_c45_baset1_able(phydev))
- ctrl2 |= MDIO_PMA_CTRL2_BASET1;
- else
- ctrl2 |= MDIO_PMA_CTRL2_10BT;
- break;
- case SPEED_100:
- ctrl1 |= MDIO_PMA_CTRL1_SPEED100;
- ctrl2 |= MDIO_PMA_CTRL2_100BTX;
- break;
- case SPEED_1000:
- ctrl1 |= MDIO_PMA_CTRL1_SPEED1000;
- /* Assume 1000base-T */
- ctrl2 |= MDIO_PMA_CTRL2_1000BT;
- break;
- case SPEED_2500:
- ctrl1 |= MDIO_PMA_CTRL1_SPEED2_5G;
- /* Assume 2.5Gbase-T */
- ctrl2 |= MDIO_PMA_CTRL2_2_5GBT;
- break;
- case SPEED_5000:
- ctrl1 |= MDIO_PMA_CTRL1_SPEED5G;
- /* Assume 5Gbase-T */
- ctrl2 |= MDIO_PMA_CTRL2_5GBT;
- break;
- case SPEED_10000:
- ctrl1 |= MDIO_CTRL1_SPEED10G;
- /* Assume 10Gbase-T */
- ctrl2 |= MDIO_PMA_CTRL2_10GBT;
- break;
- default:
- return -EINVAL;
- }
- ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, ctrl1);
- if (ret < 0)
- return ret;
- ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2, ctrl2);
- if (ret < 0)
- return ret;
- if (genphy_c45_baset1_able(phydev)) {
- ret = genphy_c45_pma_baset1_setup_master_slave(phydev);
- if (ret < 0)
- return ret;
- bt1_ctrl = 0;
- if (phydev->speed == SPEED_1000)
- bt1_ctrl = MDIO_PMA_PMD_BT1_CTRL_STRAP_B1000;
- ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL,
- MDIO_PMA_PMD_BT1_CTRL_STRAP, bt1_ctrl);
- if (ret < 0)
- return ret;
- }
- return genphy_c45_an_disable_aneg(phydev);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_pma_setup_forced);
- /* Sets master/slave preference and supported technologies.
- * The preference is set in the BIT(4) of BASE-T1 AN
- * advertisement register 7.515 and whether the status
- * is forced or not, it is set in the BIT(12) of BASE-T1
- * AN advertisement register 7.514.
- * Sets 10BASE-T1L Ability BIT(14) in BASE-T1 autonegotiation
- * advertisement register [31:16] if supported.
- */
- static int genphy_c45_baset1_an_config_aneg(struct phy_device *phydev)
- {
- u16 adv_l_mask, adv_l = 0;
- u16 adv_m_mask, adv_m = 0;
- int changed = 0;
- int ret;
- adv_l_mask = MDIO_AN_T1_ADV_L_FORCE_MS | MDIO_AN_T1_ADV_L_PAUSE_CAP |
- MDIO_AN_T1_ADV_L_PAUSE_ASYM;
- adv_m_mask = MDIO_AN_T1_ADV_M_1000BT1 | MDIO_AN_T1_ADV_M_100BT1 |
- MDIO_AN_T1_ADV_M_MST | MDIO_AN_T1_ADV_M_B10L;
- switch (phydev->master_slave_set) {
- case MASTER_SLAVE_CFG_MASTER_FORCE:
- adv_m |= MDIO_AN_T1_ADV_M_MST;
- fallthrough;
- case MASTER_SLAVE_CFG_SLAVE_FORCE:
- adv_l |= MDIO_AN_T1_ADV_L_FORCE_MS;
- break;
- case MASTER_SLAVE_CFG_MASTER_PREFERRED:
- adv_m |= MDIO_AN_T1_ADV_M_MST;
- fallthrough;
- case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
- break;
- case MASTER_SLAVE_CFG_UNKNOWN:
- case MASTER_SLAVE_CFG_UNSUPPORTED:
- /* if master/slave role is not specified, do not overwrite it */
- adv_l_mask &= ~MDIO_AN_T1_ADV_L_FORCE_MS;
- adv_m_mask &= ~MDIO_AN_T1_ADV_M_MST;
- break;
- default:
- phydev_warn(phydev, "Unsupported Master/Slave mode\n");
- return -EOPNOTSUPP;
- }
- adv_l |= linkmode_adv_to_mii_t1_adv_l_t(phydev->advertising);
- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_T1_ADV_L,
- adv_l_mask, adv_l);
- if (ret < 0)
- return ret;
- if (ret > 0)
- changed = 1;
- adv_m |= linkmode_adv_to_mii_t1_adv_m_t(phydev->advertising);
- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_T1_ADV_M,
- adv_m_mask, adv_m);
- if (ret < 0)
- return ret;
- if (ret > 0)
- changed = 1;
- return changed;
- }
- /**
- * genphy_c45_an_config_aneg - configure advertisement registers
- * @phydev: target phy_device struct
- *
- * Configure advertisement registers based on modes set in phydev->advertising
- *
- * Returns negative errno code on failure, 0 if advertisement didn't change,
- * or 1 if advertised modes changed.
- */
- int genphy_c45_an_config_aneg(struct phy_device *phydev)
- {
- int changed = 0, ret;
- u32 adv;
- linkmode_and(phydev->advertising, phydev->advertising,
- phydev->supported);
- ret = genphy_c45_an_config_eee_aneg(phydev);
- if (ret < 0)
- return ret;
- else if (ret)
- changed = true;
- if (genphy_c45_baset1_able(phydev))
- return genphy_c45_baset1_an_config_aneg(phydev);
- adv = linkmode_adv_to_mii_adv_t(phydev->advertising);
- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
- ADVERTISE_ALL | ADVERTISE_100BASE4 |
- ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
- adv);
- if (ret < 0)
- return ret;
- if (ret > 0)
- changed = 1;
- adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
- MDIO_AN_10GBT_CTRL_ADV10G |
- MDIO_AN_10GBT_CTRL_ADV5G |
- MDIO_AN_10GBT_CTRL_ADV2_5G, adv);
- if (ret < 0)
- return ret;
- if (ret > 0)
- changed = 1;
- return changed;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_an_config_aneg);
- /**
- * genphy_c45_an_disable_aneg - disable auto-negotiation
- * @phydev: target phy_device struct
- *
- * Disable auto-negotiation in the Clause 45 PHY. The link parameters
- * are controlled through the PMA/PMD MMD registers.
- *
- * Returns zero on success, negative errno code on failure.
- */
- int genphy_c45_an_disable_aneg(struct phy_device *phydev)
- {
- u16 reg = MDIO_CTRL1;
- if (genphy_c45_baset1_able(phydev))
- reg = MDIO_AN_T1_CTRL;
- return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
- MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_an_disable_aneg);
- /**
- * genphy_c45_restart_aneg - Enable and restart auto-negotiation
- * @phydev: target phy_device struct
- *
- * This assumes that the auto-negotiation MMD is present.
- *
- * Enable and restart auto-negotiation.
- */
- int genphy_c45_restart_aneg(struct phy_device *phydev)
- {
- u16 reg = MDIO_CTRL1;
- if (genphy_c45_baset1_able(phydev))
- reg = MDIO_AN_T1_CTRL;
- return phy_set_bits_mmd(phydev, MDIO_MMD_AN, reg,
- MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
- /**
- * genphy_c45_check_and_restart_aneg - Enable and restart auto-negotiation
- * @phydev: target phy_device struct
- * @restart: whether aneg restart is requested
- *
- * This assumes that the auto-negotiation MMD is present.
- *
- * Check, and restart auto-negotiation if needed.
- */
- int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
- {
- u16 reg = MDIO_CTRL1;
- int ret;
- if (genphy_c45_baset1_able(phydev))
- reg = MDIO_AN_T1_CTRL;
- if (!restart) {
- /* Configure and restart aneg if it wasn't set before */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
- if (ret < 0)
- return ret;
- if (!(ret & MDIO_AN_CTRL1_ENABLE))
- restart = true;
- }
- if (restart)
- return genphy_c45_restart_aneg(phydev);
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);
- /**
- * genphy_c45_aneg_done - return auto-negotiation complete status
- * @phydev: target phy_device struct
- *
- * This assumes that the auto-negotiation MMD is present.
- *
- * Reads the status register from the auto-negotiation MMD, returning:
- * - positive if auto-negotiation is complete
- * - negative errno code on error
- * - zero otherwise
- */
- int genphy_c45_aneg_done(struct phy_device *phydev)
- {
- int reg = MDIO_STAT1;
- int val;
- if (genphy_c45_baset1_able(phydev))
- reg = MDIO_AN_T1_STAT;
- val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
- return val < 0 ? val : val & MDIO_AN_STAT1_COMPLETE ? 1 : 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_aneg_done);
- /**
- * genphy_c45_read_link - read the overall link status from the MMDs
- * @phydev: target phy_device struct
- *
- * Read the link status from the specified MMDs, and if they all indicate
- * that the link is up, set phydev->link to 1. If an error is encountered,
- * a negative errno will be returned, otherwise zero.
- */
- int genphy_c45_read_link(struct phy_device *phydev)
- {
- u32 mmd_mask = MDIO_DEVS_PMAPMD;
- int val, devad;
- bool link = true;
- if (phydev->c45_ids.mmds_present & MDIO_DEVS_AN) {
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
- if (val < 0)
- return val;
- /* Autoneg is being started, therefore disregard current
- * link status and report link as down.
- */
- if (val & MDIO_AN_CTRL1_RESTART) {
- phydev->link = 0;
- return 0;
- }
- }
- while (mmd_mask && link) {
- devad = __ffs(mmd_mask);
- mmd_mask &= ~BIT(devad);
- /* 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) {
- val = phy_read_mmd(phydev, devad, MDIO_STAT1);
- if (val < 0)
- return val;
- else if (val & MDIO_STAT1_LSTATUS)
- continue;
- }
- val = phy_read_mmd(phydev, devad, MDIO_STAT1);
- if (val < 0)
- return val;
- if (!(val & MDIO_STAT1_LSTATUS))
- link = false;
- }
- phydev->link = link;
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_read_link);
- /* Read the Clause 45 defined BASE-T1 AN (7.513) status register to check
- * if autoneg is complete. If so read the BASE-T1 Autonegotiation
- * Advertisement registers filling in the link partner advertisement,
- * pause and asym_pause members in phydev.
- */
- static int genphy_c45_baset1_read_lpa(struct phy_device *phydev)
- {
- int val;
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_STAT);
- if (val < 0)
- return val;
- if (!(val & MDIO_AN_STAT1_COMPLETE)) {
- linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->lp_advertising);
- mii_t1_adv_l_mod_linkmode_t(phydev->lp_advertising, 0);
- mii_t1_adv_m_mod_linkmode_t(phydev->lp_advertising, 0);
- phydev->pause = false;
- phydev->asym_pause = false;
- return 0;
- }
- linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->lp_advertising, 1);
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_LP_L);
- if (val < 0)
- return val;
- mii_t1_adv_l_mod_linkmode_t(phydev->lp_advertising, val);
- phydev->pause = val & MDIO_AN_T1_ADV_L_PAUSE_CAP;
- phydev->asym_pause = val & MDIO_AN_T1_ADV_L_PAUSE_ASYM;
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_LP_M);
- if (val < 0)
- return val;
- mii_t1_adv_m_mod_linkmode_t(phydev->lp_advertising, val);
- return 0;
- }
- /**
- * genphy_c45_read_lpa - read the link partner advertisement and pause
- * @phydev: target phy_device struct
- *
- * Read the Clause 45 defined base (7.19) and 10G (7.33) status registers,
- * filling in the link partner advertisement, pause and asym_pause members
- * in @phydev. This assumes that the auto-negotiation MMD is present, and
- * the backplane bit (7.48.0) is clear. Clause 45 PHY drivers are expected
- * to fill in the remainder of the link partner advert from vendor registers.
- */
- int genphy_c45_read_lpa(struct phy_device *phydev)
- {
- int val;
- if (genphy_c45_baset1_able(phydev))
- return genphy_c45_baset1_read_lpa(phydev);
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
- if (val < 0)
- return val;
- if (!(val & MDIO_AN_STAT1_COMPLETE)) {
- linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- phydev->lp_advertising);
- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
- mii_adv_mod_linkmode_adv_t(phydev->lp_advertising, 0);
- phydev->pause = false;
- phydev->asym_pause = false;
- return 0;
- }
- linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->lp_advertising,
- val & MDIO_AN_STAT1_LPABLE);
- /* Read the link partner's base page advertisement */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
- if (val < 0)
- return val;
- mii_adv_mod_linkmode_adv_t(phydev->lp_advertising, val);
- phydev->pause = val & LPA_PAUSE_CAP;
- phydev->asym_pause = val & LPA_PAUSE_ASYM;
- /* Read the link partner's 10G advertisement */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
- if (val < 0)
- return val;
- mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, val);
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_read_lpa);
- /**
- * genphy_c45_pma_baset1_read_master_slave - read forced master/slave
- * configuration
- * @phydev: target phy_device struct
- */
- int genphy_c45_pma_baset1_read_master_slave(struct phy_device *phydev)
- {
- int val;
- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
- phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL);
- if (val < 0)
- return val;
- if (val & MDIO_PMA_PMD_BT1_CTRL_CFG_MST) {
- phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
- } else {
- phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_read_master_slave);
- /**
- * genphy_c45_read_pma - read link speed etc from PMA
- * @phydev: target phy_device struct
- */
- int genphy_c45_read_pma(struct phy_device *phydev)
- {
- int val;
- linkmode_zero(phydev->lp_advertising);
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
- if (val < 0)
- return val;
- switch (val & MDIO_CTRL1_SPEEDSEL) {
- case 0:
- phydev->speed = SPEED_10;
- break;
- case MDIO_PMA_CTRL1_SPEED100:
- phydev->speed = SPEED_100;
- break;
- case MDIO_PMA_CTRL1_SPEED1000:
- phydev->speed = SPEED_1000;
- break;
- case MDIO_PMA_CTRL1_SPEED2_5G:
- phydev->speed = SPEED_2500;
- break;
- case MDIO_PMA_CTRL1_SPEED5G:
- phydev->speed = SPEED_5000;
- break;
- case MDIO_CTRL1_SPEED10G:
- phydev->speed = SPEED_10000;
- break;
- default:
- phydev->speed = SPEED_UNKNOWN;
- break;
- }
- phydev->duplex = DUPLEX_FULL;
- if (genphy_c45_baset1_able(phydev)) {
- val = genphy_c45_pma_baset1_read_master_slave(phydev);
- if (val < 0)
- return val;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_read_pma);
- /**
- * genphy_c45_read_mdix - read mdix status from PMA
- * @phydev: target phy_device struct
- */
- int genphy_c45_read_mdix(struct phy_device *phydev)
- {
- int val;
- if (phydev->speed == SPEED_10000) {
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
- MDIO_PMA_10GBT_SWAPPOL);
- if (val < 0)
- return val;
- switch (val) {
- case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX:
- phydev->mdix = ETH_TP_MDI;
- break;
- case 0:
- phydev->mdix = ETH_TP_MDI_X;
- break;
- default:
- phydev->mdix = ETH_TP_MDI_INVALID;
- break;
- }
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_read_mdix);
- /**
- * genphy_c45_write_eee_adv - write advertised EEE link modes
- * @phydev: target phy_device struct
- * @adv: the linkmode advertisement settings
- */
- static int genphy_c45_write_eee_adv(struct phy_device *phydev,
- unsigned long *adv)
- {
- int val, changed = 0;
- if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
- val = linkmode_to_mii_eee_cap1_t(adv);
- /* IEEE 802.3-2018 45.2.7.13 EEE advertisement 1
- * (Register 7.60)
- */
- val = phy_modify_mmd_changed(phydev, MDIO_MMD_AN,
- MDIO_AN_EEE_ADV,
- MDIO_EEE_100TX | MDIO_EEE_1000T |
- MDIO_EEE_10GT | MDIO_EEE_1000KX |
- MDIO_EEE_10GKX4 | MDIO_EEE_10GKR,
- val);
- if (val < 0)
- return val;
- if (val > 0)
- changed = 1;
- }
- if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP2_FEATURES)) {
- val = linkmode_to_mii_eee_cap2_t(adv);
- /* IEEE 802.3-2022 45.2.7.16 EEE advertisement 2
- * (Register 7.62)
- */
- val = phy_modify_mmd_changed(phydev, MDIO_MMD_AN,
- MDIO_AN_EEE_ADV2,
- MDIO_EEE_2_5GT | MDIO_EEE_5GT,
- val);
- if (val < 0)
- return val;
- if (val > 0)
- changed = 1;
- }
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
- phydev->supported_eee)) {
- val = linkmode_adv_to_mii_10base_t1_t(adv);
- /* IEEE 802.3cg-2019 45.2.7.25 10BASE-T1 AN control register
- * (Register 7.526)
- */
- val = phy_modify_mmd_changed(phydev, MDIO_MMD_AN,
- MDIO_AN_10BT1_AN_CTRL,
- MDIO_AN_10BT1_AN_CTRL_ADV_EEE_T1L,
- val);
- if (val < 0)
- return val;
- if (val > 0)
- changed = 1;
- }
- return changed;
- }
- /**
- * genphy_c45_read_eee_adv - read advertised EEE link modes
- * @phydev: target phy_device struct
- * @adv: the linkmode advertisement status
- */
- int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv)
- {
- int val;
- if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
- /* IEEE 802.3-2018 45.2.7.13 EEE advertisement 1
- * (Register 7.60)
- */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV);
- if (val < 0)
- return val;
- mii_eee_cap1_mod_linkmode_t(adv, val);
- }
- if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP2_FEATURES)) {
- /* IEEE 802.3-2022 45.2.7.16 EEE advertisement 2
- * (Register 7.62)
- */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV2);
- if (val < 0)
- return val;
- mii_eee_cap2_mod_linkmode_adv_t(adv, val);
- }
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
- phydev->supported_eee)) {
- /* IEEE 802.3cg-2019 45.2.7.25 10BASE-T1 AN control register
- * (Register 7.526)
- */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10BT1_AN_CTRL);
- if (val < 0)
- return val;
- mii_10base_t1_adv_mod_linkmode_t(adv, val);
- }
- return 0;
- }
- /**
- * genphy_c45_read_eee_lpa - read advertised LP EEE link modes
- * @phydev: target phy_device struct
- * @lpa: the linkmode LP advertisement status
- */
- static int genphy_c45_read_eee_lpa(struct phy_device *phydev,
- unsigned long *lpa)
- {
- int val;
- if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
- /* IEEE 802.3-2018 45.2.7.14 EEE link partner ability 1
- * (Register 7.61)
- */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE);
- if (val < 0)
- return val;
- mii_eee_cap1_mod_linkmode_t(lpa, val);
- }
- if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP2_FEATURES)) {
- /* IEEE 802.3-2022 45.2.7.17 EEE link partner ability 2
- * (Register 7.63)
- */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE2);
- if (val < 0)
- return val;
- mii_eee_cap2_mod_linkmode_adv_t(lpa, val);
- }
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
- phydev->supported_eee)) {
- /* IEEE 802.3cg-2019 45.2.7.26 10BASE-T1 AN status register
- * (Register 7.527)
- */
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10BT1_AN_STAT);
- if (val < 0)
- return val;
- mii_10base_t1_adv_mod_linkmode_t(lpa, val);
- }
- return 0;
- }
- /**
- * genphy_c45_read_eee_cap1 - read supported EEE link modes from register 3.20
- * @phydev: target phy_device struct
- */
- static int genphy_c45_read_eee_cap1(struct phy_device *phydev)
- {
- int val;
- /* IEEE 802.3-2018 45.2.3.10 EEE control and capability 1
- * (Register 3.20)
- */
- val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
- if (val < 0)
- return val;
- /* The 802.3 2018 standard says the top 2 bits are reserved and should
- * read as 0. Also, it seems unlikely anybody will build a PHY which
- * supports 100GBASE-R deep sleep all the way down to 100BASE-TX EEE.
- * If MDIO_PCS_EEE_ABLE is 0xffff assume EEE is not supported.
- */
- if (val == 0xffff)
- return 0;
- mii_eee_cap1_mod_linkmode_t(phydev->supported_eee, val);
- /* Some buggy devices indicate EEE link modes in MDIO_PCS_EEE_ABLE
- * which they don't support as indicated by BMSR, ESTATUS etc.
- */
- linkmode_and(phydev->supported_eee, phydev->supported_eee,
- phydev->supported);
- return 0;
- }
- /**
- * genphy_c45_read_eee_cap2 - read supported EEE link modes from register 3.21
- * @phydev: target phy_device struct
- */
- static int genphy_c45_read_eee_cap2(struct phy_device *phydev)
- {
- int val;
- /* IEEE 802.3-2022 45.2.3.11 EEE control and capability 2
- * (Register 3.21)
- */
- val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE2);
- if (val < 0)
- return val;
- /* IEEE 802.3-2022 45.2.3.11 says 9 bits are reserved. */
- if (val == 0xffff)
- return 0;
- mii_eee_cap2_mod_linkmode_sup_t(phydev->supported_eee, val);
- return 0;
- }
- /**
- * genphy_c45_read_eee_abilities - read supported EEE link modes
- * @phydev: target phy_device struct
- */
- int genphy_c45_read_eee_abilities(struct phy_device *phydev)
- {
- int val;
- /* There is not indicator whether optional register
- * "EEE control and capability 1" (3.20) is supported. Read it only
- * on devices with appropriate linkmodes.
- */
- if (linkmode_intersects(phydev->supported, PHY_EEE_CAP1_FEATURES)) {
- val = genphy_c45_read_eee_cap1(phydev);
- if (val)
- return val;
- }
- /* Same for cap2 (3.21) */
- if (linkmode_intersects(phydev->supported, PHY_EEE_CAP2_FEATURES)) {
- val = genphy_c45_read_eee_cap2(phydev);
- if (val)
- return val;
- }
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
- phydev->supported)) {
- /* IEEE 802.3cg-2019 45.2.1.186b 10BASE-T1L PMA status register
- * (Register 1.2295)
- */
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10T1L_STAT);
- if (val < 0)
- return val;
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
- phydev->supported_eee,
- val & MDIO_PMA_10T1L_STAT_EEE);
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_read_eee_abilities);
- /**
- * genphy_c45_an_config_eee_aneg - configure EEE advertisement
- * @phydev: target phy_device struct
- */
- int genphy_c45_an_config_eee_aneg(struct phy_device *phydev)
- {
- if (!phydev->eee_cfg.eee_enabled) {
- __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {};
- return genphy_c45_write_eee_adv(phydev, adv);
- }
- return genphy_c45_write_eee_adv(phydev, phydev->advertising_eee);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_an_config_eee_aneg);
- /**
- * genphy_c45_pma_baset1_read_abilities - read supported baset1 link modes from PMA
- * @phydev: target phy_device struct
- *
- * Read the supported link modes from the extended BASE-T1 ability register
- */
- int genphy_c45_pma_baset1_read_abilities(struct phy_device *phydev)
- {
- int val;
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1);
- if (val < 0)
- return val;
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_PMD_BT1_B10L_ABLE);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_PMD_BT1_B100_ABLE);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_PMD_BT1_B1000_ABLE);
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_STAT);
- if (val < 0)
- return val;
- linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- phydev->supported,
- val & MDIO_AN_STAT1_ABLE);
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_read_abilities);
- /**
- * genphy_c45_pma_read_ext_abilities - read supported link modes from PMA
- * @phydev: target phy_device struct
- *
- * Read the supported link modes from the PMA/PMD extended ability register
- * (Register 1.11).
- */
- int genphy_c45_pma_read_ext_abilities(struct phy_device *phydev)
- {
- int val;
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
- if (val < 0)
- return val;
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10GBLRM);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10GBT);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10GBKX4);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10GBKR);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_1000BT);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_1000BKX);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_100BTX);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_100BTX);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10BT);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10BT);
- if (val & MDIO_PMA_EXTABLE_NBT) {
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
- MDIO_PMA_NG_EXTABLE);
- if (val < 0)
- return val;
- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_NG_EXTABLE_2_5GBT);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_NG_EXTABLE_5GBT);
- }
- if (val & MDIO_PMA_EXTABLE_BT1) {
- val = genphy_c45_pma_baset1_read_abilities(phydev);
- if (val < 0)
- return val;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_pma_read_ext_abilities);
- /**
- * genphy_c45_pma_read_abilities - read supported link modes from PMA
- * @phydev: target phy_device struct
- *
- * Read the supported link modes from the PMA Status 2 (1.8) register. If bit
- * 1.8.9 is set, the list of supported modes is build using the values in the
- * PMA Extended Abilities (1.11) register, indicating 1000BASET an 10G related
- * modes. If bit 1.11.14 is set, then the list is also extended with the modes
- * in the 2.5G/5G PMA Extended register (1.21), indicating if 2.5GBASET and
- * 5GBASET are supported.
- */
- int genphy_c45_pma_read_abilities(struct phy_device *phydev)
- {
- int val;
- linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
- if (phydev->c45_ids.mmds_present & MDIO_DEVS_AN) {
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
- if (val < 0)
- return val;
- if (val & MDIO_AN_STAT1_ABLE)
- linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- phydev->supported);
- }
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2);
- if (val < 0)
- return val;
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_STAT2_10GBSR);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_STAT2_10GBLR);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_STAT2_10GBER);
- if (val & MDIO_PMA_STAT2_EXTABLE) {
- val = genphy_c45_pma_read_ext_abilities(phydev);
- if (val < 0)
- return val;
- }
- /* This is optional functionality. If not supported, we may get an error
- * which should be ignored.
- */
- genphy_c45_read_eee_abilities(phydev);
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_pma_read_abilities);
- /* Read master/slave preference from registers.
- * The preference is read from the BIT(4) of BASE-T1 AN
- * advertisement register 7.515 and whether the preference
- * is forced or not, it is read from BASE-T1 AN advertisement
- * register 7.514.
- */
- int genphy_c45_baset1_read_status(struct phy_device *phydev)
- {
- int ret;
- int cfg;
- phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_ADV_L);
- if (ret < 0)
- return ret;
- cfg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_ADV_M);
- if (cfg < 0)
- return cfg;
- if (ret & MDIO_AN_T1_ADV_L_FORCE_MS) {
- if (cfg & MDIO_AN_T1_ADV_M_MST)
- phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
- else
- phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
- } else {
- if (cfg & MDIO_AN_T1_ADV_M_MST)
- phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_PREFERRED;
- else
- phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_PREFERRED;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_baset1_read_status);
- /**
- * genphy_c45_read_status - read PHY status
- * @phydev: target phy_device struct
- *
- * Reads status from PHY and sets phy_device members accordingly.
- */
- int genphy_c45_read_status(struct phy_device *phydev)
- {
- int ret;
- ret = genphy_c45_read_link(phydev);
- if (ret)
- return ret;
- phydev->speed = SPEED_UNKNOWN;
- phydev->duplex = DUPLEX_UNKNOWN;
- phydev->pause = false;
- phydev->asym_pause = false;
- if (phydev->autoneg == AUTONEG_ENABLE) {
- ret = genphy_c45_read_lpa(phydev);
- if (ret)
- return ret;
- if (genphy_c45_baset1_able(phydev)) {
- ret = genphy_c45_baset1_read_status(phydev);
- if (ret < 0)
- return ret;
- }
- phy_resolve_aneg_linkmode(phydev);
- } else {
- ret = genphy_c45_read_pma(phydev);
- }
- return ret;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_read_status);
- /**
- * genphy_c45_config_aneg - restart auto-negotiation or forced setup
- * @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 force a configuration.
- */
- int genphy_c45_config_aneg(struct phy_device *phydev)
- {
- bool changed = false;
- int ret;
- if (phydev->autoneg == AUTONEG_DISABLE)
- return genphy_c45_pma_setup_forced(phydev);
- ret = genphy_c45_an_config_aneg(phydev);
- if (ret < 0)
- return ret;
- if (ret > 0)
- changed = true;
- return genphy_c45_check_and_restart_aneg(phydev, changed);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_config_aneg);
- /* The gen10g_* functions are the old Clause 45 stub */
- int gen10g_config_aneg(struct phy_device *phydev)
- {
- return 0;
- }
- EXPORT_SYMBOL_GPL(gen10g_config_aneg);
- int genphy_c45_loopback(struct phy_device *phydev, bool enable, int speed)
- {
- if (enable && speed)
- return -EOPNOTSUPP;
- return phy_modify_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1,
- MDIO_PCS_CTRL1_LOOPBACK,
- enable ? MDIO_PCS_CTRL1_LOOPBACK : 0);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_loopback);
- /**
- * genphy_c45_fast_retrain - configure fast retrain registers
- * @phydev: target phy_device struct
- * @enable: enable fast retrain or not
- *
- * Description: If fast-retrain is enabled, we configure PHY as
- * advertising fast retrain capable and THP Bypass Request, then
- * enable fast retrain. If it is not enabled, we configure fast
- * retrain disabled.
- */
- int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable)
- {
- int ret;
- if (!enable)
- return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FSRT_CSR,
- MDIO_PMA_10GBR_FSRT_ENABLE);
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported)) {
- ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
- MDIO_AN_10GBT_CTRL_ADVFSRT2_5G);
- if (ret)
- return ret;
- ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MDIO_AN_CTRL2,
- MDIO_AN_THP_BP2_5GT);
- if (ret)
- return ret;
- }
- return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FSRT_CSR,
- MDIO_PMA_10GBR_FSRT_ENABLE);
- }
- EXPORT_SYMBOL_GPL(genphy_c45_fast_retrain);
- /**
- * genphy_c45_plca_get_cfg - get PLCA configuration from standard registers
- * @phydev: target phy_device struct
- * @plca_cfg: output structure to store the PLCA configuration
- *
- * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA
- * Management Registers specifications, this function can be used to retrieve
- * the current PLCA configuration from the standard registers in MMD 31.
- */
- int genphy_c45_plca_get_cfg(struct phy_device *phydev,
- struct phy_plca_cfg *plca_cfg)
- {
- int ret;
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_IDVER);
- if (ret < 0)
- return ret;
- if ((ret & MDIO_OATC14_PLCA_IDM) != OATC14_IDM)
- return -ENODEV;
- plca_cfg->version = ret & ~MDIO_OATC14_PLCA_IDM;
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_CTRL0);
- if (ret < 0)
- return ret;
- plca_cfg->enabled = !!(ret & MDIO_OATC14_PLCA_EN);
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_CTRL1);
- if (ret < 0)
- return ret;
- plca_cfg->node_cnt = (ret & MDIO_OATC14_PLCA_NCNT) >> 8;
- plca_cfg->node_id = (ret & MDIO_OATC14_PLCA_ID);
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR);
- if (ret < 0)
- return ret;
- plca_cfg->to_tmr = ret & MDIO_OATC14_PLCA_TOT;
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_BURST);
- if (ret < 0)
- return ret;
- plca_cfg->burst_cnt = (ret & MDIO_OATC14_PLCA_MAXBC) >> 8;
- plca_cfg->burst_tmr = (ret & MDIO_OATC14_PLCA_BTMR);
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_plca_get_cfg);
- /**
- * genphy_c45_plca_set_cfg - set PLCA configuration using standard registers
- * @phydev: target phy_device struct
- * @plca_cfg: structure containing the PLCA configuration. Fields set to -1 are
- * not to be changed.
- *
- * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA
- * Management Registers specifications, this function can be used to modify
- * the PLCA configuration using the standard registers in MMD 31.
- */
- int genphy_c45_plca_set_cfg(struct phy_device *phydev,
- const struct phy_plca_cfg *plca_cfg)
- {
- u16 val = 0;
- int ret;
- // PLCA IDVER is read-only
- if (plca_cfg->version >= 0)
- return -EINVAL;
- // first of all, disable PLCA if required
- if (plca_cfg->enabled == 0) {
- ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
- MDIO_OATC14_PLCA_CTRL0,
- MDIO_OATC14_PLCA_EN);
- if (ret < 0)
- return ret;
- }
- // check if we need to set the PLCA node count, node ID, or both
- if (plca_cfg->node_cnt >= 0 || plca_cfg->node_id >= 0) {
- /* if one between node count and node ID is -not- to be
- * changed, read the register to later perform merge/purge of
- * the configuration as appropriate
- */
- if (plca_cfg->node_cnt < 0 || plca_cfg->node_id < 0) {
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
- MDIO_OATC14_PLCA_CTRL1);
- if (ret < 0)
- return ret;
- val = ret;
- }
- if (plca_cfg->node_cnt >= 0)
- val = (val & ~MDIO_OATC14_PLCA_NCNT) |
- (plca_cfg->node_cnt << 8);
- if (plca_cfg->node_id >= 0)
- val = (val & ~MDIO_OATC14_PLCA_ID) |
- (plca_cfg->node_id);
- ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
- MDIO_OATC14_PLCA_CTRL1, val);
- if (ret < 0)
- return ret;
- }
- if (plca_cfg->to_tmr >= 0) {
- ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
- MDIO_OATC14_PLCA_TOTMR,
- plca_cfg->to_tmr);
- if (ret < 0)
- return ret;
- }
- // check if we need to set the PLCA burst count, burst timer, or both
- if (plca_cfg->burst_cnt >= 0 || plca_cfg->burst_tmr >= 0) {
- /* if one between burst count and burst timer is -not- to be
- * changed, read the register to later perform merge/purge of
- * the configuration as appropriate
- */
- if (plca_cfg->burst_cnt < 0 || plca_cfg->burst_tmr < 0) {
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
- MDIO_OATC14_PLCA_BURST);
- if (ret < 0)
- return ret;
- val = ret;
- }
- if (plca_cfg->burst_cnt >= 0)
- val = (val & ~MDIO_OATC14_PLCA_MAXBC) |
- (plca_cfg->burst_cnt << 8);
- if (plca_cfg->burst_tmr >= 0)
- val = (val & ~MDIO_OATC14_PLCA_BTMR) |
- (plca_cfg->burst_tmr);
- ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
- MDIO_OATC14_PLCA_BURST, val);
- if (ret < 0)
- return ret;
- }
- // if we need to enable PLCA, do it at the end
- if (plca_cfg->enabled > 0) {
- ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
- MDIO_OATC14_PLCA_CTRL0,
- MDIO_OATC14_PLCA_EN);
- if (ret < 0)
- return ret;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_plca_set_cfg);
- /**
- * genphy_c45_plca_get_status - get PLCA status from standard registers
- * @phydev: target phy_device struct
- * @plca_st: output structure to store the PLCA status
- *
- * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA
- * Management Registers specifications, this function can be used to retrieve
- * the current PLCA status information from the standard registers in MMD 31.
- */
- int genphy_c45_plca_get_status(struct phy_device *phydev,
- struct phy_plca_status *plca_st)
- {
- int ret;
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_STATUS);
- if (ret < 0)
- return ret;
- plca_st->pst = !!(ret & MDIO_OATC14_PLCA_PST);
- return 0;
- }
- EXPORT_SYMBOL_GPL(genphy_c45_plca_get_status);
- /**
- * genphy_c45_eee_is_active - get EEE status
- * @phydev: target phy_device struct
- * @lp: variable to store LP advertised linkmodes
- *
- * Description: this function will read link partner PHY advertisement
- * and compare it to local advertisement to return current EEE state.
- */
- int genphy_c45_eee_is_active(struct phy_device *phydev, unsigned long *lp)
- {
- __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp_lp) = {};
- __ETHTOOL_DECLARE_LINK_MODE_MASK(common);
- int ret;
- if (!phydev->eee_cfg.eee_enabled)
- return 0;
- ret = genphy_c45_read_eee_lpa(phydev, tmp_lp);
- if (ret)
- return ret;
- if (lp)
- linkmode_copy(lp, tmp_lp);
- linkmode_and(common, phydev->advertising_eee, tmp_lp);
- if (linkmode_empty(common))
- return 0;
- return phy_check_valid(phydev->speed, phydev->duplex, common);
- }
- EXPORT_SYMBOL(genphy_c45_eee_is_active);
- /**
- * genphy_c45_ethtool_get_eee - get EEE supported and status
- * @phydev: target phy_device struct
- * @data: ethtool_keee data
- *
- * Description: it reports the Supported/Advertisement/LP Advertisement
- * capabilities.
- */
- int genphy_c45_ethtool_get_eee(struct phy_device *phydev,
- struct ethtool_keee *data)
- {
- int ret;
- ret = genphy_c45_eee_is_active(phydev, data->lp_advertised);
- if (ret < 0)
- return ret;
- data->eee_active = phydev->eee_active;
- linkmode_andnot(data->supported, phydev->supported_eee,
- phydev->eee_disabled_modes);
- linkmode_copy(data->advertised, phydev->advertising_eee);
- return 0;
- }
- EXPORT_SYMBOL(genphy_c45_ethtool_get_eee);
- /**
- * genphy_c45_ethtool_set_eee - set EEE supported and status
- * @phydev: target phy_device struct
- * @data: ethtool_keee data
- *
- * Description: sets the Supported/Advertisement/LP Advertisement
- * capabilities. If eee_enabled is false, no links modes are
- * advertised, but the previously advertised link modes are
- * retained. This allows EEE to be enabled/disabled in a
- * non-destructive way.
- * Returns either error code, 0 if there was no change, or positive
- * value if there was a change which triggered auto-neg.
- */
- int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
- struct ethtool_keee *data)
- {
- int ret;
- if (data->eee_enabled) {
- unsigned long *adv = data->advertised;
- if (!linkmode_empty(adv)) {
- __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp);
- if (linkmode_andnot(tmp, adv, phydev->supported_eee)) {
- phydev_warn(phydev, "At least some EEE link modes are not supported.\n");
- return -EINVAL;
- }
- linkmode_andnot(phydev->advertising_eee, adv,
- phydev->eee_disabled_modes);
- } else if (linkmode_empty(phydev->advertising_eee)) {
- phy_advertise_eee_all(phydev);
- }
- }
- ret = genphy_c45_an_config_eee_aneg(phydev);
- if (ret > 0) {
- ret = phy_restart_aneg(phydev);
- if (ret < 0)
- return ret;
- /* explicitly return 1, otherwise (ret > 0) value will be
- * overwritten by phy_restart_aneg().
- */
- return 1;
- }
- return ret;
- }
- EXPORT_SYMBOL(genphy_c45_ethtool_set_eee);
- /**
- * oatc14_cable_test_get_result_code - Convert hardware cable test status to
- * ethtool result code.
- * @status: The hardware-reported cable test status
- *
- * This helper function maps the OATC14 HDD cable test status to the
- * corresponding ethtool cable test result code. It provides a translation
- * between the device-specific status values and the standardized ethtool
- * result codes.
- *
- * Return:
- * * ETHTOOL_A_CABLE_RESULT_CODE_OK - Cable is OK
- * * ETHTOOL_A_CABLE_RESULT_CODE_OPEN - Open circuit detected
- * * ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT - Short circuit detected
- * * ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC - Status not detectable or invalid
- */
- static int oatc14_cable_test_get_result_code(enum oatc14_hdd_status status)
- {
- switch (status) {
- case OATC14_HDD_STATUS_CABLE_OK:
- return ETHTOOL_A_CABLE_RESULT_CODE_OK;
- case OATC14_HDD_STATUS_OPEN:
- return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
- case OATC14_HDD_STATUS_SHORT:
- return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
- case OATC14_HDD_STATUS_NOT_DETECTABLE:
- default:
- return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
- }
- }
- /**
- * genphy_c45_oatc14_cable_test_get_status - Get status of OATC14 10Base-T1S
- * PHY cable test.
- * @phydev: pointer to the PHY device structure
- * @finished: pointer to a boolean set true if the test is complete
- *
- * Retrieves the current status of the OATC14 10Base-T1S PHY cable test.
- * This function reads the OATC14 HDD register to determine whether the test
- * results are valid and whether the test has finished.
- *
- * If the test is complete, the function reports the cable test result via
- * the ethtool cable test interface using ethnl_cable_test_result(), and then
- * clears the test control bit in the PHY register to reset the test state.
- *
- * Return: 0 on success, or a negative error code on failure (e.g. register
- * read/write error).
- */
- int genphy_c45_oatc14_cable_test_get_status(struct phy_device *phydev,
- bool *finished)
- {
- int ret;
- u8 sts;
- *finished = false;
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_HDD);
- if (ret < 0)
- return ret;
- if (!(ret & OATC14_HDD_VALID))
- return 0;
- *finished = true;
- sts = FIELD_GET(OATC14_HDD_SHORT_OPEN_STATUS, ret);
- ret = ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
- oatc14_cable_test_get_result_code(sts));
- if (ret)
- return ret;
- return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
- MDIO_OATC14_HDD, OATC14_HDD_CONTROL);
- }
- EXPORT_SYMBOL(genphy_c45_oatc14_cable_test_get_status);
- /**
- * genphy_c45_oatc14_cable_test_start - Start a cable test on an OATC14
- * 10Base-T1S PHY.
- * @phydev: Pointer to the PHY device structure
- *
- * This function initiates a cable diagnostic test on a Clause 45 OATC14
- * 10Base-T1S capable PHY device. It first reads the PHY’s advanced diagnostic
- * capability register to check if High Definition Diagnostics (HDD) mode is
- * supported. If the PHY does not report HDD capability, cable testing is not
- * supported and the function returns -EOPNOTSUPP.
- *
- * For PHYs that support HDD, the function sets the appropriate control bits in
- * the OATC14_HDD register to enable and start the cable diagnostic test.
- *
- * Return:
- * * 0 on success
- * * -EOPNOTSUPP if the PHY does not support HDD capability
- * * A negative error code on I/O or register access failures
- */
- int genphy_c45_oatc14_cable_test_start(struct phy_device *phydev)
- {
- int ret;
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_ADFCAP);
- if (ret < 0)
- return ret;
- if (!(ret & OATC14_ADFCAP_HDD_CAPABILITY))
- return -EOPNOTSUPP;
- ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_HDD,
- OATC14_HDD_CONTROL);
- if (ret)
- return ret;
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_HDD);
- if (ret < 0)
- return ret;
- return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_HDD,
- OATC14_HDD_START_CONTROL);
- }
- EXPORT_SYMBOL(genphy_c45_oatc14_cable_test_start);
- /**
- * oatc14_update_sqi_capability - Read and update OATC14 10Base-T1S PHY SQI/SQI+
- * capability
- * @phydev: Pointer to the PHY device structure
- *
- * This helper reads the OATC14 ADFCAP capability register to determine whether
- * the PHY supports SQI or SQI+ reporting.
- *
- * SQI+ capability is detected first. The SQI+ field indicates the number of
- * valid MSBs (3–8), corresponding to 8–256 SQI+ levels. When present, the
- * function stores the number of SQI+ bits and computes the maximum SQI+ value
- * as (2^bits - 1).
- *
- * If SQI+ is not supported, the function checks for basic SQI capability,
- * which provides 0–7 SQI levels.
- *
- * On success, the capability information is stored in
- * @phydev->oatc14_sqi_capability and marked as updated.
- *
- * Return:
- * * 0 - capability successfully read and stored
- * * -EOPNOTSUPP - SQI/SQI+ not supported by this PHY
- * * Negative errno on read failure
- */
- static int oatc14_update_sqi_capability(struct phy_device *phydev)
- {
- u8 bits;
- int ret;
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_ADFCAP);
- if (ret < 0)
- return ret;
- /* Check for SQI+ capability
- * 0 - SQI+ is not supported
- * (3-8) bits for (8-256) SQI+ levels supported
- */
- bits = FIELD_GET(OATC14_ADFCAP_SQIPLUS_CAPABILITY, ret);
- if (bits) {
- phydev->oatc14_sqi_capability.sqiplus_bits = bits;
- /* Max sqi+ level supported: (2 ^ bits) - 1 */
- phydev->oatc14_sqi_capability.sqi_max = BIT(bits) - 1;
- goto update_done;
- }
- /* Check for SQI capability
- * 0 - SQI is not supported
- * 1 - SQI is supported (0-7 levels)
- */
- if (ret & OATC14_ADFCAP_SQI_CAPABILITY) {
- phydev->oatc14_sqi_capability.sqi_max = OATC14_SQI_MAX_LEVEL;
- goto update_done;
- }
- return -EOPNOTSUPP;
- update_done:
- phydev->oatc14_sqi_capability.updated = true;
- return 0;
- }
- /**
- * genphy_c45_oatc14_get_sqi_max - Get maximum supported SQI or SQI+ level of
- * OATC14 10Base-T1S PHY
- * @phydev: pointer to the PHY device structure
- *
- * This function returns the maximum supported Signal Quality Indicator (SQI) or
- * SQI+ level. The SQI capability is updated on first invocation if it has not
- * already been updated.
- *
- * Return:
- * * Maximum SQI/SQI+ level supported
- * * Negative errno on capability read failure
- */
- int genphy_c45_oatc14_get_sqi_max(struct phy_device *phydev)
- {
- int ret;
- if (!phydev->oatc14_sqi_capability.updated) {
- ret = oatc14_update_sqi_capability(phydev);
- if (ret)
- return ret;
- }
- return phydev->oatc14_sqi_capability.sqi_max;
- }
- EXPORT_SYMBOL(genphy_c45_oatc14_get_sqi_max);
- /**
- * genphy_c45_oatc14_get_sqi - Get Signal Quality Indicator (SQI) from an OATC14
- * 10Base-T1S PHY
- * @phydev: pointer to the PHY device structure
- *
- * This function reads the SQI+ or SQI value from an OATC14-compatible
- * 10Base-T1S PHY. If SQI+ capability is supported, the function returns the
- * extended SQI+ value; otherwise, it returns the basic SQI value. The SQI
- * capability is updated on first invocation if it has not already been updated.
- *
- * Return:
- * * SQI/SQI+ value on success
- * * Negative errno on read failure
- */
- int genphy_c45_oatc14_get_sqi(struct phy_device *phydev)
- {
- u8 shift;
- int ret;
- if (!phydev->oatc14_sqi_capability.updated) {
- ret = oatc14_update_sqi_capability(phydev);
- if (ret)
- return ret;
- }
- /* Calculate and return SQI+ value if supported */
- if (phydev->oatc14_sqi_capability.sqiplus_bits) {
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
- MDIO_OATC14_DCQ_SQIPLUS);
- if (ret < 0)
- return ret;
- /* SQI+ uses N MSBs out of 8 bits, left-aligned with padding 1's
- * Calculate the right-shift needed to isolate the N bits.
- */
- shift = 8 - phydev->oatc14_sqi_capability.sqiplus_bits;
- return (ret & OATC14_DCQ_SQIPLUS_VALUE) >> shift;
- }
- /* Read and return SQI value if SQI+ capability is not supported */
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_DCQ_SQI);
- if (ret < 0)
- return ret;
- return ret & OATC14_DCQ_SQI_VALUE;
- }
- EXPORT_SYMBOL(genphy_c45_oatc14_get_sqi);
|