Skip site navigation (1)Skip section navigation (2)
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>