Module Name:    src
Committed By:   yamaguchi
Date:           Fri Jan 17 09:42:05 UTC 2020

Modified Files:
        src/sys/dev/pci: if_ixl.c if_ixlvar.h

Log Message:
Print nvm version of ixl(4) when attaching

reviewed by msaitoh


To generate a diff of this commit:
cvs rdiff -u -r1.25 -r1.26 src/sys/dev/pci/if_ixl.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/pci/if_ixlvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_ixl.c
diff -u src/sys/dev/pci/if_ixl.c:1.25 src/sys/dev/pci/if_ixl.c:1.26
--- src/sys/dev/pci/if_ixl.c:1.25	Fri Jan 17 09:37:42 2020
+++ src/sys/dev/pci/if_ixl.c	Fri Jan 17 09:42:05 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ixl.c,v 1.25 2020/01/17 09:37:42 yamaguchi Exp $	*/
+/*	$NetBSD: if_ixl.c,v 1.26 2020/01/17 09:42:05 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2013-2015, Intel Corporation
@@ -198,6 +198,8 @@ struct ixl_softc; /* defined */
 
 #define IXL_ATQ_EXEC_TIMEOUT		(10 * hz)
 
+#define IXL_SRRD_SRCTL_ATTEMPTS		100000
+
 struct ixl_aq_regs {
 	bus_size_t		atq_tail;
 	bus_size_t		atq_head;
@@ -653,11 +655,14 @@ struct ixl_softc {
 	unsigned int		 sc_msix_vector_queue;
 
 	struct ixl_dmamem	 sc_scratch;
+	struct ixl_dmamem	 sc_aqbuf;
 
 	const struct ixl_aq_regs *
 				 sc_aq_regs;
 	uint32_t		 sc_aq_flags;
 #define IXL_SC_AQ_FLAG_RXCTL	__BIT(0)
+#define IXL_SC_AQ_FLAG_NVMLOCK	__BIT(1)
+#define IXL_SC_AQ_FLAG_NVMREAD	__BIT(2)
 
 	kmutex_t		 sc_atq_lock;
 	kcondvar_t		 sc_atq_cv;
@@ -753,6 +758,7 @@ static int	ixl_atq_post_locked(struct ix
 static void	ixl_atq_done(struct ixl_softc *);
 static int	ixl_atq_exec(struct ixl_softc *, struct ixl_atq *);
 static int	ixl_get_version(struct ixl_softc *);
+static int	ixl_get_nvm_version(struct ixl_softc *);
 static int	ixl_get_hw_capabilities(struct ixl_softc *);
 static int	ixl_pxe_clear(struct ixl_softc *);
 static int	ixl_lldp_shut(struct ixl_softc *);
@@ -780,6 +786,7 @@ static void	ixl_hmc_pack(void *, const v
 		    const struct ixl_hmc_pack *, unsigned int);
 static uint32_t	ixl_rd_rx_csr(struct ixl_softc *, uint32_t);
 static void	ixl_wr_rx_csr(struct ixl_softc *, uint32_t, uint32_t);
+static int	ixl_rd16_nvm(struct ixl_softc *, uint16_t, uint16_t *);
 
 static int	ixl_match(device_t, cfdata_t, void *);
 static void	ixl_attach(device_t, device_t, void *);
@@ -1176,6 +1183,13 @@ ixl_attach(device_t parent, device_t sel
 
 	ixl_wr(sc, sc->sc_aq_regs->arq_tail, sc->sc_arq_prod);
 
+	if (ixl_dmamem_alloc(sc, &sc->sc_aqbuf, IXL_AQ_BUFLEN, 0) != 0) {
+		aprint_error_dev(self, ", unable to allocate nvm buffer\n");
+		goto shutdown;
+	}
+
+	ixl_get_nvm_version(sc);
+
 	if (sc->sc_mac_type == I40E_MAC_X722)
 		sc->sc_nqueue_pairs_device = 128;
 	else
@@ -1185,7 +1199,7 @@ ixl_attach(device_t parent, device_t sel
 	if (rv != 0) {
 		aprint_error(", GET HW CAPABILITIES %s\n",
 		    rv == ETIMEDOUT ? "timeout" : "error");
-		goto shutdown;
+		goto free_aqbuf;
 	}
 
 	sc->sc_nqueue_pairs_max = MIN((int)sc->sc_nqueue_pairs_device, ncpu);
@@ -1203,7 +1217,7 @@ ixl_attach(device_t parent, device_t sel
 
 	if (ixl_get_mac(sc) != 0) {
 		/* error printed by ixl_get_mac */
-		goto shutdown;
+		goto free_aqbuf;
 	}
 
 	aprint_normal("\n");
@@ -1222,7 +1236,7 @@ ixl_attach(device_t parent, device_t sel
 
 	if (ixl_hmc(sc) != 0) {
 		/* error printed by ixl_hmc */
-		goto shutdown;
+		goto free_aqbuf;
 	}
 
 	if (ixl_lldp_shut(sc) != 0) {
@@ -1408,6 +1422,8 @@ free_scratch:
 	ixl_dmamem_free(sc, &sc->sc_scratch);
 free_hmc:
 	ixl_hmc_free(sc);
+free_aqbuf:
+	ixl_dmamem_free(sc, &sc->sc_aqbuf);
 shutdown:
 	ixl_wr(sc, sc->sc_aq_regs->atq_head, 0);
 	ixl_wr(sc, sc->sc_aq_regs->arq_head, 0);
@@ -1514,6 +1530,7 @@ ixl_detach(device_t self, int flags)
 
 	ixl_dmamem_free(sc, &sc->sc_arq);
 	ixl_dmamem_free(sc, &sc->sc_atq);
+	ixl_dmamem_free(sc, &sc->sc_aqbuf);
 
 	cv_destroy(&sc->sc_atq_cv);
 	mutex_destroy(&sc->sc_atq_lock);
@@ -3789,11 +3806,17 @@ ixl_get_version(struct ixl_softc *sc)
 	aprint_normal(", FW %hu.%hu.%05u API %hu.%hu", (uint16_t)fwver,
 	    (uint16_t)(fwver >> 16), fwbuild, api_maj_ver, api_min_ver);
 
+	if (sc->sc_mac_type == I40E_MAC_X722) {
+		SET(sc->sc_aq_flags, IXL_SC_AQ_FLAG_NVMLOCK |
+		    IXL_SC_AQ_FLAG_NVMREAD);
+	}
+
 #define IXL_API_VER(maj, min)	(((uint32_t)(maj) << 16) | (min))
 	if (IXL_API_VER(api_maj_ver, api_min_ver) >= IXL_API_VER(1, 5)) {
 		if (sc->sc_mac_type == I40E_MAC_X722) {
 			SET(sc->sc_aq_flags, IXL_SC_AQ_FLAG_RXCTL);
 		}
+		SET(sc->sc_aq_flags, IXL_SC_AQ_FLAG_NVMLOCK);
 	}
 #undef IXL_API_VER
 
@@ -3801,6 +3824,37 @@ ixl_get_version(struct ixl_softc *sc)
 }
 
 static int
+ixl_get_nvm_version(struct ixl_softc *sc)
+{
+	uint16_t nvmver, cfg_ptr, eetrack_hi, eetrack_lo, oem_hi, oem_lo;
+	uint32_t eetrack, oem;
+	uint16_t nvm_maj_ver, nvm_min_ver, oem_build;
+	uint8_t oem_ver, oem_patch;
+
+	nvmver = cfg_ptr = eetrack_hi = eetrack_lo = oem_hi = oem_lo = 0;
+	ixl_rd16_nvm(sc, I40E_SR_NVM_DEV_STARTER_VERSION, &nvmver);
+	ixl_rd16_nvm(sc, I40E_SR_NVM_EETRACK_HI, &eetrack_hi);
+	ixl_rd16_nvm(sc, I40E_SR_NVM_EETRACK_LO, &eetrack_lo);
+	ixl_rd16_nvm(sc, I40E_SR_BOOT_CONFIG_PTR, &cfg_ptr);
+	ixl_rd16_nvm(sc, cfg_ptr + I40E_NVM_OEM_VER_OFF, &oem_hi);
+	ixl_rd16_nvm(sc, cfg_ptr + I40E_NVM_OEM_VER_OFF + 1, &oem_lo);
+
+	nvm_maj_ver = (uint16_t)__SHIFTOUT(nvmver, IXL_NVM_VERSION_HI_MASK);
+	nvm_min_ver = (uint16_t)__SHIFTOUT(nvmver, IXL_NVM_VERSION_LO_MASK);
+	eetrack = ((uint32_t)eetrack_hi << 16) | eetrack_lo;
+	oem = ((uint32_t)oem_hi << 16) | oem_lo;
+	oem_ver = __SHIFTOUT(oem, IXL_NVM_OEMVERSION_MASK);
+	oem_build = __SHIFTOUT(oem, IXL_NVM_OEMBUILD_MASK);
+	oem_patch = __SHIFTOUT(oem, IXL_NVM_OEMPATCH_MASK);
+
+	aprint_normal(" nvm %x.%02x etid %08x oem %d.%d.%d",
+	    nvm_maj_ver, nvm_min_ver, eetrack,
+	    oem_ver, oem_build, oem_patch);
+
+	return 0;
+}
+
+static int
 ixl_pxe_clear(struct ixl_softc *sc)
 {
 	struct ixl_aq_desc iaq;
@@ -6344,6 +6398,208 @@ ixl_wr_rx_csr(struct ixl_softc *sc, uint
 	ixl_wr(sc, reg, value);
 }
 
+static int
+ixl_nvm_lock(struct ixl_softc *sc, char rw)
+{
+	struct ixl_aq_desc iaq;
+	struct ixl_aq_req_resource_param *param;
+	int rv;
+
+	if (!ISSET(sc->sc_aq_flags, IXL_SC_AQ_FLAG_NVMLOCK))
+		return 0;
+
+	memset(&iaq, 0, sizeof(iaq));
+	iaq.iaq_opcode = htole16(IXL_AQ_OP_REQUEST_RESOURCE);
+
+	param = (struct ixl_aq_req_resource_param *)&iaq.iaq_param;
+	param->resource_id = htole16(IXL_AQ_RESOURCE_ID_NVM);
+	if (rw == 'R') {
+		param->access_type = htole16(IXL_AQ_RESOURCE_ACCES_READ);
+	} else {
+		param->access_type = htole16(IXL_AQ_RESOURCE_ACCES_WRITE);
+	}
+
+	rv = ixl_atq_poll(sc, &iaq, 250);
+
+	if (rv != 0)
+		return ETIMEDOUT;
+
+	switch (le16toh(iaq.iaq_retval)) {
+	case IXL_AQ_RC_OK:
+		break;
+	case IXL_AQ_RC_EACCES:
+		return EACCES;
+	case IXL_AQ_RC_EBUSY:
+		return EBUSY;
+	case IXL_AQ_RC_EPERM:
+		return EPERM;
+	}
+
+	return 0;
+}
+
+static int
+ixl_nvm_unlock(struct ixl_softc *sc)
+{
+	struct ixl_aq_desc iaq;
+	struct ixl_aq_rel_resource_param *param;
+	int rv;
+
+	if (!ISSET(sc->sc_aq_flags, IXL_SC_AQ_FLAG_NVMLOCK))
+		return 0;
+
+	memset(&iaq, 0, sizeof(iaq));
+	iaq.iaq_opcode = htole16(IXL_AQ_OP_RELEASE_RESOURCE);
+
+	param = (struct ixl_aq_rel_resource_param *)&iaq.iaq_param;
+	param->resource_id = htole16(IXL_AQ_RESOURCE_ID_NVM);
+
+	rv = ixl_atq_poll(sc, &iaq, 250);
+
+	if (rv != 0)
+		return ETIMEDOUT;
+
+	switch (le16toh(iaq.iaq_retval)) {
+	case IXL_AQ_RC_OK:
+		break;
+	default:
+		return EIO;
+	}
+	return 0;
+}
+
+static int
+ixl_srdone_poll(struct ixl_softc *sc)
+{
+	int wait_count;
+	uint32_t reg;
+
+	for (wait_count = 0; wait_count < IXL_SRRD_SRCTL_ATTEMPTS;
+	    wait_count++) {
+		reg = ixl_rd(sc, I40E_GLNVM_SRCTL);
+		if (ISSET(reg, I40E_GLNVM_SRCTL_DONE_MASK))
+			break;
+
+		delaymsec(5);
+	}
+
+	if (wait_count == IXL_SRRD_SRCTL_ATTEMPTS)
+		return -1;
+
+	return 0;
+}
+
+static int
+ixl_nvm_read_srctl(struct ixl_softc *sc, uint16_t offset, uint16_t *data)
+{
+	uint32_t reg;
+
+	if (ixl_srdone_poll(sc) != 0)
+		return ETIMEDOUT;
+
+	reg = ((uint32_t)offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
+	    __BIT(I40E_GLNVM_SRCTL_START_SHIFT);
+	ixl_wr(sc, I40E_GLNVM_SRCTL, reg);
+
+	if (ixl_srdone_poll(sc) != 0) {
+		aprint_debug("NVM read error: couldn't access "
+		    "Shadow RAM address: 0x%x\n", offset);
+		return ETIMEDOUT;
+	}
+
+	reg = ixl_rd(sc, I40E_GLNVM_SRDATA);
+	*data = (uint16_t)__SHIFTOUT(reg, I40E_GLNVM_SRDATA_RDDATA_MASK);
+
+	return 0;
+}
+
+static int
+ixl_nvm_read_aq(struct ixl_softc *sc, uint16_t offset_word,
+    void *data, size_t len)
+{
+	struct ixl_dmamem *idm;
+	struct ixl_aq_desc iaq;
+	struct ixl_aq_nvm_param *param;
+	uint32_t offset_bytes;
+	int rv;
+
+	idm = &sc->sc_aqbuf;
+	if (len > IXL_DMA_LEN(idm))
+		return ENOMEM;
+
+	memset(IXL_DMA_KVA(idm), 0, IXL_DMA_LEN(idm));
+	memset(&iaq, 0, sizeof(iaq));
+	iaq.iaq_opcode = htole16(IXL_AQ_OP_NVM_READ);
+	iaq.iaq_flags = htole16(IXL_AQ_BUF |
+	    ((len > I40E_AQ_LARGE_BUF) ? IXL_AQ_LB : 0));
+	iaq.iaq_datalen = htole16(len);
+	ixl_aq_dva(&iaq, IXL_DMA_DVA(idm));
+
+	param = (struct ixl_aq_nvm_param *)iaq.iaq_param;
+	param->command_flags = IXL_AQ_NVM_LAST_CMD;
+	param->module_pointer = 0;
+	param->length = htole16(len);
+	offset_bytes = (uint32_t)offset_word * 2;
+	offset_bytes &= 0x00FFFFFF;
+	param->offset = htole32(offset_bytes);
+
+	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(idm), 0, IXL_DMA_LEN(idm),
+	    BUS_DMASYNC_PREREAD);
+
+	rv = ixl_atq_poll(sc, &iaq, 250);
+
+	bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(idm), 0, IXL_DMA_LEN(idm),
+	    BUS_DMASYNC_POSTREAD);
+
+	if (rv != 0) {
+		return ETIMEDOUT;
+	}
+
+	switch (le16toh(iaq.iaq_retval)) {
+	case IXL_AQ_RC_OK:
+		break;
+	case IXL_AQ_RC_EPERM:
+		return EPERM;
+	case IXL_AQ_RC_EINVAL:
+		return EINVAL;
+	case IXL_AQ_RC_EBUSY:
+		return EBUSY;
+	case IXL_AQ_RC_EIO:
+	default:
+		return EIO;
+	}
+
+	memcpy(data, IXL_DMA_KVA(idm), len);
+
+	return 0;
+}
+
+static int
+ixl_rd16_nvm(struct ixl_softc *sc, uint16_t offset, uint16_t *data)
+{
+	int error;
+	uint16_t buf;
+
+	error = ixl_nvm_lock(sc, 'R');
+	if (error)
+		return error;
+
+	if (ISSET(sc->sc_aq_flags, IXL_SC_AQ_FLAG_NVMREAD)) {
+		error = ixl_nvm_read_aq(sc, offset,
+		    &buf, sizeof(buf));
+		if (error == 0)
+			*data = le16toh(buf);
+	} else {
+		error = ixl_nvm_read_srctl(sc, offset, &buf);
+		if (error == 0)
+			*data = buf;
+	}
+
+	ixl_nvm_unlock(sc);
+
+	return error;
+}
+
 MODULE(MODULE_CLASS_DRIVER, if_ixl, "pci");
 
 #ifdef _MODULE

Index: src/sys/dev/pci/if_ixlvar.h
diff -u src/sys/dev/pci/if_ixlvar.h:1.3 src/sys/dev/pci/if_ixlvar.h:1.4
--- src/sys/dev/pci/if_ixlvar.h:1.3	Thu Dec 26 03:17:01 2019
+++ src/sys/dev/pci/if_ixlvar.h	Fri Jan 17 09:42:05 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ixlvar.h,v 1.3 2019/12/26 03:17:01 yamaguchi Exp $	*/
+/*	$NetBSD: if_ixlvar.h,v 1.4 2020/01/17 09:42:05 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2019 Internet Initiative Japan, Inc.
@@ -129,6 +129,7 @@ struct ixl_aq_desc {
 #define IXL_AQ_OP_PHY_SET_EVENT_MASK	0x0613
 #define IXL_AQ_OP_PHY_SET_REGISTER	0x0628
 #define IXL_AQ_OP_PHY_GET_REGISTER	0x0629
+#define IXL_AQ_OP_NVM_READ		0x0701
 #define IXL_AQ_OP_LLDP_GET_MIB		0x0a00
 #define IXL_AQ_OP_LLDP_MIB_CHG_EV	0x0a01
 #define IXL_AQ_OP_LLDP_ADD_TLV		0x0a02
@@ -656,6 +657,39 @@ struct ixl_aq_link_status { /* this occu
 #define IXL_AQ_PHY_EV_MODULE_QUAL_FAIL	(1 << 8)
 #define IXL_AQ_PHY_EV_PORT_TX_SUSPENDED	(1 << 9)
 
+struct ixl_aq_req_resource_param {
+	uint16_t	 resource_id;
+#define IXL_AQ_RESOURCE_ID_NVM		0x0001
+#define IXL_AQ_RESOURCE_ID_SDP		0x0002
+
+	uint16_t	 access_type;
+#define IXL_AQ_RESOURCE_ACCES_READ	0x01
+#define IXL_AQ_RESOURCE_ACCES_WRITE	0x02
+
+	uint16_t	 timeout;
+	uint32_t	 resource_num;
+	uint32_t	 reserved;
+} __packed __aligned(8);
+
+struct ixl_aq_rel_resource_param {
+	uint16_t	 resource_id;
+/* defined in ixl_aq_req_resource_param */
+	uint16_t	 _reserved1[3];
+	uint32_t	 resource_num;
+	uint32_t	 _reserved2;
+} __packed __aligned(8);
+
+struct ixl_aq_nvm_param {
+	uint8_t		 command_flags;
+#define IXL_AQ_NVM_LAST_CMD	(1 << 0)
+#define IXL_AQ_NVM_FLASH_ONLY	(1 << 7)
+	uint8_t		 module_pointer;
+	uint16_t	 length;
+	uint32_t	 offset;
+	uint32_t	 addr_hi;
+	uint32_t	 addr_lo;
+} __packed __aligned(4);
+
 /* aq response codes */
 #define IXL_AQ_RC_OK			0  /* success */
 #define IXL_AQ_RC_EPERM			1  /* Operation not permitted */
@@ -819,4 +853,20 @@ enum i40e_mac_type {
 	I40E_MAC_GENERIC
 };
 
+#define I40E_SR_NVM_DEV_STARTER_VERSION	0x18
+#define I40E_SR_BOOT_CONFIG_PTR		0x17
+#define I40E_NVM_OEM_VER_OFF		0x83
+#define I40E_SR_NVM_EETRACK_LO		0x2D
+#define I40E_SR_NVM_EETRACK_HI		0x2E
+
+#define IXL_NVM_VERSION_LO_SHIFT	0
+#define IXL_NVM_VERSION_LO_MASK		(0xffUL << IXL_NVM_VERSION_LO_SHIFT)
+#define IXL_NVM_VERSION_HI_SHIFT	12
+#define IXL_NVM_VERSION_HI_MASK		(0xfUL << IXL_NVM_VERSION_HI_SHIFT)
+#define IXL_NVM_OEMVERSION_SHIFT	24
+#define IXL_NVM_OEMVERSION_MASK		(0xffUL << IXL_NVM_OEMVERSION_SHIFT)
+#define IXL_NVM_OEMBUILD_SHIFT		8
+#define IXL_NVM_OEMBUILD_MASK		(0xffffUL << IXL_NVM_OEMBUILD_SHIFT)
+#define IXL_NVM_OEMPATCH_SHIFT		0
+#define IXL_NVM_OEMPATCH_MASK		(0xff << IXL_NVM_OEMPATCH_SHIFT)
 #endif

Reply via email to