ef10_vpd.c revision 293756
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 293756 2016-01-12 13:37:58Z 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 48293755Sarybchikef10_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); 57293755Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 58293755Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 59283514Sarybchik 60283514Sarybchik pci_pf = enp->en_nic_cfg.enc_pf; 61283514Sarybchik /* 62283514Sarybchik * The VPD interface exposes VPD resources from the combined static and 63283514Sarybchik * dynamic VPD storage. As the static VPD configuration should *never* 64283514Sarybchik * change, we can cache it. 65283514Sarybchik */ 66283514Sarybchik svpd = NULL; 67283514Sarybchik svpd_size = 0; 68293756Sarybchik rc = ef10_nvram_partn_read_tlv(enp, 69283514Sarybchik NVRAM_PARTITION_TYPE_STATIC_CONFIG, 70283514Sarybchik TLV_TAG_PF_STATIC_VPD(pci_pf), 71283514Sarybchik &svpd, &svpd_size); 72283514Sarybchik if (rc != 0) { 73283514Sarybchik if (rc == EACCES) { 74283514Sarybchik /* Unpriviledged functions cannot access VPD */ 75283514Sarybchik goto out; 76283514Sarybchik } 77283514Sarybchik goto fail1; 78283514Sarybchik } 79283514Sarybchik 80283514Sarybchik if (svpd != NULL && svpd_size > 0) { 81283514Sarybchik if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0) 82283514Sarybchik goto fail2; 83283514Sarybchik } 84283514Sarybchik 85293748Sarybchik enp->en_arch.ef10.ena_svpd = svpd; 86293748Sarybchik enp->en_arch.ef10.ena_svpd_length = svpd_size; 87283514Sarybchik 88283514Sarybchikout: 89283514Sarybchik return (0); 90283514Sarybchik 91283514Sarybchikfail2: 92283514Sarybchik EFSYS_PROBE(fail2); 93283514Sarybchik 94283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd); 95283514Sarybchikfail1: 96291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 97283514Sarybchik 98283514Sarybchik return (rc); 99283514Sarybchik} 100283514Sarybchik 101291436Sarybchik __checkReturn efx_rc_t 102293755Sarybchikef10_vpd_size( 103283514Sarybchik __in efx_nic_t *enp, 104283514Sarybchik __out size_t *sizep) 105283514Sarybchik{ 106291436Sarybchik efx_rc_t rc; 107283514Sarybchik 108293755Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 109293755Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 110283514Sarybchik 111283514Sarybchik /* 112283514Sarybchik * This function returns the total size the user should allocate 113283514Sarybchik * for all VPD operations. We've already cached the static vpd, 114283514Sarybchik * so we just need to return an upper bound on the dynamic vpd, 115283514Sarybchik * which is the size of the DYNAMIC_CONFIG partition. 116283514Sarybchik */ 117283514Sarybchik if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 118291746Sarybchik sizep, NULL, NULL, NULL)) != 0) 119283514Sarybchik goto fail1; 120283514Sarybchik 121283514Sarybchik return (0); 122283514Sarybchik 123283514Sarybchikfail1: 124291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 125283514Sarybchik 126283514Sarybchik return (rc); 127283514Sarybchik} 128283514Sarybchik 129291436Sarybchik __checkReturn efx_rc_t 130293755Sarybchikef10_vpd_read( 131283514Sarybchik __in efx_nic_t *enp, 132283514Sarybchik __out_bcount(size) caddr_t data, 133283514Sarybchik __in size_t size) 134283514Sarybchik{ 135283514Sarybchik caddr_t dvpd; 136283514Sarybchik size_t dvpd_size; 137283514Sarybchik uint32_t pci_pf; 138291436Sarybchik efx_rc_t rc; 139283514Sarybchik 140293755Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 141293755Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 142283514Sarybchik 143283514Sarybchik pci_pf = enp->en_nic_cfg.enc_pf; 144283514Sarybchik 145293756Sarybchik if ((rc = ef10_nvram_partn_read_tlv(enp, 146283514Sarybchik NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 147283514Sarybchik TLV_TAG_PF_DYNAMIC_VPD(pci_pf), 148283514Sarybchik &dvpd, &dvpd_size)) != 0) 149283514Sarybchik goto fail1; 150283514Sarybchik 151283514Sarybchik if (dvpd_size > size) { 152283514Sarybchik rc = ENOSPC; 153283514Sarybchik goto fail2; 154283514Sarybchik } 155283514Sarybchik memcpy(data, dvpd, dvpd_size); 156283514Sarybchik 157283514Sarybchik /* Pad data with all-1s, consistent with update operations */ 158283514Sarybchik memset(data + dvpd_size, 0xff, size - dvpd_size); 159283514Sarybchik 160283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); 161283514Sarybchik 162283514Sarybchik return (0); 163283514Sarybchik 164283514Sarybchikfail2: 165283514Sarybchik EFSYS_PROBE(fail2); 166283514Sarybchik 167283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); 168283514Sarybchikfail1: 169291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 170283514Sarybchik 171283514Sarybchik return (rc); 172283514Sarybchik} 173283514Sarybchik 174291436Sarybchik __checkReturn efx_rc_t 175293755Sarybchikef10_vpd_verify( 176283514Sarybchik __in efx_nic_t *enp, 177283514Sarybchik __in_bcount(size) caddr_t data, 178283514Sarybchik __in size_t size) 179283514Sarybchik{ 180283514Sarybchik efx_vpd_tag_t stag; 181283514Sarybchik efx_vpd_tag_t dtag; 182283514Sarybchik efx_vpd_keyword_t skey; 183283514Sarybchik efx_vpd_keyword_t dkey; 184283514Sarybchik unsigned int scont; 185283514Sarybchik unsigned int dcont; 186291436Sarybchik efx_rc_t rc; 187283514Sarybchik 188293755Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 189293755Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 190283514Sarybchik 191283514Sarybchik /* 192283514Sarybchik * Strictly you could take the view that dynamic vpd is optional. 193283514Sarybchik * Instead, to conform more closely to the read/verify/reinit() 194293755Sarybchik * paradigm, we require dynamic vpd. ef10_vpd_reinit() will 195283514Sarybchik * reinitialize it as required. 196283514Sarybchik */ 197283514Sarybchik if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0) 198283514Sarybchik goto fail1; 199283514Sarybchik 200283514Sarybchik /* 201283514Sarybchik * Verify that there is no duplication between the static and 202283514Sarybchik * dynamic cfg sectors. 203283514Sarybchik */ 204293748Sarybchik if (enp->en_arch.ef10.ena_svpd_length == 0) 205283514Sarybchik goto done; 206283514Sarybchik 207283514Sarybchik dcont = 0; 208283514Sarybchik _NOTE(CONSTANTCONDITION) 209283514Sarybchik while (1) { 210283514Sarybchik if ((rc = efx_vpd_hunk_next(data, size, &dtag, 211283514Sarybchik &dkey, NULL, NULL, &dcont)) != 0) 212283514Sarybchik goto fail2; 213283514Sarybchik if (dcont == 0) 214283514Sarybchik break; 215283514Sarybchik 216283514Sarybchik scont = 0; 217283514Sarybchik _NOTE(CONSTANTCONDITION) 218283514Sarybchik while (1) { 219283514Sarybchik if ((rc = efx_vpd_hunk_next( 220293748Sarybchik enp->en_arch.ef10.ena_svpd, 221293748Sarybchik enp->en_arch.ef10.ena_svpd_length, &stag, &skey, 222283514Sarybchik NULL, NULL, &scont)) != 0) 223283514Sarybchik goto fail3; 224283514Sarybchik if (scont == 0) 225283514Sarybchik break; 226283514Sarybchik 227283514Sarybchik if (stag == dtag && skey == dkey) { 228283514Sarybchik rc = EEXIST; 229283514Sarybchik goto fail4; 230283514Sarybchik } 231283514Sarybchik } 232283514Sarybchik } 233283514Sarybchik 234283514Sarybchikdone: 235283514Sarybchik return (0); 236283514Sarybchik 237283514Sarybchikfail4: 238283514Sarybchik EFSYS_PROBE(fail4); 239283514Sarybchikfail3: 240283514Sarybchik EFSYS_PROBE(fail3); 241283514Sarybchikfail2: 242283514Sarybchik EFSYS_PROBE(fail2); 243283514Sarybchikfail1: 244291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 245283514Sarybchik 246283514Sarybchik return (rc); 247283514Sarybchik} 248283514Sarybchik 249291436Sarybchik __checkReturn efx_rc_t 250293755Sarybchikef10_vpd_reinit( 251283514Sarybchik __in efx_nic_t *enp, 252283514Sarybchik __in_bcount(size) caddr_t data, 253283514Sarybchik __in size_t size) 254283514Sarybchik{ 255283514Sarybchik boolean_t wantpid; 256291436Sarybchik efx_rc_t rc; 257283514Sarybchik 258283514Sarybchik /* 259283514Sarybchik * Only create an ID string if the dynamic cfg doesn't have one 260283514Sarybchik */ 261293748Sarybchik if (enp->en_arch.ef10.ena_svpd_length == 0) 262283514Sarybchik wantpid = B_TRUE; 263283514Sarybchik else { 264283514Sarybchik unsigned int offset; 265283514Sarybchik uint8_t length; 266283514Sarybchik 267293748Sarybchik rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, 268293748Sarybchik enp->en_arch.ef10.ena_svpd_length, 269283514Sarybchik EFX_VPD_ID, 0, &offset, &length); 270283514Sarybchik if (rc == 0) 271283514Sarybchik wantpid = B_FALSE; 272283514Sarybchik else if (rc == ENOENT) 273283514Sarybchik wantpid = B_TRUE; 274283514Sarybchik else 275283514Sarybchik goto fail1; 276283514Sarybchik } 277283514Sarybchik 278283514Sarybchik if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0) 279283514Sarybchik goto fail2; 280283514Sarybchik 281283514Sarybchik return (0); 282283514Sarybchik 283283514Sarybchikfail2: 284283514Sarybchik EFSYS_PROBE(fail2); 285283514Sarybchikfail1: 286291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 287283514Sarybchik 288283514Sarybchik return (rc); 289283514Sarybchik} 290283514Sarybchik 291291436Sarybchik __checkReturn efx_rc_t 292293755Sarybchikef10_vpd_get( 293283514Sarybchik __in efx_nic_t *enp, 294283514Sarybchik __in_bcount(size) caddr_t data, 295283514Sarybchik __in size_t size, 296283514Sarybchik __inout efx_vpd_value_t *evvp) 297283514Sarybchik{ 298283514Sarybchik unsigned int offset; 299283514Sarybchik uint8_t length; 300291436Sarybchik efx_rc_t rc; 301283514Sarybchik 302293755Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 303293755Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 304283514Sarybchik 305283514Sarybchik /* Attempt to satisfy the request from svpd first */ 306293748Sarybchik if (enp->en_arch.ef10.ena_svpd_length > 0) { 307293748Sarybchik if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, 308293748Sarybchik enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag, 309283514Sarybchik evvp->evv_keyword, &offset, &length)) == 0) { 310283514Sarybchik evvp->evv_length = length; 311283514Sarybchik memcpy(evvp->evv_value, 312293748Sarybchik enp->en_arch.ef10.ena_svpd + offset, length); 313283514Sarybchik return (0); 314283514Sarybchik } else if (rc != ENOENT) 315283514Sarybchik goto fail1; 316283514Sarybchik } 317283514Sarybchik 318283514Sarybchik /* And then from the provided data buffer */ 319283514Sarybchik if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, 320283514Sarybchik evvp->evv_keyword, &offset, &length)) != 0) 321283514Sarybchik goto fail2; 322283514Sarybchik 323283514Sarybchik evvp->evv_length = length; 324283514Sarybchik memcpy(evvp->evv_value, data + offset, length); 325283514Sarybchik 326283514Sarybchik return (0); 327283514Sarybchik 328283514Sarybchikfail2: 329283514Sarybchik EFSYS_PROBE(fail2); 330283514Sarybchikfail1: 331291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 332283514Sarybchik 333283514Sarybchik return (rc); 334283514Sarybchik} 335283514Sarybchik 336291436Sarybchik __checkReturn efx_rc_t 337293755Sarybchikef10_vpd_set( 338283514Sarybchik __in efx_nic_t *enp, 339283514Sarybchik __in_bcount(size) caddr_t data, 340283514Sarybchik __in size_t size, 341283514Sarybchik __in efx_vpd_value_t *evvp) 342283514Sarybchik{ 343291436Sarybchik efx_rc_t rc; 344283514Sarybchik 345293755Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 346293755Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 347283514Sarybchik 348283514Sarybchik /* If the provided (tag,keyword) exists in svpd, then it is readonly */ 349293748Sarybchik if (enp->en_arch.ef10.ena_svpd_length > 0) { 350283514Sarybchik unsigned int offset; 351283514Sarybchik uint8_t length; 352283514Sarybchik 353293748Sarybchik if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, 354293748Sarybchik enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag, 355283514Sarybchik evvp->evv_keyword, &offset, &length)) == 0) { 356283514Sarybchik rc = EACCES; 357283514Sarybchik goto fail1; 358283514Sarybchik } 359283514Sarybchik } 360283514Sarybchik 361283514Sarybchik if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) 362283514Sarybchik goto fail2; 363283514Sarybchik 364283514Sarybchik return (0); 365283514Sarybchik 366283514Sarybchikfail2: 367283514Sarybchik EFSYS_PROBE(fail2); 368283514Sarybchikfail1: 369291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 370283514Sarybchik 371283514Sarybchik return (rc); 372283514Sarybchik} 373283514Sarybchik 374291436Sarybchik __checkReturn efx_rc_t 375293755Sarybchikef10_vpd_next( 376283514Sarybchik __in efx_nic_t *enp, 377283514Sarybchik __in_bcount(size) caddr_t data, 378283514Sarybchik __in size_t size, 379283514Sarybchik __out efx_vpd_value_t *evvp, 380283514Sarybchik __inout unsigned int *contp) 381283514Sarybchik{ 382283514Sarybchik _NOTE(ARGUNUSED(enp, data, size, evvp, contp)) 383283514Sarybchik 384283514Sarybchik return (ENOTSUP); 385283514Sarybchik} 386283514Sarybchik 387291436Sarybchik __checkReturn efx_rc_t 388293755Sarybchikef10_vpd_write( 389283514Sarybchik __in efx_nic_t *enp, 390283514Sarybchik __in_bcount(size) caddr_t data, 391283514Sarybchik __in size_t size) 392283514Sarybchik{ 393283514Sarybchik size_t vpd_length; 394283514Sarybchik uint32_t pci_pf; 395291436Sarybchik efx_rc_t rc; 396283514Sarybchik 397293755Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 398293755Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 399283514Sarybchik 400283514Sarybchik pci_pf = enp->en_nic_cfg.enc_pf; 401283514Sarybchik 402283514Sarybchik /* Determine total length of new dynamic VPD */ 403283514Sarybchik if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) 404283514Sarybchik goto fail1; 405283514Sarybchik 406291432Sarybchik /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */ 407293756Sarybchik if ((rc = ef10_nvram_partn_write_segment_tlv(enp, 408283514Sarybchik NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 409283514Sarybchik TLV_TAG_PF_DYNAMIC_VPD(pci_pf), 410291432Sarybchik data, vpd_length, B_TRUE)) != 0) { 411283514Sarybchik goto fail2; 412283514Sarybchik } 413283514Sarybchik 414283514Sarybchik return (0); 415283514Sarybchik 416283514Sarybchikfail2: 417283514Sarybchik EFSYS_PROBE(fail2); 418283514Sarybchik 419283514Sarybchikfail1: 420291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 421283514Sarybchik 422283514Sarybchik return (rc); 423283514Sarybchik} 424283514Sarybchik 425283514Sarybchik void 426293755Sarybchikef10_vpd_fini( 427283514Sarybchik __in efx_nic_t *enp) 428283514Sarybchik{ 429293755Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 430293755Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 431283514Sarybchik 432293748Sarybchik if (enp->en_arch.ef10.ena_svpd_length > 0) { 433293748Sarybchik EFSYS_KMEM_FREE(enp->en_esip, enp->en_arch.ef10.ena_svpd_length, 434293748Sarybchik enp->en_arch.ef10.ena_svpd); 435283514Sarybchik 436293748Sarybchik enp->en_arch.ef10.ena_svpd = NULL; 437293748Sarybchik enp->en_arch.ef10.ena_svpd_length = 0; 438283514Sarybchik } 439283514Sarybchik} 440283514Sarybchik 441283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 442283514Sarybchik 443283514Sarybchik#endif /* EFSYS_OPT_VPD */ 444