Date: Sun, 27 Apr 2025 21:00:17 -0700 From: Adrian Chadd <adrian@freebsd.org> To: freebsd-net@freebsd.org Subject: ixgbe, mdio, and marvell ethernet switches Message-ID: <CAJ-VmonZS--HHpHS4jZ_HFevgKGca=18byQLXcKn0Z5gDeU2Mg@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
[-- Attachment #2 --]
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 <net/netmap.h>
+#include <dev/mdio/mdio.h>
#include <dev/netmap/netmap_kern.h>
/************************************************************************
@@ -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));
}
/**
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ-VmonZS--HHpHS4jZ_HFevgKGca=18byQLXcKn0Z5gDeU2Mg>
