From nobody Fri Feb 02 19:38:06 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4TRQzf4cSvz586qY; Fri, 2 Feb 2024 19:38:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4TRQzf4NrNz4rW3; Fri, 2 Feb 2024 19:38:06 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1706902686; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=M0RGcOpt1ZblBdGBwA09bJEtwixmt8tkIwW4WS1AoVw=; b=hn2V+fameGvcARnQvuYr6xZd+j7d0su4W4XKbJ9M8wabUbrfkbfmcdoTfhtN8rZ0wmRlXE R8+9pMbNmHxrdDg8thLrQ4/8USvRrlH0Ed0IdhrFSAbcr85ckNBrvDlrAmcGrYsx+LFvVi C+6NaSn0C1AR/qAZHJXOJI8DM5XeBx2UEHkvNSvzViGAbskqELBoCCX2Uk0WSB4EmfIXC0 FmFBChrQJ7g34sO+yFuRLIC0mDQzZO+Ukk+47ZlbDjLhURFOfiE9ZvKe7+tHD/rz++HCq6 9Bg4+uZ893B5lRb4lWUxCgBdub/YqE9SdBCxZoTtsfjtynIU3yWABdg4mU2O8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1706902686; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=M0RGcOpt1ZblBdGBwA09bJEtwixmt8tkIwW4WS1AoVw=; b=b2SfX8fFs1hQjVohtfCFVbZS/EjWpxsucOVmT+DFXaDWiQp0AKej5t854pi0MHsed/Q+tW 56G2JHXPyZYDxHA5Nz4KNc4GalE3ZzhU/gpdWB7tdVgyI1y1d+/e1HT76o9ff/R4uTOhdU Y14YetSW3bcv6K1AfG2gEfJYcJwZgTHEeGDMdqqvB16xJKMr2WBkQw6vJxyVC/vyi1bDpa na0bzpjQTUk8a4549ZpP3FslKJMZsjDYpo6RVEiHtujkqukVZZXF9KtlOTz/M463yzpNax Mco3EBZaBWfkN3xyvB0Ki1uLT3JBYJTBs8/Z/dOmwrbTIA0FmN/o83ZnsxhGoA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1706902686; a=rsa-sha256; cv=none; b=NQfCY7wxCSZUmMY+mIpxB0e1UceWS2fILUV0U3YMnm+qKeNm/5F/Nk5fvIwG9Iv8ydO89Q 0G+WKgkwd4DjMHrx2xXQ0OhBcb8TBLkGSv6DSFzE/NDX0fcWG/iHQUJ6UPiEUNJQ9S7Ox+ LdgzbFaSQM0xUzStUpJiD14IwxYj5Kryq6pllMzVmorWM/K4x5XuRJvHryd47jwNRJOypa S2j9lhmvZjQ27TOKFWAikI0fbh1SiOVko3Fp589DWlBJ9bHZ6cM3F5f8z6NeJm36aSGsOI PyqYp8fhOMlLRJ2kWNwRE9H/E0C+hkvDxsgvsS2L+eesv3mYXJ4zNlEWjgyWAg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4TRQzf3SqSzjtd; Fri, 2 Feb 2024 19:38:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 412Jc61p005043; Fri, 2 Feb 2024 19:38:06 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 412Jc61x005040; Fri, 2 Feb 2024 19:38:06 GMT (envelope-from git) Date: Fri, 2 Feb 2024 19:38:06 GMT Message-Id: <202402021938.412Jc61x005040@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Warner Losh Subject: git: 445bed5c4d85 - main - axgbe: Various link stability and module compatibilty improvements List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: imp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 445bed5c4d859575951361e432024396b938f863 Auto-Submitted: auto-generated The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=445bed5c4d859575951361e432024396b938f863 commit 445bed5c4d859575951361e432024396b938f863 Author: Stephan de Wit AuthorDate: 2024-02-02 19:17:14 +0000 Commit: Warner Losh CommitDate: 2024-02-02 19:21:00 +0000 axgbe: Various link stability and module compatibilty improvements Move the phy_stop() routine to if_detach() to prevent link interruptions when configuring the interface. Accompanying this is a sanity check using phy_started, which was already there but remained unused. We do not move phy_start(), as the logic there is needed for any init routine, be it attach or start. Also bring in the linux PMA_PLL change which addresses the flapping of back-to-back fiber connections. Use miibus for SFP PHYs up to 1G copper. We retry in cases where the PHY is not directly reachable. Set the correct IFM_100_SGMII flag when the phy speed has been set to 100. We remove xgbe_phy_start_aneg() since it's handled by miibus. Add support for 100 and 1000 BASE-BX fiber modules Add support for 25G multirate DACs which are capable of 10G. While here, also fixup the LINK_ERR state. It was impossible to recover from this previously. [[ Note: light style fixes by imp, slight commit message adjustment, and a warning that I don't have the hardware to validate, but the changes do track the commit message and seem otherwise OK ]] Reviewed by: imp Pull Request: https://github.com/freebsd/freebsd-src/pull/768 --- sys/dev/axgbe/if_axgbe_pci.c | 4 +- sys/dev/axgbe/xgbe-common.h | 8 ++ sys/dev/axgbe/xgbe-i2c.c | 5 +- sys/dev/axgbe/xgbe-mdio.c | 12 +- sys/dev/axgbe/xgbe-phy-v2.c | 271 ++++++++++++++++++++++++++++++------------- 5 files changed, 209 insertions(+), 91 deletions(-) diff --git a/sys/dev/axgbe/if_axgbe_pci.c b/sys/dev/axgbe/if_axgbe_pci.c index dcf769d14f75..beb4ff338dc7 100644 --- a/sys/dev/axgbe/if_axgbe_pci.c +++ b/sys/dev/axgbe/if_axgbe_pci.c @@ -1534,6 +1534,7 @@ axgbe_if_detach(if_ctx_t ctx) mac_res[0] = pdata->xgmac_res; mac_res[1] = pdata->xpcs_res; + phy_if->phy_stop(pdata); phy_if->phy_exit(pdata); /* Free Interrupts */ @@ -1605,7 +1606,6 @@ axgbe_pci_stop(if_ctx_t ctx) { struct axgbe_if_softc *sc = iflib_get_softc(ctx); struct xgbe_prv_data *pdata = &sc->pdata; - struct xgbe_phy_if *phy_if = &pdata->phy_if; struct xgbe_hw_if *hw_if = &pdata->hw_if; int ret; @@ -1620,8 +1620,6 @@ axgbe_pci_stop(if_ctx_t ctx) hw_if->disable_tx(pdata); hw_if->disable_rx(pdata); - phy_if->phy_stop(pdata); - ret = hw_if->exit(pdata); if (ret) axgbe_error("%s: exit error %d\n", __func__, ret); diff --git a/sys/dev/axgbe/xgbe-common.h b/sys/dev/axgbe/xgbe-common.h index 0f497e53cb6f..4d504682d1af 100644 --- a/sys/dev/axgbe/xgbe-common.h +++ b/sys/dev/axgbe/xgbe-common.h @@ -1363,6 +1363,10 @@ #define MDIO_VEND2_PMA_CDR_CONTROL 0x8056 #endif +#ifndef MDIO_VEND2_PMA_MISC_CTRL0 +#define MDIO_VEND2_PMA_MISC_CTRL0 0x8090 +#endif + #ifndef MDIO_CTRL1_SPEED1G #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) #endif @@ -1415,6 +1419,10 @@ #define XGBE_PMA_CDR_TRACK_EN_OFF 0x00 #define XGBE_PMA_CDR_TRACK_EN_ON 0x01 +#define XGBE_PMA_PLL_CTRL_MASK BIT(15) +#define XGBE_PMA_PLL_CTRL_ENABLE BIT(15) +#define XGBE_PMA_PLL_CTRL_DISABLE 0x0000 + /* Bit setting and getting macros * The get macro will extract the current bit field value from within * the variable diff --git a/sys/dev/axgbe/xgbe-i2c.c b/sys/dev/axgbe/xgbe-i2c.c index 59c767d0efc7..5883e96ed37e 100644 --- a/sys/dev/axgbe/xgbe-i2c.c +++ b/sys/dev/axgbe/xgbe-i2c.c @@ -438,11 +438,10 @@ xgbe_i2c_xfer(struct xgbe_prv_data *pdata, struct xgbe_i2c_op *op) } ret = state->ret; - axgbe_printf(3, "%s: i2c xfer ret %d abrt_source 0x%x \n", __func__, + axgbe_printf(3, "%s: i2c xfer ret %d abrt_source 0x%x\n", __func__, ret, state->tx_abort_source); if (ret) { - - axgbe_error("%s: i2c xfer ret %d abrt_source 0x%x \n", __func__, + axgbe_printf(1, "%s: i2c xfer ret %d abrt_source 0x%x\n", __func__, ret, state->tx_abort_source); if (state->tx_abort_source & IC_TX_ABRT_7B_ADDR_NOACK) ret = -ENOTCONN; diff --git a/sys/dev/axgbe/xgbe-mdio.c b/sys/dev/axgbe/xgbe-mdio.c index 16488055e2c6..a5a9fdd016bc 100644 --- a/sys/dev/axgbe/xgbe-mdio.c +++ b/sys/dev/axgbe/xgbe-mdio.c @@ -734,11 +734,6 @@ xgbe_an37_state_machine(struct xgbe_prv_data *pdata) if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) { pdata->an_state = XGBE_AN_COMPLETE; pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT; - - /* If SGMII is enabled, check the link status */ - if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) && - !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS)) - pdata->an_state = XGBE_AN_NO_LINK; } axgbe_printf(2, "%s: CL37 AN %s\n", __func__, @@ -1364,6 +1359,7 @@ xgbe_phy_status(struct xgbe_prv_data *pdata) if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) { axgbe_error("%s: LINK_ERR\n", __func__); pdata->phy.link = 0; + clear_bit(XGBE_LINK_ERR, &pdata->dev_state); goto adjust_link; } @@ -1443,7 +1439,10 @@ xgbe_phy_stop(struct xgbe_prv_data *pdata) static int xgbe_phy_start(struct xgbe_prv_data *pdata) { - int ret; + int ret = 0; + + if (pdata->phy_started) + return (ret); DBGPR("-->xgbe_phy_start\n"); @@ -1588,6 +1587,7 @@ xgbe_phy_init(struct xgbe_prv_data *pdata) pdata->phy.duplex = DUPLEX_FULL; } + pdata->phy_started = 0; pdata->phy.link = 0; pdata->phy.pause_autoneg = pdata->pause_autoneg; diff --git a/sys/dev/axgbe/xgbe-phy-v2.c b/sys/dev/axgbe/xgbe-phy-v2.c index 9a057c34c6c9..d8c372cac642 100644 --- a/sys/dev/axgbe/xgbe-phy-v2.c +++ b/sys/dev/axgbe/xgbe-phy-v2.c @@ -150,6 +150,9 @@ struct mtx xgbe_phy_comm_lock; /* RRC frequency during link status check */ #define XGBE_RRC_FREQUENCY 10 +/* SFP port max PHY probe retries */ +#define XGBE_SFP_PHY_RETRY_MAX 5 + enum xgbe_port_mode { XGBE_PORT_MODE_RSVD = 0, XGBE_PORT_MODE_BACKPLANE, @@ -186,10 +189,16 @@ enum xgbe_sfp_cable { enum xgbe_sfp_base { XGBE_SFP_BASE_UNKNOWN = 0, + XGBE_SFP_BASE_PX, + XGBE_SFP_BASE_BX10, + XGBE_SFP_BASE_100_FX, + XGBE_SFP_BASE_100_LX10, + XGBE_SFP_BASE_100_BX, XGBE_SFP_BASE_1000_T, XGBE_SFP_BASE_1000_SX, XGBE_SFP_BASE_1000_LX, XGBE_SFP_BASE_1000_CX, + XGBE_SFP_BASE_1000_BX, XGBE_SFP_BASE_10000_SR, XGBE_SFP_BASE_10000_LR, XGBE_SFP_BASE_10000_LRM, @@ -199,9 +208,11 @@ enum xgbe_sfp_base { enum xgbe_sfp_speed { XGBE_SFP_SPEED_UNKNOWN = 0, + XGBE_SFP_SPEED_100, XGBE_SFP_SPEED_100_1000, XGBE_SFP_SPEED_1000, XGBE_SFP_SPEED_10000, + XGBE_SFP_SPEED_25000, }; /* SFP Serial ID Base ID values relative to an offset of 0 */ @@ -225,16 +236,31 @@ enum xgbe_sfp_speed { #define XGBE_SFP_BASE_1GBE_CC_LX BIT(1) #define XGBE_SFP_BASE_1GBE_CC_CX BIT(2) #define XGBE_SFP_BASE_1GBE_CC_T BIT(3) +#define XGBE_SFP_BASE_100M_CC_LX10 BIT(4) +#define XGBE_SFP_BASE_100M_CC_FX BIT(5) +#define XGBE_SFP_BASE_CC_BX10 BIT(6) +#define XGBE_SFP_BASE_CC_PX BIT(7) #define XGBE_SFP_BASE_CABLE 8 #define XGBE_SFP_BASE_CABLE_PASSIVE BIT(2) #define XGBE_SFP_BASE_CABLE_ACTIVE BIT(3) #define XGBE_SFP_BASE_BR 12 +#define XGBE_SFP_BASE_BR_100M_MIN 0x1 +#define XGBE_SFP_BASE_BR_100M_MAX 0x2 #define XGBE_SFP_BASE_BR_1GBE_MIN 0x0a #define XGBE_SFP_BASE_BR_1GBE_MAX 0x0d #define XGBE_SFP_BASE_BR_10GBE_MIN 0x64 #define XGBE_SFP_BASE_BR_10GBE_MAX 0x68 +#define XGBE_SFP_BASE_BR_25GBE 0xFF + +/* Single mode, length of fiber in units of km */ +#define XGBE_SFP_BASE_SM_LEN_KM 14 +#define XGBE_SFP_BASE_SM_LEN_KM_MIN 0x0A + +/* Single mode, length of fiber in units of 100m */ +#define XGBE_SFP_BASE_SM_LEN_100M 15 +#define XGBE_SFP_BASE_SM_LEN_100M_MIN 0x64 #define XGBE_SFP_BASE_CU_CABLE_LEN 18 @@ -245,6 +271,14 @@ enum xgbe_sfp_speed { #define XGBE_SFP_BASE_VENDOR_REV 56 #define XGBE_SFP_BASE_VENDOR_REV_LEN 4 +/* + * Optical specification compliance - denotes wavelength + * for optical tranceivers + */ +#define XGBE_SFP_BASE_OSC 60 +#define XGBE_SFP_BASE_OSC_LEN 2 +#define XGBE_SFP_BASE_OSC_1310 0x051E + #define XGBE_SFP_BASE_CC 63 /* SFP Serial ID Extended ID values relative to an offset of 64 */ @@ -365,6 +399,7 @@ struct xgbe_phy_data { enum xgbe_mdio_reset mdio_reset; unsigned int mdio_reset_addr; unsigned int mdio_reset_gpio; + int sfp_phy_retries; /* Re-driver support */ unsigned int redrv; @@ -382,6 +417,8 @@ struct xgbe_phy_data { static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata); static int xgbe_phy_reset(struct xgbe_prv_data *pdata); +static int axgbe_ifmedia_upd(struct ifnet *ifp); +static void axgbe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); static int xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata, struct xgbe_i2c_op *i2c_op) @@ -756,6 +793,14 @@ xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) } switch (phy_data->sfp_base) { + case XGBE_SFP_BASE_100_FX: + case XGBE_SFP_BASE_100_LX10: + case XGBE_SFP_BASE_100_BX: + pdata->phy.speed = SPEED_100; + pdata->phy.duplex = DUPLEX_FULL; + pdata->phy.autoneg = AUTONEG_DISABLE; + pdata->phy.pause_autoneg = AUTONEG_DISABLE; + break; case XGBE_SFP_BASE_1000_T: case XGBE_SFP_BASE_1000_SX: case XGBE_SFP_BASE_1000_LX: @@ -777,6 +822,13 @@ xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) XGBE_SET_SUP(&pdata->phy, 1000baseX_Full); } break; + case XGBE_SFP_BASE_1000_BX: + case XGBE_SFP_BASE_PX: + pdata->phy.speed = SPEED_1000; + pdata->phy.duplex = DUPLEX_FULL; + pdata->phy.autoneg = AUTONEG_DISABLE; + pdata->phy.pause_autoneg = AUTONEG_DISABLE; + break; case XGBE_SFP_BASE_10000_SR: case XGBE_SFP_BASE_10000_LR: case XGBE_SFP_BASE_10000_LRM: @@ -844,6 +896,10 @@ xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, sfp_base = sfp_eeprom->base; switch (sfp_speed) { + case XGBE_SFP_SPEED_100: + min = XGBE_SFP_BASE_BR_100M_MIN; + max = XGBE_SFP_BASE_BR_100M_MAX; + break; case XGBE_SFP_SPEED_1000: min = XGBE_SFP_BASE_BR_1GBE_MIN; max = XGBE_SFP_BASE_BR_1GBE_MAX; @@ -852,6 +908,10 @@ xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, min = XGBE_SFP_BASE_BR_10GBE_MIN; max = XGBE_SFP_BASE_BR_10GBE_MAX; break; + case XGBE_SFP_SPEED_25000: + min = XGBE_SFP_BASE_BR_25GBE; + max = XGBE_SFP_BASE_BR_25GBE; + break; default: return (false); } @@ -867,6 +927,11 @@ xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata) if (phy_data->phydev) phy_data->phydev = 0; + + if (pdata->axgbe_miibus != NULL) { + device_delete_child(pdata->dev, pdata->axgbe_miibus); + pdata->axgbe_miibus = NULL; + } } static bool @@ -1009,49 +1074,6 @@ xgbe_get_phy_id(struct xgbe_prv_data *pdata) return (0); } -static int -xgbe_phy_start_aneg(struct xgbe_prv_data *pdata) -{ - uint16_t ctl = 0; - int changed = 0; - int ret; - - if (AUTONEG_ENABLE != pdata->phy.autoneg) { - if (SPEED_1000 == pdata->phy.speed) - ctl |= BMCR_SPEED1; - else if (SPEED_100 == pdata->phy.speed) - ctl |= BMCR_SPEED100; - - if (DUPLEX_FULL == pdata->phy.duplex) - ctl |= BMCR_FDX; - - ret = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMCR); - if (ret) - return (ret); - - ret = xgbe_phy_mii_write(pdata, pdata->mdio_addr, MII_BMCR, - (ret & ~(~(BMCR_LOOP | BMCR_ISO | BMCR_PDOWN))) | ctl); - } - - ctl = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMCR); - if (ctl < 0) - return (ctl); - - if (!(ctl & BMCR_AUTOEN) || (ctl & BMCR_ISO)) - changed = 1; - - if (changed > 0) { - ret = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMCR); - if (ret) - return (ret); - - ret = xgbe_phy_mii_write(pdata, pdata->mdio_addr, MII_BMCR, - (ret & ~(BMCR_ISO)) | (BMCR_AUTOEN | BMCR_STARTNEG)); - } - - return (0); -} - static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) { @@ -1102,7 +1124,6 @@ xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) phy_data->phydev = 1; xgbe_phy_external_phy_quirks(pdata); - xgbe_phy_start_aneg(pdata); return (0); } @@ -1115,7 +1136,7 @@ xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata) axgbe_printf(3, "%s: sfp_changed: 0x%x\n", __func__, phy_data->sfp_changed); - if (!phy_data->sfp_changed) + if (!phy_data->sfp_phy_retries && !phy_data->sfp_changed) return; phy_data->sfp_phy_avail = 0; @@ -1126,13 +1147,26 @@ xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata) /* Check access to the PHY by reading CTRL1 */ ret = xgbe_phy_i2c_mii_read(pdata, MII_BMCR); if (ret < 0) { - axgbe_error("%s: ext phy fail %d\n", __func__, ret); + phy_data->sfp_phy_retries++; + if (phy_data->sfp_phy_retries >= XGBE_SFP_PHY_RETRY_MAX) + phy_data->sfp_phy_retries = 0; + axgbe_printf(1, "%s: ext phy fail %d. retrying.\n", __func__, ret); return; } /* Successfully accessed the PHY */ phy_data->sfp_phy_avail = 1; axgbe_printf(3, "Successfully accessed External PHY\n"); + + /* Attach external PHY to the miibus */ + ret = mii_attach(pdata->dev, &pdata->axgbe_miibus, pdata->netdev, + (ifm_change_cb_t)axgbe_ifmedia_upd, + (ifm_stat_cb_t)axgbe_ifmedia_sts, BMSR_DEFCAPMASK, + pdata->mdio_addr, MII_OFFSET_ANY, MIIF_FORCEANEG); + + if (ret) { + axgbe_error("mii attach failed with err=(%d)\n", ret); + } } static bool @@ -1187,6 +1221,7 @@ xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom; uint8_t *sfp_base; + uint16_t wavelen = 0; sfp_base = sfp_eeprom->base; @@ -1211,14 +1246,19 @@ xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata) } else phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE; + wavelen = (sfp_base[XGBE_SFP_BASE_OSC] << 8) | sfp_base[XGBE_SFP_BASE_OSC + 1]; + /* * Determine the type of SFP. Certain 10G SFP+ modules read as * 1000BASE-CX. To prevent 10G DAC cables to be recognized as * 1G, we first check if it is a DAC and the bitrate is 10G. + * If it's greater than 10G, we assume the DAC is capable + * of multiple bitrates, set the MAC to 10G and hope for the best. */ if (((sfp_base[XGBE_SFP_BASE_CV] & XGBE_SFP_BASE_CV_CP) || - (phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE)) && - xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) + (phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE)) && + (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000) || + xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_25000))) phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR) phy_data->sfp_base = XGBE_SFP_BASE_10000_SR; @@ -1236,14 +1276,44 @@ xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata) phy_data->sfp_base = XGBE_SFP_BASE_1000_CX; else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_T) phy_data->sfp_base = XGBE_SFP_BASE_1000_T; + else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_100M_CC_LX10) + phy_data->sfp_base = XGBE_SFP_BASE_100_LX10; + else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_100M_CC_FX) + phy_data->sfp_base = XGBE_SFP_BASE_100_FX; + else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_CC_BX10) { + /* BX10 can be either 100 or 1000 */ + if (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_100)) { + phy_data->sfp_base = XGBE_SFP_BASE_100_BX; + } else { + /* default to 1000 */ + phy_data->sfp_base = XGBE_SFP_BASE_1000_BX; + } + } else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_CC_PX) + phy_data->sfp_base = XGBE_SFP_BASE_PX; + else if (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_1000) + && (sfp_base[XGBE_SFP_BASE_SM_LEN_KM] >= XGBE_SFP_BASE_SM_LEN_KM_MIN + || sfp_base[XGBE_SFP_BASE_SM_LEN_100M] >= XGBE_SFP_BASE_SM_LEN_100M_MIN) + && wavelen >= XGBE_SFP_BASE_OSC_1310) + phy_data->sfp_base = XGBE_SFP_BASE_1000_BX; + else if (xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_100) + && (sfp_base[XGBE_SFP_BASE_SM_LEN_KM] >= XGBE_SFP_BASE_SM_LEN_KM_MIN + || sfp_base[XGBE_SFP_BASE_SM_LEN_100M] >= XGBE_SFP_BASE_SM_LEN_100M_MIN) + && wavelen >= XGBE_SFP_BASE_OSC_1310) + phy_data->sfp_base = XGBE_SFP_BASE_100_BX; switch (phy_data->sfp_base) { + case XGBE_SFP_BASE_100_FX: + case XGBE_SFP_BASE_100_LX10: + case XGBE_SFP_BASE_100_BX: + phy_data->sfp_speed = XGBE_SFP_SPEED_100; case XGBE_SFP_BASE_1000_T: phy_data->sfp_speed = XGBE_SFP_SPEED_100_1000; break; + case XGBE_SFP_BASE_PX: case XGBE_SFP_BASE_1000_SX: case XGBE_SFP_BASE_1000_LX: case XGBE_SFP_BASE_1000_CX: + case XGBE_SFP_BASE_1000_BX: phy_data->sfp_speed = XGBE_SFP_SPEED_1000; break; case XGBE_SFP_BASE_10000_SR: @@ -1269,29 +1339,29 @@ xgbe_phy_sfp_eeprom_info(struct xgbe_prv_data *pdata, struct xgbe_sfp_ascii sfp_ascii; char *sfp_data = (char *)&sfp_ascii; - axgbe_printf(3, "SFP detected:\n"); + axgbe_printf(0, "SFP detected:\n"); memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME], XGBE_SFP_BASE_VENDOR_NAME_LEN); sfp_data[XGBE_SFP_BASE_VENDOR_NAME_LEN] = '\0'; - axgbe_printf(3, " vendor: %s\n", + axgbe_printf(0, " vendor: %s\n", sfp_data); memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN], XGBE_SFP_BASE_VENDOR_PN_LEN); sfp_data[XGBE_SFP_BASE_VENDOR_PN_LEN] = '\0'; - axgbe_printf(3, " part number: %s\n", + axgbe_printf(0, " part number: %s\n", sfp_data); memcpy(sfp_data, &sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_REV], XGBE_SFP_BASE_VENDOR_REV_LEN); sfp_data[XGBE_SFP_BASE_VENDOR_REV_LEN] = '\0'; - axgbe_printf(3, " revision level: %s\n", + axgbe_printf(0, " revision level: %s\n", sfp_data); memcpy(sfp_data, &sfp_eeprom->extd[XGBE_SFP_BASE_VENDOR_SN], XGBE_SFP_BASE_VENDOR_SN_LEN); sfp_data[XGBE_SFP_BASE_VENDOR_SN_LEN] = '\0'; - axgbe_printf(3, " serial number: %s\n", + axgbe_printf(0, " serial number: %s\n", sfp_data); } @@ -1337,14 +1407,15 @@ xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata) &eeprom_addr, sizeof(eeprom_addr), &sfp_eeprom, sizeof(sfp_eeprom)); - eeprom = &sfp_eeprom; - base = eeprom->base; - dump_sfp_eeprom(pdata, base); if (ret) { axgbe_error("I2C error reading SFP EEPROM\n"); goto put; } + eeprom = &sfp_eeprom; + base = eeprom->base; + dump_sfp_eeprom(pdata, base); + /* Validate the contents read */ if (!xgbe_phy_sfp_verify_eeprom(sfp_eeprom.base[XGBE_SFP_BASE_CC], sfp_eeprom.base, sizeof(sfp_eeprom.base) - 1)) { @@ -1610,17 +1681,17 @@ xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) } break; case XGBE_SGMII_AN_LINK_SPEED_1000: + default: + /* Default to 1000 */ if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { XGBE_SET_LP_ADV(&pdata->phy, 1000baseT_Full); mode = XGBE_MODE_SGMII_1000; } else { /* Half-duplex not supported */ XGBE_SET_LP_ADV(&pdata->phy, 1000baseT_Half); - mode = XGBE_MODE_UNKNOWN; + mode = XGBE_MODE_SGMII_1000; } break; - default: - mode = XGBE_MODE_UNKNOWN; } return (mode); @@ -1913,7 +1984,6 @@ xgbe_phy_an_config(struct xgbe_prv_data *pdata) if (!phy_data->phydev) return (0); - ret = xgbe_phy_start_aneg(pdata); return (ret); } @@ -2022,6 +2092,16 @@ xgbe_phy_set_redrv_mode(struct xgbe_prv_data *pdata) xgbe_phy_put_comm_ownership(pdata); } +static void +xgbe_phy_pll_ctrl(struct xgbe_prv_data *pdata, bool enable) +{ + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_MISC_CTRL0, + XGBE_PMA_PLL_CTRL_MASK, + enable ? XGBE_PMA_PLL_CTRL_ENABLE + : XGBE_PMA_PLL_CTRL_DISABLE); + DELAY(200); +} + static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, unsigned int cmd, unsigned int sub_cmd) @@ -2029,6 +2109,8 @@ xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, unsigned int cmd, unsigned int s0 = 0; unsigned int wait; + xgbe_phy_pll_ctrl(pdata, false); + /* Log if a previous command did not complete */ if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) axgbe_error("firmware mailbox not ready for command\n"); @@ -2047,13 +2129,16 @@ xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, unsigned int cmd, while (wait--) { if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) { axgbe_printf(3, "%s: Rate change done\n", __func__); - return; + goto reenable_pll; } DELAY(2000); } axgbe_printf(3, "firmware mailbox command did not complete\n"); + +reenable_pll: + xgbe_phy_pll_ctrl(pdata, true); } static void @@ -2436,7 +2521,7 @@ xgbe_phy_get_type(struct xgbe_prv_data *pdata, struct ifmediareq * ifmr) if(phy_data->port_mode == XGBE_PORT_MODE_NBASE_T) ifmr->ifm_active |= IFM_100_T; else if(phy_data->port_mode == XGBE_PORT_MODE_SFP) - ifmr->ifm_active |= IFM_1000_SGMII; + ifmr->ifm_active |= IFM_100_SGMII; else ifmr->ifm_active |= IFM_OTHER; break; @@ -2631,7 +2716,8 @@ xgbe_phy_valid_speed_sfp_mode(struct xgbe_phy_data *phy_data, int speed) switch (speed) { case SPEED_100: - return (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000); + return ((phy_data->sfp_speed == XGBE_SFP_SPEED_100) || + (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000)); case SPEED_1000: return ((phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000) || (phy_data->sfp_speed == XGBE_SFP_SPEED_1000)); @@ -2698,6 +2784,7 @@ xgbe_upd_link(struct xgbe_prv_data *pdata) axgbe_printf(2, "%s: Link %d\n", __func__, pdata->phy.link); reg = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMSR); + reg = xgbe_phy_mii_read(pdata, pdata->mdio_addr, MII_BMSR); if (reg < 0) return (reg); @@ -2823,6 +2910,25 @@ xgbe_phy_read_status(struct xgbe_prv_data *pdata) return (0); } +static void +xgbe_rrc(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + int ret; + + if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) { + axgbe_printf(1, "ENTERED RRC: rrc_count: %d\n", + phy_data->rrc_count); + phy_data->rrc_count = 0; + if (pdata->link_workaround) { + ret = xgbe_phy_reset(pdata); + if (ret) + axgbe_error("Error resetting phy\n"); + } else + xgbe_phy_rrc(pdata); + } +} + static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) { @@ -2848,16 +2954,28 @@ xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) axgbe_printf(1, "%s: SFP absent 0x%x & sfp_rx_los 0x%x\n", __func__, phy_data->sfp_mod_absent, phy_data->sfp_rx_los); + + if (!phy_data->sfp_mod_absent) { + xgbe_rrc(pdata); + } + return (0); } - } else { + } + + if (phy_data->phydev || phy_data->port_mode != XGBE_PORT_MODE_SFP) { + if (pdata->axgbe_miibus == NULL) { + axgbe_printf(1, "%s: miibus not initialized", __func__); + goto mdio_read; + } + mii = device_get_softc(pdata->axgbe_miibus); mii_tick(mii); - + ret = xgbe_phy_read_status(pdata); if (ret) { - axgbe_printf(2, "Link: Read status returned %d\n", ret); - return (ret); + axgbe_error("Link: Read status returned %d\n", ret); + return (0); } axgbe_printf(2, "%s: link speed %#x duplex %#x media %#x " @@ -2869,9 +2987,14 @@ xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) if ((pdata->phy.autoneg == AUTONEG_ENABLE) && !ret) return (0); - return (pdata->phy.link); + if (pdata->phy.link) + return (1); + + xgbe_rrc(pdata); } +mdio_read: + /* Link status is latched low, so read once to clear * and then read again to get current state */ @@ -2882,17 +3005,7 @@ xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) return (1); /* No link, attempt a receiver reset cycle */ - if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) { - axgbe_printf(1, "ENTERED RRC: rrc_count: %d\n", - phy_data->rrc_count); - phy_data->rrc_count = 0; - if (pdata->link_workaround) { - ret = xgbe_phy_reset(pdata); - if (ret) - axgbe_error("Error resetting phy\n"); - } else - xgbe_phy_rrc(pdata); - } + xgbe_rrc(pdata); return (0); }