// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause) /* * Copyright (c) 2014-2025, Advanced Micro Devices, Inc. * Copyright (c) 2014, Synopsys, Inc. * All rights reserved
*/
staticvoid xgbe_kr_mode(struct xgbe_prv_data *pdata)
{ /* Set MAC to 10G speed */
pdata->hw_if.set_speed(pdata, SPEED_10000);
/* Call PHY implementation support to complete rate change */
pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR);
}
staticvoid xgbe_kx_2500_mode(struct xgbe_prv_data *pdata)
{ /* Set MAC to 2.5G speed */
pdata->hw_if.set_speed(pdata, SPEED_2500);
/* Call PHY implementation support to complete rate change */
pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500);
}
staticvoid xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
{ /* Set MAC to 1G speed */
pdata->hw_if.set_speed(pdata, SPEED_1000);
/* Call PHY implementation support to complete rate change */
pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000);
}
staticvoid xgbe_sfi_mode(struct xgbe_prv_data *pdata)
{ /* If a KR re-driver is present, change to KR mode instead */ if (pdata->kr_redrv) return xgbe_kr_mode(pdata);
/* Set MAC to 10G speed */
pdata->hw_if.set_speed(pdata, SPEED_10000);
/* Call PHY implementation support to complete rate change */
pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SFI);
}
staticvoid xgbe_x_mode(struct xgbe_prv_data *pdata)
{ /* Set MAC to 1G speed */
pdata->hw_if.set_speed(pdata, SPEED_1000);
/* Call PHY implementation support to complete rate change */
pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_X);
}
staticvoid xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
{ /* Set MAC to 1G speed */
pdata->hw_if.set_speed(pdata, SPEED_1000);
/* Call PHY implementation support to complete rate change */
pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000);
}
staticvoid xgbe_sgmii_10_mode(struct xgbe_prv_data *pdata)
{ /* Set MAC to 10M speed */
pdata->hw_if.set_speed(pdata, SPEED_10);
/* Call PHY implementation support to complete rate change */
pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_10);
}
staticvoid xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata)
{ /* Set MAC to 1G speed */
pdata->hw_if.set_speed(pdata, SPEED_1000);
/* Call PHY implementation support to complete rate change */
pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_100);
}
netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n");
}
staticvoid xgbe_an_restart(struct xgbe_prv_data *pdata)
{ if (pdata->phy_if.phy_impl.an_pre)
pdata->phy_if.phy_impl.an_pre(pdata);
switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_restart(pdata); break; case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37_SGMII:
xgbe_an37_restart(pdata); break; default: break;
}
}
staticvoid xgbe_an_disable(struct xgbe_prv_data *pdata)
{ if (pdata->phy_if.phy_impl.an_post)
pdata->phy_if.phy_impl.an_post(pdata);
switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_disable(pdata); break; case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37_SGMII:
xgbe_an37_disable(pdata); break; default: break;
}
}
/* Read Base Ability register 2 first */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
/* Check for a supported mode, otherwise restart in a different one */
link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20; if (!(reg & link_support)) return XGBE_AN_INCOMPAT_LINK;
/* Check Extended Next Page support */
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
/* Disable AN interrupts */
xgbe_an37_disable_interrupts(pdata);
/* Save the interrupt(s) that fired */
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
pdata->an_int = reg & XGBE_AN_CL37_INT_MASK;
pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK;
if (pdata->an_int) { /* Clear the interrupt(s) that fired and process them */
reg &= ~XGBE_AN_CL37_INT_MASK;
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_isr(pdata); break; case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37_SGMII:
xgbe_an37_isr(pdata); break; default: break;
}
}
/* Avoid a race between enabling the IRQ and exiting the work by * waiting for the work to finish and then queueing it
*/
flush_work(&pdata->an_work);
queue_work(pdata->an_workqueue, &pdata->an_work);
}
staticconstchar *xgbe_state_as_string(enum xgbe_an state)
{ switch (state) { case XGBE_AN_READY: return"Ready"; case XGBE_AN_PAGE_RECEIVED: return"Page-Received"; case XGBE_AN_INCOMPAT_LINK: return"Incompatible-Link"; case XGBE_AN_COMPLETE: return"Complete"; case XGBE_AN_NO_LINK: return"No-Link"; case XGBE_AN_ERROR: return"Error"; default: return"Undefined";
}
}
/* 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;
}
netif_dbg(pdata, link, pdata->netdev, "CL37 AN %s\n",
xgbe_state_as_string(pdata->an_state));
cur_state = pdata->an_state;
switch (pdata->an_state) { case XGBE_AN_READY: break;
case XGBE_AN_COMPLETE:
netif_dbg(pdata, link, pdata->netdev, "Auto negotiation successful\n"); break;
case XGBE_AN_NO_LINK: break;
default:
pdata->an_state = XGBE_AN_ERROR;
}
if (pdata->an_state == XGBE_AN_ERROR) {
netdev_err(pdata->netdev, "error during auto-negotiation, state=%u\n",
cur_state);
switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_state_machine(pdata); break; case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37_SGMII:
xgbe_an37_state_machine(pdata); break; default: break;
}
/* Reissue interrupt if status is not clear */ if (pdata->vdata->irq_reissue_support)
XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
/* Set up the Control register */
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
reg &= ~XGBE_AN_CL37_TX_CONFIG_MASK;
reg &= ~XGBE_AN_CL37_PCS_MODE_MASK;
switch (pdata->an_mode) { case XGBE_AN_MODE_CL37:
reg |= XGBE_AN_CL37_PCS_MODE_BASEX; break; case XGBE_AN_MODE_CL37_SGMII:
reg |= XGBE_AN_CL37_PCS_MODE_SGMII; break; default: break;
}
netif_dbg(pdata, link, pdata->netdev, "CL73 AN initialized\n");
}
staticvoid xgbe_an_init(struct xgbe_prv_data *pdata)
{ /* Set up advertisement registers based on current settings */
pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata); switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_init(pdata); break; case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37_SGMII:
xgbe_an37_init(pdata); break; default: break;
}
}
staticconstchar *xgbe_phy_speed_string(int speed)
{ switch (speed) { case SPEED_10: return"10Mbps"; case SPEED_100: return"100Mbps"; case SPEED_1000: return"1Gbps"; case SPEED_2500: return"2.5Gbps"; case SPEED_10000: return"10Gbps"; case SPEED_UNKNOWN: return"Unknown"; default: return"Unsupported";
}
}
staticvoid xgbe_phy_print_status(struct xgbe_prv_data *pdata)
{ if (pdata->phy.link)
netdev_info(pdata->netdev, "Link is Up - %s/%s - flow control %s\n",
xgbe_phy_speed_string(pdata->phy.speed),
pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
xgbe_phy_fc_string(pdata)); else
netdev_info(pdata->netdev, "Link is Down\n");
}
staticvoid xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
{ int new_state = 0;
if (pdata->phy.link) { /* Flow control support */
pdata->pause_autoneg = pdata->phy.pause_autoneg;
/* Set specified mode for specified speed */
mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed); switch (mode) { case XGBE_MODE_KX_1000: case XGBE_MODE_KX_2500: case XGBE_MODE_KR: case XGBE_MODE_SGMII_10: case XGBE_MODE_SGMII_100: case XGBE_MODE_SGMII_1000: case XGBE_MODE_X: case XGBE_MODE_SFI: break; case XGBE_MODE_UNKNOWN: default: return -EINVAL;
}
/* Force the mode change for SFI in Fixed PHY config. * Fixed PHY configs needs PLL to be enabled while doing mode set. * When the SFP module isn't connected during boot, driver assumes * AN is ON and attempts autonegotiation. However, if the connected * SFP comes up in Fixed PHY config, the link will not come up as * PLL isn't enabled while the initial mode set command is issued. * So, force the mode change for SFI in Fixed PHY configuration to * fix link issues.
*/ if (mode == XGBE_MODE_SFI)
xgbe_change_mode(pdata, mode); else
xgbe_set_mode(pdata, mode);
return 0;
}
staticint __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
{ int ret;
link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ); if (time_after(jiffies, link_timeout)) { if ((xgbe_cur_mode(pdata) == XGBE_MODE_KR) &&
pdata->phy.autoneg == AUTONEG_ENABLE) { /* AN restart should not happen while KR training is in progress. * The while loop ensures no AN restart during KR training, * waits up to 500ms and AN restart is triggered only if KR * training is failed.
*/
wait = XGBE_KR_TRAINING_WAIT_ITER; while (wait--) {
kr_time = pdata->kr_start_time +
msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); if (time_after(jiffies, kr_time)) break; /* AN restart is not required, if AN result is COMPLETE */ if (pdata->an_result == XGBE_AN_COMPLETE) return;
usleep_range(10000, 11000);
}
}
netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n");
xgbe_phy_config_aneg(pdata);
}
}
pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata,
&an_restart); /* bail out if the link status register read fails */ if (pdata->phy.link < 0) return;
if (an_restart) {
xgbe_phy_config_aneg(pdata); goto adjust_link;
}
if (pdata->phy.link) { if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
xgbe_check_link_timeout(pdata); return;
}
if (xgbe_phy_status_result(pdata)) return;
if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
netif_carrier_on(pdata->netdev);
} else { if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
xgbe_check_link_timeout(pdata);
/* Fix up Flow Control advertising */
XGBE_CLR_ADV(lks, Pause);
XGBE_CLR_ADV(lks, Asym_Pause);
if (pdata->rx_pause) {
XGBE_SET_ADV(lks, Pause);
XGBE_SET_ADV(lks, Asym_Pause);
}
if (pdata->tx_pause) { /* Equivalent to XOR of Asym_Pause */ if (XGBE_ADV(lks, Asym_Pause))
XGBE_CLR_ADV(lks, Asym_Pause); else
XGBE_SET_ADV(lks, Asym_Pause);
}
if (netif_msg_drv(pdata))
xgbe_dump_phy_registers(pdata);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.