Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
ifconfig transceiver support for ice(4)
To:
tech@openbsd.org
Date:
Fri, 15 Aug 2025 11:43:14 +0200

Download raw body.

Thread
This patch makes ifconfig ice0 transceiver (as root) display information
about inserted transceivers.

ok?

M  sys/dev/pci/if_ice.c     |  113+  0-
M  sys/dev/pci/if_icevar.h  |    2+  0-

2 files changed, 115 insertions(+), 0 deletions(-)

commit - f8d6ec95fb2ba7d8706e3c32ac858af54a306b15
commit + d980c1256612baaf0dc40c0794b3556a724e0bad
blob - 16687434ef41bfc3779d7f511b14e64aacc54602
blob + 188a1de7816a1d009d9bdea306227a11654ae3e2
--- sys/dev/pci/if_ice.c
+++ sys/dev/pci/if_ice.c
@@ -261,6 +261,8 @@ struct ice_intr_vector {
 
 #define ICE_MAX_VECTORS			8 /* XXX this is pretty arbitrary */
 
+static struct rwlock ice_sff_lock = RWLOCK_INITIALIZER("icesff");
+
 struct ice_softc {
 	struct device sc_dev;
 	struct arpcom		sc_ac;
@@ -13568,7 +13570,111 @@ ice_down(struct ice_softc *sc)
 	return 0;
 }
 
+/* Read/Write SFF EEPROM (0x06EE) */
 int
+ice_aq_sff_eeprom(struct ice_hw *hw, uint16_t lport, uint8_t bus_addr,
+    uint16_t mem_addr, uint8_t page, uint8_t set_page, uint8_t *data,
+    uint8_t length, struct ice_sq_cd *cd)
+{
+	struct ice_aqc_sff_eeprom *cmd;
+	struct ice_aq_desc desc;
+	int status;
+
+	if (!data || (mem_addr & 0xff00))
+		return ICE_ERR_PARAM;
+
+	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_sff_eeprom);
+	cmd = &desc.params.read_write_sff_param;
+	desc.flags = htole16(ICE_AQ_FLAG_RD);
+	cmd->lport_num = (uint8_t)(lport & 0xff);
+	cmd->lport_num_valid = (uint8_t)((lport >> 8) & 0x01);
+	cmd->i2c_bus_addr = htole16(
+	    ((bus_addr >> 1) & ICE_AQC_SFF_I2CBUS_7BIT_M) |
+	    ((set_page << ICE_AQC_SFF_SET_EEPROM_PAGE_S) &
+	    ICE_AQC_SFF_SET_EEPROM_PAGE_M));
+	cmd->i2c_mem_addr = htole16(mem_addr & 0xff);
+	cmd->eeprom_page = htole16((uint16_t)page << ICE_AQC_SFF_EEPROM_PAGE_S);
+
+	status = ice_aq_send_cmd(hw, &desc, data, length, cd);
+	return status;
+}
+
+/*
+ * Read from the SFF eeprom.
+ * The I2C device address is typically 0xA0 or 0xA2. For more details on
+ * the contents of an SFF eeprom, refer to SFF-8724 (SFP), SFF-8636 (QSFP),
+ * and SFF-8024 (both).
+ */
+int
+ice_read_sff_eeprom(struct ice_softc *sc, uint16_t dev_addr, uint16_t offset,
+    uint8_t* data, uint16_t length)
+{
+	struct ice_hw *hw = &sc->hw;
+	int ret = 0, retries = 0;
+	int status;
+
+	if (length > 16)
+		return (EINVAL);
+
+	if (ice_test_state(&sc->state, ICE_STATE_RECOVERY_MODE))
+		return (ENOSYS);
+
+	if (ice_test_state(&sc->state, ICE_STATE_NO_MEDIA))
+		return (ENXIO);
+
+	do {
+		status = ice_aq_sff_eeprom(hw, 0, dev_addr,
+					   offset, 0, 0, data, length, NULL);
+		if (!status) {
+			ret = 0;
+			break;
+		}
+		if (status == ICE_ERR_AQ_ERROR &&
+		    hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY) {
+			ret = EBUSY;
+			continue;
+		}
+		if (status == ICE_ERR_AQ_ERROR &&
+		    hw->adminq.sq_last_status == ICE_AQ_RC_EACCES) {
+			/* FW says I2C access isn't supported */
+			ret = EACCES;
+			break;
+		}
+		if (status == ICE_ERR_AQ_ERROR &&
+		    hw->adminq.sq_last_status == ICE_AQ_RC_EPERM) {
+			ret = EPERM;
+			break;
+		} else {
+			ret = EIO;
+			break;
+		}
+	} while (retries++ < ICE_I2C_MAX_RETRIES);
+
+	return (ret);
+}
+
+int
+ice_get_sffpage(struct ice_softc *sc, struct if_sffpage *sff)
+{
+	const uint16_t chunksize = 16;
+	uint16_t offset = 0;
+	int error;
+
+	if (sff->sff_addr != IFSFF_ADDR_EEPROM &&
+	    sff->sff_addr != IFSFF_ADDR_DDM)
+		return (EINVAL);
+
+	 for (; offset <= IFSFF_DATA_LEN - chunksize; offset += chunksize) {
+		error = ice_read_sff_eeprom(sc, sff->sff_addr, offset,
+		    &sff->sff_data[0] + offset, chunksize);
+		if (error)
+			return error;
+	}
+
+	return 0;
+}
+
+int
 ice_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
 	struct ice_softc *sc = ifp->if_softc;
@@ -13637,6 +13743,13 @@ ice_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 			}
 		}
 		break;
+	case SIOCGIFSFFPAGE:
+		error = rw_enter(&ice_sff_lock, RW_WRITE|RW_INTR);
+		if (error)
+			break;
+		error = ice_get_sffpage(sc, (struct if_sffpage *)data);
+		rw_exit(&ice_sff_lock);
+		break;
 	default:
 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
 		break;
blob - b73c60d9c9575c5ccdb6e9795b8d170fa16d1af3
blob + 6f02d39411437519a5da618307f55fc27765b826
--- sys/dev/pci/if_icevar.h
+++ sys/dev/pci/if_icevar.h
@@ -4694,3 +4694,5 @@ struct ice_vsi {
 
 /* Driver always calls main vsi_handle first */
 #define ICE_MAIN_VSI_HANDLE		0
+
+#define ICE_I2C_MAX_RETRIES		10