siena_nvram.c revision 294250
1227569Sphilip/*- 2283514Sarybchik * Copyright (c) 2009-2015 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4227569Sphilip * 5227569Sphilip * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7227569Sphilip * 8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9283514Sarybchik * this list of conditions and the following disclaimer. 10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11283514Sarybchik * this list of conditions and the following disclaimer in the documentation 12283514Sarybchik * and/or other materials provided with the distribution. 13283514Sarybchik * 14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25283514Sarybchik * 26283514Sarybchik * The views and conclusions contained in the software and documentation are 27283514Sarybchik * those of the authors and should not be interpreted as representing official 28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29227569Sphilip */ 30227569Sphilip 31228078Sphilip#include <sys/cdefs.h> 32228078Sphilip__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/siena_nvram.c 294250 2016-01-18 06:14:43Z arybchik $"); 33228078Sphilip 34227569Sphilip#include "efx.h" 35227569Sphilip#include "efx_impl.h" 36227569Sphilip 37227569Sphilip#if EFSYS_OPT_SIENA 38227569Sphilip 39227569Sphilip#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM 40227569Sphilip 41291436Sarybchik __checkReturn efx_rc_t 42227569Sphilipsiena_nvram_partn_size( 43227569Sphilip __in efx_nic_t *enp, 44293770Sarybchik __in uint32_t partn, 45227569Sphilip __out size_t *sizep) 46227569Sphilip{ 47291436Sarybchik efx_rc_t rc; 48227569Sphilip 49227569Sphilip if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 50227569Sphilip rc = ENOTSUP; 51227569Sphilip goto fail1; 52227569Sphilip } 53227569Sphilip 54291746Sarybchik if ((rc = efx_mcdi_nvram_info(enp, partn, sizep, 55291746Sarybchik NULL, NULL, NULL)) != 0) { 56227569Sphilip goto fail2; 57227569Sphilip } 58227569Sphilip 59227569Sphilip return (0); 60227569Sphilip 61227569Sphilipfail2: 62227569Sphilip EFSYS_PROBE(fail2); 63227569Sphilipfail1: 64291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 65227569Sphilip 66227569Sphilip return (rc); 67227569Sphilip} 68227569Sphilip 69291436Sarybchik __checkReturn efx_rc_t 70227569Sphilipsiena_nvram_partn_lock( 71227569Sphilip __in efx_nic_t *enp, 72293770Sarybchik __in uint32_t partn) 73227569Sphilip{ 74291436Sarybchik efx_rc_t rc; 75227569Sphilip 76283514Sarybchik if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) { 77227569Sphilip goto fail1; 78227569Sphilip } 79227569Sphilip 80227569Sphilip return (0); 81227569Sphilip 82227569Sphilipfail1: 83291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 84227569Sphilip 85227569Sphilip return (rc); 86227569Sphilip} 87227569Sphilip 88291436Sarybchik __checkReturn efx_rc_t 89227569Sphilipsiena_nvram_partn_read( 90227569Sphilip __in efx_nic_t *enp, 91293770Sarybchik __in uint32_t partn, 92227569Sphilip __in unsigned int offset, 93227569Sphilip __out_bcount(size) caddr_t data, 94227569Sphilip __in size_t size) 95227569Sphilip{ 96227569Sphilip size_t chunk; 97291436Sarybchik efx_rc_t rc; 98227569Sphilip 99227569Sphilip while (size > 0) { 100227569Sphilip chunk = MIN(size, SIENA_NVRAM_CHUNK); 101227569Sphilip 102283514Sarybchik if ((rc = efx_mcdi_nvram_read(enp, partn, offset, 103283514Sarybchik data, chunk)) != 0) { 104227569Sphilip goto fail1; 105227569Sphilip } 106227569Sphilip 107227569Sphilip size -= chunk; 108227569Sphilip data += chunk; 109227569Sphilip offset += chunk; 110227569Sphilip } 111227569Sphilip 112227569Sphilip return (0); 113227569Sphilip 114227569Sphilipfail1: 115291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 116227569Sphilip 117227569Sphilip return (rc); 118227569Sphilip} 119227569Sphilip 120291436Sarybchik __checkReturn efx_rc_t 121227569Sphilipsiena_nvram_partn_erase( 122227569Sphilip __in efx_nic_t *enp, 123293770Sarybchik __in uint32_t partn, 124227569Sphilip __in unsigned int offset, 125227569Sphilip __in size_t size) 126227569Sphilip{ 127291436Sarybchik efx_rc_t rc; 128227569Sphilip 129283514Sarybchik if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) { 130227569Sphilip goto fail1; 131227569Sphilip } 132227569Sphilip 133227569Sphilip return (0); 134227569Sphilip 135227569Sphilipfail1: 136291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 137227569Sphilip 138227569Sphilip return (rc); 139227569Sphilip} 140227569Sphilip 141291436Sarybchik __checkReturn efx_rc_t 142227569Sphilipsiena_nvram_partn_write( 143227569Sphilip __in efx_nic_t *enp, 144293770Sarybchik __in uint32_t partn, 145227569Sphilip __in unsigned int offset, 146227569Sphilip __out_bcount(size) caddr_t data, 147227569Sphilip __in size_t size) 148227569Sphilip{ 149227569Sphilip size_t chunk; 150291436Sarybchik efx_rc_t rc; 151227569Sphilip 152227569Sphilip while (size > 0) { 153227569Sphilip chunk = MIN(size, SIENA_NVRAM_CHUNK); 154227569Sphilip 155283514Sarybchik if ((rc = efx_mcdi_nvram_write(enp, partn, offset, 156283514Sarybchik data, chunk)) != 0) { 157227569Sphilip goto fail1; 158227569Sphilip } 159227569Sphilip 160227569Sphilip size -= chunk; 161227569Sphilip data += chunk; 162227569Sphilip offset += chunk; 163227569Sphilip } 164227569Sphilip 165227569Sphilip return (0); 166227569Sphilip 167227569Sphilipfail1: 168291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 169227569Sphilip 170227569Sphilip return (rc); 171227569Sphilip} 172227569Sphilip 173227569Sphilip void 174227569Sphilipsiena_nvram_partn_unlock( 175227569Sphilip __in efx_nic_t *enp, 176293770Sarybchik __in uint32_t partn) 177227569Sphilip{ 178283514Sarybchik boolean_t reboot; 179291436Sarybchik efx_rc_t rc; 180227569Sphilip 181227569Sphilip /* 182227569Sphilip * Reboot into the new image only for PHYs. The driver has to 183227569Sphilip * explicitly cope with an MC reboot after a firmware update. 184227569Sphilip */ 185227569Sphilip reboot = (partn == MC_CMD_NVRAM_TYPE_PHY_PORT0 || 186227569Sphilip partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 || 187227569Sphilip partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO); 188227569Sphilip 189283514Sarybchik if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0) { 190227569Sphilip goto fail1; 191227569Sphilip } 192227569Sphilip 193227569Sphilip return; 194227569Sphilip 195227569Sphilipfail1: 196291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 197227569Sphilip} 198227569Sphilip 199227569Sphilip#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ 200227569Sphilip 201227569Sphilip#if EFSYS_OPT_NVRAM 202227569Sphilip 203227569Sphiliptypedef struct siena_parttbl_entry_s { 204227569Sphilip unsigned int partn; 205227569Sphilip unsigned int port; 206227569Sphilip efx_nvram_type_t nvtype; 207227569Sphilip} siena_parttbl_entry_t; 208227569Sphilip 209227569Sphilipstatic siena_parttbl_entry_t siena_parttbl[] = { 210227569Sphilip {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 1, EFX_NVRAM_NULLPHY}, 211227569Sphilip {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 2, EFX_NVRAM_NULLPHY}, 212227569Sphilip {MC_CMD_NVRAM_TYPE_MC_FW, 1, EFX_NVRAM_MC_FIRMWARE}, 213227569Sphilip {MC_CMD_NVRAM_TYPE_MC_FW, 2, EFX_NVRAM_MC_FIRMWARE}, 214227569Sphilip {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, 215227569Sphilip {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, 216227569Sphilip {MC_CMD_NVRAM_TYPE_EXP_ROM, 1, EFX_NVRAM_BOOTROM}, 217227569Sphilip {MC_CMD_NVRAM_TYPE_EXP_ROM, 2, EFX_NVRAM_BOOTROM}, 218227569Sphilip {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, 219227569Sphilip {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG}, 220227569Sphilip {MC_CMD_NVRAM_TYPE_PHY_PORT0, 1, EFX_NVRAM_PHY}, 221227569Sphilip {MC_CMD_NVRAM_TYPE_PHY_PORT1, 2, EFX_NVRAM_PHY}, 222279173Sarybchik {MC_CMD_NVRAM_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, 223279173Sarybchik {MC_CMD_NVRAM_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, 224279173Sarybchik {MC_CMD_NVRAM_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, 225279173Sarybchik {MC_CMD_NVRAM_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, 226279173Sarybchik {MC_CMD_NVRAM_TYPE_FC_FW, 1, EFX_NVRAM_FCFW}, 227279173Sarybchik {MC_CMD_NVRAM_TYPE_FC_FW, 2, EFX_NVRAM_FCFW}, 228279173Sarybchik {MC_CMD_NVRAM_TYPE_CPLD, 1, EFX_NVRAM_CPLD}, 229279173Sarybchik {MC_CMD_NVRAM_TYPE_CPLD, 2, EFX_NVRAM_CPLD}, 230293900Sarybchik {MC_CMD_NVRAM_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, 231293900Sarybchik {MC_CMD_NVRAM_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE} 232227569Sphilip}; 233227569Sphilip 234293810Sarybchik __checkReturn efx_rc_t 235293810Sarybchiksiena_nvram_type_to_partn( 236227569Sphilip __in efx_nic_t *enp, 237293810Sarybchik __in efx_nvram_type_t type, 238293810Sarybchik __out uint32_t *partnp) 239227569Sphilip{ 240283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 241283514Sarybchik unsigned int i; 242227569Sphilip 243227569Sphilip EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 244293810Sarybchik EFSYS_ASSERT(partnp != NULL); 245227569Sphilip 246283514Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) { 247293810Sarybchik siena_parttbl_entry_t *entry = &siena_parttbl[i]; 248283514Sarybchik 249293810Sarybchik if (entry->port == emip->emi_port && entry->nvtype == type) { 250293810Sarybchik *partnp = entry->partn; 251293810Sarybchik return (0); 252293810Sarybchik } 253227569Sphilip } 254227569Sphilip 255293810Sarybchik return (ENOTSUP); 256227569Sphilip} 257227569Sphilip 258293810Sarybchik 259227569Sphilip#if EFSYS_OPT_DIAG 260227569Sphilip 261291436Sarybchik __checkReturn efx_rc_t 262227569Sphilipsiena_nvram_test( 263227569Sphilip __in efx_nic_t *enp) 264227569Sphilip{ 265283514Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 266227569Sphilip siena_parttbl_entry_t *entry; 267283514Sarybchik unsigned int i; 268291436Sarybchik efx_rc_t rc; 269227569Sphilip 270227569Sphilip /* 271227569Sphilip * Iterate over the list of supported partition types 272227569Sphilip * applicable to *this* port 273227569Sphilip */ 274283514Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) { 275283514Sarybchik entry = &siena_parttbl[i]; 276283514Sarybchik 277227569Sphilip if (entry->port != emip->emi_port || 278227569Sphilip !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn))) 279227569Sphilip continue; 280227569Sphilip 281283514Sarybchik if ((rc = efx_mcdi_nvram_test(enp, entry->partn)) != 0) { 282227569Sphilip goto fail1; 283227569Sphilip } 284227569Sphilip } 285227569Sphilip 286227569Sphilip return (0); 287227569Sphilip 288227569Sphilipfail1: 289291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 290227569Sphilip 291227569Sphilip return (rc); 292227569Sphilip} 293227569Sphilip 294227569Sphilip#endif /* EFSYS_OPT_DIAG */ 295227569Sphilip 296227569Sphilip 297227569Sphilip#define SIENA_DYNAMIC_CFG_SIZE(_nitems) \ 298227569Sphilip (sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) * \ 299227569Sphilip sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0]))) 300227569Sphilip 301291436Sarybchik __checkReturn efx_rc_t 302227569Sphilipsiena_nvram_get_dynamic_cfg( 303227569Sphilip __in efx_nic_t *enp, 304293770Sarybchik __in uint32_t partn, 305227569Sphilip __in boolean_t vpd, 306227569Sphilip __out siena_mc_dynamic_config_hdr_t **dcfgp, 307227569Sphilip __out size_t *sizep) 308227569Sphilip{ 309283514Sarybchik siena_mc_dynamic_config_hdr_t *dcfg = NULL; 310227569Sphilip size_t size; 311227569Sphilip uint8_t cksum; 312227569Sphilip unsigned int vpd_offset; 313227569Sphilip unsigned int vpd_length; 314227569Sphilip unsigned int hdr_length; 315227569Sphilip unsigned int nversions; 316227569Sphilip unsigned int pos; 317227569Sphilip unsigned int region; 318291436Sarybchik efx_rc_t rc; 319227569Sphilip 320227569Sphilip EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 || 321227569Sphilip partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1); 322227569Sphilip 323227569Sphilip /* 324227569Sphilip * Allocate sufficient memory for the entire dynamiccfg area, even 325227569Sphilip * if we're not actually going to read in the VPD. 326227569Sphilip */ 327227569Sphilip if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0) 328227569Sphilip goto fail1; 329227569Sphilip 330227569Sphilip EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg); 331227569Sphilip if (dcfg == NULL) { 332227569Sphilip rc = ENOMEM; 333227569Sphilip goto fail2; 334227569Sphilip } 335227569Sphilip 336227569Sphilip if ((rc = siena_nvram_partn_read(enp, partn, 0, 337227569Sphilip (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0) 338227569Sphilip goto fail3; 339227569Sphilip 340227569Sphilip /* Verify the magic */ 341227569Sphilip if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0) 342227569Sphilip != SIENA_MC_DYNAMIC_CONFIG_MAGIC) 343227569Sphilip goto invalid1; 344227569Sphilip 345227569Sphilip /* All future versions of the structure must be backwards compatable */ 346227569Sphilip EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0); 347227569Sphilip 348227569Sphilip hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 349227569Sphilip nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 350227569Sphilip vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 351227569Sphilip vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 352227569Sphilip 353227569Sphilip /* Verify the hdr doesn't overflow the partn size */ 354227569Sphilip if (hdr_length > size || vpd_offset > size || vpd_length > size || 355227569Sphilip vpd_length + vpd_offset > size) 356227569Sphilip goto invalid2; 357227569Sphilip 358227569Sphilip /* Verify the header has room for all it's versions */ 359227569Sphilip if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) || 360227569Sphilip hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions)) 361227569Sphilip goto invalid3; 362227569Sphilip 363227569Sphilip /* 364227569Sphilip * Read the remaining portion of the dcfg, either including 365227569Sphilip * the whole of VPD (there is no vpd length in this structure, 366227569Sphilip * so we have to parse each tag), or just the dcfg header itself 367227569Sphilip */ 368227569Sphilip region = vpd ? vpd_offset + vpd_length : hdr_length; 369227569Sphilip if (region > SIENA_NVRAM_CHUNK) { 370227569Sphilip if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK, 371227569Sphilip (caddr_t)dcfg + SIENA_NVRAM_CHUNK, 372227569Sphilip region - SIENA_NVRAM_CHUNK)) != 0) 373227569Sphilip goto fail4; 374227569Sphilip } 375227569Sphilip 376227569Sphilip /* Verify checksum */ 377227569Sphilip cksum = 0; 378227569Sphilip for (pos = 0; pos < hdr_length; pos++) 379227569Sphilip cksum += ((uint8_t *)dcfg)[pos]; 380227569Sphilip if (cksum != 0) 381227569Sphilip goto invalid4; 382227569Sphilip 383227569Sphilip goto done; 384227569Sphilip 385227569Sphilipinvalid4: 386227569Sphilip EFSYS_PROBE(invalid4); 387227569Sphilipinvalid3: 388227569Sphilip EFSYS_PROBE(invalid3); 389227569Sphilipinvalid2: 390227569Sphilip EFSYS_PROBE(invalid2); 391227569Sphilipinvalid1: 392227569Sphilip EFSYS_PROBE(invalid1); 393227569Sphilip 394227569Sphilip /* 395227569Sphilip * Construct a new "null" dcfg, with an empty version vector, 396227569Sphilip * and an empty VPD chunk trailing. This has the neat side effect 397227569Sphilip * of testing the exception paths in the write path. 398227569Sphilip */ 399227569Sphilip EFX_POPULATE_DWORD_1(dcfg->magic, 400227569Sphilip EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC); 401227569Sphilip EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg)); 402227569Sphilip EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0, 403227569Sphilip SIENA_MC_DYNAMIC_CONFIG_VERSION); 404227569Sphilip EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 405227569Sphilip EFX_DWORD_0, sizeof (*dcfg)); 406227569Sphilip EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0); 407227569Sphilip EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0); 408227569Sphilip 409227569Sphilipdone: 410227569Sphilip *dcfgp = dcfg; 411227569Sphilip *sizep = size; 412227569Sphilip 413227569Sphilip return (0); 414227569Sphilip 415227569Sphilipfail4: 416227569Sphilip EFSYS_PROBE(fail4); 417227569Sphilipfail3: 418227569Sphilip EFSYS_PROBE(fail3); 419227569Sphilip 420227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, size, dcfg); 421227569Sphilip 422283514Sarybchikfail2: 423283514Sarybchik EFSYS_PROBE(fail2); 424227569Sphilipfail1: 425291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 426227569Sphilip 427227569Sphilip return (rc); 428227569Sphilip} 429227569Sphilip 430291436Sarybchik __checkReturn efx_rc_t 431227569Sphilipsiena_nvram_get_subtype( 432227569Sphilip __in efx_nic_t *enp, 433293770Sarybchik __in uint32_t partn, 434227569Sphilip __out uint32_t *subtypep) 435227569Sphilip{ 436227569Sphilip efx_mcdi_req_t req; 437283514Sarybchik uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN, 438283514Sarybchik MC_CMD_GET_BOARD_CFG_OUT_LENMAX)]; 439227569Sphilip efx_word_t *fw_list; 440291436Sarybchik efx_rc_t rc; 441227569Sphilip 442283514Sarybchik (void) memset(payload, 0, sizeof (payload)); 443227569Sphilip req.emr_cmd = MC_CMD_GET_BOARD_CFG; 444283514Sarybchik req.emr_in_buf = payload; 445283514Sarybchik req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; 446283514Sarybchik req.emr_out_buf = payload; 447283514Sarybchik req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMAX; 448227569Sphilip 449227569Sphilip efx_mcdi_execute(enp, &req); 450227569Sphilip 451227569Sphilip if (req.emr_rc != 0) { 452227569Sphilip rc = req.emr_rc; 453227569Sphilip goto fail1; 454227569Sphilip } 455227569Sphilip 456278941Sarybchik if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 457227569Sphilip rc = EMSGSIZE; 458227569Sphilip goto fail2; 459227569Sphilip } 460227569Sphilip 461278941Sarybchik if (req.emr_out_length_used < 462278941Sarybchik MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST + 463279141Sarybchik (partn + 1) * sizeof (efx_word_t)) { 464278941Sarybchik rc = ENOENT; 465278941Sarybchik goto fail3; 466278941Sarybchik } 467278941Sarybchik 468227569Sphilip fw_list = MCDI_OUT2(req, efx_word_t, 469227569Sphilip GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST); 470227569Sphilip *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0); 471227569Sphilip 472227569Sphilip return (0); 473227569Sphilip 474278941Sarybchikfail3: 475278941Sarybchik EFSYS_PROBE(fail3); 476227569Sphilipfail2: 477227569Sphilip EFSYS_PROBE(fail2); 478227569Sphilipfail1: 479291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 480227569Sphilip 481227569Sphilip return (rc); 482227569Sphilip} 483227569Sphilip 484291436Sarybchik __checkReturn efx_rc_t 485227569Sphilipsiena_nvram_get_version( 486227569Sphilip __in efx_nic_t *enp, 487227569Sphilip __in efx_nvram_type_t type, 488227569Sphilip __out uint32_t *subtypep, 489227569Sphilip __out_ecount(4) uint16_t version[4]) 490227569Sphilip{ 491227569Sphilip siena_mc_dynamic_config_hdr_t *dcfg; 492227569Sphilip siena_parttbl_entry_t *entry; 493293770Sarybchik uint32_t dcfg_partn; 494293770Sarybchik uint32_t partn; 495283514Sarybchik unsigned int i; 496291436Sarybchik efx_rc_t rc; 497227569Sphilip 498293810Sarybchik if ((rc = siena_nvram_type_to_partn(enp, type, &partn)) != 0) 499227569Sphilip goto fail1; 500227569Sphilip 501227569Sphilip if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 502227569Sphilip rc = ENOTSUP; 503227569Sphilip goto fail2; 504227569Sphilip } 505227569Sphilip 506227569Sphilip if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0) 507227569Sphilip goto fail3; 508227569Sphilip 509227569Sphilip /* 510227569Sphilip * Some partitions are accessible from both ports (for instance BOOTROM) 511227569Sphilip * Find the highest version reported by all dcfg structures on ports 512227569Sphilip * that have access to this partition. 513227569Sphilip */ 514227569Sphilip version[0] = version[1] = version[2] = version[3] = 0; 515283514Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) { 516227569Sphilip unsigned int nitems; 517227569Sphilip uint16_t temp[4]; 518227569Sphilip size_t length; 519227569Sphilip 520283514Sarybchik entry = &siena_parttbl[i]; 521227569Sphilip if (entry->partn != partn) 522227569Sphilip continue; 523227569Sphilip 524227569Sphilip dcfg_partn = (entry->port == 1) 525227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 526227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 527227569Sphilip /* 528227569Sphilip * Ingore missing partitions on port 2, assuming they're due 529227569Sphilip * to to running on a single port part. 530227569Sphilip */ 531227569Sphilip if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) { 532227569Sphilip if (entry->port == 2) 533227569Sphilip continue; 534227569Sphilip } 535227569Sphilip 536227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 537227569Sphilip B_FALSE, &dcfg, &length)) != 0) 538227569Sphilip goto fail4; 539227569Sphilip 540227569Sphilip nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, 541227569Sphilip EFX_DWORD_0); 542227569Sphilip if (nitems < entry->partn) 543227569Sphilip goto done; 544227569Sphilip 545227569Sphilip temp[0] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_w, 546227569Sphilip EFX_WORD_0); 547227569Sphilip temp[1] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_x, 548227569Sphilip EFX_WORD_0); 549227569Sphilip temp[2] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_y, 550227569Sphilip EFX_WORD_0); 551227569Sphilip temp[3] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_z, 552227569Sphilip EFX_WORD_0); 553227569Sphilip if (memcmp(version, temp, sizeof (temp)) < 0) 554227569Sphilip memcpy(version, temp, sizeof (temp)); 555227569Sphilip 556227569Sphilip done: 557227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 558227569Sphilip } 559227569Sphilip 560227569Sphilip return (0); 561227569Sphilip 562227569Sphilipfail4: 563227569Sphilip EFSYS_PROBE(fail4); 564227569Sphilipfail3: 565227569Sphilip EFSYS_PROBE(fail3); 566227569Sphilipfail2: 567227569Sphilip EFSYS_PROBE(fail2); 568227569Sphilipfail1: 569291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 570227569Sphilip 571227569Sphilip return (rc); 572227569Sphilip} 573227569Sphilip 574291436Sarybchik __checkReturn efx_rc_t 575294080Sarybchiksiena_nvram_partn_rw_start( 576227569Sphilip __in efx_nic_t *enp, 577294080Sarybchik __in uint32_t partn, 578227569Sphilip __out size_t *chunk_sizep) 579227569Sphilip{ 580291436Sarybchik efx_rc_t rc; 581227569Sphilip 582294080Sarybchik if ((rc = siena_nvram_partn_lock(enp, partn)) != 0) 583227569Sphilip goto fail1; 584227569Sphilip 585227569Sphilip if (chunk_sizep != NULL) 586227569Sphilip *chunk_sizep = SIENA_NVRAM_CHUNK; 587227569Sphilip 588227569Sphilip return (0); 589227569Sphilip 590227569Sphilipfail1: 591291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 592227569Sphilip 593227569Sphilip return (rc); 594227569Sphilip} 595227569Sphilip 596227569Sphilip void 597294250Sarybchiksiena_nvram_partn_rw_finish( 598227569Sphilip __in efx_nic_t *enp, 599294250Sarybchik __in uint32_t partn) 600227569Sphilip{ 601294250Sarybchik siena_nvram_partn_unlock(enp, partn); 602227569Sphilip} 603227569Sphilip 604291436Sarybchik __checkReturn efx_rc_t 605227569Sphilipsiena_nvram_set_version( 606227569Sphilip __in efx_nic_t *enp, 607227569Sphilip __in efx_nvram_type_t type, 608283514Sarybchik __in_ecount(4) uint16_t version[4]) 609227569Sphilip{ 610293810Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 611227569Sphilip siena_mc_dynamic_config_hdr_t *dcfg = NULL; 612293810Sarybchik siena_mc_fw_version_t *fwverp; 613293810Sarybchik uint32_t dcfg_partn, partn; 614293810Sarybchik size_t dcfg_size; 615227569Sphilip unsigned int hdr_length; 616227569Sphilip unsigned int vpd_length; 617227569Sphilip unsigned int vpd_offset; 618227569Sphilip unsigned int nitems; 619227569Sphilip unsigned int required_hdr_length; 620227569Sphilip unsigned int pos; 621227569Sphilip uint8_t cksum; 622227569Sphilip uint32_t subtype; 623227569Sphilip size_t length; 624291436Sarybchik efx_rc_t rc; 625227569Sphilip 626293810Sarybchik if ((rc = siena_nvram_type_to_partn(enp, type, &partn)) != 0) 627227569Sphilip goto fail1; 628227569Sphilip 629293810Sarybchik dcfg_partn = (emip->emi_port == 1) 630227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 631227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 632227569Sphilip 633293810Sarybchik if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &dcfg_size)) != 0) 634227569Sphilip goto fail2; 635227569Sphilip 636227569Sphilip if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 637227569Sphilip goto fail2; 638227569Sphilip 639227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 640227569Sphilip B_TRUE, &dcfg, &length)) != 0) 641227569Sphilip goto fail3; 642227569Sphilip 643227569Sphilip hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 644227569Sphilip nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 645227569Sphilip vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 646227569Sphilip vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 647227569Sphilip 648227569Sphilip /* 649227569Sphilip * NOTE: This function will blatt any fields trailing the version 650227569Sphilip * vector, or the VPD chunk. 651227569Sphilip */ 652293810Sarybchik required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(partn + 1); 653227569Sphilip if (required_hdr_length + vpd_length > length) { 654227569Sphilip rc = ENOSPC; 655227569Sphilip goto fail4; 656227569Sphilip } 657227569Sphilip 658227569Sphilip if (vpd_offset < required_hdr_length) { 659227569Sphilip (void) memmove((caddr_t)dcfg + required_hdr_length, 660227569Sphilip (caddr_t)dcfg + vpd_offset, vpd_length); 661227569Sphilip vpd_offset = required_hdr_length; 662227569Sphilip EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 663227569Sphilip EFX_DWORD_0, vpd_offset); 664227569Sphilip } 665227569Sphilip 666227569Sphilip if (hdr_length < required_hdr_length) { 667227569Sphilip (void) memset((caddr_t)dcfg + hdr_length, 0, 668227569Sphilip required_hdr_length - hdr_length); 669227569Sphilip hdr_length = required_hdr_length; 670227569Sphilip EFX_POPULATE_WORD_1(dcfg->length, 671227569Sphilip EFX_WORD_0, hdr_length); 672227569Sphilip } 673227569Sphilip 674227569Sphilip /* Get the subtype to insert into the fw_subtype array */ 675293810Sarybchik if ((rc = siena_nvram_get_subtype(enp, partn, &subtype)) != 0) 676227569Sphilip goto fail5; 677227569Sphilip 678227569Sphilip /* Fill out the new version */ 679293810Sarybchik fwverp = &dcfg->fw_version[partn]; 680293810Sarybchik EFX_POPULATE_DWORD_1(fwverp->fw_subtype, EFX_DWORD_0, subtype); 681293810Sarybchik EFX_POPULATE_WORD_1(fwverp->version_w, EFX_WORD_0, version[0]); 682293810Sarybchik EFX_POPULATE_WORD_1(fwverp->version_x, EFX_WORD_0, version[1]); 683293810Sarybchik EFX_POPULATE_WORD_1(fwverp->version_y, EFX_WORD_0, version[2]); 684293810Sarybchik EFX_POPULATE_WORD_1(fwverp->version_z, EFX_WORD_0, version[3]); 685227569Sphilip 686227569Sphilip /* Update the version count */ 687293810Sarybchik if (nitems < partn + 1) { 688293810Sarybchik nitems = partn + 1; 689227569Sphilip EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, 690227569Sphilip EFX_DWORD_0, nitems); 691227569Sphilip } 692227569Sphilip 693227569Sphilip /* Update the checksum */ 694227569Sphilip cksum = 0; 695227569Sphilip for (pos = 0; pos < hdr_length; pos++) 696227569Sphilip cksum += ((uint8_t *)dcfg)[pos]; 697227569Sphilip dcfg->csum.eb_u8[0] -= cksum; 698227569Sphilip 699227569Sphilip /* Erase and write the new partition */ 700293810Sarybchik if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, dcfg_size)) != 0) 701227569Sphilip goto fail6; 702227569Sphilip 703227569Sphilip /* Write out the new structure to nvram */ 704227569Sphilip if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, 705227569Sphilip (caddr_t)dcfg, vpd_offset + vpd_length)) != 0) 706227569Sphilip goto fail7; 707227569Sphilip 708227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 709227569Sphilip 710227569Sphilip siena_nvram_partn_unlock(enp, dcfg_partn); 711227569Sphilip 712227569Sphilip return (0); 713227569Sphilip 714227569Sphilipfail7: 715227569Sphilip EFSYS_PROBE(fail7); 716227569Sphilipfail6: 717227569Sphilip EFSYS_PROBE(fail6); 718227569Sphilipfail5: 719227569Sphilip EFSYS_PROBE(fail5); 720227569Sphilipfail4: 721227569Sphilip EFSYS_PROBE(fail4); 722227569Sphilip 723227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 724227569Sphilipfail3: 725227569Sphilip EFSYS_PROBE(fail3); 726227569Sphilipfail2: 727227569Sphilip EFSYS_PROBE(fail2); 728227569Sphilipfail1: 729291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 730227569Sphilip 731227569Sphilip return (rc); 732227569Sphilip} 733227569Sphilip 734227569Sphilip#endif /* EFSYS_OPT_NVRAM */ 735227569Sphilip 736227569Sphilip#endif /* EFSYS_OPT_SIENA */ 737