ef10_vpd.c revision 291436
1283514Sarybchik/*- 2283514Sarybchik * Copyright (c) 2009-2015 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4283514Sarybchik * 5283514Sarybchik * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7283514Sarybchik * 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. 29283514Sarybchik */ 30283514Sarybchik 31283514Sarybchik#include <sys/cdefs.h> 32283514Sarybchik__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_vpd.c 291436 2015-11-29 05:42:49Z arybchik $"); 33283514Sarybchik 34283514Sarybchik#include "efsys.h" 35283514Sarybchik#include "efx.h" 36283514Sarybchik#include "efx_types.h" 37283514Sarybchik#include "efx_regs.h" 38283514Sarybchik#include "efx_impl.h" 39283514Sarybchik 40283514Sarybchik 41283514Sarybchik#if EFSYS_OPT_VPD 42283514Sarybchik 43283514Sarybchik#if EFSYS_OPT_HUNTINGTON 44283514Sarybchik 45283514Sarybchik#include "ef10_tlv_layout.h" 46283514Sarybchik 47291436Sarybchik __checkReturn efx_rc_t 48283514Sarybchikhunt_vpd_init( 49283514Sarybchik __in efx_nic_t *enp) 50283514Sarybchik{ 51283514Sarybchik caddr_t svpd; 52283514Sarybchik size_t svpd_size; 53283514Sarybchik uint32_t pci_pf; 54291436Sarybchik efx_rc_t rc; 55283514Sarybchik 56283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 57283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 58283514Sarybchik 59283514Sarybchik pci_pf = enp->en_nic_cfg.enc_pf; 60283514Sarybchik /* 61283514Sarybchik * The VPD interface exposes VPD resources from the combined static and 62283514Sarybchik * dynamic VPD storage. As the static VPD configuration should *never* 63283514Sarybchik * change, we can cache it. 64283514Sarybchik */ 65283514Sarybchik svpd = NULL; 66283514Sarybchik svpd_size = 0; 67283514Sarybchik rc = hunt_nvram_partn_read_tlv(enp, 68283514Sarybchik NVRAM_PARTITION_TYPE_STATIC_CONFIG, 69283514Sarybchik TLV_TAG_PF_STATIC_VPD(pci_pf), 70283514Sarybchik &svpd, &svpd_size); 71283514Sarybchik if (rc != 0) { 72283514Sarybchik if (rc == EACCES) { 73283514Sarybchik /* Unpriviledged functions cannot access VPD */ 74283514Sarybchik goto out; 75283514Sarybchik } 76283514Sarybchik goto fail1; 77283514Sarybchik } 78283514Sarybchik 79283514Sarybchik if (svpd != NULL && svpd_size > 0) { 80283514Sarybchik if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0) 81283514Sarybchik goto fail2; 82283514Sarybchik } 83283514Sarybchik 84283514Sarybchik enp->en_u.hunt.enu_svpd = svpd; 85283514Sarybchik enp->en_u.hunt.enu_svpd_length = svpd_size; 86283514Sarybchik 87283514Sarybchikout: 88283514Sarybchik return (0); 89283514Sarybchik 90283514Sarybchikfail2: 91283514Sarybchik EFSYS_PROBE(fail2); 92283514Sarybchik 93283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd); 94283514Sarybchikfail1: 95291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 96283514Sarybchik 97283514Sarybchik return (rc); 98283514Sarybchik} 99283514Sarybchik 100291436Sarybchik __checkReturn efx_rc_t 101283514Sarybchikhunt_vpd_size( 102283514Sarybchik __in efx_nic_t *enp, 103283514Sarybchik __out size_t *sizep) 104283514Sarybchik{ 105291436Sarybchik efx_rc_t rc; 106283514Sarybchik 107283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 108283514Sarybchik 109283514Sarybchik /* 110283514Sarybchik * This function returns the total size the user should allocate 111283514Sarybchik * for all VPD operations. We've already cached the static vpd, 112283514Sarybchik * so we just need to return an upper bound on the dynamic vpd, 113283514Sarybchik * which is the size of the DYNAMIC_CONFIG partition. 114283514Sarybchik */ 115283514Sarybchik if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 116283514Sarybchik sizep, NULL, NULL)) != 0) 117283514Sarybchik goto fail1; 118283514Sarybchik 119283514Sarybchik return (0); 120283514Sarybchik 121283514Sarybchikfail1: 122291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 123283514Sarybchik 124283514Sarybchik return (rc); 125283514Sarybchik} 126283514Sarybchik 127291436Sarybchik __checkReturn efx_rc_t 128283514Sarybchikhunt_vpd_read( 129283514Sarybchik __in efx_nic_t *enp, 130283514Sarybchik __out_bcount(size) caddr_t data, 131283514Sarybchik __in size_t size) 132283514Sarybchik{ 133283514Sarybchik caddr_t dvpd; 134283514Sarybchik size_t dvpd_size; 135283514Sarybchik uint32_t pci_pf; 136291436Sarybchik efx_rc_t rc; 137283514Sarybchik 138283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 139283514Sarybchik 140283514Sarybchik pci_pf = enp->en_nic_cfg.enc_pf; 141283514Sarybchik 142283514Sarybchik if ((rc = hunt_nvram_partn_read_tlv(enp, 143283514Sarybchik NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 144283514Sarybchik TLV_TAG_PF_DYNAMIC_VPD(pci_pf), 145283514Sarybchik &dvpd, &dvpd_size)) != 0) 146283514Sarybchik goto fail1; 147283514Sarybchik 148283514Sarybchik if (dvpd_size > size) { 149283514Sarybchik rc = ENOSPC; 150283514Sarybchik goto fail2; 151283514Sarybchik } 152283514Sarybchik memcpy(data, dvpd, dvpd_size); 153283514Sarybchik 154283514Sarybchik /* Pad data with all-1s, consistent with update operations */ 155283514Sarybchik memset(data + dvpd_size, 0xff, size - dvpd_size); 156283514Sarybchik 157283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); 158283514Sarybchik 159283514Sarybchik return (0); 160283514Sarybchik 161283514Sarybchikfail2: 162283514Sarybchik EFSYS_PROBE(fail2); 163283514Sarybchik 164283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); 165283514Sarybchikfail1: 166291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 167283514Sarybchik 168283514Sarybchik return (rc); 169283514Sarybchik} 170283514Sarybchik 171291436Sarybchik __checkReturn efx_rc_t 172283514Sarybchikhunt_vpd_verify( 173283514Sarybchik __in efx_nic_t *enp, 174283514Sarybchik __in_bcount(size) caddr_t data, 175283514Sarybchik __in size_t size) 176283514Sarybchik{ 177283514Sarybchik efx_vpd_tag_t stag; 178283514Sarybchik efx_vpd_tag_t dtag; 179283514Sarybchik efx_vpd_keyword_t skey; 180283514Sarybchik efx_vpd_keyword_t dkey; 181283514Sarybchik unsigned int scont; 182283514Sarybchik unsigned int dcont; 183291436Sarybchik efx_rc_t rc; 184283514Sarybchik 185283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 186283514Sarybchik 187283514Sarybchik /* 188283514Sarybchik * Strictly you could take the view that dynamic vpd is optional. 189283514Sarybchik * Instead, to conform more closely to the read/verify/reinit() 190283514Sarybchik * paradigm, we require dynamic vpd. hunt_vpd_reinit() will 191283514Sarybchik * reinitialize it as required. 192283514Sarybchik */ 193283514Sarybchik if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0) 194283514Sarybchik goto fail1; 195283514Sarybchik 196283514Sarybchik /* 197283514Sarybchik * Verify that there is no duplication between the static and 198283514Sarybchik * dynamic cfg sectors. 199283514Sarybchik */ 200283514Sarybchik if (enp->en_u.hunt.enu_svpd_length == 0) 201283514Sarybchik goto done; 202283514Sarybchik 203283514Sarybchik dcont = 0; 204283514Sarybchik _NOTE(CONSTANTCONDITION) 205283514Sarybchik while (1) { 206283514Sarybchik if ((rc = efx_vpd_hunk_next(data, size, &dtag, 207283514Sarybchik &dkey, NULL, NULL, &dcont)) != 0) 208283514Sarybchik goto fail2; 209283514Sarybchik if (dcont == 0) 210283514Sarybchik break; 211283514Sarybchik 212283514Sarybchik scont = 0; 213283514Sarybchik _NOTE(CONSTANTCONDITION) 214283514Sarybchik while (1) { 215283514Sarybchik if ((rc = efx_vpd_hunk_next( 216283514Sarybchik enp->en_u.hunt.enu_svpd, 217283514Sarybchik enp->en_u.hunt.enu_svpd_length, &stag, &skey, 218283514Sarybchik NULL, NULL, &scont)) != 0) 219283514Sarybchik goto fail3; 220283514Sarybchik if (scont == 0) 221283514Sarybchik break; 222283514Sarybchik 223283514Sarybchik if (stag == dtag && skey == dkey) { 224283514Sarybchik rc = EEXIST; 225283514Sarybchik goto fail4; 226283514Sarybchik } 227283514Sarybchik } 228283514Sarybchik } 229283514Sarybchik 230283514Sarybchikdone: 231283514Sarybchik return (0); 232283514Sarybchik 233283514Sarybchikfail4: 234283514Sarybchik EFSYS_PROBE(fail4); 235283514Sarybchikfail3: 236283514Sarybchik EFSYS_PROBE(fail3); 237283514Sarybchikfail2: 238283514Sarybchik EFSYS_PROBE(fail2); 239283514Sarybchikfail1: 240291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 241283514Sarybchik 242283514Sarybchik return (rc); 243283514Sarybchik} 244283514Sarybchik 245291436Sarybchik __checkReturn efx_rc_t 246283514Sarybchikhunt_vpd_reinit( 247283514Sarybchik __in efx_nic_t *enp, 248283514Sarybchik __in_bcount(size) caddr_t data, 249283514Sarybchik __in size_t size) 250283514Sarybchik{ 251283514Sarybchik boolean_t wantpid; 252291436Sarybchik efx_rc_t rc; 253283514Sarybchik 254283514Sarybchik /* 255283514Sarybchik * Only create an ID string if the dynamic cfg doesn't have one 256283514Sarybchik */ 257283514Sarybchik if (enp->en_u.hunt.enu_svpd_length == 0) 258283514Sarybchik wantpid = B_TRUE; 259283514Sarybchik else { 260283514Sarybchik unsigned int offset; 261283514Sarybchik uint8_t length; 262283514Sarybchik 263283514Sarybchik rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd, 264283514Sarybchik enp->en_u.hunt.enu_svpd_length, 265283514Sarybchik EFX_VPD_ID, 0, &offset, &length); 266283514Sarybchik if (rc == 0) 267283514Sarybchik wantpid = B_FALSE; 268283514Sarybchik else if (rc == ENOENT) 269283514Sarybchik wantpid = B_TRUE; 270283514Sarybchik else 271283514Sarybchik goto fail1; 272283514Sarybchik } 273283514Sarybchik 274283514Sarybchik if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0) 275283514Sarybchik goto fail2; 276283514Sarybchik 277283514Sarybchik return (0); 278283514Sarybchik 279283514Sarybchikfail2: 280283514Sarybchik EFSYS_PROBE(fail2); 281283514Sarybchikfail1: 282291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 283283514Sarybchik 284283514Sarybchik return (rc); 285283514Sarybchik} 286283514Sarybchik 287291436Sarybchik __checkReturn efx_rc_t 288283514Sarybchikhunt_vpd_get( 289283514Sarybchik __in efx_nic_t *enp, 290283514Sarybchik __in_bcount(size) caddr_t data, 291283514Sarybchik __in size_t size, 292283514Sarybchik __inout efx_vpd_value_t *evvp) 293283514Sarybchik{ 294283514Sarybchik unsigned int offset; 295283514Sarybchik uint8_t length; 296291436Sarybchik efx_rc_t rc; 297283514Sarybchik 298283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 299283514Sarybchik 300283514Sarybchik /* Attempt to satisfy the request from svpd first */ 301283514Sarybchik if (enp->en_u.hunt.enu_svpd_length > 0) { 302283514Sarybchik if ((rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd, 303283514Sarybchik enp->en_u.hunt.enu_svpd_length, evvp->evv_tag, 304283514Sarybchik evvp->evv_keyword, &offset, &length)) == 0) { 305283514Sarybchik evvp->evv_length = length; 306283514Sarybchik memcpy(evvp->evv_value, 307283514Sarybchik enp->en_u.hunt.enu_svpd + offset, length); 308283514Sarybchik return (0); 309283514Sarybchik } else if (rc != ENOENT) 310283514Sarybchik goto fail1; 311283514Sarybchik } 312283514Sarybchik 313283514Sarybchik /* And then from the provided data buffer */ 314283514Sarybchik if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, 315283514Sarybchik evvp->evv_keyword, &offset, &length)) != 0) 316283514Sarybchik goto fail2; 317283514Sarybchik 318283514Sarybchik evvp->evv_length = length; 319283514Sarybchik memcpy(evvp->evv_value, data + offset, length); 320283514Sarybchik 321283514Sarybchik return (0); 322283514Sarybchik 323283514Sarybchikfail2: 324283514Sarybchik EFSYS_PROBE(fail2); 325283514Sarybchikfail1: 326291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 327283514Sarybchik 328283514Sarybchik return (rc); 329283514Sarybchik} 330283514Sarybchik 331291436Sarybchik __checkReturn efx_rc_t 332283514Sarybchikhunt_vpd_set( 333283514Sarybchik __in efx_nic_t *enp, 334283514Sarybchik __in_bcount(size) caddr_t data, 335283514Sarybchik __in size_t size, 336283514Sarybchik __in efx_vpd_value_t *evvp) 337283514Sarybchik{ 338291436Sarybchik efx_rc_t rc; 339283514Sarybchik 340283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 341283514Sarybchik 342283514Sarybchik /* If the provided (tag,keyword) exists in svpd, then it is readonly */ 343283514Sarybchik if (enp->en_u.hunt.enu_svpd_length > 0) { 344283514Sarybchik unsigned int offset; 345283514Sarybchik uint8_t length; 346283514Sarybchik 347283514Sarybchik if ((rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd, 348283514Sarybchik enp->en_u.hunt.enu_svpd_length, evvp->evv_tag, 349283514Sarybchik evvp->evv_keyword, &offset, &length)) == 0) { 350283514Sarybchik rc = EACCES; 351283514Sarybchik goto fail1; 352283514Sarybchik } 353283514Sarybchik } 354283514Sarybchik 355283514Sarybchik if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) 356283514Sarybchik goto fail2; 357283514Sarybchik 358283514Sarybchik return (0); 359283514Sarybchik 360283514Sarybchikfail2: 361283514Sarybchik EFSYS_PROBE(fail2); 362283514Sarybchikfail1: 363291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 364283514Sarybchik 365283514Sarybchik return (rc); 366283514Sarybchik} 367283514Sarybchik 368291436Sarybchik __checkReturn efx_rc_t 369283514Sarybchikhunt_vpd_next( 370283514Sarybchik __in efx_nic_t *enp, 371283514Sarybchik __in_bcount(size) caddr_t data, 372283514Sarybchik __in size_t size, 373283514Sarybchik __out efx_vpd_value_t *evvp, 374283514Sarybchik __inout unsigned int *contp) 375283514Sarybchik{ 376283514Sarybchik _NOTE(ARGUNUSED(enp, data, size, evvp, contp)) 377283514Sarybchik 378283514Sarybchik return (ENOTSUP); 379283514Sarybchik} 380283514Sarybchik 381291436Sarybchik __checkReturn efx_rc_t 382283514Sarybchikhunt_vpd_write( 383283514Sarybchik __in efx_nic_t *enp, 384283514Sarybchik __in_bcount(size) caddr_t data, 385283514Sarybchik __in size_t size) 386283514Sarybchik{ 387283514Sarybchik size_t vpd_length; 388283514Sarybchik uint32_t pci_pf; 389291436Sarybchik efx_rc_t rc; 390283514Sarybchik 391283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 392283514Sarybchik 393283514Sarybchik pci_pf = enp->en_nic_cfg.enc_pf; 394283514Sarybchik 395283514Sarybchik /* Determine total length of new dynamic VPD */ 396283514Sarybchik if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) 397283514Sarybchik goto fail1; 398283514Sarybchik 399291432Sarybchik /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */ 400291432Sarybchik if ((rc = hunt_nvram_partn_write_segment_tlv(enp, 401283514Sarybchik NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 402283514Sarybchik TLV_TAG_PF_DYNAMIC_VPD(pci_pf), 403291432Sarybchik data, vpd_length, B_TRUE)) != 0) { 404283514Sarybchik goto fail2; 405283514Sarybchik } 406283514Sarybchik 407283514Sarybchik return (0); 408283514Sarybchik 409283514Sarybchikfail2: 410283514Sarybchik EFSYS_PROBE(fail2); 411283514Sarybchik 412283514Sarybchikfail1: 413291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 414283514Sarybchik 415283514Sarybchik return (rc); 416283514Sarybchik} 417283514Sarybchik 418283514Sarybchik void 419283514Sarybchikhunt_vpd_fini( 420283514Sarybchik __in efx_nic_t *enp) 421283514Sarybchik{ 422283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 423283514Sarybchik 424283514Sarybchik if (enp->en_u.hunt.enu_svpd_length > 0) { 425283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.hunt.enu_svpd_length, 426283514Sarybchik enp->en_u.hunt.enu_svpd); 427283514Sarybchik 428283514Sarybchik enp->en_u.hunt.enu_svpd = NULL; 429283514Sarybchik enp->en_u.hunt.enu_svpd_length = 0; 430283514Sarybchik } 431283514Sarybchik} 432283514Sarybchik 433283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 434283514Sarybchik 435283514Sarybchik#endif /* EFSYS_OPT_VPD */ 436