ef10_vpd.c revision 283514
1/*- 2 * Copyright (c) 2009-2015 Solarflare Communications Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * The views and conclusions contained in the software and documentation are 27 * those of the authors and should not be interpreted as representing official 28 * policies, either expressed or implied, of the FreeBSD Project. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_vpd.c 283514 2015-05-25 08:34:55Z arybchik $"); 33 34#include "efsys.h" 35#include "efx.h" 36#include "efx_types.h" 37#include "efx_regs.h" 38#include "efx_impl.h" 39 40 41#if EFSYS_OPT_VPD 42 43#if EFSYS_OPT_HUNTINGTON 44 45#include "ef10_tlv_layout.h" 46 47 __checkReturn int 48hunt_vpd_init( 49 __in efx_nic_t *enp) 50{ 51 caddr_t svpd; 52 size_t svpd_size; 53 uint32_t pci_pf; 54 int rc; 55 56 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 57 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 58 59 pci_pf = enp->en_nic_cfg.enc_pf; 60 /* 61 * The VPD interface exposes VPD resources from the combined static and 62 * dynamic VPD storage. As the static VPD configuration should *never* 63 * change, we can cache it. 64 */ 65 svpd = NULL; 66 svpd_size = 0; 67 rc = hunt_nvram_partn_read_tlv(enp, 68 NVRAM_PARTITION_TYPE_STATIC_CONFIG, 69 TLV_TAG_PF_STATIC_VPD(pci_pf), 70 &svpd, &svpd_size); 71 if (rc != 0) { 72 if (rc == EACCES) { 73 /* Unpriviledged functions cannot access VPD */ 74 goto out; 75 } 76 goto fail1; 77 } 78 79 if (svpd != NULL && svpd_size > 0) { 80 if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0) 81 goto fail2; 82 } 83 84 enp->en_u.hunt.enu_svpd = svpd; 85 enp->en_u.hunt.enu_svpd_length = svpd_size; 86 87out: 88 return (0); 89 90fail2: 91 EFSYS_PROBE(fail2); 92 93 EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd); 94fail1: 95 EFSYS_PROBE1(fail1, int, rc); 96 97 return (rc); 98} 99 100 __checkReturn int 101hunt_vpd_size( 102 __in efx_nic_t *enp, 103 __out size_t *sizep) 104{ 105 int rc; 106 107 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 108 109 /* 110 * This function returns the total size the user should allocate 111 * for all VPD operations. We've already cached the static vpd, 112 * so we just need to return an upper bound on the dynamic vpd, 113 * which is the size of the DYNAMIC_CONFIG partition. 114 */ 115 if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 116 sizep, NULL, NULL)) != 0) 117 goto fail1; 118 119 return (0); 120 121fail1: 122 EFSYS_PROBE1(fail1, int, rc); 123 124 return (rc); 125} 126 127 __checkReturn int 128hunt_vpd_read( 129 __in efx_nic_t *enp, 130 __out_bcount(size) caddr_t data, 131 __in size_t size) 132{ 133 caddr_t dvpd; 134 size_t dvpd_size; 135 uint32_t pci_pf; 136 int rc; 137 138 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 139 140 pci_pf = enp->en_nic_cfg.enc_pf; 141 142 if ((rc = hunt_nvram_partn_read_tlv(enp, 143 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 144 TLV_TAG_PF_DYNAMIC_VPD(pci_pf), 145 &dvpd, &dvpd_size)) != 0) 146 goto fail1; 147 148 if (dvpd_size > size) { 149 rc = ENOSPC; 150 goto fail2; 151 } 152 memcpy(data, dvpd, dvpd_size); 153 154 /* Pad data with all-1s, consistent with update operations */ 155 memset(data + dvpd_size, 0xff, size - dvpd_size); 156 157 EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); 158 159 return (0); 160 161fail2: 162 EFSYS_PROBE(fail2); 163 164 EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); 165fail1: 166 EFSYS_PROBE1(fail1, int, rc); 167 168 return (rc); 169} 170 171 __checkReturn int 172hunt_vpd_verify( 173 __in efx_nic_t *enp, 174 __in_bcount(size) caddr_t data, 175 __in size_t size) 176{ 177 efx_vpd_tag_t stag; 178 efx_vpd_tag_t dtag; 179 efx_vpd_keyword_t skey; 180 efx_vpd_keyword_t dkey; 181 unsigned int scont; 182 unsigned int dcont; 183 int rc; 184 185 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 186 187 /* 188 * Strictly you could take the view that dynamic vpd is optional. 189 * Instead, to conform more closely to the read/verify/reinit() 190 * paradigm, we require dynamic vpd. hunt_vpd_reinit() will 191 * reinitialize it as required. 192 */ 193 if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0) 194 goto fail1; 195 196 /* 197 * Verify that there is no duplication between the static and 198 * dynamic cfg sectors. 199 */ 200 if (enp->en_u.hunt.enu_svpd_length == 0) 201 goto done; 202 203 dcont = 0; 204 _NOTE(CONSTANTCONDITION) 205 while (1) { 206 if ((rc = efx_vpd_hunk_next(data, size, &dtag, 207 &dkey, NULL, NULL, &dcont)) != 0) 208 goto fail2; 209 if (dcont == 0) 210 break; 211 212 scont = 0; 213 _NOTE(CONSTANTCONDITION) 214 while (1) { 215 if ((rc = efx_vpd_hunk_next( 216 enp->en_u.hunt.enu_svpd, 217 enp->en_u.hunt.enu_svpd_length, &stag, &skey, 218 NULL, NULL, &scont)) != 0) 219 goto fail3; 220 if (scont == 0) 221 break; 222 223 if (stag == dtag && skey == dkey) { 224 rc = EEXIST; 225 goto fail4; 226 } 227 } 228 } 229 230done: 231 return (0); 232 233fail4: 234 EFSYS_PROBE(fail4); 235fail3: 236 EFSYS_PROBE(fail3); 237fail2: 238 EFSYS_PROBE(fail2); 239fail1: 240 EFSYS_PROBE1(fail1, int, rc); 241 242 return (rc); 243} 244 245 __checkReturn int 246hunt_vpd_reinit( 247 __in efx_nic_t *enp, 248 __in_bcount(size) caddr_t data, 249 __in size_t size) 250{ 251 boolean_t wantpid; 252 int rc; 253 254 /* 255 * Only create an ID string if the dynamic cfg doesn't have one 256 */ 257 if (enp->en_u.hunt.enu_svpd_length == 0) 258 wantpid = B_TRUE; 259 else { 260 unsigned int offset; 261 uint8_t length; 262 263 rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd, 264 enp->en_u.hunt.enu_svpd_length, 265 EFX_VPD_ID, 0, &offset, &length); 266 if (rc == 0) 267 wantpid = B_FALSE; 268 else if (rc == ENOENT) 269 wantpid = B_TRUE; 270 else 271 goto fail1; 272 } 273 274 if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0) 275 goto fail2; 276 277 return (0); 278 279fail2: 280 EFSYS_PROBE(fail2); 281fail1: 282 EFSYS_PROBE1(fail1, int, rc); 283 284 return (rc); 285} 286 287 __checkReturn int 288hunt_vpd_get( 289 __in efx_nic_t *enp, 290 __in_bcount(size) caddr_t data, 291 __in size_t size, 292 __inout efx_vpd_value_t *evvp) 293{ 294 unsigned int offset; 295 uint8_t length; 296 int rc; 297 298 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 299 300 /* Attempt to satisfy the request from svpd first */ 301 if (enp->en_u.hunt.enu_svpd_length > 0) { 302 if ((rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd, 303 enp->en_u.hunt.enu_svpd_length, evvp->evv_tag, 304 evvp->evv_keyword, &offset, &length)) == 0) { 305 evvp->evv_length = length; 306 memcpy(evvp->evv_value, 307 enp->en_u.hunt.enu_svpd + offset, length); 308 return (0); 309 } else if (rc != ENOENT) 310 goto fail1; 311 } 312 313 /* And then from the provided data buffer */ 314 if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, 315 evvp->evv_keyword, &offset, &length)) != 0) 316 goto fail2; 317 318 evvp->evv_length = length; 319 memcpy(evvp->evv_value, data + offset, length); 320 321 return (0); 322 323fail2: 324 EFSYS_PROBE(fail2); 325fail1: 326 EFSYS_PROBE1(fail1, int, rc); 327 328 return (rc); 329} 330 331 __checkReturn int 332hunt_vpd_set( 333 __in efx_nic_t *enp, 334 __in_bcount(size) caddr_t data, 335 __in size_t size, 336 __in efx_vpd_value_t *evvp) 337{ 338 int rc; 339 340 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 341 342 /* If the provided (tag,keyword) exists in svpd, then it is readonly */ 343 if (enp->en_u.hunt.enu_svpd_length > 0) { 344 unsigned int offset; 345 uint8_t length; 346 347 if ((rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd, 348 enp->en_u.hunt.enu_svpd_length, evvp->evv_tag, 349 evvp->evv_keyword, &offset, &length)) == 0) { 350 rc = EACCES; 351 goto fail1; 352 } 353 } 354 355 if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) 356 goto fail2; 357 358 return (0); 359 360fail2: 361 EFSYS_PROBE(fail2); 362fail1: 363 EFSYS_PROBE1(fail1, int, rc); 364 365 return (rc); 366} 367 368 __checkReturn int 369hunt_vpd_next( 370 __in efx_nic_t *enp, 371 __in_bcount(size) caddr_t data, 372 __in size_t size, 373 __out efx_vpd_value_t *evvp, 374 __inout unsigned int *contp) 375{ 376 _NOTE(ARGUNUSED(enp, data, size, evvp, contp)) 377 378 return (ENOTSUP); 379} 380 381 __checkReturn int 382hunt_vpd_write( 383 __in efx_nic_t *enp, 384 __in_bcount(size) caddr_t data, 385 __in size_t size) 386{ 387 size_t vpd_length; 388 uint32_t pci_pf; 389 int rc; 390 391 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 392 393 pci_pf = enp->en_nic_cfg.enc_pf; 394 395 /* Determine total length of new dynamic VPD */ 396 if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) 397 goto fail1; 398 399 /* Store new dynamic VPD in DYNAMIC_CONFIG partition */ 400 if ((rc = hunt_nvram_partn_write_tlv(enp, 401 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 402 TLV_TAG_PF_DYNAMIC_VPD(pci_pf), 403 data, vpd_length)) != 0) { 404 goto fail2; 405 } 406 407 return (0); 408 409fail2: 410 EFSYS_PROBE(fail2); 411 412fail1: 413 EFSYS_PROBE1(fail1, int, rc); 414 415 return (rc); 416} 417 418 void 419hunt_vpd_fini( 420 __in efx_nic_t *enp) 421{ 422 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 423 424 if (enp->en_u.hunt.enu_svpd_length > 0) { 425 EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.hunt.enu_svpd_length, 426 enp->en_u.hunt.enu_svpd); 427 428 enp->en_u.hunt.enu_svpd = NULL; 429 enp->en_u.hunt.enu_svpd_length = 0; 430 } 431} 432 433#endif /* EFSYS_OPT_HUNTINGTON */ 434 435#endif /* EFSYS_OPT_VPD */ 436