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
This commit is contained in:
Stephan de Wit 2024-02-02 12:17:14 -07:00 committed by Warner Losh
parent d56a6f0516
commit 445bed5c4d
5 changed files with 209 additions and 91 deletions

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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);
}