diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c index 959afa79e7da..8894cbe1ff56 100644 --- a/sys/dev/ixgbe/if_ix.c +++ b/sys/dev/ixgbe/if_ix.c @@ -36,10 +36,12 @@ #include "opt_rss.h" #include "ixgbe.h" +#include "mdio_if.h" #include "ixgbe_sriov.h" #include "ifdi_if.h" #include +#include #include /************************************************************************ @@ -254,6 +256,139 @@ static void ixgbe_handle_msf(void *); static void ixgbe_handle_mod(void *); static void ixgbe_handle_phy(void *); +static s32 +ixgbe_read_phy_reg_mdi_22(struct ixgbe_hw *hw, u16 phy, u16 reg, u16 *phy_data) +{ + u32 i, data, command; + + /* Setup and write the read command */ + command = (reg << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (phy << IXGBE_MSCA_PHY_ADDR_SHIFT) | + IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_READ_AUTOINC | + IXGBE_MSCA_MDI_COMMAND; + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* Check every 10 usec to see if the access completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + usec_delay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + if (!(command & IXGBE_MSCA_MDI_COMMAND)) + break; + } + + if (command & IXGBE_MSCA_MDI_COMMAND) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "PHY read command did not complete.\n"); + return IXGBE_ERR_PHY; + } + + /* Read operation is complete. Get the data from MSRWD */ + data = IXGBE_READ_REG(hw, IXGBE_MSRWD); + data >>= IXGBE_MSRWD_READ_DATA_SHIFT; + *phy_data = (u16)data; + + return IXGBE_SUCCESS; +} + + +static s32 +ixgbe_write_phy_reg_mdi_22(struct ixgbe_hw *hw, u16 phy, u16 reg, u16 phy_data) +{ + u32 i, command; + + /* Put the data in the MDI single read and write data register*/ + IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); + + /* Setup and write the write command */ + command = (reg << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (phy << IXGBE_MSCA_PHY_ADDR_SHIFT) | + IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_WRITE | + IXGBE_MSCA_MDI_COMMAND; + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* Check every 10 usec to see if the access completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + usec_delay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + if (!(command & IXGBE_MSCA_MDI_COMMAND)) + break; + } + + if (command & IXGBE_MSCA_MDI_COMMAND) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "PHY write cmd didn't complete\n"); + return IXGBE_ERR_PHY; + } + + return IXGBE_SUCCESS; +} + +static int +ixgbe_mdio_readreg(device_t dev, int phy, int reg) +{ + if_ctx_t ctx = device_get_softc(dev); + struct ixgbe_softc *sc = iflib_get_softc(ctx); + struct ixgbe_hw *hw = &sc->hw; + uint16_t val = 0; + int32_t ret = 0; + +#if 0 + /* The interface takes a register, clause 45 devtype and data */ + ret = hw->phy.ops.read_reg_mdi(hw, reg, phy, &val); +#else + u32 gssr = hw->phy.phy_semaphore_mask | IXGBE_GSSR_PHY0_SM | IXGBE_GSSR_TOKEN_SM; + + if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) { + device_printf(dev, "%s: failed to acquire lock\n", __func__); + return (-1); + } + ret = ixgbe_read_phy_reg_mdi_22(hw, phy, reg, &val); + if (ret != IXGBE_SUCCESS) { + device_printf(dev, "%s: read_mdi_22 failed (%d)\n", __func__, ret); + } + hw->mac.ops.release_swfw_sync(hw, gssr); + (void) ret; // XXX return a suitable error if this is non-zero +#endif + return (val); +} + +static int +ixgbe_mdio_writereg(device_t dev, int phy, int reg, int data) +{ + if_ctx_t ctx = device_get_softc(dev); + struct ixgbe_softc *sc = iflib_get_softc(ctx); + struct ixgbe_hw *hw = &sc->hw; + int32_t ret; + +#if 0 + ret = hw->phy.ops.write_reg_mdi(hw, reg, phy, data); +#else + u32 gssr = hw->phy.phy_semaphore_mask | IXGBE_GSSR_PHY0_SM | IXGBE_GSSR_TOKEN_SM; + + if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) { + device_printf(dev, "%s: failed to acquire lock\n", __func__); + return (-1); + } + ret = ixgbe_write_phy_reg_mdi_22(hw, phy, reg, data); + if (ret != IXGBE_SUCCESS) { + device_printf(dev, "%s: write_mdi_22 failed (%d)\n", __func__, ret); + } + hw->mac.ops.release_swfw_sync(hw, gssr); + (void) ret; // XXX return a suitable error if this is non-zero +#endif + return (0); +} + /************************************************************************ * FreeBSD Device Interface Entry Points ************************************************************************/ @@ -271,6 +406,13 @@ static device_method_t ix_methods[] = { DEVMETHOD(pci_iov_uninit, iflib_device_iov_uninit), DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf), #endif /* PCI_IOV */ + + DEVMETHOD(bus_add_child, device_add_child_ordered), +#if 1 + DEVMETHOD(mdio_readreg, ixgbe_mdio_readreg), + DEVMETHOD(mdio_writereg, ixgbe_mdio_writereg), +#endif + DEVMETHOD_END }; @@ -279,10 +421,12 @@ static driver_t ix_driver = { }; DRIVER_MODULE(ix, pci, ix_driver, 0, 0); +DRIVER_MODULE(mdio, ix, mdio_driver, 0, 0); IFLIB_PNP_INFO(pci, ix_driver, ixgbe_vendor_info_array); MODULE_DEPEND(ix, pci, 1, 1, 1); MODULE_DEPEND(ix, ether, 1, 1, 1); MODULE_DEPEND(ix, iflib, 1, 1, 1); +MODULE_DEPEND(ix, mdio, 1, 1, 1); static device_method_t ixgbe_if_methods[] = { DEVMETHOD(ifdi_attach_pre, ixgbe_if_attach_pre), diff --git a/sys/dev/ixgbe/ixgbe_phy.c b/sys/dev/ixgbe/ixgbe_phy.c index 2a735ead9a12..2bfb286c91c4 100644 --- a/sys/dev/ixgbe/ixgbe_phy.c +++ b/sys/dev/ixgbe/ixgbe_phy.c @@ -599,6 +599,8 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, { u32 i, data, command; + printf("%s: called; reg_addr=%d, type=%d, phy.addr=%d\n", __func__, reg_addr, device_type, hw->phy.addr); + /* Setup and write the address cycle command */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | @@ -636,6 +638,7 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); + printf("%s: writing 0x%08x -> MSCA\n", __func__, command); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); /* @@ -652,6 +655,7 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, } if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + printf("%s: timeout!\n", __func__); ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY read command didn't complete\n"); DEBUGOUT("PHY read command didn't complete, returning IXGBE_ERR_PHY\n"); return IXGBE_ERR_PHY; @@ -662,6 +666,7 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, * from MSRWD */ data = IXGBE_READ_REG(hw, IXGBE_MSRWD); + printf("%s: read 0x%08x <- MSRWD\n", __func__, data); data >>= IXGBE_MSRWD_READ_DATA_SHIFT; *phy_data = (u16)(data); @@ -707,6 +712,8 @@ s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, { u32 i, command; + printf("%s: called; reg_addr=%d, type=%d, phy.addr=%d\n", __func__, reg_addr, device_type, hw->phy.addr); + /* Put the data in the MDI single read and write data register*/ IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); @@ -716,6 +723,7 @@ s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + printf("%s: (1) writing 0x%08x -> MSCA\n", __func__, command); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); /* @@ -732,6 +740,7 @@ s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, } if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + printf("%s: timeout (1)!\n", __func__); ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address cmd didn't complete\n"); return IXGBE_ERR_PHY; } @@ -745,6 +754,7 @@ s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); + printf("%s: (2) writing 0x%08x -> MSCA\n", __func__, command); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); /* @@ -761,6 +771,7 @@ s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, } if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + printf("%s: timeout (2)!\n", __func__); ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY write cmd didn't complete\n"); return IXGBE_ERR_PHY; } diff --git a/sys/dev/ixgbe/ixgbe_x550.c b/sys/dev/ixgbe/ixgbe_x550.c index 7f07190f832c..5947d89fe11e 100644 --- a/sys/dev/ixgbe/ixgbe_x550.c +++ b/sys/dev/ixgbe/ixgbe_x550.c @@ -520,15 +520,38 @@ s32 ixgbe_shutdown_fw_phy(struct ixgbe_hw *hw) static s32 ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data) { - UNREFERENCED_4PARAMETER(*hw, reg_addr, device_type, *phy_data); - return IXGBE_NOT_IMPLEMENTED; + s32 status; + u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM; + + DEBUGFUNC("ixgbe_read_phy_reg_x550em"); + + if (hw->mac.ops.acquire_swfw_sync(hw, mask)) + return IXGBE_ERR_SWFW_SYNC; + + status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data); + + hw->mac.ops.release_swfw_sync(hw, mask); + + return status; } static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data) { - UNREFERENCED_4PARAMETER(*hw, reg_addr, device_type, phy_data); - return IXGBE_NOT_IMPLEMENTED; + s32 status; + u32 mask = hw->phy.phy_semaphore_mask | IXGBE_GSSR_TOKEN_SM; + + DEBUGFUNC("ixgbe_write_phy_reg_x550em"); + + if (hw->mac.ops.acquire_swfw_sync(hw, mask) == IXGBE_SUCCESS) { + status = hw->phy.ops.write_reg_mdi(hw, reg_addr, device_type, + phy_data); + hw->mac.ops.release_swfw_sync(hw, mask); + } else { + status = IXGBE_ERR_SWFW_SYNC; + } + + return status; } /** @@ -2275,11 +2298,15 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) /* Set functions pointers based on phy type */ switch (hw->phy.type) { case ixgbe_phy_x550em_kx4: + printf("%s: x550em_kx4\n", __func__); phy->ops.setup_link = NULL; phy->ops.read_reg = ixgbe_read_phy_reg_x550em; phy->ops.write_reg = ixgbe_write_phy_reg_x550em; break; case ixgbe_phy_x550em_kr: + printf("%s: x550em_kr\n", __func__); + phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi; + phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi; phy->ops.setup_link = ixgbe_setup_kr_x550em; phy->ops.read_reg = ixgbe_read_phy_reg_x550em; phy->ops.write_reg = ixgbe_write_phy_reg_x550em; @@ -2290,12 +2317,14 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) phy->ops.reset = NULL; break; case ixgbe_phy_x550em_xfi: + printf("%s: x550em_xfi\n", __func__); /* link is managed by HW */ phy->ops.setup_link = NULL; phy->ops.read_reg = ixgbe_read_phy_reg_x550em; phy->ops.write_reg = ixgbe_write_phy_reg_x550em; break; case ixgbe_phy_x550em_ext_t: + printf("%s: x550em_ext_t\n", __func__); /* If internal link mode is XFI, then setup iXFI internal link, * else setup KR now. */ @@ -2312,13 +2341,16 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) phy->ops.reset = ixgbe_reset_phy_t_X550em; break; case ixgbe_phy_sgmii: + printf("%s: phy_sgmii\n", __func__); phy->ops.setup_link = NULL; break; case ixgbe_phy_fw: + printf("%s: phy_fw\n", __func__); phy->ops.setup_link = ixgbe_setup_fw_link; phy->ops.reset = ixgbe_reset_phy_fw; break; default: + printf("%s: default\n", __func__); break; } return ret_val; @@ -2332,6 +2364,8 @@ static void ixgbe_set_mdio_speed(struct ixgbe_hw *hw) { u32 hlreg0; + printf("%s: called, device_id=%04x\n", __func__, hw->device_id); + switch (hw->device_id) { case IXGBE_DEV_ID_X550EM_X_10G_T: case IXGBE_DEV_ID_X550EM_A_SGMII: @@ -2354,6 +2388,9 @@ static void ixgbe_set_mdio_speed(struct ixgbe_hw *hw) default: break; } + + printf("%s: HLREG0=0x%08x\n", __func__, + IXGBE_READ_REG(hw, IXGBE_HLREG0)); } /**