siena_nvram.c revision 294251
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 294251 2016-01-18 06:16:51Z 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 485294251Sarybchiksiena_nvram_partn_get_version( 486227569Sphilip __in efx_nic_t *enp, 487294251Sarybchik __in uint32_t partn, 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; 494283514Sarybchik unsigned int i; 495291436Sarybchik efx_rc_t rc; 496227569Sphilip 497227569Sphilip if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 498227569Sphilip rc = ENOTSUP; 499294251Sarybchik goto fail1; 500227569Sphilip } 501227569Sphilip 502227569Sphilip if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0) 503294251Sarybchik goto fail2; 504227569Sphilip 505227569Sphilip /* 506227569Sphilip * Some partitions are accessible from both ports (for instance BOOTROM) 507227569Sphilip * Find the highest version reported by all dcfg structures on ports 508227569Sphilip * that have access to this partition. 509227569Sphilip */ 510227569Sphilip version[0] = version[1] = version[2] = version[3] = 0; 511283514Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) { 512294251Sarybchik siena_mc_fw_version_t *verp; 513227569Sphilip unsigned int nitems; 514227569Sphilip uint16_t temp[4]; 515227569Sphilip size_t length; 516227569Sphilip 517283514Sarybchik entry = &siena_parttbl[i]; 518227569Sphilip if (entry->partn != partn) 519227569Sphilip continue; 520227569Sphilip 521227569Sphilip dcfg_partn = (entry->port == 1) 522227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 523227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 524227569Sphilip /* 525227569Sphilip * Ingore missing partitions on port 2, assuming they're due 526227569Sphilip * to to running on a single port part. 527227569Sphilip */ 528227569Sphilip if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) { 529227569Sphilip if (entry->port == 2) 530227569Sphilip continue; 531227569Sphilip } 532227569Sphilip 533227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 534227569Sphilip B_FALSE, &dcfg, &length)) != 0) 535294251Sarybchik goto fail3; 536227569Sphilip 537227569Sphilip nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, 538227569Sphilip EFX_DWORD_0); 539227569Sphilip if (nitems < entry->partn) 540227569Sphilip goto done; 541227569Sphilip 542294251Sarybchik verp = &dcfg->fw_version[partn]; 543294251Sarybchik temp[0] = EFX_WORD_FIELD(verp->version_w, EFX_WORD_0); 544294251Sarybchik temp[1] = EFX_WORD_FIELD(verp->version_x, EFX_WORD_0); 545294251Sarybchik temp[2] = EFX_WORD_FIELD(verp->version_y, EFX_WORD_0); 546294251Sarybchik temp[3] = EFX_WORD_FIELD(verp->version_z, EFX_WORD_0); 547227569Sphilip if (memcmp(version, temp, sizeof (temp)) < 0) 548227569Sphilip memcpy(version, temp, sizeof (temp)); 549227569Sphilip 550294251Sarybchikdone: 551227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 552227569Sphilip } 553227569Sphilip 554227569Sphilip return (0); 555227569Sphilip 556227569Sphilipfail3: 557227569Sphilip EFSYS_PROBE(fail3); 558227569Sphilipfail2: 559227569Sphilip EFSYS_PROBE(fail2); 560227569Sphilipfail1: 561291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 562227569Sphilip 563227569Sphilip return (rc); 564227569Sphilip} 565227569Sphilip 566291436Sarybchik __checkReturn efx_rc_t 567294080Sarybchiksiena_nvram_partn_rw_start( 568227569Sphilip __in efx_nic_t *enp, 569294080Sarybchik __in uint32_t partn, 570227569Sphilip __out size_t *chunk_sizep) 571227569Sphilip{ 572291436Sarybchik efx_rc_t rc; 573227569Sphilip 574294080Sarybchik if ((rc = siena_nvram_partn_lock(enp, partn)) != 0) 575227569Sphilip goto fail1; 576227569Sphilip 577227569Sphilip if (chunk_sizep != NULL) 578227569Sphilip *chunk_sizep = SIENA_NVRAM_CHUNK; 579227569Sphilip 580227569Sphilip return (0); 581227569Sphilip 582227569Sphilipfail1: 583291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 584227569Sphilip 585227569Sphilip return (rc); 586227569Sphilip} 587227569Sphilip 588227569Sphilip void 589294250Sarybchiksiena_nvram_partn_rw_finish( 590227569Sphilip __in efx_nic_t *enp, 591294250Sarybchik __in uint32_t partn) 592227569Sphilip{ 593294250Sarybchik siena_nvram_partn_unlock(enp, partn); 594227569Sphilip} 595227569Sphilip 596291436Sarybchik __checkReturn efx_rc_t 597227569Sphilipsiena_nvram_set_version( 598227569Sphilip __in efx_nic_t *enp, 599227569Sphilip __in efx_nvram_type_t type, 600283514Sarybchik __in_ecount(4) uint16_t version[4]) 601227569Sphilip{ 602293810Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 603227569Sphilip siena_mc_dynamic_config_hdr_t *dcfg = NULL; 604293810Sarybchik siena_mc_fw_version_t *fwverp; 605293810Sarybchik uint32_t dcfg_partn, partn; 606293810Sarybchik size_t dcfg_size; 607227569Sphilip unsigned int hdr_length; 608227569Sphilip unsigned int vpd_length; 609227569Sphilip unsigned int vpd_offset; 610227569Sphilip unsigned int nitems; 611227569Sphilip unsigned int required_hdr_length; 612227569Sphilip unsigned int pos; 613227569Sphilip uint8_t cksum; 614227569Sphilip uint32_t subtype; 615227569Sphilip size_t length; 616291436Sarybchik efx_rc_t rc; 617227569Sphilip 618293810Sarybchik if ((rc = siena_nvram_type_to_partn(enp, type, &partn)) != 0) 619227569Sphilip goto fail1; 620227569Sphilip 621293810Sarybchik dcfg_partn = (emip->emi_port == 1) 622227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 623227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 624227569Sphilip 625293810Sarybchik if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &dcfg_size)) != 0) 626227569Sphilip goto fail2; 627227569Sphilip 628227569Sphilip if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 629227569Sphilip goto fail2; 630227569Sphilip 631227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 632227569Sphilip B_TRUE, &dcfg, &length)) != 0) 633227569Sphilip goto fail3; 634227569Sphilip 635227569Sphilip hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 636227569Sphilip nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 637227569Sphilip vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 638227569Sphilip vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 639227569Sphilip 640227569Sphilip /* 641227569Sphilip * NOTE: This function will blatt any fields trailing the version 642227569Sphilip * vector, or the VPD chunk. 643227569Sphilip */ 644293810Sarybchik required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(partn + 1); 645227569Sphilip if (required_hdr_length + vpd_length > length) { 646227569Sphilip rc = ENOSPC; 647227569Sphilip goto fail4; 648227569Sphilip } 649227569Sphilip 650227569Sphilip if (vpd_offset < required_hdr_length) { 651227569Sphilip (void) memmove((caddr_t)dcfg + required_hdr_length, 652227569Sphilip (caddr_t)dcfg + vpd_offset, vpd_length); 653227569Sphilip vpd_offset = required_hdr_length; 654227569Sphilip EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 655227569Sphilip EFX_DWORD_0, vpd_offset); 656227569Sphilip } 657227569Sphilip 658227569Sphilip if (hdr_length < required_hdr_length) { 659227569Sphilip (void) memset((caddr_t)dcfg + hdr_length, 0, 660227569Sphilip required_hdr_length - hdr_length); 661227569Sphilip hdr_length = required_hdr_length; 662227569Sphilip EFX_POPULATE_WORD_1(dcfg->length, 663227569Sphilip EFX_WORD_0, hdr_length); 664227569Sphilip } 665227569Sphilip 666227569Sphilip /* Get the subtype to insert into the fw_subtype array */ 667293810Sarybchik if ((rc = siena_nvram_get_subtype(enp, partn, &subtype)) != 0) 668227569Sphilip goto fail5; 669227569Sphilip 670227569Sphilip /* Fill out the new version */ 671293810Sarybchik fwverp = &dcfg->fw_version[partn]; 672293810Sarybchik EFX_POPULATE_DWORD_1(fwverp->fw_subtype, EFX_DWORD_0, subtype); 673293810Sarybchik EFX_POPULATE_WORD_1(fwverp->version_w, EFX_WORD_0, version[0]); 674293810Sarybchik EFX_POPULATE_WORD_1(fwverp->version_x, EFX_WORD_0, version[1]); 675293810Sarybchik EFX_POPULATE_WORD_1(fwverp->version_y, EFX_WORD_0, version[2]); 676293810Sarybchik EFX_POPULATE_WORD_1(fwverp->version_z, EFX_WORD_0, version[3]); 677227569Sphilip 678227569Sphilip /* Update the version count */ 679293810Sarybchik if (nitems < partn + 1) { 680293810Sarybchik nitems = partn + 1; 681227569Sphilip EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, 682227569Sphilip EFX_DWORD_0, nitems); 683227569Sphilip } 684227569Sphilip 685227569Sphilip /* Update the checksum */ 686227569Sphilip cksum = 0; 687227569Sphilip for (pos = 0; pos < hdr_length; pos++) 688227569Sphilip cksum += ((uint8_t *)dcfg)[pos]; 689227569Sphilip dcfg->csum.eb_u8[0] -= cksum; 690227569Sphilip 691227569Sphilip /* Erase and write the new partition */ 692293810Sarybchik if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, dcfg_size)) != 0) 693227569Sphilip goto fail6; 694227569Sphilip 695227569Sphilip /* Write out the new structure to nvram */ 696227569Sphilip if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, 697227569Sphilip (caddr_t)dcfg, vpd_offset + vpd_length)) != 0) 698227569Sphilip goto fail7; 699227569Sphilip 700227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 701227569Sphilip 702227569Sphilip siena_nvram_partn_unlock(enp, dcfg_partn); 703227569Sphilip 704227569Sphilip return (0); 705227569Sphilip 706227569Sphilipfail7: 707227569Sphilip EFSYS_PROBE(fail7); 708227569Sphilipfail6: 709227569Sphilip EFSYS_PROBE(fail6); 710227569Sphilipfail5: 711227569Sphilip EFSYS_PROBE(fail5); 712227569Sphilipfail4: 713227569Sphilip EFSYS_PROBE(fail4); 714227569Sphilip 715227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 716227569Sphilipfail3: 717227569Sphilip EFSYS_PROBE(fail3); 718227569Sphilipfail2: 719227569Sphilip EFSYS_PROBE(fail2); 720227569Sphilipfail1: 721291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 722227569Sphilip 723227569Sphilip return (rc); 724227569Sphilip} 725227569Sphilip 726227569Sphilip#endif /* EFSYS_OPT_NVRAM */ 727227569Sphilip 728227569Sphilip#endif /* EFSYS_OPT_SIENA */ 729