xref: /freebsd/sys/dev/sfxge/sfxge_nvram.c (revision d5106d05)
13c838a9fSAndrew Rybchenko /*-
2929c7febSAndrew Rybchenko  * Copyright (c) 2010-2016 Solarflare Communications, Inc.
33c838a9fSAndrew Rybchenko  * All rights reserved.
43c838a9fSAndrew Rybchenko  *
53c838a9fSAndrew Rybchenko  * This software was developed in part by OKTET Labs Ltd. under contract for
63c838a9fSAndrew Rybchenko  * Solarflare Communications, Inc.
73c838a9fSAndrew Rybchenko  *
83c838a9fSAndrew Rybchenko  * Redistribution and use in source and binary forms, with or without
93c838a9fSAndrew Rybchenko  * modification, are permitted provided that the following conditions
103c838a9fSAndrew Rybchenko  * are met:
113c838a9fSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright
123c838a9fSAndrew Rybchenko  *    notice, this list of conditions and the following disclaimer.
133c838a9fSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright
143c838a9fSAndrew Rybchenko  *    notice, this list of conditions and the following disclaimer in the
153c838a9fSAndrew Rybchenko  *    documentation and/or other materials provided with the distribution.
163c838a9fSAndrew Rybchenko  *
173c838a9fSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
183c838a9fSAndrew Rybchenko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
193c838a9fSAndrew Rybchenko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
203c838a9fSAndrew Rybchenko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
213c838a9fSAndrew Rybchenko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
223c838a9fSAndrew Rybchenko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
233c838a9fSAndrew Rybchenko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
243c838a9fSAndrew Rybchenko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
253c838a9fSAndrew Rybchenko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
263c838a9fSAndrew Rybchenko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
273c838a9fSAndrew Rybchenko  * SUCH DAMAGE.
283c838a9fSAndrew Rybchenko  */
293c838a9fSAndrew Rybchenko 
303c838a9fSAndrew Rybchenko #include <sys/cdefs.h>
313c838a9fSAndrew Rybchenko __FBSDID("$FreeBSD$");
323c838a9fSAndrew Rybchenko 
333c838a9fSAndrew Rybchenko 
343c838a9fSAndrew Rybchenko #include <sys/types.h>
353c838a9fSAndrew Rybchenko #include <sys/malloc.h>
363c838a9fSAndrew Rybchenko 
373c838a9fSAndrew Rybchenko #include "common/efx.h"
383c838a9fSAndrew Rybchenko #include "sfxge.h"
393c838a9fSAndrew Rybchenko 
403c838a9fSAndrew Rybchenko /* These data make no real sense, they are here just to make sfupdate happy.
413c838a9fSAndrew Rybchenko  * Any code that would rely on it is broken.
423c838a9fSAndrew Rybchenko  */
433c838a9fSAndrew Rybchenko static const uint8_t fake_dynamic_cfg_nvram[] = {
443c838a9fSAndrew Rybchenko 	0x7a, 0xda, 0x10, 0xef, 0x0c, 0x00, 0x00, 0x00,
453c838a9fSAndrew Rybchenko 	0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
463c838a9fSAndrew Rybchenko 	0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10,
473c838a9fSAndrew Rybchenko 	0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
483c838a9fSAndrew Rybchenko 	0x56, 0x01, 0xc3, 0x78, 0x01, 0x00, 0x03, 0x10,
493c838a9fSAndrew Rybchenko 	0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
503c838a9fSAndrew Rybchenko 	0x56, 0x01, 0xc3, 0x78, 0x57, 0x1a, 0x10, 0xef,
513c838a9fSAndrew Rybchenko 	0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
523c838a9fSAndrew Rybchenko 	0x02, 0x0b, 0x64, 0x7d, 0xee, 0xee, 0xee, 0xee
533c838a9fSAndrew Rybchenko };
543c838a9fSAndrew Rybchenko 
553c838a9fSAndrew Rybchenko static int
563c838a9fSAndrew Rybchenko sfxge_nvram_rw(struct sfxge_softc *sc, sfxge_ioc_t *ip, efx_nvram_type_t type,
573c838a9fSAndrew Rybchenko 	       boolean_t write)
583c838a9fSAndrew Rybchenko {
593c838a9fSAndrew Rybchenko 	efx_nic_t *enp = sc->enp;
603c838a9fSAndrew Rybchenko 	size_t total_size = ip->u.nvram.size;
613c838a9fSAndrew Rybchenko 	size_t chunk_size;
623c838a9fSAndrew Rybchenko 	off_t off;
633c838a9fSAndrew Rybchenko 	int rc = 0;
643c838a9fSAndrew Rybchenko 	uint8_t *buf;
653c838a9fSAndrew Rybchenko 
663c838a9fSAndrew Rybchenko 	if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
673c838a9fSAndrew Rybchenko 		if (write)
683c838a9fSAndrew Rybchenko 			return (0);
693c838a9fSAndrew Rybchenko 		rc = copyout(fake_dynamic_cfg_nvram, ip->u.nvram.data,
703c838a9fSAndrew Rybchenko 			     MIN(total_size, sizeof(fake_dynamic_cfg_nvram)));
713c838a9fSAndrew Rybchenko 		return (rc);
723c838a9fSAndrew Rybchenko 	}
733c838a9fSAndrew Rybchenko 
743c838a9fSAndrew Rybchenko 	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
753c838a9fSAndrew Rybchenko 		goto fail1;
763c838a9fSAndrew Rybchenko 
773c838a9fSAndrew Rybchenko 	buf = malloc(chunk_size, M_TEMP, M_WAITOK);
783c838a9fSAndrew Rybchenko 
793c838a9fSAndrew Rybchenko 	off = 0;
803c838a9fSAndrew Rybchenko 	while (total_size) {
813c838a9fSAndrew Rybchenko 		size_t len = MIN(chunk_size, total_size);
823c838a9fSAndrew Rybchenko 
833c838a9fSAndrew Rybchenko 		if (write) {
843c838a9fSAndrew Rybchenko 			rc = copyin(ip->u.nvram.data + off, buf, len);
853c838a9fSAndrew Rybchenko 			if (rc != 0)
863c838a9fSAndrew Rybchenko 				goto fail3;
873c838a9fSAndrew Rybchenko 			rc = efx_nvram_write_chunk(enp, type,
883c838a9fSAndrew Rybchenko 						   ip->u.nvram.offset + off, buf, len);
893c838a9fSAndrew Rybchenko 			if (rc != 0)
903c838a9fSAndrew Rybchenko 				goto fail3;
913c838a9fSAndrew Rybchenko 		} else {
923c838a9fSAndrew Rybchenko 			rc = efx_nvram_read_chunk(enp, type,
933c838a9fSAndrew Rybchenko 						  ip->u.nvram.offset + off, buf, len);
943c838a9fSAndrew Rybchenko 			if (rc != 0)
953c838a9fSAndrew Rybchenko 				goto fail3;
963c838a9fSAndrew Rybchenko 			rc = copyout(buf, ip->u.nvram.data + off, len);
973c838a9fSAndrew Rybchenko 			if (rc != 0)
983c838a9fSAndrew Rybchenko 				goto fail3;
993c838a9fSAndrew Rybchenko 		}
1003c838a9fSAndrew Rybchenko 
1013c838a9fSAndrew Rybchenko 		total_size -= len;
1023c838a9fSAndrew Rybchenko 		off += len;
1033c838a9fSAndrew Rybchenko 	}
1043c838a9fSAndrew Rybchenko 
1053c838a9fSAndrew Rybchenko fail3:
1063c838a9fSAndrew Rybchenko 	free(buf, M_TEMP);
107d5106d05SAndrew Rybchenko 	efx_nvram_rw_finish(enp, type, NULL);
1083c838a9fSAndrew Rybchenko fail1:
1093c838a9fSAndrew Rybchenko 	return (rc);
1103c838a9fSAndrew Rybchenko }
1113c838a9fSAndrew Rybchenko 
1123c838a9fSAndrew Rybchenko 
1133c838a9fSAndrew Rybchenko static int
1143c838a9fSAndrew Rybchenko sfxge_nvram_erase(struct sfxge_softc *sc, efx_nvram_type_t type)
1153c838a9fSAndrew Rybchenko {
1163c838a9fSAndrew Rybchenko 	efx_nic_t *enp = sc->enp;
1173c838a9fSAndrew Rybchenko 	size_t chunk_size;
1183c838a9fSAndrew Rybchenko 	int rc = 0;
1193c838a9fSAndrew Rybchenko 
1203c838a9fSAndrew Rybchenko 	if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA)
1213c838a9fSAndrew Rybchenko 		return (0);
1223c838a9fSAndrew Rybchenko 
1233c838a9fSAndrew Rybchenko 	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
1243c838a9fSAndrew Rybchenko 		return (rc);
1253c838a9fSAndrew Rybchenko 
1263c838a9fSAndrew Rybchenko 	rc = efx_nvram_erase(enp, type);
1273c838a9fSAndrew Rybchenko 
128d5106d05SAndrew Rybchenko 	efx_nvram_rw_finish(enp, type, NULL);
1293c838a9fSAndrew Rybchenko 	return (rc);
1303c838a9fSAndrew Rybchenko }
1313c838a9fSAndrew Rybchenko 
1323c838a9fSAndrew Rybchenko int
1333c838a9fSAndrew Rybchenko sfxge_nvram_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
1343c838a9fSAndrew Rybchenko {
1353c838a9fSAndrew Rybchenko 	static const efx_nvram_type_t nvram_types[] = {
1363c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_BOOTROM]  = EFX_NVRAM_BOOTROM,
1373c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_BOOTROM_CFG]  = EFX_NVRAM_BOOTROM_CFG,
1383c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_MC]  = EFX_NVRAM_MC_FIRMWARE,
1393c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_MC_GOLDEN]  = EFX_NVRAM_MC_GOLDEN,
1403c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_PHY]  = EFX_NVRAM_PHY,
1413c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_NULL_PHY]  = EFX_NVRAM_NULLPHY,
1423c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_FPGA]  = EFX_NVRAM_FPGA,
1433c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_FCFW]  = EFX_NVRAM_FCFW,
1443c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_CPLD]  = EFX_NVRAM_CPLD,
1453c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_FPGA_BACKUP]  = EFX_NVRAM_FPGA_BACKUP,
1463c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_DYNAMIC_CFG]  = EFX_NVRAM_DYNAMIC_CFG,
1473c838a9fSAndrew Rybchenko 	};
1483c838a9fSAndrew Rybchenko 
1493c838a9fSAndrew Rybchenko 	efx_nic_t *enp = sc->enp;
1503c838a9fSAndrew Rybchenko 	efx_nvram_type_t type;
1513c838a9fSAndrew Rybchenko 	int rc = 0;
1523c838a9fSAndrew Rybchenko 
1533c838a9fSAndrew Rybchenko 	if (ip->u.nvram.type > SFXGE_NVRAM_TYPE_DYNAMIC_CFG)
1543c838a9fSAndrew Rybchenko 		return (EINVAL);
1553c838a9fSAndrew Rybchenko 	type = nvram_types[ip->u.nvram.type];
1563c838a9fSAndrew Rybchenko 	if (type == EFX_NVRAM_MC_GOLDEN &&
1573c838a9fSAndrew Rybchenko 	    (ip->u.nvram.op == SFXGE_NVRAM_OP_WRITE ||
1583c838a9fSAndrew Rybchenko 	     ip->u.nvram.op == SFXGE_NVRAM_OP_ERASE ||
1593c838a9fSAndrew Rybchenko 	     ip->u.nvram.op == SFXGE_NVRAM_OP_SET_VER))
1603c838a9fSAndrew Rybchenko 		return (EOPNOTSUPP);
1613c838a9fSAndrew Rybchenko 
1623c838a9fSAndrew Rybchenko 	switch (ip->u.nvram.op) {
1633c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_SIZE:
1643c838a9fSAndrew Rybchenko 	{
1653c838a9fSAndrew Rybchenko 		size_t size;
1663c838a9fSAndrew Rybchenko 
1673c838a9fSAndrew Rybchenko 		if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
1683c838a9fSAndrew Rybchenko 			ip->u.nvram.size = sizeof(fake_dynamic_cfg_nvram);
1693c838a9fSAndrew Rybchenko 		} else {
1703c838a9fSAndrew Rybchenko 			if ((rc = efx_nvram_size(enp, type, &size)) != 0)
1713c838a9fSAndrew Rybchenko 				return (rc);
1723c838a9fSAndrew Rybchenko 			ip->u.nvram.size = size;
1733c838a9fSAndrew Rybchenko 		}
1743c838a9fSAndrew Rybchenko 		break;
1753c838a9fSAndrew Rybchenko 	}
1763c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_READ:
1773c838a9fSAndrew Rybchenko 		rc = sfxge_nvram_rw(sc, ip, type, B_FALSE);
1783c838a9fSAndrew Rybchenko 		break;
1793c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_WRITE:
1803c838a9fSAndrew Rybchenko 		rc = sfxge_nvram_rw(sc, ip, type, B_TRUE);
1813c838a9fSAndrew Rybchenko 		break;
1823c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_ERASE:
1833c838a9fSAndrew Rybchenko 		rc = sfxge_nvram_erase(sc, type);
1843c838a9fSAndrew Rybchenko 		break;
1853c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_GET_VER:
1863c838a9fSAndrew Rybchenko 		rc = efx_nvram_get_version(enp, type, &ip->u.nvram.subtype,
1873c838a9fSAndrew Rybchenko 					   &ip->u.nvram.version[0]);
1883c838a9fSAndrew Rybchenko 		break;
1893c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_SET_VER:
1903c838a9fSAndrew Rybchenko 		rc = efx_nvram_set_version(enp, type, &ip->u.nvram.version[0]);
1913c838a9fSAndrew Rybchenko 		break;
1923c838a9fSAndrew Rybchenko 	default:
1933c838a9fSAndrew Rybchenko 		rc = EOPNOTSUPP;
1943c838a9fSAndrew Rybchenko 		break;
1953c838a9fSAndrew Rybchenko 	}
1963c838a9fSAndrew Rybchenko 
1973c838a9fSAndrew Rybchenko 	return (rc);
1983c838a9fSAndrew Rybchenko }
199