mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-22 10:48:02 +00:00
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:
parent
d56a6f0516
commit
445bed5c4d
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue