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