Index | Thread | Search

From:
Jan Klemkow <jan@openbsd.org>
Subject:
Re: ifconfig transceiver support for ice(4)
To:
tech@openbsd.org
Date:
Mon, 18 Aug 2025 13:44:16 +0200

Download raw body.

Thread
On Sat, Aug 16, 2025 at 02:15:23PM +0200, Stefan Sperling wrote:
> On Fri, Aug 15, 2025 at 11:43:14AM +0200, Stefan Sperling wrote:
> > This patch makes ifconfig ice0 transceiver (as root) display information
> > about inserted transceivers.
> 
> Updated version which adds eeprom page flipping for SFP devices,
> as requested by dlg@.
> 
> ok?

Diff looks good and works for me.

ok jan@

ot37# ifconfig ice sff
ice0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 1500
        lladdr 50:7c:6f:86:fc:80
        index 11 priority 0 llprio 3
        media: Ethernet autoselect (25GbaseSR full-duplex)
        status: active
        transceiver: SFP LC, 850 nm, 140m OM3, 10m
        model: FS SFP-10/25GSR-85 rev 1A
        serial: S2308417658, date: 2023-10-13
        voltage: 3.34 V, bias current: 6.23 mA
        temp: 33.00 C (low -5.00 C, high 75.00 C)
        tx: 0.74 dBm (low -11.40 dBm, high 4.00 dBm)
        rx: 1.10 dBm (low -13.31 dBm, high 4.00 dBm)

root@ot41:.../~# ifconfig ice sff
ice0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 6c:fe:54:9b:12:e8
        description: Intel E810-C QSFP
        index 11 priority 0 llprio 3
        media: Ethernet autoselect (100GbaseSR4 full-duplex)
        status: active
        transceiver: QSFP28 MPO 1x12, 850 nm, 70m OM3, 50m
        model: Intel Corp Q.851HG.02 rev A0
        serial: FHC36G6 date: 2024-11-12
        max case temp: 70 C
        temp: 42.66 C, voltage: 3.35 V
        channel 1: bias current: 6.63 mA, rx: -0.95 dBm, tx: -0.11 dBm
        channel 2: bias current: 6.68 mA, rx: -0.16 dBm, tx: -0.86 dBm
        channel 3: bias current: 6.61 mA, rx: -0.39 dBm, tx: -0.74 dBm
        channel 4: bias current: 6.58 mA, rx: -0.46 dBm, tx: -1.03 dBm

> M  sys/dev/pci/if_ice.c     |  163+  0-
> M  sys/dev/pci/if_icereg.h  |    5+  0-
> M  sys/dev/pci/if_icevar.h  |    2+  0-
> 
> 3 files changed, 170 insertions(+), 0 deletions(-)
> 
> commit - eec461d818a542e83f2ba358378f3c806987b4c1
> commit + 521a9cf1dca52ced98fabf1e946f0ac2f2c9770d
> blob - 306e5c3df38b8fa103eb8f65cae9e5b8b0d5a6f7
> blob + f909a9dcedd04bd0d87c597c5b2d0c70b674ea38
> --- 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,161 @@ ice_down(struct ice_softc *sc)
>  	return 0;
>  }
>  
> +/* Read 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, int write, 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);
> +	if (write)
> +		cmd->i2c_bus_addr |= htole16(ICE_AQC_SFF_IS_WRITE);
> +
> +	status = ice_aq_send_cmd(hw, &desc, data, length, cd);
> +	return status;
> +}
> +
> +int
> +ice_rw_sff_eeprom(struct ice_softc *sc, uint16_t dev_addr, uint16_t offset,
> +    uint8_t page, uint8_t* data, uint16_t length, uint8_t set_page, int write)
> +{
> +	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, page,
> +		    set_page, data, length, write, 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);
> +}
> +
> +/*
> + * 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 page, uint8_t* data, uint16_t length)
> +{
> +	return ice_rw_sff_eeprom(sc, dev_addr, offset, page, data, length,
> +	    0, 0);
> +}
> +
> +/* Write to the SFF eeprom. */
> +int
> +ice_write_sff_eeprom(struct ice_softc *sc, uint16_t dev_addr, uint16_t offset,
> +    uint8_t page, uint8_t* data, uint16_t length, uint8_t set_page)
> +{
> +	return ice_rw_sff_eeprom(sc, dev_addr, offset, page, data, length,
> +	    1, set_page);
> +}
> +
> +int
> +ice_get_sffpage(struct ice_softc *sc, struct if_sffpage *sff)
> +{
> +	struct ice_hw *hw = &sc->hw;
> +	struct ice_port_info *pi = hw->port_info;
> +	struct ice_link_status *li = &pi->phy.link_info;
> +	const uint16_t chunksize = 16;
> +	uint16_t offset = 0;
> +	uint8_t curpage = 0;
> +	int error;
> +
> +	if (sff->sff_addr != IFSFF_ADDR_EEPROM &&
> +	    sff->sff_addr != IFSFF_ADDR_DDM)
> +		return (EINVAL);
> +
> +	if (li->module_type[0] == ICE_SFF8024_ID_NONE)
> +		return (ENXIO);
> +
> +	if (sff->sff_addr == IFSFF_ADDR_EEPROM &&
> +	    li->module_type[0] == ICE_SFF8024_ID_SFP) {
> +		error = ice_read_sff_eeprom(sc, sff->sff_addr, 127, 0,
> +		    &curpage, 1);
> +		if (error)
> +			return error;
> +
> +		if (curpage != sff->sff_page) {
> +			error = ice_write_sff_eeprom(sc, sff->sff_addr, 127, 0,
> +			    &sff->sff_page, 1, 1);
> +			if (error)
> +				return error;
> +		}
> +	}
> +
> +	for (; offset <= IFSFF_DATA_LEN - chunksize; offset += chunksize) {
> +		error = ice_read_sff_eeprom(sc, sff->sff_addr, offset,
> +		    sff->sff_page, &sff->sff_data[0] + offset, chunksize);
> +		if (error)
> +			return error;
> +	}
> +
> +	if (sff->sff_addr == IFSFF_ADDR_EEPROM &&
> +	    li->module_type[0] == ICE_SFF8024_ID_SFP &&
> +	    curpage != sff->sff_page) {
> +		error = ice_write_sff_eeprom(sc, sff->sff_addr, 127, 0,
> +		    &curpage, 1, 1);
> +		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 +13793,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 - 14492fcd80c0b755e7520839bec186cec82d6976
> blob + 9efcd6b6fb3223541bc528c2eec39ba96dcc1486
> --- sys/dev/pci/if_icereg.h
> +++ sys/dev/pci/if_icereg.h
> @@ -10900,6 +10900,11 @@ struct ice_aqc_get_phy_caps_data {
>  	uint8_t extended_compliance_code;
>  #define ICE_MODULE_TYPE_TOTAL_BYTE			3
>  	uint8_t module_type[ICE_MODULE_TYPE_TOTAL_BYTE];
> +#define ICE_SFF8024_ID_NONE				0x00
> +#define ICE_SFF8024_ID_SFP				0x03
> +#define ICE_SFF8024_ID_QSFP				0x0c
> +#define ICE_SFF8024_ID_QSFP_PLUS			0x0d
> +#define ICE_SFF8024_ID_QSFP28				0x11
>  #define ICE_AQC_MOD_TYPE_BYTE0_SFP_PLUS			0xA0
>  #define ICE_AQC_MOD_TYPE_BYTE0_QSFP_PLUS		0x80
>  #define ICE_AQC_MOD_TYPE_IDENT				1
> 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
>