xref: /freebsd/sys/dev/sfxge/sfxge_nvram.c (revision fdafd315)
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/types.h>
313c838a9fSAndrew Rybchenko #include <sys/malloc.h>
323c838a9fSAndrew Rybchenko 
333c838a9fSAndrew Rybchenko #include "common/efx.h"
343c838a9fSAndrew Rybchenko #include "sfxge.h"
353c838a9fSAndrew Rybchenko 
363c838a9fSAndrew Rybchenko /* These data make no real sense, they are here just to make sfupdate happy.
373c838a9fSAndrew Rybchenko  * Any code that would rely on it is broken.
383c838a9fSAndrew Rybchenko  */
393c838a9fSAndrew Rybchenko static const uint8_t fake_dynamic_cfg_nvram[] = {
403c838a9fSAndrew Rybchenko 	0x7a, 0xda, 0x10, 0xef, 0x0c, 0x00, 0x00, 0x00,
413c838a9fSAndrew Rybchenko 	0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
423c838a9fSAndrew Rybchenko 	0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10,
433c838a9fSAndrew Rybchenko 	0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
443c838a9fSAndrew Rybchenko 	0x56, 0x01, 0xc3, 0x78, 0x01, 0x00, 0x03, 0x10,
453c838a9fSAndrew Rybchenko 	0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
463c838a9fSAndrew Rybchenko 	0x56, 0x01, 0xc3, 0x78, 0x57, 0x1a, 0x10, 0xef,
473c838a9fSAndrew Rybchenko 	0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
483c838a9fSAndrew Rybchenko 	0x02, 0x0b, 0x64, 0x7d, 0xee, 0xee, 0xee, 0xee
493c838a9fSAndrew Rybchenko };
503c838a9fSAndrew Rybchenko 
513c838a9fSAndrew Rybchenko static int
sfxge_nvram_rw(struct sfxge_softc * sc,sfxge_ioc_t * ip,efx_nvram_type_t type,boolean_t write)523c838a9fSAndrew Rybchenko sfxge_nvram_rw(struct sfxge_softc *sc, sfxge_ioc_t *ip, efx_nvram_type_t type,
533c838a9fSAndrew Rybchenko 	       boolean_t write)
543c838a9fSAndrew Rybchenko {
553c838a9fSAndrew Rybchenko 	efx_nic_t *enp = sc->enp;
563c838a9fSAndrew Rybchenko 	size_t total_size = ip->u.nvram.size;
573c838a9fSAndrew Rybchenko 	size_t chunk_size;
583c838a9fSAndrew Rybchenko 	off_t off;
593c838a9fSAndrew Rybchenko 	int rc = 0;
603c838a9fSAndrew Rybchenko 	uint8_t *buf;
613c838a9fSAndrew Rybchenko 
623c838a9fSAndrew Rybchenko 	if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
633c838a9fSAndrew Rybchenko 		if (write)
643c838a9fSAndrew Rybchenko 			return (0);
653c838a9fSAndrew Rybchenko 		rc = copyout(fake_dynamic_cfg_nvram, ip->u.nvram.data,
663c838a9fSAndrew Rybchenko 			     MIN(total_size, sizeof(fake_dynamic_cfg_nvram)));
673c838a9fSAndrew Rybchenko 		return (rc);
683c838a9fSAndrew Rybchenko 	}
693c838a9fSAndrew Rybchenko 
703c838a9fSAndrew Rybchenko 	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
713c838a9fSAndrew Rybchenko 		goto fail1;
723c838a9fSAndrew Rybchenko 
733c838a9fSAndrew Rybchenko 	buf = malloc(chunk_size, M_TEMP, M_WAITOK);
743c838a9fSAndrew Rybchenko 
753c838a9fSAndrew Rybchenko 	off = 0;
763c838a9fSAndrew Rybchenko 	while (total_size) {
773c838a9fSAndrew Rybchenko 		size_t len = MIN(chunk_size, total_size);
783c838a9fSAndrew Rybchenko 
793c838a9fSAndrew Rybchenko 		if (write) {
803c838a9fSAndrew Rybchenko 			rc = copyin(ip->u.nvram.data + off, buf, len);
813c838a9fSAndrew Rybchenko 			if (rc != 0)
823c838a9fSAndrew Rybchenko 				goto fail3;
833c838a9fSAndrew Rybchenko 			rc = efx_nvram_write_chunk(enp, type,
843c838a9fSAndrew Rybchenko 						   ip->u.nvram.offset + off, buf, len);
853c838a9fSAndrew Rybchenko 			if (rc != 0)
863c838a9fSAndrew Rybchenko 				goto fail3;
873c838a9fSAndrew Rybchenko 		} else {
883c838a9fSAndrew Rybchenko 			rc = efx_nvram_read_chunk(enp, type,
893c838a9fSAndrew Rybchenko 						  ip->u.nvram.offset + off, buf, len);
903c838a9fSAndrew Rybchenko 			if (rc != 0)
913c838a9fSAndrew Rybchenko 				goto fail3;
923c838a9fSAndrew Rybchenko 			rc = copyout(buf, ip->u.nvram.data + off, len);
933c838a9fSAndrew Rybchenko 			if (rc != 0)
943c838a9fSAndrew Rybchenko 				goto fail3;
953c838a9fSAndrew Rybchenko 		}
963c838a9fSAndrew Rybchenko 
973c838a9fSAndrew Rybchenko 		total_size -= len;
983c838a9fSAndrew Rybchenko 		off += len;
993c838a9fSAndrew Rybchenko 	}
1003c838a9fSAndrew Rybchenko 
1013c838a9fSAndrew Rybchenko fail3:
1023c838a9fSAndrew Rybchenko 	free(buf, M_TEMP);
103d5106d05SAndrew Rybchenko 	efx_nvram_rw_finish(enp, type, NULL);
1043c838a9fSAndrew Rybchenko fail1:
1053c838a9fSAndrew Rybchenko 	return (rc);
1063c838a9fSAndrew Rybchenko }
1073c838a9fSAndrew Rybchenko 
1083c838a9fSAndrew Rybchenko static int
sfxge_nvram_erase(struct sfxge_softc * sc,efx_nvram_type_t type)1093c838a9fSAndrew Rybchenko sfxge_nvram_erase(struct sfxge_softc *sc, efx_nvram_type_t type)
1103c838a9fSAndrew Rybchenko {
1113c838a9fSAndrew Rybchenko 	efx_nic_t *enp = sc->enp;
1123c838a9fSAndrew Rybchenko 	size_t chunk_size;
1133c838a9fSAndrew Rybchenko 	int rc = 0;
1143c838a9fSAndrew Rybchenko 
1153c838a9fSAndrew Rybchenko 	if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA)
1163c838a9fSAndrew Rybchenko 		return (0);
1173c838a9fSAndrew Rybchenko 
1183c838a9fSAndrew Rybchenko 	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
1193c838a9fSAndrew Rybchenko 		return (rc);
1203c838a9fSAndrew Rybchenko 
1213c838a9fSAndrew Rybchenko 	rc = efx_nvram_erase(enp, type);
1223c838a9fSAndrew Rybchenko 
123d5106d05SAndrew Rybchenko 	efx_nvram_rw_finish(enp, type, NULL);
1243c838a9fSAndrew Rybchenko 	return (rc);
1253c838a9fSAndrew Rybchenko }
1263c838a9fSAndrew Rybchenko 
1273c838a9fSAndrew Rybchenko int
sfxge_nvram_ioctl(struct sfxge_softc * sc,sfxge_ioc_t * ip)1283c838a9fSAndrew Rybchenko sfxge_nvram_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
1293c838a9fSAndrew Rybchenko {
1303c838a9fSAndrew Rybchenko 	static const efx_nvram_type_t nvram_types[] = {
1313c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_BOOTROM]  = EFX_NVRAM_BOOTROM,
1323c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_BOOTROM_CFG]  = EFX_NVRAM_BOOTROM_CFG,
1333c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_MC]  = EFX_NVRAM_MC_FIRMWARE,
1343c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_MC_GOLDEN]  = EFX_NVRAM_MC_GOLDEN,
1353c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_PHY]  = EFX_NVRAM_PHY,
1363c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_NULL_PHY]  = EFX_NVRAM_NULLPHY,
1373c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_FPGA]  = EFX_NVRAM_FPGA,
1383c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_FCFW]  = EFX_NVRAM_FCFW,
1393c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_CPLD]  = EFX_NVRAM_CPLD,
1403c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_FPGA_BACKUP]  = EFX_NVRAM_FPGA_BACKUP,
1413c838a9fSAndrew Rybchenko 		[SFXGE_NVRAM_TYPE_DYNAMIC_CFG]  = EFX_NVRAM_DYNAMIC_CFG,
1423c838a9fSAndrew Rybchenko 	};
1433c838a9fSAndrew Rybchenko 
1443c838a9fSAndrew Rybchenko 	efx_nic_t *enp = sc->enp;
1453c838a9fSAndrew Rybchenko 	efx_nvram_type_t type;
1463c838a9fSAndrew Rybchenko 	int rc = 0;
1473c838a9fSAndrew Rybchenko 
1483c838a9fSAndrew Rybchenko 	if (ip->u.nvram.type > SFXGE_NVRAM_TYPE_DYNAMIC_CFG)
1493c838a9fSAndrew Rybchenko 		return (EINVAL);
1503c838a9fSAndrew Rybchenko 	type = nvram_types[ip->u.nvram.type];
1513c838a9fSAndrew Rybchenko 	if (type == EFX_NVRAM_MC_GOLDEN &&
1523c838a9fSAndrew Rybchenko 	    (ip->u.nvram.op == SFXGE_NVRAM_OP_WRITE ||
1533c838a9fSAndrew Rybchenko 	     ip->u.nvram.op == SFXGE_NVRAM_OP_ERASE ||
1543c838a9fSAndrew Rybchenko 	     ip->u.nvram.op == SFXGE_NVRAM_OP_SET_VER))
1553c838a9fSAndrew Rybchenko 		return (EOPNOTSUPP);
1563c838a9fSAndrew Rybchenko 
1573c838a9fSAndrew Rybchenko 	switch (ip->u.nvram.op) {
1583c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_SIZE:
1593c838a9fSAndrew Rybchenko 	{
1603c838a9fSAndrew Rybchenko 		size_t size;
1613c838a9fSAndrew Rybchenko 
1623c838a9fSAndrew Rybchenko 		if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
1633c838a9fSAndrew Rybchenko 			ip->u.nvram.size = sizeof(fake_dynamic_cfg_nvram);
1643c838a9fSAndrew Rybchenko 		} else {
1653c838a9fSAndrew Rybchenko 			if ((rc = efx_nvram_size(enp, type, &size)) != 0)
1663c838a9fSAndrew Rybchenko 				return (rc);
1673c838a9fSAndrew Rybchenko 			ip->u.nvram.size = size;
1683c838a9fSAndrew Rybchenko 		}
1693c838a9fSAndrew Rybchenko 		break;
1703c838a9fSAndrew Rybchenko 	}
1713c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_READ:
1723c838a9fSAndrew Rybchenko 		rc = sfxge_nvram_rw(sc, ip, type, B_FALSE);
1733c838a9fSAndrew Rybchenko 		break;
1743c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_WRITE:
1753c838a9fSAndrew Rybchenko 		rc = sfxge_nvram_rw(sc, ip, type, B_TRUE);
1763c838a9fSAndrew Rybchenko 		break;
1773c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_ERASE:
1783c838a9fSAndrew Rybchenko 		rc = sfxge_nvram_erase(sc, type);
1793c838a9fSAndrew Rybchenko 		break;
1803c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_GET_VER:
1813c838a9fSAndrew Rybchenko 		rc = efx_nvram_get_version(enp, type, &ip->u.nvram.subtype,
1823c838a9fSAndrew Rybchenko 					   &ip->u.nvram.version[0]);
1833c838a9fSAndrew Rybchenko 		break;
1843c838a9fSAndrew Rybchenko 	case SFXGE_NVRAM_OP_SET_VER:
1853c838a9fSAndrew Rybchenko 		rc = efx_nvram_set_version(enp, type, &ip->u.nvram.version[0]);
1863c838a9fSAndrew Rybchenko 		break;
1873c838a9fSAndrew Rybchenko 	default:
1883c838a9fSAndrew Rybchenko 		rc = EOPNOTSUPP;
1893c838a9fSAndrew Rybchenko 		break;
1903c838a9fSAndrew Rybchenko 	}
1913c838a9fSAndrew Rybchenko 
1923c838a9fSAndrew Rybchenko 	return (rc);
1933c838a9fSAndrew Rybchenko }
194