diff options
Diffstat (limited to 'common/dpdk/recipes-extended/dpdk/dpdk/dpdk-dev-v3-06-18-net-axgbe-add-phy-programming-apis.patch')
-rw-r--r-- | common/dpdk/recipes-extended/dpdk/dpdk/dpdk-dev-v3-06-18-net-axgbe-add-phy-programming-apis.patch | 2468 |
1 files changed, 0 insertions, 2468 deletions
diff --git a/common/dpdk/recipes-extended/dpdk/dpdk/dpdk-dev-v3-06-18-net-axgbe-add-phy-programming-apis.patch b/common/dpdk/recipes-extended/dpdk/dpdk/dpdk-dev-v3-06-18-net-axgbe-add-phy-programming-apis.patch deleted file mode 100644 index 3202f23a..00000000 --- a/common/dpdk/recipes-extended/dpdk/dpdk/dpdk-dev-v3-06-18-net-axgbe-add-phy-programming-apis.patch +++ /dev/null @@ -1,2468 +0,0 @@ -From patchwork Fri Mar 9 08:42:22 2018 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [dpdk-dev,v3,06/18] net/axgbe: add phy programming apis -From: Ravi Kumar <ravi1.kumar@amd.com> -X-Patchwork-Id: 35825 -X-Patchwork-Delegate: ferruh.yigit@intel.com -Message-Id: <1520584954-130575-6-git-send-email-Ravi1.kumar@amd.com> -List-Id: dev.dpdk.org -To: dev@dpdk.org -Cc: ferruh.yigit@intel.com -Date: Fri, 9 Mar 2018 03:42:22 -0500 - -Signed-off-by: Ravi Kumar <Ravi1.kumar@amd.com> ---- - drivers/net/axgbe/axgbe_dev.c | 27 + - drivers/net/axgbe/axgbe_mdio.c | 963 +++++++++++++++++++++++++ - drivers/net/axgbe/axgbe_phy_impl.c | 1397 ++++++++++++++++++++++++++++++++++++ - 3 files changed, 2387 insertions(+) - -diff --git a/drivers/net/axgbe/axgbe_dev.c b/drivers/net/axgbe/axgbe_dev.c -index 90a99c4..528241e 100644 ---- a/drivers/net/axgbe/axgbe_dev.c -+++ b/drivers/net/axgbe/axgbe_dev.c -@@ -310,6 +310,30 @@ static void axgbe_write_mmd_regs(struct axgbe_port *pdata, int prtad, - } - } - -+static int axgbe_set_speed(struct axgbe_port *pdata, int speed) -+{ -+ unsigned int ss; -+ -+ switch (speed) { -+ case SPEED_1000: -+ ss = 0x03; -+ break; -+ case SPEED_2500: -+ ss = 0x02; -+ break; -+ case SPEED_10000: -+ ss = 0x00; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (AXGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) != ss) -+ AXGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, ss); -+ -+ return 0; -+} -+ - static int __axgbe_exit(struct axgbe_port *pdata) - { - unsigned int count = 2000; -@@ -346,9 +370,12 @@ void axgbe_init_function_ptrs_dev(struct axgbe_hw_if *hw_if) - { - hw_if->exit = axgbe_exit; - -+ - hw_if->read_mmd_regs = axgbe_read_mmd_regs; - hw_if->write_mmd_regs = axgbe_write_mmd_regs; - -+ hw_if->set_speed = axgbe_set_speed; -+ - hw_if->set_ext_mii_mode = axgbe_set_ext_mii_mode; - hw_if->read_ext_mii_regs = axgbe_read_ext_mii_regs; - hw_if->write_ext_mii_regs = axgbe_write_ext_mii_regs; -diff --git a/drivers/net/axgbe/axgbe_mdio.c b/drivers/net/axgbe/axgbe_mdio.c -index 4fbf5c3..753dde9 100644 ---- a/drivers/net/axgbe/axgbe_mdio.c -+++ b/drivers/net/axgbe/axgbe_mdio.c -@@ -129,6 +129,963 @@ - #include "axgbe_common.h" - #include "axgbe_phy.h" - -+static void axgbe_an37_clear_interrupts(struct axgbe_port *pdata) -+{ -+ int reg; -+ -+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT); -+ reg &= ~AXGBE_AN_CL37_INT_MASK; -+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg); -+} -+ -+static void axgbe_an37_disable_interrupts(struct axgbe_port *pdata) -+{ -+ int reg; -+ -+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); -+ reg &= ~AXGBE_AN_CL37_INT_MASK; -+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); -+ -+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL); -+ reg &= ~AXGBE_PCS_CL37_BP; -+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg); -+} -+ -+static void axgbe_an73_clear_interrupts(struct axgbe_port *pdata) -+{ -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); -+} -+ -+static void axgbe_an73_disable_interrupts(struct axgbe_port *pdata) -+{ -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); -+} -+ -+static void axgbe_an73_enable_interrupts(struct axgbe_port *pdata) -+{ -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, -+ AXGBE_AN_CL73_INT_MASK); -+} -+ -+static void axgbe_an_enable_interrupts(struct axgbe_port *pdata) -+{ -+ switch (pdata->an_mode) { -+ case AXGBE_AN_MODE_CL73: -+ case AXGBE_AN_MODE_CL73_REDRV: -+ axgbe_an73_enable_interrupts(pdata); -+ break; -+ case AXGBE_AN_MODE_CL37: -+ case AXGBE_AN_MODE_CL37_SGMII: -+ PMD_DRV_LOG(ERR, "Unsupported AN_MOD_37"); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void axgbe_an_clear_interrupts_all(struct axgbe_port *pdata) -+{ -+ axgbe_an73_clear_interrupts(pdata); -+ axgbe_an37_clear_interrupts(pdata); -+} -+ -+static void axgbe_an73_enable_kr_training(struct axgbe_port *pdata) -+{ -+ unsigned int reg; -+ -+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); -+ -+ reg |= AXGBE_KR_TRAINING_ENABLE; -+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); -+} -+ -+static void axgbe_an73_disable_kr_training(struct axgbe_port *pdata) -+{ -+ unsigned int reg; -+ -+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); -+ -+ reg &= ~AXGBE_KR_TRAINING_ENABLE; -+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); -+} -+ -+static void axgbe_kr_mode(struct axgbe_port *pdata) -+{ -+ /* Enable KR training */ -+ axgbe_an73_enable_kr_training(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, AXGBE_MODE_KR); -+} -+ -+static void axgbe_kx_2500_mode(struct axgbe_port *pdata) -+{ -+ /* Disable KR training */ -+ axgbe_an73_disable_kr_training(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, AXGBE_MODE_KX_2500); -+} -+ -+static void axgbe_kx_1000_mode(struct axgbe_port *pdata) -+{ -+ /* Disable KR training */ -+ axgbe_an73_disable_kr_training(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, AXGBE_MODE_KX_1000); -+} -+ -+static void axgbe_sfi_mode(struct axgbe_port *pdata) -+{ -+ /* If a KR re-driver is present, change to KR mode instead */ -+ if (pdata->kr_redrv) -+ return axgbe_kr_mode(pdata); -+ -+ /* Disable KR training */ -+ axgbe_an73_disable_kr_training(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, AXGBE_MODE_SFI); -+} -+ -+static void axgbe_x_mode(struct axgbe_port *pdata) -+{ -+ /* Disable KR training */ -+ axgbe_an73_disable_kr_training(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, AXGBE_MODE_X); -+} -+ -+static void axgbe_sgmii_1000_mode(struct axgbe_port *pdata) -+{ -+ /* Disable KR training */ -+ axgbe_an73_disable_kr_training(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, AXGBE_MODE_SGMII_1000); -+} -+ -+static void axgbe_sgmii_100_mode(struct axgbe_port *pdata) -+{ -+ /* Disable KR training */ -+ axgbe_an73_disable_kr_training(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, AXGBE_MODE_SGMII_100); -+} -+ -+static enum axgbe_mode axgbe_cur_mode(struct axgbe_port *pdata) -+{ -+ return pdata->phy_if.phy_impl.cur_mode(pdata); -+} -+ -+static bool axgbe_in_kr_mode(struct axgbe_port *pdata) -+{ -+ return axgbe_cur_mode(pdata) == AXGBE_MODE_KR; -+} -+ -+static void axgbe_change_mode(struct axgbe_port *pdata, -+ enum axgbe_mode mode) -+{ -+ switch (mode) { -+ case AXGBE_MODE_KX_1000: -+ axgbe_kx_1000_mode(pdata); -+ break; -+ case AXGBE_MODE_KX_2500: -+ axgbe_kx_2500_mode(pdata); -+ break; -+ case AXGBE_MODE_KR: -+ axgbe_kr_mode(pdata); -+ break; -+ case AXGBE_MODE_SGMII_100: -+ axgbe_sgmii_100_mode(pdata); -+ break; -+ case AXGBE_MODE_SGMII_1000: -+ axgbe_sgmii_1000_mode(pdata); -+ break; -+ case AXGBE_MODE_X: -+ axgbe_x_mode(pdata); -+ break; -+ case AXGBE_MODE_SFI: -+ axgbe_sfi_mode(pdata); -+ break; -+ case AXGBE_MODE_UNKNOWN: -+ break; -+ default: -+ PMD_DRV_LOG(ERR, "invalid operation mode requested (%u)", mode); -+ } -+} -+ -+static void axgbe_switch_mode(struct axgbe_port *pdata) -+{ -+ axgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata)); -+} -+ -+static void axgbe_set_mode(struct axgbe_port *pdata, -+ enum axgbe_mode mode) -+{ -+ if (mode == axgbe_cur_mode(pdata)) -+ return; -+ -+ axgbe_change_mode(pdata, mode); -+} -+ -+static bool axgbe_use_mode(struct axgbe_port *pdata, -+ enum axgbe_mode mode) -+{ -+ return pdata->phy_if.phy_impl.use_mode(pdata, mode); -+} -+ -+static void axgbe_an37_set(struct axgbe_port *pdata, bool enable, -+ bool restart) -+{ -+ unsigned int reg; -+ -+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1); -+ reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE; -+ -+ if (enable) -+ reg |= MDIO_VEND2_CTRL1_AN_ENABLE; -+ -+ if (restart) -+ reg |= MDIO_VEND2_CTRL1_AN_RESTART; -+ -+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg); -+} -+ -+static void axgbe_an37_disable(struct axgbe_port *pdata) -+{ -+ axgbe_an37_set(pdata, false, false); -+ axgbe_an37_disable_interrupts(pdata); -+} -+ -+static void axgbe_an73_set(struct axgbe_port *pdata, bool enable, -+ bool restart) -+{ -+ unsigned int reg; -+ -+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1); -+ reg &= ~MDIO_AN_CTRL1_ENABLE; -+ -+ if (enable) -+ reg |= MDIO_AN_CTRL1_ENABLE; -+ -+ if (restart) -+ reg |= MDIO_AN_CTRL1_RESTART; -+ -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg); -+} -+ -+static void axgbe_an73_restart(struct axgbe_port *pdata) -+{ -+ axgbe_an73_enable_interrupts(pdata); -+ axgbe_an73_set(pdata, true, true); -+} -+ -+static void axgbe_an73_disable(struct axgbe_port *pdata) -+{ -+ axgbe_an73_set(pdata, false, false); -+ axgbe_an73_disable_interrupts(pdata); -+} -+ -+static void axgbe_an_restart(struct axgbe_port *pdata) -+{ -+ switch (pdata->an_mode) { -+ case AXGBE_AN_MODE_CL73: -+ case AXGBE_AN_MODE_CL73_REDRV: -+ axgbe_an73_restart(pdata); -+ break; -+ case AXGBE_AN_MODE_CL37: -+ case AXGBE_AN_MODE_CL37_SGMII: -+ PMD_DRV_LOG(ERR, "Unsupported AN_MODE_CL37"); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void axgbe_an_disable(struct axgbe_port *pdata) -+{ -+ switch (pdata->an_mode) { -+ case AXGBE_AN_MODE_CL73: -+ case AXGBE_AN_MODE_CL73_REDRV: -+ axgbe_an73_disable(pdata); -+ break; -+ case AXGBE_AN_MODE_CL37: -+ case AXGBE_AN_MODE_CL37_SGMII: -+ PMD_DRV_LOG(ERR, "Unsupported AN_MODE_CL37"); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void axgbe_an_disable_all(struct axgbe_port *pdata) -+{ -+ axgbe_an73_disable(pdata); -+ axgbe_an37_disable(pdata); -+} -+ -+static enum axgbe_an axgbe_an73_tx_training(struct axgbe_port *pdata, -+ enum axgbe_rx *state) -+{ -+ unsigned int ad_reg, lp_reg, reg; -+ -+ *state = AXGBE_RX_COMPLETE; -+ -+ /* If we're not in KR mode then we're done */ -+ if (!axgbe_in_kr_mode(pdata)) -+ return AXGBE_AN_PAGE_RECEIVED; -+ -+ /* Enable/Disable FEC */ -+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); -+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); -+ -+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL); -+ reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE); -+ if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) -+ reg |= pdata->fec_ability; -+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg); -+ -+ /* Start KR training */ -+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); -+ if (reg & AXGBE_KR_TRAINING_ENABLE) { -+ if (pdata->phy_if.phy_impl.kr_training_pre) -+ pdata->phy_if.phy_impl.kr_training_pre(pdata); -+ -+ reg |= AXGBE_KR_TRAINING_START; -+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, -+ reg); -+ -+ if (pdata->phy_if.phy_impl.kr_training_post) -+ pdata->phy_if.phy_impl.kr_training_post(pdata); -+ } -+ -+ return AXGBE_AN_PAGE_RECEIVED; -+} -+ -+static enum axgbe_an axgbe_an73_tx_xnp(struct axgbe_port *pdata, -+ enum axgbe_rx *state) -+{ -+ u16 msg; -+ -+ *state = AXGBE_RX_XNP; -+ -+ msg = AXGBE_XNP_MCF_NULL_MESSAGE; -+ msg |= AXGBE_XNP_MP_FORMATTED; -+ -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0); -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0); -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg); -+ -+ return AXGBE_AN_PAGE_RECEIVED; -+} -+ -+static enum axgbe_an axgbe_an73_rx_bpa(struct axgbe_port *pdata, -+ enum axgbe_rx *state) -+{ -+ unsigned int link_support; -+ unsigned int reg, ad_reg, lp_reg; -+ -+ /* 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 = axgbe_in_kr_mode(pdata) ? 0x80 : 0x20; -+ if (!(reg & link_support)) -+ return AXGBE_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); -+ -+ return ((ad_reg & AXGBE_XNP_NP_EXCHANGE) || -+ (lp_reg & AXGBE_XNP_NP_EXCHANGE)) -+ ? axgbe_an73_tx_xnp(pdata, state) -+ : axgbe_an73_tx_training(pdata, state); -+} -+ -+static enum axgbe_an axgbe_an73_rx_xnp(struct axgbe_port *pdata, -+ enum axgbe_rx *state) -+{ -+ unsigned int ad_reg, lp_reg; -+ -+ /* Check Extended Next Page support */ -+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP); -+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX); -+ -+ return ((ad_reg & AXGBE_XNP_NP_EXCHANGE) || -+ (lp_reg & AXGBE_XNP_NP_EXCHANGE)) -+ ? axgbe_an73_tx_xnp(pdata, state) -+ : axgbe_an73_tx_training(pdata, state); -+} -+ -+static enum axgbe_an axgbe_an73_page_received(struct axgbe_port *pdata) -+{ -+ enum axgbe_rx *state; -+ unsigned long an_timeout; -+ enum axgbe_an ret; -+ unsigned long ticks; -+ -+ if (!pdata->an_start) { -+ pdata->an_start = rte_get_timer_cycles(); -+ } else { -+ an_timeout = pdata->an_start + -+ msecs_to_timer_cycles(AXGBE_AN_MS_TIMEOUT); -+ ticks = rte_get_timer_cycles(); -+ if (time_after(ticks, an_timeout)) { -+ /* Auto-negotiation timed out, reset state */ -+ pdata->kr_state = AXGBE_RX_BPA; -+ pdata->kx_state = AXGBE_RX_BPA; -+ -+ pdata->an_start = rte_get_timer_cycles(); -+ } -+ } -+ -+ state = axgbe_in_kr_mode(pdata) ? &pdata->kr_state -+ : &pdata->kx_state; -+ -+ switch (*state) { -+ case AXGBE_RX_BPA: -+ ret = axgbe_an73_rx_bpa(pdata, state); -+ break; -+ case AXGBE_RX_XNP: -+ ret = axgbe_an73_rx_xnp(pdata, state); -+ break; -+ default: -+ ret = AXGBE_AN_ERROR; -+ } -+ -+ return ret; -+} -+ -+static enum axgbe_an axgbe_an73_incompat_link(struct axgbe_port *pdata) -+{ -+ /* Be sure we aren't looping trying to negotiate */ -+ if (axgbe_in_kr_mode(pdata)) { -+ pdata->kr_state = AXGBE_RX_ERROR; -+ -+ if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) && -+ !(pdata->phy.advertising & ADVERTISED_2500baseX_Full)) -+ return AXGBE_AN_NO_LINK; -+ -+ if (pdata->kx_state != AXGBE_RX_BPA) -+ return AXGBE_AN_NO_LINK; -+ } else { -+ pdata->kx_state = AXGBE_RX_ERROR; -+ -+ if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full)) -+ return AXGBE_AN_NO_LINK; -+ -+ if (pdata->kr_state != AXGBE_RX_BPA) -+ return AXGBE_AN_NO_LINK; -+ } -+ -+ axgbe_an73_disable(pdata); -+ axgbe_switch_mode(pdata); -+ axgbe_an73_restart(pdata); -+ -+ return AXGBE_AN_INCOMPAT_LINK; -+} -+ -+static void axgbe_an73_state_machine(struct axgbe_port *pdata) -+{ -+ enum axgbe_an cur_state = pdata->an_state; -+ -+ if (!pdata->an_int) -+ return; -+ -+next_int: -+ if (pdata->an_int & AXGBE_AN_CL73_PG_RCV) { -+ pdata->an_state = AXGBE_AN_PAGE_RECEIVED; -+ pdata->an_int &= ~AXGBE_AN_CL73_PG_RCV; -+ } else if (pdata->an_int & AXGBE_AN_CL73_INC_LINK) { -+ pdata->an_state = AXGBE_AN_INCOMPAT_LINK; -+ pdata->an_int &= ~AXGBE_AN_CL73_INC_LINK; -+ } else if (pdata->an_int & AXGBE_AN_CL73_INT_CMPLT) { -+ pdata->an_state = AXGBE_AN_COMPLETE; -+ pdata->an_int &= ~AXGBE_AN_CL73_INT_CMPLT; -+ } else { -+ pdata->an_state = AXGBE_AN_ERROR; -+ } -+ -+again: -+ cur_state = pdata->an_state; -+ -+ switch (pdata->an_state) { -+ case AXGBE_AN_READY: -+ pdata->an_supported = 0; -+ break; -+ case AXGBE_AN_PAGE_RECEIVED: -+ pdata->an_state = axgbe_an73_page_received(pdata); -+ pdata->an_supported++; -+ break; -+ case AXGBE_AN_INCOMPAT_LINK: -+ pdata->an_supported = 0; -+ pdata->parallel_detect = 0; -+ pdata->an_state = axgbe_an73_incompat_link(pdata); -+ break; -+ case AXGBE_AN_COMPLETE: -+ pdata->parallel_detect = pdata->an_supported ? 0 : 1; -+ break; -+ case AXGBE_AN_NO_LINK: -+ break; -+ default: -+ pdata->an_state = AXGBE_AN_ERROR; -+ } -+ -+ if (pdata->an_state == AXGBE_AN_NO_LINK) { -+ pdata->an_int = 0; -+ axgbe_an73_clear_interrupts(pdata); -+ pdata->eth_dev->data->dev_link.link_status = -+ ETH_LINK_DOWN; -+ } else if (pdata->an_state == AXGBE_AN_ERROR) { -+ PMD_DRV_LOG(ERR, "error during auto-negotiation, state=%u\n", -+ cur_state); -+ pdata->an_int = 0; -+ axgbe_an73_clear_interrupts(pdata); -+ } -+ -+ if (pdata->an_state >= AXGBE_AN_COMPLETE) { -+ pdata->an_result = pdata->an_state; -+ pdata->an_state = AXGBE_AN_READY; -+ pdata->kr_state = AXGBE_RX_BPA; -+ pdata->kx_state = AXGBE_RX_BPA; -+ pdata->an_start = 0; -+ } -+ -+ if (cur_state != pdata->an_state) -+ goto again; -+ -+ if (pdata->an_int) -+ goto next_int; -+ -+ axgbe_an73_enable_interrupts(pdata); -+} -+ -+static void axgbe_an73_isr(struct axgbe_port *pdata) -+{ -+ /* Disable AN interrupts */ -+ axgbe_an73_disable_interrupts(pdata); -+ -+ /* Save the interrupt(s) that fired */ -+ pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT); -+ -+ if (pdata->an_int) { -+ /* Clear the interrupt(s) that fired and process them */ -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int); -+ pthread_mutex_lock(&pdata->an_mutex); -+ axgbe_an73_state_machine(pdata); -+ pthread_mutex_unlock(&pdata->an_mutex); -+ } else { -+ /* Enable AN interrupts */ -+ axgbe_an73_enable_interrupts(pdata); -+ } -+} -+ -+static void axgbe_an_isr(struct axgbe_port *pdata) -+{ -+ switch (pdata->an_mode) { -+ case AXGBE_AN_MODE_CL73: -+ case AXGBE_AN_MODE_CL73_REDRV: -+ axgbe_an73_isr(pdata); -+ break; -+ case AXGBE_AN_MODE_CL37: -+ case AXGBE_AN_MODE_CL37_SGMII: -+ PMD_DRV_LOG(ERR, "AN_MODE_37 not supported"); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void axgbe_an_combined_isr(struct axgbe_port *pdata) -+{ -+ axgbe_an_isr(pdata); -+} -+ -+static void axgbe_an73_init(struct axgbe_port *pdata) -+{ -+ unsigned int advertising, reg; -+ -+ advertising = pdata->phy_if.phy_impl.an_advertising(pdata); -+ -+ /* Set up Advertisement register 3 first */ -+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); -+ if (advertising & ADVERTISED_10000baseR_FEC) -+ reg |= 0xc000; -+ else -+ reg &= ~0xc000; -+ -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg); -+ -+ /* Set up Advertisement register 2 next */ -+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); -+ if (advertising & ADVERTISED_10000baseKR_Full) -+ reg |= 0x80; -+ else -+ reg &= ~0x80; -+ -+ if ((advertising & ADVERTISED_1000baseKX_Full) || -+ (advertising & ADVERTISED_2500baseX_Full)) -+ reg |= 0x20; -+ else -+ reg &= ~0x20; -+ -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg); -+ -+ /* Set up Advertisement register 1 last */ -+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); -+ if (advertising & ADVERTISED_Pause) -+ reg |= 0x400; -+ else -+ reg &= ~0x400; -+ -+ if (advertising & ADVERTISED_Asym_Pause) -+ reg |= 0x800; -+ else -+ reg &= ~0x800; -+ -+ /* We don't intend to perform XNP */ -+ reg &= ~AXGBE_XNP_NP_EXCHANGE; -+ -+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); -+} -+ -+static void axgbe_an_init(struct axgbe_port *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 AXGBE_AN_MODE_CL73: -+ case AXGBE_AN_MODE_CL73_REDRV: -+ axgbe_an73_init(pdata); -+ break; -+ case AXGBE_AN_MODE_CL37: -+ case AXGBE_AN_MODE_CL37_SGMII: -+ PMD_DRV_LOG(ERR, "Unsupported AN_CL37"); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void axgbe_phy_adjust_link(struct axgbe_port *pdata) -+{ -+ if (pdata->phy.link) { -+ /* Speed support */ -+ if (pdata->phy_speed != pdata->phy.speed) -+ pdata->phy_speed = pdata->phy.speed; -+ if (pdata->phy_link != pdata->phy.link) -+ pdata->phy_link = pdata->phy.link; -+ } else if (pdata->phy_link) { -+ pdata->phy_link = 0; -+ pdata->phy_speed = SPEED_UNKNOWN; -+ } -+} -+ -+static int axgbe_phy_config_fixed(struct axgbe_port *pdata) -+{ -+ enum axgbe_mode mode; -+ -+ /* Disable auto-negotiation */ -+ axgbe_an_disable(pdata); -+ -+ /* Set specified mode for specified speed */ -+ mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed); -+ switch (mode) { -+ case AXGBE_MODE_KX_1000: -+ case AXGBE_MODE_KX_2500: -+ case AXGBE_MODE_KR: -+ case AXGBE_MODE_SGMII_100: -+ case AXGBE_MODE_SGMII_1000: -+ case AXGBE_MODE_X: -+ case AXGBE_MODE_SFI: -+ break; -+ case AXGBE_MODE_UNKNOWN: -+ default: -+ return -EINVAL; -+ } -+ -+ /* Validate duplex mode */ -+ if (pdata->phy.duplex != DUPLEX_FULL) -+ return -EINVAL; -+ -+ axgbe_set_mode(pdata, mode); -+ -+ return 0; -+} -+ -+static int __axgbe_phy_config_aneg(struct axgbe_port *pdata) -+{ -+ int ret; -+ -+ axgbe_set_bit(AXGBE_LINK_INIT, &pdata->dev_state); -+ pdata->link_check = rte_get_timer_cycles(); -+ -+ ret = pdata->phy_if.phy_impl.an_config(pdata); -+ if (ret) -+ return ret; -+ -+ if (pdata->phy.autoneg != AUTONEG_ENABLE) { -+ ret = axgbe_phy_config_fixed(pdata); -+ if (ret || !pdata->kr_redrv) -+ return ret; -+ } -+ -+ /* Disable auto-negotiation interrupt */ -+ rte_intr_disable(&pdata->pci_dev->intr_handle); -+ -+ /* Start auto-negotiation in a supported mode */ -+ if (axgbe_use_mode(pdata, AXGBE_MODE_KR)) { -+ axgbe_set_mode(pdata, AXGBE_MODE_KR); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_KX_2500)) { -+ axgbe_set_mode(pdata, AXGBE_MODE_KX_2500); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_KX_1000)) { -+ axgbe_set_mode(pdata, AXGBE_MODE_KX_1000); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_SFI)) { -+ axgbe_set_mode(pdata, AXGBE_MODE_SFI); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_X)) { -+ axgbe_set_mode(pdata, AXGBE_MODE_X); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_SGMII_1000)) { -+ axgbe_set_mode(pdata, AXGBE_MODE_SGMII_1000); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_SGMII_100)) { -+ axgbe_set_mode(pdata, AXGBE_MODE_SGMII_100); -+ } else { -+ rte_intr_enable(&pdata->pci_dev->intr_handle); -+ return -EINVAL; -+ } -+ -+ /* Disable and stop any in progress auto-negotiation */ -+ axgbe_an_disable_all(pdata); -+ -+ /* Clear any auto-negotitation interrupts */ -+ axgbe_an_clear_interrupts_all(pdata); -+ -+ pdata->an_result = AXGBE_AN_READY; -+ pdata->an_state = AXGBE_AN_READY; -+ pdata->kr_state = AXGBE_RX_BPA; -+ pdata->kx_state = AXGBE_RX_BPA; -+ -+ /* Re-enable auto-negotiation interrupt */ -+ rte_intr_enable(&pdata->pci_dev->intr_handle); -+ -+ axgbe_an_init(pdata); -+ axgbe_an_restart(pdata); -+ -+ return 0; -+} -+ -+static int axgbe_phy_config_aneg(struct axgbe_port *pdata) -+{ -+ int ret; -+ -+ pthread_mutex_lock(&pdata->an_mutex); -+ -+ ret = __axgbe_phy_config_aneg(pdata); -+ if (ret) -+ axgbe_set_bit(AXGBE_LINK_ERR, &pdata->dev_state); -+ else -+ axgbe_clear_bit(AXGBE_LINK_ERR, &pdata->dev_state); -+ -+ pthread_mutex_unlock(&pdata->an_mutex); -+ -+ return ret; -+} -+ -+static bool axgbe_phy_aneg_done(struct axgbe_port *pdata) -+{ -+ return pdata->an_result == AXGBE_AN_COMPLETE; -+} -+ -+static void axgbe_check_link_timeout(struct axgbe_port *pdata) -+{ -+ unsigned long link_timeout; -+ unsigned long ticks; -+ -+ link_timeout = pdata->link_check + (AXGBE_LINK_TIMEOUT * -+ 2 * rte_get_timer_hz()); -+ ticks = rte_get_timer_cycles(); -+ if (time_after(ticks, link_timeout)) -+ axgbe_phy_config_aneg(pdata); -+} -+ -+static enum axgbe_mode axgbe_phy_status_aneg(struct axgbe_port *pdata) -+{ -+ return pdata->phy_if.phy_impl.an_outcome(pdata); -+} -+ -+static void axgbe_phy_status_result(struct axgbe_port *pdata) -+{ -+ enum axgbe_mode mode; -+ -+ pdata->phy.lp_advertising = 0; -+ -+ if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect) -+ mode = axgbe_cur_mode(pdata); -+ else -+ mode = axgbe_phy_status_aneg(pdata); -+ -+ switch (mode) { -+ case AXGBE_MODE_SGMII_100: -+ pdata->phy.speed = SPEED_100; -+ break; -+ case AXGBE_MODE_X: -+ case AXGBE_MODE_KX_1000: -+ case AXGBE_MODE_SGMII_1000: -+ pdata->phy.speed = SPEED_1000; -+ break; -+ case AXGBE_MODE_KX_2500: -+ pdata->phy.speed = SPEED_2500; -+ break; -+ case AXGBE_MODE_KR: -+ case AXGBE_MODE_SFI: -+ pdata->phy.speed = SPEED_10000; -+ break; -+ case AXGBE_MODE_UNKNOWN: -+ default: -+ pdata->phy.speed = SPEED_UNKNOWN; -+ } -+ -+ pdata->phy.duplex = DUPLEX_FULL; -+ -+ axgbe_set_mode(pdata, mode); -+} -+ -+static void axgbe_phy_status(struct axgbe_port *pdata) -+{ -+ unsigned int link_aneg; -+ int an_restart; -+ -+ if (axgbe_test_bit(AXGBE_LINK_ERR, &pdata->dev_state)) { -+ pdata->phy.link = 0; -+ goto adjust_link; -+ } -+ -+ link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE); -+ -+ pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata, -+ &an_restart); -+ if (an_restart) { -+ axgbe_phy_config_aneg(pdata); -+ return; -+ } -+ -+ if (pdata->phy.link) { -+ if (link_aneg && !axgbe_phy_aneg_done(pdata)) { -+ axgbe_check_link_timeout(pdata); -+ return; -+ } -+ axgbe_phy_status_result(pdata); -+ if (axgbe_test_bit(AXGBE_LINK_INIT, &pdata->dev_state)) -+ axgbe_clear_bit(AXGBE_LINK_INIT, &pdata->dev_state); -+ } else { -+ if (axgbe_test_bit(AXGBE_LINK_INIT, &pdata->dev_state)) { -+ axgbe_check_link_timeout(pdata); -+ -+ if (link_aneg) -+ return; -+ } -+ axgbe_phy_status_result(pdata); -+ } -+ -+adjust_link: -+ axgbe_phy_adjust_link(pdata); -+} -+ -+static void axgbe_phy_stop(struct axgbe_port *pdata) -+{ -+ if (!pdata->phy_started) -+ return; -+ /* Indicate the PHY is down */ -+ pdata->phy_started = 0; -+ /* Disable auto-negotiation */ -+ axgbe_an_disable_all(pdata); -+ pdata->phy_if.phy_impl.stop(pdata); -+ pdata->phy.link = 0; -+ axgbe_phy_adjust_link(pdata); -+} -+ -+static int axgbe_phy_start(struct axgbe_port *pdata) -+{ -+ int ret; -+ -+ ret = pdata->phy_if.phy_impl.start(pdata); -+ if (ret) -+ return ret; -+ /* Set initial mode - call the mode setting routines -+ * directly to insure we are properly configured -+ */ -+ if (axgbe_use_mode(pdata, AXGBE_MODE_KR)) { -+ axgbe_kr_mode(pdata); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_KX_2500)) { -+ axgbe_kx_2500_mode(pdata); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_KX_1000)) { -+ axgbe_kx_1000_mode(pdata); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_SFI)) { -+ axgbe_sfi_mode(pdata); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_X)) { -+ axgbe_x_mode(pdata); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_SGMII_1000)) { -+ axgbe_sgmii_1000_mode(pdata); -+ } else if (axgbe_use_mode(pdata, AXGBE_MODE_SGMII_100)) { -+ axgbe_sgmii_100_mode(pdata); -+ } else { -+ ret = -EINVAL; -+ goto err_stop; -+ } -+ /* Indicate the PHY is up and running */ -+ pdata->phy_started = 1; -+ axgbe_an_init(pdata); -+ axgbe_an_enable_interrupts(pdata); -+ return axgbe_phy_config_aneg(pdata); -+ -+err_stop: -+ pdata->phy_if.phy_impl.stop(pdata); -+ -+ return ret; -+} -+ -+static int axgbe_phy_reset(struct axgbe_port *pdata) -+{ -+ int ret; -+ -+ ret = pdata->phy_if.phy_impl.reset(pdata); -+ if (ret) -+ return ret; -+ -+ /* Disable auto-negotiation for now */ -+ axgbe_an_disable_all(pdata); -+ -+ /* Clear auto-negotiation interrupts */ -+ axgbe_an_clear_interrupts_all(pdata); -+ -+ return 0; -+} -+ - static int axgbe_phy_best_advertised_speed(struct axgbe_port *pdata) - { - if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) -@@ -200,4 +1157,10 @@ static int axgbe_phy_init(struct axgbe_port *pdata) - void axgbe_init_function_ptrs_phy(struct axgbe_phy_if *phy_if) - { - phy_if->phy_init = axgbe_phy_init; -+ phy_if->phy_reset = axgbe_phy_reset; -+ phy_if->phy_start = axgbe_phy_start; -+ phy_if->phy_stop = axgbe_phy_stop; -+ phy_if->phy_status = axgbe_phy_status; -+ phy_if->phy_config_aneg = axgbe_phy_config_aneg; -+ phy_if->an_isr = axgbe_an_combined_isr; - } -diff --git a/drivers/net/axgbe/axgbe_phy_impl.c b/drivers/net/axgbe/axgbe_phy_impl.c -index cea4266..5f69651 100644 ---- a/drivers/net/axgbe/axgbe_phy_impl.c -+++ b/drivers/net/axgbe/axgbe_phy_impl.c -@@ -361,6 +361,1337 @@ struct axgbe_phy_data { - unsigned int redrv_model; - }; - -+static enum axgbe_an_mode axgbe_phy_an_mode(struct axgbe_port *pdata); -+ -+static int axgbe_phy_i2c_xfer(struct axgbe_port *pdata, -+ struct axgbe_i2c_op *i2c_op) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ /* Be sure we own the bus */ -+ if (!phy_data->comm_owned) -+ return -EIO; -+ -+ return pdata->i2c_if.i2c_xfer(pdata, i2c_op); -+} -+ -+static int axgbe_phy_redrv_write(struct axgbe_port *pdata, unsigned int reg, -+ unsigned int val) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ struct axgbe_i2c_op i2c_op; -+ uint16_t *redrv_val; -+ u8 redrv_data[5], csum; -+ unsigned int i, retry; -+ int ret; -+ -+ /* High byte of register contains read/write indicator */ -+ redrv_data[0] = ((reg >> 8) & 0xff) << 1; -+ redrv_data[1] = reg & 0xff; -+ redrv_val = (uint16_t *)&redrv_data[2]; -+ *redrv_val = rte_cpu_to_be_16(val); -+ -+ /* Calculate 1 byte checksum */ -+ csum = 0; -+ for (i = 0; i < 4; i++) { -+ csum += redrv_data[i]; -+ if (redrv_data[i] > csum) -+ csum++; -+ } -+ redrv_data[4] = ~csum; -+ -+ retry = 1; -+again1: -+ i2c_op.cmd = AXGBE_I2C_CMD_WRITE; -+ i2c_op.target = phy_data->redrv_addr; -+ i2c_op.len = sizeof(redrv_data); -+ i2c_op.buf = redrv_data; -+ ret = axgbe_phy_i2c_xfer(pdata, &i2c_op); -+ if (ret) { -+ if ((ret == -EAGAIN) && retry--) -+ goto again1; -+ -+ return ret; -+ } -+ -+ retry = 1; -+again2: -+ i2c_op.cmd = AXGBE_I2C_CMD_READ; -+ i2c_op.target = phy_data->redrv_addr; -+ i2c_op.len = 1; -+ i2c_op.buf = redrv_data; -+ ret = axgbe_phy_i2c_xfer(pdata, &i2c_op); -+ if (ret) { -+ if ((ret == -EAGAIN) && retry--) -+ goto again2; -+ -+ return ret; -+ } -+ -+ if (redrv_data[0] != 0xff) { -+ PMD_DRV_LOG(ERR, "Redriver write checksum error\n"); -+ ret = -EIO; -+ } -+ -+ return ret; -+} -+ -+static int axgbe_phy_i2c_read(struct axgbe_port *pdata, unsigned int target, -+ void *reg, unsigned int reg_len, -+ void *val, unsigned int val_len) -+{ -+ struct axgbe_i2c_op i2c_op; -+ int retry, ret; -+ -+ retry = 1; -+again1: -+ /* Set the specified register to read */ -+ i2c_op.cmd = AXGBE_I2C_CMD_WRITE; -+ i2c_op.target = target; -+ i2c_op.len = reg_len; -+ i2c_op.buf = reg; -+ ret = axgbe_phy_i2c_xfer(pdata, &i2c_op); -+ if (ret) { -+ if ((ret == -EAGAIN) && retry--) -+ goto again1; -+ -+ return ret; -+ } -+ -+ retry = 1; -+again2: -+ /* Read the specfied register */ -+ i2c_op.cmd = AXGBE_I2C_CMD_READ; -+ i2c_op.target = target; -+ i2c_op.len = val_len; -+ i2c_op.buf = val; -+ ret = axgbe_phy_i2c_xfer(pdata, &i2c_op); -+ if ((ret == -EAGAIN) && retry--) -+ goto again2; -+ -+ return ret; -+} -+ -+static int axgbe_phy_sfp_put_mux(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ struct axgbe_i2c_op i2c_op; -+ uint8_t mux_channel; -+ -+ if (phy_data->sfp_comm == AXGBE_SFP_COMM_DIRECT) -+ return 0; -+ -+ /* Select no mux channels */ -+ mux_channel = 0; -+ i2c_op.cmd = AXGBE_I2C_CMD_WRITE; -+ i2c_op.target = phy_data->sfp_mux_address; -+ i2c_op.len = sizeof(mux_channel); -+ i2c_op.buf = &mux_channel; -+ -+ return axgbe_phy_i2c_xfer(pdata, &i2c_op); -+} -+ -+static int axgbe_phy_sfp_get_mux(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ struct axgbe_i2c_op i2c_op; -+ u8 mux_channel; -+ -+ if (phy_data->sfp_comm == AXGBE_SFP_COMM_DIRECT) -+ return 0; -+ -+ /* Select desired mux channel */ -+ mux_channel = 1 << phy_data->sfp_mux_channel; -+ i2c_op.cmd = AXGBE_I2C_CMD_WRITE; -+ i2c_op.target = phy_data->sfp_mux_address; -+ i2c_op.len = sizeof(mux_channel); -+ i2c_op.buf = &mux_channel; -+ -+ return axgbe_phy_i2c_xfer(pdata, &i2c_op); -+} -+ -+static void axgbe_phy_put_comm_ownership(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ phy_data->comm_owned = 0; -+ -+ pthread_mutex_unlock(&pdata->phy_mutex); -+} -+ -+static int axgbe_phy_get_comm_ownership(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ uint64_t timeout; -+ unsigned int mutex_id; -+ -+ if (phy_data->comm_owned) -+ return 0; -+ -+ /* The I2C and MDIO/GPIO bus is multiplexed between multiple devices, -+ * the driver needs to take the software mutex and then the hardware -+ * mutexes before being able to use the busses. -+ */ -+ pthread_mutex_lock(&pdata->phy_mutex); -+ -+ /* Clear the mutexes */ -+ XP_IOWRITE(pdata, XP_I2C_MUTEX, AXGBE_MUTEX_RELEASE); -+ XP_IOWRITE(pdata, XP_MDIO_MUTEX, AXGBE_MUTEX_RELEASE); -+ -+ /* Mutex formats are the same for I2C and MDIO/GPIO */ -+ mutex_id = 0; -+ XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ID, phy_data->port_id); -+ XP_SET_BITS(mutex_id, XP_I2C_MUTEX, ACTIVE, 1); -+ -+ timeout = rte_get_timer_cycles() + (rte_get_timer_hz() * 5); -+ while (time_before(rte_get_timer_cycles(), timeout)) { -+ /* Must be all zeroes in order to obtain the mutex */ -+ if (XP_IOREAD(pdata, XP_I2C_MUTEX) || -+ XP_IOREAD(pdata, XP_MDIO_MUTEX)) { -+ rte_delay_us(100); -+ continue; -+ } -+ -+ /* Obtain the mutex */ -+ XP_IOWRITE(pdata, XP_I2C_MUTEX, mutex_id); -+ XP_IOWRITE(pdata, XP_MDIO_MUTEX, mutex_id); -+ -+ phy_data->comm_owned = 1; -+ return 0; -+ } -+ -+ pthread_mutex_unlock(&pdata->phy_mutex); -+ -+ PMD_DRV_LOG(ERR, "unable to obtain hardware mutexes"); -+ -+ return -ETIMEDOUT; -+} -+ -+static void axgbe_phy_sfp_phy_settings(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ if (phy_data->sfp_mod_absent) { -+ pdata->phy.speed = SPEED_UNKNOWN; -+ pdata->phy.duplex = DUPLEX_UNKNOWN; -+ pdata->phy.autoneg = AUTONEG_ENABLE; -+ pdata->phy.advertising = pdata->phy.supported; -+ } -+ -+ pdata->phy.advertising &= ~ADVERTISED_Autoneg; -+ pdata->phy.advertising &= ~ADVERTISED_TP; -+ pdata->phy.advertising &= ~ADVERTISED_FIBRE; -+ pdata->phy.advertising &= ~ADVERTISED_100baseT_Full; -+ pdata->phy.advertising &= ~ADVERTISED_1000baseT_Full; -+ pdata->phy.advertising &= ~ADVERTISED_10000baseT_Full; -+ pdata->phy.advertising &= ~ADVERTISED_10000baseR_FEC; -+ -+ switch (phy_data->sfp_base) { -+ case AXGBE_SFP_BASE_1000_T: -+ case AXGBE_SFP_BASE_1000_SX: -+ case AXGBE_SFP_BASE_1000_LX: -+ case AXGBE_SFP_BASE_1000_CX: -+ pdata->phy.speed = SPEED_UNKNOWN; -+ pdata->phy.duplex = DUPLEX_UNKNOWN; -+ pdata->phy.autoneg = AUTONEG_ENABLE; -+ pdata->phy.advertising |= ADVERTISED_Autoneg; -+ break; -+ case AXGBE_SFP_BASE_10000_SR: -+ case AXGBE_SFP_BASE_10000_LR: -+ case AXGBE_SFP_BASE_10000_LRM: -+ case AXGBE_SFP_BASE_10000_ER: -+ case AXGBE_SFP_BASE_10000_CR: -+ default: -+ pdata->phy.speed = SPEED_10000; -+ pdata->phy.duplex = DUPLEX_FULL; -+ pdata->phy.autoneg = AUTONEG_DISABLE; -+ break; -+ } -+ -+ switch (phy_data->sfp_base) { -+ case AXGBE_SFP_BASE_1000_T: -+ case AXGBE_SFP_BASE_1000_CX: -+ case AXGBE_SFP_BASE_10000_CR: -+ pdata->phy.advertising |= ADVERTISED_TP; -+ break; -+ default: -+ pdata->phy.advertising |= ADVERTISED_FIBRE; -+ } -+ -+ switch (phy_data->sfp_speed) { -+ case AXGBE_SFP_SPEED_100_1000: -+ if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) -+ pdata->phy.advertising |= ADVERTISED_100baseT_Full; -+ if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) -+ pdata->phy.advertising |= ADVERTISED_1000baseT_Full; -+ break; -+ case AXGBE_SFP_SPEED_1000: -+ if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) -+ pdata->phy.advertising |= ADVERTISED_1000baseT_Full; -+ break; -+ case AXGBE_SFP_SPEED_10000: -+ if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000) -+ pdata->phy.advertising |= ADVERTISED_10000baseT_Full; -+ break; -+ default: -+ /* Choose the fastest supported speed */ -+ if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_10000) -+ pdata->phy.advertising |= ADVERTISED_10000baseT_Full; -+ else if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_1000) -+ pdata->phy.advertising |= ADVERTISED_1000baseT_Full; -+ else if (phy_data->port_speeds & AXGBE_PHY_PORT_SPEED_100) -+ pdata->phy.advertising |= ADVERTISED_100baseT_Full; -+ } -+} -+ -+static bool axgbe_phy_sfp_bit_rate(struct axgbe_sfp_eeprom *sfp_eeprom, -+ enum axgbe_sfp_speed sfp_speed) -+{ -+ u8 *sfp_base, min, max; -+ -+ sfp_base = sfp_eeprom->base; -+ -+ switch (sfp_speed) { -+ case AXGBE_SFP_SPEED_1000: -+ min = AXGBE_SFP_BASE_BR_1GBE_MIN; -+ max = AXGBE_SFP_BASE_BR_1GBE_MAX; -+ break; -+ case AXGBE_SFP_SPEED_10000: -+ min = AXGBE_SFP_BASE_BR_10GBE_MIN; -+ max = AXGBE_SFP_BASE_BR_10GBE_MAX; -+ break; -+ default: -+ return false; -+ } -+ -+ return ((sfp_base[AXGBE_SFP_BASE_BR] >= min) && -+ (sfp_base[AXGBE_SFP_BASE_BR] <= max)); -+} -+ -+static void axgbe_phy_sfp_external_phy(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ if (!phy_data->sfp_changed) -+ return; -+ -+ phy_data->sfp_phy_avail = 0; -+ -+ if (phy_data->sfp_base != AXGBE_SFP_BASE_1000_T) -+ return; -+} -+ -+static bool axgbe_phy_belfuse_parse_quirks(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ struct axgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom; -+ -+ if (memcmp(&sfp_eeprom->base[AXGBE_SFP_BASE_VENDOR_NAME], -+ AXGBE_BEL_FUSE_VENDOR, AXGBE_SFP_BASE_VENDOR_NAME_LEN)) -+ return false; -+ -+ if (!memcmp(&sfp_eeprom->base[AXGBE_SFP_BASE_VENDOR_PN], -+ AXGBE_BEL_FUSE_PARTNO, AXGBE_SFP_BASE_VENDOR_PN_LEN)) { -+ phy_data->sfp_base = AXGBE_SFP_BASE_1000_SX; -+ phy_data->sfp_cable = AXGBE_SFP_CABLE_ACTIVE; -+ phy_data->sfp_speed = AXGBE_SFP_SPEED_1000; -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool axgbe_phy_sfp_parse_quirks(struct axgbe_port *pdata) -+{ -+ if (axgbe_phy_belfuse_parse_quirks(pdata)) -+ return true; -+ -+ return false; -+} -+ -+static void axgbe_phy_sfp_parse_eeprom(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ struct axgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom; -+ uint8_t *sfp_base; -+ -+ sfp_base = sfp_eeprom->base; -+ -+ if (sfp_base[AXGBE_SFP_BASE_ID] != AXGBE_SFP_ID_SFP) -+ return; -+ -+ if (sfp_base[AXGBE_SFP_BASE_EXT_ID] != AXGBE_SFP_EXT_ID_SFP) -+ return; -+ -+ if (axgbe_phy_sfp_parse_quirks(pdata)) -+ return; -+ -+ /* Assume ACTIVE cable unless told it is PASSIVE */ -+ if (sfp_base[AXGBE_SFP_BASE_CABLE] & AXGBE_SFP_BASE_CABLE_PASSIVE) { -+ phy_data->sfp_cable = AXGBE_SFP_CABLE_PASSIVE; -+ phy_data->sfp_cable_len = sfp_base[AXGBE_SFP_BASE_CU_CABLE_LEN]; -+ } else { -+ phy_data->sfp_cable = AXGBE_SFP_CABLE_ACTIVE; -+ } -+ -+ /* Determine the type of SFP */ -+ if (sfp_base[AXGBE_SFP_BASE_10GBE_CC] & AXGBE_SFP_BASE_10GBE_CC_SR) -+ phy_data->sfp_base = AXGBE_SFP_BASE_10000_SR; -+ else if (sfp_base[AXGBE_SFP_BASE_10GBE_CC] & AXGBE_SFP_BASE_10GBE_CC_LR) -+ phy_data->sfp_base = AXGBE_SFP_BASE_10000_LR; -+ else if (sfp_base[AXGBE_SFP_BASE_10GBE_CC] & -+ AXGBE_SFP_BASE_10GBE_CC_LRM) -+ phy_data->sfp_base = AXGBE_SFP_BASE_10000_LRM; -+ else if (sfp_base[AXGBE_SFP_BASE_10GBE_CC] & AXGBE_SFP_BASE_10GBE_CC_ER) -+ phy_data->sfp_base = AXGBE_SFP_BASE_10000_ER; -+ else if (sfp_base[AXGBE_SFP_BASE_1GBE_CC] & AXGBE_SFP_BASE_1GBE_CC_SX) -+ phy_data->sfp_base = AXGBE_SFP_BASE_1000_SX; -+ else if (sfp_base[AXGBE_SFP_BASE_1GBE_CC] & AXGBE_SFP_BASE_1GBE_CC_LX) -+ phy_data->sfp_base = AXGBE_SFP_BASE_1000_LX; -+ else if (sfp_base[AXGBE_SFP_BASE_1GBE_CC] & AXGBE_SFP_BASE_1GBE_CC_CX) -+ phy_data->sfp_base = AXGBE_SFP_BASE_1000_CX; -+ else if (sfp_base[AXGBE_SFP_BASE_1GBE_CC] & AXGBE_SFP_BASE_1GBE_CC_T) -+ phy_data->sfp_base = AXGBE_SFP_BASE_1000_T; -+ else if ((phy_data->sfp_cable == AXGBE_SFP_CABLE_PASSIVE) && -+ axgbe_phy_sfp_bit_rate(sfp_eeprom, AXGBE_SFP_SPEED_10000)) -+ phy_data->sfp_base = AXGBE_SFP_BASE_10000_CR; -+ -+ switch (phy_data->sfp_base) { -+ case AXGBE_SFP_BASE_1000_T: -+ phy_data->sfp_speed = AXGBE_SFP_SPEED_100_1000; -+ break; -+ case AXGBE_SFP_BASE_1000_SX: -+ case AXGBE_SFP_BASE_1000_LX: -+ case AXGBE_SFP_BASE_1000_CX: -+ phy_data->sfp_speed = AXGBE_SFP_SPEED_1000; -+ break; -+ case AXGBE_SFP_BASE_10000_SR: -+ case AXGBE_SFP_BASE_10000_LR: -+ case AXGBE_SFP_BASE_10000_LRM: -+ case AXGBE_SFP_BASE_10000_ER: -+ case AXGBE_SFP_BASE_10000_CR: -+ phy_data->sfp_speed = AXGBE_SFP_SPEED_10000; -+ break; -+ default: -+ break; -+ } -+} -+ -+static bool axgbe_phy_sfp_verify_eeprom(uint8_t cc_in, uint8_t *buf, -+ unsigned int len) -+{ -+ uint8_t cc; -+ -+ for (cc = 0; len; buf++, len--) -+ cc += *buf; -+ -+ return (cc == cc_in) ? true : false; -+} -+ -+static int axgbe_phy_sfp_read_eeprom(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ struct axgbe_sfp_eeprom sfp_eeprom; -+ uint8_t eeprom_addr; -+ int ret; -+ -+ ret = axgbe_phy_sfp_get_mux(pdata); -+ if (ret) { -+ PMD_DRV_LOG(ERR, "I2C error setting SFP MUX"); -+ return ret; -+ } -+ -+ /* Read the SFP serial ID eeprom */ -+ eeprom_addr = 0; -+ ret = axgbe_phy_i2c_read(pdata, AXGBE_SFP_SERIAL_ID_ADDRESS, -+ &eeprom_addr, sizeof(eeprom_addr), -+ &sfp_eeprom, sizeof(sfp_eeprom)); -+ if (ret) { -+ PMD_DRV_LOG(ERR, "I2C error reading SFP EEPROM"); -+ goto put; -+ } -+ -+ /* Validate the contents read */ -+ if (!axgbe_phy_sfp_verify_eeprom(sfp_eeprom.base[AXGBE_SFP_BASE_CC], -+ sfp_eeprom.base, -+ sizeof(sfp_eeprom.base) - 1)) { -+ ret = -EINVAL; -+ goto put; -+ } -+ -+ if (!axgbe_phy_sfp_verify_eeprom(sfp_eeprom.extd[AXGBE_SFP_EXTD_CC], -+ sfp_eeprom.extd, -+ sizeof(sfp_eeprom.extd) - 1)) { -+ ret = -EINVAL; -+ goto put; -+ } -+ -+ /* Check for an added or changed SFP */ -+ if (memcmp(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom))) { -+ phy_data->sfp_changed = 1; -+ memcpy(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom)); -+ -+ if (sfp_eeprom.extd[AXGBE_SFP_EXTD_SFF_8472]) { -+ uint8_t diag_type; -+ diag_type = sfp_eeprom.extd[AXGBE_SFP_EXTD_DIAG]; -+ -+ if (!(diag_type & AXGBE_SFP_EXTD_DIAG_ADDR_CHANGE)) -+ phy_data->sfp_diags = 1; -+ } -+ } else { -+ phy_data->sfp_changed = 0; -+ } -+ -+put: -+ axgbe_phy_sfp_put_mux(pdata); -+ -+ return ret; -+} -+ -+static void axgbe_phy_sfp_signals(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ unsigned int gpio_input; -+ u8 gpio_reg, gpio_ports[2]; -+ int ret; -+ -+ /* Read the input port registers */ -+ gpio_reg = 0; -+ ret = axgbe_phy_i2c_read(pdata, phy_data->sfp_gpio_address, -+ &gpio_reg, sizeof(gpio_reg), -+ gpio_ports, sizeof(gpio_ports)); -+ if (ret) { -+ PMD_DRV_LOG(ERR, "I2C error reading SFP GPIOs"); -+ return; -+ } -+ -+ gpio_input = (gpio_ports[1] << 8) | gpio_ports[0]; -+ -+ if (phy_data->sfp_gpio_mask & AXGBE_GPIO_NO_MOD_ABSENT) { -+ /* No GPIO, just assume the module is present for now */ -+ phy_data->sfp_mod_absent = 0; -+ } else { -+ if (!(gpio_input & (1 << phy_data->sfp_gpio_mod_absent))) -+ phy_data->sfp_mod_absent = 0; -+ } -+ -+ if (!(phy_data->sfp_gpio_mask & AXGBE_GPIO_NO_RX_LOS) && -+ (gpio_input & (1 << phy_data->sfp_gpio_rx_los))) -+ phy_data->sfp_rx_los = 1; -+ -+ if (!(phy_data->sfp_gpio_mask & AXGBE_GPIO_NO_TX_FAULT) && -+ (gpio_input & (1 << phy_data->sfp_gpio_tx_fault))) -+ phy_data->sfp_tx_fault = 1; -+} -+ -+static void axgbe_phy_sfp_mod_absent(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ phy_data->sfp_mod_absent = 1; -+ phy_data->sfp_phy_avail = 0; -+ memset(&phy_data->sfp_eeprom, 0, sizeof(phy_data->sfp_eeprom)); -+} -+ -+static void axgbe_phy_sfp_reset(struct axgbe_phy_data *phy_data) -+{ -+ phy_data->sfp_rx_los = 0; -+ phy_data->sfp_tx_fault = 0; -+ phy_data->sfp_mod_absent = 1; -+ phy_data->sfp_diags = 0; -+ phy_data->sfp_base = AXGBE_SFP_BASE_UNKNOWN; -+ phy_data->sfp_cable = AXGBE_SFP_CABLE_UNKNOWN; -+ phy_data->sfp_speed = AXGBE_SFP_SPEED_UNKNOWN; -+} -+ -+static void axgbe_phy_sfp_detect(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ int ret; -+ -+ /* Reset the SFP signals and info */ -+ axgbe_phy_sfp_reset(phy_data); -+ -+ ret = axgbe_phy_get_comm_ownership(pdata); -+ if (ret) -+ return; -+ -+ /* Read the SFP signals and check for module presence */ -+ axgbe_phy_sfp_signals(pdata); -+ if (phy_data->sfp_mod_absent) { -+ axgbe_phy_sfp_mod_absent(pdata); -+ goto put; -+ } -+ -+ ret = axgbe_phy_sfp_read_eeprom(pdata); -+ if (ret) { -+ /* Treat any error as if there isn't an SFP plugged in */ -+ axgbe_phy_sfp_reset(phy_data); -+ axgbe_phy_sfp_mod_absent(pdata); -+ goto put; -+ } -+ -+ axgbe_phy_sfp_parse_eeprom(pdata); -+ axgbe_phy_sfp_external_phy(pdata); -+ -+put: -+ axgbe_phy_sfp_phy_settings(pdata); -+ axgbe_phy_put_comm_ownership(pdata); -+} -+ -+static void axgbe_phy_phydev_flowctrl(struct axgbe_port *pdata) -+{ -+ pdata->phy.tx_pause = 0; -+ pdata->phy.rx_pause = 0; -+} -+ -+static enum axgbe_mode axgbe_phy_an73_redrv_outcome(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ enum axgbe_mode mode; -+ unsigned int ad_reg, lp_reg; -+ -+ pdata->phy.lp_advertising |= ADVERTISED_Autoneg; -+ pdata->phy.lp_advertising |= ADVERTISED_Backplane; -+ -+ /* Use external PHY to determine flow control */ -+ if (pdata->phy.pause_autoneg) -+ axgbe_phy_phydev_flowctrl(pdata); -+ -+ /* Compare Advertisement and Link Partner register 2 */ -+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); -+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); -+ if (lp_reg & 0x80) -+ pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; -+ if (lp_reg & 0x20) -+ pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; -+ -+ ad_reg &= lp_reg; -+ if (ad_reg & 0x80) { -+ switch (phy_data->port_mode) { -+ case AXGBE_PORT_MODE_BACKPLANE: -+ mode = AXGBE_MODE_KR; -+ break; -+ default: -+ mode = AXGBE_MODE_SFI; -+ break; -+ } -+ } else if (ad_reg & 0x20) { -+ switch (phy_data->port_mode) { -+ case AXGBE_PORT_MODE_BACKPLANE: -+ mode = AXGBE_MODE_KX_1000; -+ break; -+ case AXGBE_PORT_MODE_1000BASE_X: -+ mode = AXGBE_MODE_X; -+ break; -+ case AXGBE_PORT_MODE_SFP: -+ switch (phy_data->sfp_base) { -+ case AXGBE_SFP_BASE_1000_T: -+ mode = AXGBE_MODE_SGMII_1000; -+ break; -+ case AXGBE_SFP_BASE_1000_SX: -+ case AXGBE_SFP_BASE_1000_LX: -+ case AXGBE_SFP_BASE_1000_CX: -+ default: -+ mode = AXGBE_MODE_X; -+ break; -+ } -+ break; -+ default: -+ mode = AXGBE_MODE_SGMII_1000; -+ break; -+ } -+ } else { -+ mode = AXGBE_MODE_UNKNOWN; -+ } -+ -+ /* Compare Advertisement and Link Partner register 3 */ -+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); -+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); -+ if (lp_reg & 0xc000) -+ pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; -+ -+ return mode; -+} -+ -+static enum axgbe_mode axgbe_phy_an73_outcome(struct axgbe_port *pdata) -+{ -+ enum axgbe_mode mode; -+ unsigned int ad_reg, lp_reg; -+ -+ pdata->phy.lp_advertising |= ADVERTISED_Autoneg; -+ pdata->phy.lp_advertising |= ADVERTISED_Backplane; -+ -+ /* Compare Advertisement and Link Partner register 1 */ -+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); -+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); -+ if (lp_reg & 0x400) -+ pdata->phy.lp_advertising |= ADVERTISED_Pause; -+ if (lp_reg & 0x800) -+ pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; -+ -+ if (pdata->phy.pause_autoneg) { -+ /* Set flow control based on auto-negotiation result */ -+ pdata->phy.tx_pause = 0; -+ pdata->phy.rx_pause = 0; -+ -+ if (ad_reg & lp_reg & 0x400) { -+ pdata->phy.tx_pause = 1; -+ pdata->phy.rx_pause = 1; -+ } else if (ad_reg & lp_reg & 0x800) { -+ if (ad_reg & 0x400) -+ pdata->phy.rx_pause = 1; -+ else if (lp_reg & 0x400) -+ pdata->phy.tx_pause = 1; -+ } -+ } -+ -+ /* Compare Advertisement and Link Partner register 2 */ -+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); -+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); -+ if (lp_reg & 0x80) -+ pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; -+ if (lp_reg & 0x20) -+ pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; -+ -+ ad_reg &= lp_reg; -+ if (ad_reg & 0x80) -+ mode = AXGBE_MODE_KR; -+ else if (ad_reg & 0x20) -+ mode = AXGBE_MODE_KX_1000; -+ else -+ mode = AXGBE_MODE_UNKNOWN; -+ -+ /* Compare Advertisement and Link Partner register 3 */ -+ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); -+ lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); -+ if (lp_reg & 0xc000) -+ pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; -+ -+ return mode; -+} -+ -+static enum axgbe_mode axgbe_phy_an_outcome(struct axgbe_port *pdata) -+{ -+ switch (pdata->an_mode) { -+ case AXGBE_AN_MODE_CL73: -+ return axgbe_phy_an73_outcome(pdata); -+ case AXGBE_AN_MODE_CL73_REDRV: -+ return axgbe_phy_an73_redrv_outcome(pdata); -+ case AXGBE_AN_MODE_CL37: -+ case AXGBE_AN_MODE_CL37_SGMII: -+ default: -+ return AXGBE_MODE_UNKNOWN; -+ } -+} -+ -+static unsigned int axgbe_phy_an_advertising(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ unsigned int advertising; -+ -+ /* Without a re-driver, just return current advertising */ -+ if (!phy_data->redrv) -+ return pdata->phy.advertising; -+ -+ /* With the KR re-driver we need to advertise a single speed */ -+ advertising = pdata->phy.advertising; -+ advertising &= ~ADVERTISED_1000baseKX_Full; -+ advertising &= ~ADVERTISED_10000baseKR_Full; -+ -+ switch (phy_data->port_mode) { -+ case AXGBE_PORT_MODE_BACKPLANE: -+ advertising |= ADVERTISED_10000baseKR_Full; -+ break; -+ case AXGBE_PORT_MODE_BACKPLANE_2500: -+ advertising |= ADVERTISED_1000baseKX_Full; -+ break; -+ case AXGBE_PORT_MODE_1000BASE_T: -+ case AXGBE_PORT_MODE_1000BASE_X: -+ case AXGBE_PORT_MODE_NBASE_T: -+ advertising |= ADVERTISED_1000baseKX_Full; -+ break; -+ case AXGBE_PORT_MODE_10GBASE_T: -+ PMD_DRV_LOG(ERR, "10GBASE_T mode is not supported"); -+ break; -+ case AXGBE_PORT_MODE_10GBASE_R: -+ advertising |= ADVERTISED_10000baseKR_Full; -+ break; -+ case AXGBE_PORT_MODE_SFP: -+ switch (phy_data->sfp_base) { -+ case AXGBE_SFP_BASE_1000_T: -+ case AXGBE_SFP_BASE_1000_SX: -+ case AXGBE_SFP_BASE_1000_LX: -+ case AXGBE_SFP_BASE_1000_CX: -+ advertising |= ADVERTISED_1000baseKX_Full; -+ break; -+ default: -+ advertising |= ADVERTISED_10000baseKR_Full; -+ break; -+ } -+ break; -+ default: -+ advertising |= ADVERTISED_10000baseKR_Full; -+ break; -+ } -+ -+ return advertising; -+} -+ -+static int axgbe_phy_an_config(struct axgbe_port *pdata __rte_unused) -+{ -+ return 0; -+ /* Dummy API since there is no case to support -+ * external phy devices registred through kerenl apis -+ */ -+} -+ -+static enum axgbe_an_mode axgbe_phy_an_sfp_mode(struct axgbe_phy_data *phy_data) -+{ -+ switch (phy_data->sfp_base) { -+ case AXGBE_SFP_BASE_1000_T: -+ return AXGBE_AN_MODE_CL37_SGMII; -+ case AXGBE_SFP_BASE_1000_SX: -+ case AXGBE_SFP_BASE_1000_LX: -+ case AXGBE_SFP_BASE_1000_CX: -+ return AXGBE_AN_MODE_CL37; -+ default: -+ return AXGBE_AN_MODE_NONE; -+ } -+} -+ -+static enum axgbe_an_mode axgbe_phy_an_mode(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ /* A KR re-driver will always require CL73 AN */ -+ if (phy_data->redrv) -+ return AXGBE_AN_MODE_CL73_REDRV; -+ -+ switch (phy_data->port_mode) { -+ case AXGBE_PORT_MODE_BACKPLANE: -+ return AXGBE_AN_MODE_CL73; -+ case AXGBE_PORT_MODE_BACKPLANE_2500: -+ return AXGBE_AN_MODE_NONE; -+ case AXGBE_PORT_MODE_1000BASE_T: -+ return AXGBE_AN_MODE_CL37_SGMII; -+ case AXGBE_PORT_MODE_1000BASE_X: -+ return AXGBE_AN_MODE_CL37; -+ case AXGBE_PORT_MODE_NBASE_T: -+ return AXGBE_AN_MODE_CL37_SGMII; -+ case AXGBE_PORT_MODE_10GBASE_T: -+ return AXGBE_AN_MODE_CL73; -+ case AXGBE_PORT_MODE_10GBASE_R: -+ return AXGBE_AN_MODE_NONE; -+ case AXGBE_PORT_MODE_SFP: -+ return axgbe_phy_an_sfp_mode(phy_data); -+ default: -+ return AXGBE_AN_MODE_NONE; -+ } -+} -+ -+static int axgbe_phy_set_redrv_mode_mdio(struct axgbe_port *pdata, -+ enum axgbe_phy_redrv_mode mode) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ u16 redrv_reg, redrv_val; -+ -+ redrv_reg = AXGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000); -+ redrv_val = (u16)mode; -+ -+ return pdata->hw_if.write_ext_mii_regs(pdata, phy_data->redrv_addr, -+ redrv_reg, redrv_val); -+} -+ -+static int axgbe_phy_set_redrv_mode_i2c(struct axgbe_port *pdata, -+ enum axgbe_phy_redrv_mode mode) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ unsigned int redrv_reg; -+ int ret; -+ -+ /* Calculate the register to write */ -+ redrv_reg = AXGBE_PHY_REDRV_MODE_REG + (phy_data->redrv_lane * 0x1000); -+ -+ ret = axgbe_phy_redrv_write(pdata, redrv_reg, mode); -+ -+ return ret; -+} -+ -+static void axgbe_phy_set_redrv_mode(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ enum axgbe_phy_redrv_mode mode; -+ int ret; -+ -+ if (!phy_data->redrv) -+ return; -+ -+ mode = AXGBE_PHY_REDRV_MODE_CX; -+ if ((phy_data->port_mode == AXGBE_PORT_MODE_SFP) && -+ (phy_data->sfp_base != AXGBE_SFP_BASE_1000_CX) && -+ (phy_data->sfp_base != AXGBE_SFP_BASE_10000_CR)) -+ mode = AXGBE_PHY_REDRV_MODE_SR; -+ -+ ret = axgbe_phy_get_comm_ownership(pdata); -+ if (ret) -+ return; -+ -+ if (phy_data->redrv_if) -+ axgbe_phy_set_redrv_mode_i2c(pdata, mode); -+ else -+ axgbe_phy_set_redrv_mode_mdio(pdata, mode); -+ -+ axgbe_phy_put_comm_ownership(pdata); -+} -+ -+static void axgbe_phy_start_ratechange(struct axgbe_port *pdata) -+{ -+ if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) -+ return; -+} -+ -+static void axgbe_phy_complete_ratechange(struct axgbe_port *pdata) -+{ -+ unsigned int wait; -+ -+ /* Wait for command to complete */ -+ wait = AXGBE_RATECHANGE_COUNT; -+ while (wait--) { -+ if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) -+ return; -+ -+ rte_delay_us(1500); -+ } -+} -+ -+static void axgbe_phy_rrc(struct axgbe_port *pdata) -+{ -+ unsigned int s0; -+ -+ axgbe_phy_start_ratechange(pdata); -+ -+ /* Receiver Reset Cycle */ -+ s0 = 0; -+ XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 5); -+ XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 0); -+ -+ /* Call FW to make the change */ -+ XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); -+ XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); -+ XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); -+ -+ axgbe_phy_complete_ratechange(pdata); -+} -+ -+static void axgbe_phy_power_off(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ axgbe_phy_start_ratechange(pdata); -+ -+ /* Call FW to make the change */ -+ XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, 0); -+ XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); -+ XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); -+ axgbe_phy_complete_ratechange(pdata); -+ phy_data->cur_mode = AXGBE_MODE_UNKNOWN; -+} -+ -+static void axgbe_phy_sfi_mode(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ unsigned int s0; -+ -+ axgbe_phy_set_redrv_mode(pdata); -+ -+ axgbe_phy_start_ratechange(pdata); -+ -+ /* 10G/SFI */ -+ s0 = 0; -+ XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 3); -+ if (phy_data->sfp_cable != AXGBE_SFP_CABLE_PASSIVE) { -+ XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 0); -+ } else { -+ if (phy_data->sfp_cable_len <= 1) -+ XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 1); -+ else if (phy_data->sfp_cable_len <= 3) -+ XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 2); -+ else -+ XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 3); -+ } -+ -+ /* Call FW to make the change */ -+ XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); -+ XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); -+ XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); -+ axgbe_phy_complete_ratechange(pdata); -+ phy_data->cur_mode = AXGBE_MODE_SFI; -+} -+ -+static void axgbe_phy_kr_mode(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ unsigned int s0; -+ -+ axgbe_phy_set_redrv_mode(pdata); -+ -+ axgbe_phy_start_ratechange(pdata); -+ -+ /* 10G/KR */ -+ s0 = 0; -+ XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 4); -+ XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 0); -+ -+ /* Call FW to make the change */ -+ XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); -+ XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); -+ XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); -+ axgbe_phy_complete_ratechange(pdata); -+ phy_data->cur_mode = AXGBE_MODE_KR; -+} -+ -+static enum axgbe_mode axgbe_phy_cur_mode(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ return phy_data->cur_mode; -+} -+ -+static enum axgbe_mode axgbe_phy_switch_baset_mode(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ /* No switching if not 10GBase-T */ -+ if (phy_data->port_mode != AXGBE_PORT_MODE_10GBASE_T) -+ return axgbe_phy_cur_mode(pdata); -+ -+ switch (axgbe_phy_cur_mode(pdata)) { -+ case AXGBE_MODE_SGMII_100: -+ case AXGBE_MODE_SGMII_1000: -+ return AXGBE_MODE_KR; -+ case AXGBE_MODE_KR: -+ default: -+ return AXGBE_MODE_SGMII_1000; -+ } -+} -+ -+static enum axgbe_mode axgbe_phy_switch_bp_2500_mode(struct axgbe_port *pdata -+ __rte_unused) -+{ -+ return AXGBE_MODE_KX_2500; -+} -+ -+static enum axgbe_mode axgbe_phy_switch_bp_mode(struct axgbe_port *pdata) -+{ -+ /* If we are in KR switch to KX, and vice-versa */ -+ switch (axgbe_phy_cur_mode(pdata)) { -+ case AXGBE_MODE_KX_1000: -+ return AXGBE_MODE_KR; -+ case AXGBE_MODE_KR: -+ default: -+ return AXGBE_MODE_KX_1000; -+ } -+} -+ -+static enum axgbe_mode axgbe_phy_switch_mode(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ switch (phy_data->port_mode) { -+ case AXGBE_PORT_MODE_BACKPLANE: -+ return axgbe_phy_switch_bp_mode(pdata); -+ case AXGBE_PORT_MODE_BACKPLANE_2500: -+ return axgbe_phy_switch_bp_2500_mode(pdata); -+ case AXGBE_PORT_MODE_1000BASE_T: -+ case AXGBE_PORT_MODE_NBASE_T: -+ case AXGBE_PORT_MODE_10GBASE_T: -+ return axgbe_phy_switch_baset_mode(pdata); -+ case AXGBE_PORT_MODE_1000BASE_X: -+ case AXGBE_PORT_MODE_10GBASE_R: -+ case AXGBE_PORT_MODE_SFP: -+ /* No switching, so just return current mode */ -+ return axgbe_phy_cur_mode(pdata); -+ default: -+ return AXGBE_MODE_UNKNOWN; -+ } -+} -+ -+static enum axgbe_mode axgbe_phy_get_basex_mode(struct axgbe_phy_data *phy_data -+ __rte_unused, -+ int speed) -+{ -+ switch (speed) { -+ case SPEED_1000: -+ return AXGBE_MODE_X; -+ case SPEED_10000: -+ return AXGBE_MODE_KR; -+ default: -+ return AXGBE_MODE_UNKNOWN; -+ } -+} -+ -+static enum axgbe_mode axgbe_phy_get_baset_mode(struct axgbe_phy_data *phy_data -+ __rte_unused, -+ int speed) -+{ -+ switch (speed) { -+ case SPEED_100: -+ return AXGBE_MODE_SGMII_100; -+ case SPEED_1000: -+ return AXGBE_MODE_SGMII_1000; -+ case SPEED_10000: -+ return AXGBE_MODE_KR; -+ default: -+ return AXGBE_MODE_UNKNOWN; -+ } -+} -+ -+static enum axgbe_mode axgbe_phy_get_sfp_mode(struct axgbe_phy_data *phy_data, -+ int speed) -+{ -+ switch (speed) { -+ case SPEED_100: -+ return AXGBE_MODE_SGMII_100; -+ case SPEED_1000: -+ if (phy_data->sfp_base == AXGBE_SFP_BASE_1000_T) -+ return AXGBE_MODE_SGMII_1000; -+ else -+ return AXGBE_MODE_X; -+ case SPEED_10000: -+ case SPEED_UNKNOWN: -+ return AXGBE_MODE_SFI; -+ default: -+ return AXGBE_MODE_UNKNOWN; -+ } -+} -+ -+static enum axgbe_mode axgbe_phy_get_bp_2500_mode(int speed) -+{ -+ switch (speed) { -+ case SPEED_2500: -+ return AXGBE_MODE_KX_2500; -+ default: -+ return AXGBE_MODE_UNKNOWN; -+ } -+} -+ -+static enum axgbe_mode axgbe_phy_get_bp_mode(int speed) -+{ -+ switch (speed) { -+ case SPEED_1000: -+ return AXGBE_MODE_KX_1000; -+ case SPEED_10000: -+ return AXGBE_MODE_KR; -+ default: -+ return AXGBE_MODE_UNKNOWN; -+ } -+} -+ -+static enum axgbe_mode axgbe_phy_get_mode(struct axgbe_port *pdata, -+ int speed) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ switch (phy_data->port_mode) { -+ case AXGBE_PORT_MODE_BACKPLANE: -+ return axgbe_phy_get_bp_mode(speed); -+ case AXGBE_PORT_MODE_BACKPLANE_2500: -+ return axgbe_phy_get_bp_2500_mode(speed); -+ case AXGBE_PORT_MODE_1000BASE_T: -+ case AXGBE_PORT_MODE_NBASE_T: -+ case AXGBE_PORT_MODE_10GBASE_T: -+ return axgbe_phy_get_baset_mode(phy_data, speed); -+ case AXGBE_PORT_MODE_1000BASE_X: -+ case AXGBE_PORT_MODE_10GBASE_R: -+ return axgbe_phy_get_basex_mode(phy_data, speed); -+ case AXGBE_PORT_MODE_SFP: -+ return axgbe_phy_get_sfp_mode(phy_data, speed); -+ default: -+ return AXGBE_MODE_UNKNOWN; -+ } -+} -+ -+static void axgbe_phy_set_mode(struct axgbe_port *pdata, enum axgbe_mode mode) -+{ -+ switch (mode) { -+ case AXGBE_MODE_KR: -+ axgbe_phy_kr_mode(pdata); -+ break; -+ case AXGBE_MODE_SFI: -+ axgbe_phy_sfi_mode(pdata); -+ break; -+ default: -+ break; -+ } -+} -+ -+static bool axgbe_phy_check_mode(struct axgbe_port *pdata, -+ enum axgbe_mode mode, u32 advert) -+{ -+ if (pdata->phy.autoneg == AUTONEG_ENABLE) { -+ if (pdata->phy.advertising & advert) -+ return true; -+ } else { -+ enum axgbe_mode cur_mode; -+ -+ cur_mode = axgbe_phy_get_mode(pdata, pdata->phy.speed); -+ if (cur_mode == mode) -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool axgbe_phy_use_basex_mode(struct axgbe_port *pdata, -+ enum axgbe_mode mode) -+{ -+ switch (mode) { -+ case AXGBE_MODE_X: -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_1000baseT_Full); -+ case AXGBE_MODE_KR: -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_10000baseT_Full); -+ default: -+ return false; -+ } -+} -+ -+static bool axgbe_phy_use_baset_mode(struct axgbe_port *pdata, -+ enum axgbe_mode mode) -+{ -+ switch (mode) { -+ case AXGBE_MODE_SGMII_100: -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_100baseT_Full); -+ case AXGBE_MODE_SGMII_1000: -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_1000baseT_Full); -+ case AXGBE_MODE_KR: -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_10000baseT_Full); -+ default: -+ return false; -+ } -+} -+ -+static bool axgbe_phy_use_sfp_mode(struct axgbe_port *pdata, -+ enum axgbe_mode mode) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ switch (mode) { -+ case AXGBE_MODE_X: -+ if (phy_data->sfp_base == AXGBE_SFP_BASE_1000_T) -+ return false; -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_1000baseT_Full); -+ case AXGBE_MODE_SGMII_100: -+ if (phy_data->sfp_base != AXGBE_SFP_BASE_1000_T) -+ return false; -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_100baseT_Full); -+ case AXGBE_MODE_SGMII_1000: -+ if (phy_data->sfp_base != AXGBE_SFP_BASE_1000_T) -+ return false; -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_1000baseT_Full); -+ case AXGBE_MODE_SFI: -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_10000baseT_Full); -+ default: -+ return false; -+ } -+} -+ -+static bool axgbe_phy_use_bp_2500_mode(struct axgbe_port *pdata, -+ enum axgbe_mode mode) -+{ -+ switch (mode) { -+ case AXGBE_MODE_KX_2500: -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_2500baseX_Full); -+ default: -+ return false; -+ } -+} -+ -+static bool axgbe_phy_use_bp_mode(struct axgbe_port *pdata, -+ enum axgbe_mode mode) -+{ -+ switch (mode) { -+ case AXGBE_MODE_KX_1000: -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_1000baseKX_Full); -+ case AXGBE_MODE_KR: -+ return axgbe_phy_check_mode(pdata, mode, -+ ADVERTISED_10000baseKR_Full); -+ default: -+ return false; -+ } -+} -+ -+static bool axgbe_phy_use_mode(struct axgbe_port *pdata, enum axgbe_mode mode) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ switch (phy_data->port_mode) { -+ case AXGBE_PORT_MODE_BACKPLANE: -+ return axgbe_phy_use_bp_mode(pdata, mode); -+ case AXGBE_PORT_MODE_BACKPLANE_2500: -+ return axgbe_phy_use_bp_2500_mode(pdata, mode); -+ case AXGBE_PORT_MODE_1000BASE_T: -+ case AXGBE_PORT_MODE_NBASE_T: -+ case AXGBE_PORT_MODE_10GBASE_T: -+ return axgbe_phy_use_baset_mode(pdata, mode); -+ case AXGBE_PORT_MODE_1000BASE_X: -+ case AXGBE_PORT_MODE_10GBASE_R: -+ return axgbe_phy_use_basex_mode(pdata, mode); -+ case AXGBE_PORT_MODE_SFP: -+ return axgbe_phy_use_sfp_mode(pdata, mode); -+ default: -+ return false; -+ } -+} -+ -+static int axgbe_phy_link_status(struct axgbe_port *pdata, int *an_restart) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ unsigned int reg; -+ -+ *an_restart = 0; -+ -+ if (phy_data->port_mode == AXGBE_PORT_MODE_SFP) { -+ /* Check SFP signals */ -+ axgbe_phy_sfp_detect(pdata); -+ -+ if (phy_data->sfp_changed) { -+ *an_restart = 1; -+ return 0; -+ } -+ -+ if (phy_data->sfp_mod_absent || phy_data->sfp_rx_los) -+ return 0; -+ } -+ -+ /* Link status is latched low, so read once to clear -+ * and then read again to get current state -+ */ -+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); -+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); -+ if (reg & MDIO_STAT1_LSTATUS) -+ return 1; -+ -+ /* No link, attempt a receiver reset cycle */ -+ if (phy_data->rrc_count++) { -+ phy_data->rrc_count = 0; -+ axgbe_phy_rrc(pdata); -+ } -+ -+ return 0; -+} -+ - static void axgbe_phy_sfp_gpio_setup(struct axgbe_port *pdata) - { - struct axgbe_phy_data *phy_data = pdata->phy_data; -@@ -557,6 +1888,59 @@ static bool axgbe_phy_port_enabled(struct axgbe_port *pdata) - return true; - } - -+static void axgbe_phy_stop(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ -+ /* Reset SFP data */ -+ axgbe_phy_sfp_reset(phy_data); -+ axgbe_phy_sfp_mod_absent(pdata); -+ -+ /* Power off the PHY */ -+ axgbe_phy_power_off(pdata); -+ -+ /* Stop the I2C controller */ -+ pdata->i2c_if.i2c_stop(pdata); -+} -+ -+static int axgbe_phy_start(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ int ret; -+ -+ /* Start the I2C controller */ -+ ret = pdata->i2c_if.i2c_start(pdata); -+ if (ret) -+ return ret; -+ -+ /* Start in highest supported mode */ -+ axgbe_phy_set_mode(pdata, phy_data->start_mode); -+ -+ /* After starting the I2C controller, we can check for an SFP */ -+ switch (phy_data->port_mode) { -+ case AXGBE_PORT_MODE_SFP: -+ axgbe_phy_sfp_detect(pdata); -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+static int axgbe_phy_reset(struct axgbe_port *pdata) -+{ -+ struct axgbe_phy_data *phy_data = pdata->phy_data; -+ enum axgbe_mode cur_mode; -+ -+ /* Reset by power cycling the PHY */ -+ cur_mode = phy_data->cur_mode; -+ axgbe_phy_power_off(pdata); -+ /* First time reset is done with passed unknown mode*/ -+ axgbe_phy_set_mode(pdata, cur_mode); -+ return 0; -+} -+ - static int axgbe_phy_init(struct axgbe_port *pdata) - { - struct axgbe_phy_data *phy_data; -@@ -796,4 +2180,17 @@ void axgbe_init_function_ptrs_phy_v2(struct axgbe_phy_if *phy_if) - struct axgbe_phy_impl_if *phy_impl = &phy_if->phy_impl; - - phy_impl->init = axgbe_phy_init; -+ phy_impl->reset = axgbe_phy_reset; -+ phy_impl->start = axgbe_phy_start; -+ phy_impl->stop = axgbe_phy_stop; -+ phy_impl->link_status = axgbe_phy_link_status; -+ phy_impl->use_mode = axgbe_phy_use_mode; -+ phy_impl->set_mode = axgbe_phy_set_mode; -+ phy_impl->get_mode = axgbe_phy_get_mode; -+ phy_impl->switch_mode = axgbe_phy_switch_mode; -+ phy_impl->cur_mode = axgbe_phy_cur_mode; -+ phy_impl->an_mode = axgbe_phy_an_mode; -+ phy_impl->an_config = axgbe_phy_an_config; -+ phy_impl->an_advertising = axgbe_phy_an_advertising; -+ phy_impl->an_outcome = axgbe_phy_an_outcome; - } |