1 /*- 2 * Copyright (c) 2009-2016 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 #include "efx.h" 33 #include "efx_impl.h" 34 35 #if EFSYS_OPT_VPD 36 37 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 38 39 #include "ef10_tlv_layout.h" 40 41 __checkReturn efx_rc_t 42 ef10_vpd_init( 43 __in efx_nic_t *enp) 44 { 45 caddr_t svpd; 46 size_t svpd_size; 47 uint32_t pci_pf; 48 uint32_t tag; 49 efx_rc_t rc; 50 51 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 52 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 53 enp->en_family == EFX_FAMILY_MEDFORD || 54 enp->en_family == EFX_FAMILY_MEDFORD2); 55 56 if (enp->en_nic_cfg.enc_vpd_is_global) { 57 tag = TLV_TAG_GLOBAL_STATIC_VPD; 58 } else { 59 pci_pf = enp->en_nic_cfg.enc_pf; 60 tag = TLV_TAG_PF_STATIC_VPD(pci_pf); 61 } 62 63 /* 64 * The VPD interface exposes VPD resources from the combined static and 65 * dynamic VPD storage. As the static VPD configuration should *never* 66 * change, we can cache it. 67 */ 68 svpd = NULL; 69 svpd_size = 0; 70 rc = ef10_nvram_partn_read_tlv(enp, 71 NVRAM_PARTITION_TYPE_STATIC_CONFIG, 72 tag, &svpd, &svpd_size); 73 if (rc != 0) { 74 if (rc == EACCES) { 75 /* Unprivileged functions cannot access VPD */ 76 goto out; 77 } 78 goto fail1; 79 } 80 81 if (svpd != NULL && svpd_size > 0) { 82 if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0) 83 goto fail2; 84 } 85 86 enp->en_arch.ef10.ena_svpd = svpd; 87 enp->en_arch.ef10.ena_svpd_length = svpd_size; 88 89 out: 90 return (0); 91 92 fail2: 93 EFSYS_PROBE(fail2); 94 95 EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd); 96 fail1: 97 EFSYS_PROBE1(fail1, efx_rc_t, rc); 98 99 return (rc); 100 } 101 102 __checkReturn efx_rc_t 103 ef10_vpd_size( 104 __in efx_nic_t *enp, 105 __out size_t *sizep) 106 { 107 efx_rc_t rc; 108 109 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 110 enp->en_family == EFX_FAMILY_MEDFORD || 111 enp->en_family == EFX_FAMILY_MEDFORD2); 112 113 /* 114 * This function returns the total size the user should allocate 115 * for all VPD operations. We've already cached the static vpd, 116 * so we just need to return an upper bound on the dynamic vpd, 117 * which is the size of the DYNAMIC_CONFIG partition. 118 */ 119 if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 120 sizep, NULL, NULL, NULL)) != 0) 121 goto fail1; 122 123 return (0); 124 125 fail1: 126 EFSYS_PROBE1(fail1, efx_rc_t, rc); 127 128 return (rc); 129 } 130 131 __checkReturn efx_rc_t 132 ef10_vpd_read( 133 __in efx_nic_t *enp, 134 __out_bcount(size) caddr_t data, 135 __in size_t size) 136 { 137 caddr_t dvpd; 138 size_t dvpd_size; 139 uint32_t pci_pf; 140 uint32_t tag; 141 efx_rc_t rc; 142 143 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 144 enp->en_family == EFX_FAMILY_MEDFORD || 145 enp->en_family == EFX_FAMILY_MEDFORD2); 146 147 if (enp->en_nic_cfg.enc_vpd_is_global) { 148 tag = TLV_TAG_GLOBAL_DYNAMIC_VPD; 149 } else { 150 pci_pf = enp->en_nic_cfg.enc_pf; 151 tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf); 152 } 153 154 if ((rc = ef10_nvram_partn_read_tlv(enp, 155 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 156 tag, &dvpd, &dvpd_size)) != 0) 157 goto fail1; 158 159 if (dvpd_size > size) { 160 rc = ENOSPC; 161 goto fail2; 162 } 163 if (dvpd != NULL) 164 memcpy(data, dvpd, dvpd_size); 165 166 /* Pad data with all-1s, consistent with update operations */ 167 memset(data + dvpd_size, 0xff, size - dvpd_size); 168 169 if (dvpd != NULL) 170 EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); 171 172 return (0); 173 174 fail2: 175 EFSYS_PROBE(fail2); 176 177 if (dvpd != NULL) 178 EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); 179 fail1: 180 EFSYS_PROBE1(fail1, efx_rc_t, rc); 181 182 return (rc); 183 } 184 185 __checkReturn efx_rc_t 186 ef10_vpd_verify( 187 __in efx_nic_t *enp, 188 __in_bcount(size) caddr_t data, 189 __in size_t size) 190 { 191 efx_vpd_tag_t stag; 192 efx_vpd_tag_t dtag; 193 efx_vpd_keyword_t skey; 194 efx_vpd_keyword_t dkey; 195 unsigned int scont; 196 unsigned int dcont; 197 efx_rc_t rc; 198 199 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 200 enp->en_family == EFX_FAMILY_MEDFORD || 201 enp->en_family == EFX_FAMILY_MEDFORD2); 202 203 /* 204 * Strictly you could take the view that dynamic vpd is optional. 205 * Instead, to conform more closely to the read/verify/reinit() 206 * paradigm, we require dynamic vpd. ef10_vpd_reinit() will 207 * reinitialize it as required. 208 */ 209 if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0) 210 goto fail1; 211 212 /* 213 * Verify that there is no duplication between the static and 214 * dynamic cfg sectors. 215 */ 216 if (enp->en_arch.ef10.ena_svpd_length == 0) 217 goto done; 218 219 dcont = 0; 220 _NOTE(CONSTANTCONDITION) 221 while (1) { 222 if ((rc = efx_vpd_hunk_next(data, size, &dtag, 223 &dkey, NULL, NULL, &dcont)) != 0) 224 goto fail2; 225 if (dcont == 0) 226 break; 227 228 /* 229 * Skip the RV keyword. It should be present in both the static 230 * and dynamic cfg sectors. 231 */ 232 if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V')) 233 continue; 234 235 scont = 0; 236 _NOTE(CONSTANTCONDITION) 237 while (1) { 238 if ((rc = efx_vpd_hunk_next( 239 enp->en_arch.ef10.ena_svpd, 240 enp->en_arch.ef10.ena_svpd_length, &stag, &skey, 241 NULL, NULL, &scont)) != 0) 242 goto fail3; 243 if (scont == 0) 244 break; 245 246 if (stag == dtag && skey == dkey) { 247 rc = EEXIST; 248 goto fail4; 249 } 250 } 251 } 252 253 done: 254 return (0); 255 256 fail4: 257 EFSYS_PROBE(fail4); 258 fail3: 259 EFSYS_PROBE(fail3); 260 fail2: 261 EFSYS_PROBE(fail2); 262 fail1: 263 EFSYS_PROBE1(fail1, efx_rc_t, rc); 264 265 return (rc); 266 } 267 268 __checkReturn efx_rc_t 269 ef10_vpd_reinit( 270 __in efx_nic_t *enp, 271 __in_bcount(size) caddr_t data, 272 __in size_t size) 273 { 274 boolean_t wantpid; 275 efx_rc_t rc; 276 277 /* 278 * Only create an ID string if the dynamic cfg doesn't have one 279 */ 280 if (enp->en_arch.ef10.ena_svpd_length == 0) 281 wantpid = B_TRUE; 282 else { 283 unsigned int offset; 284 uint8_t length; 285 286 rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, 287 enp->en_arch.ef10.ena_svpd_length, 288 EFX_VPD_ID, 0, &offset, &length); 289 if (rc == 0) 290 wantpid = B_FALSE; 291 else if (rc == ENOENT) 292 wantpid = B_TRUE; 293 else 294 goto fail1; 295 } 296 297 if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0) 298 goto fail2; 299 300 return (0); 301 302 fail2: 303 EFSYS_PROBE(fail2); 304 fail1: 305 EFSYS_PROBE1(fail1, efx_rc_t, rc); 306 307 return (rc); 308 } 309 310 __checkReturn efx_rc_t 311 ef10_vpd_get( 312 __in efx_nic_t *enp, 313 __in_bcount(size) caddr_t data, 314 __in size_t size, 315 __inout efx_vpd_value_t *evvp) 316 { 317 unsigned int offset; 318 uint8_t length; 319 efx_rc_t rc; 320 321 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 322 enp->en_family == EFX_FAMILY_MEDFORD || 323 enp->en_family == EFX_FAMILY_MEDFORD2); 324 325 /* Attempt to satisfy the request from svpd first */ 326 if (enp->en_arch.ef10.ena_svpd_length > 0) { 327 if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, 328 enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag, 329 evvp->evv_keyword, &offset, &length)) == 0) { 330 evvp->evv_length = length; 331 memcpy(evvp->evv_value, 332 enp->en_arch.ef10.ena_svpd + offset, length); 333 return (0); 334 } else if (rc != ENOENT) 335 goto fail1; 336 } 337 338 /* And then from the provided data buffer */ 339 if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, 340 evvp->evv_keyword, &offset, &length)) != 0) { 341 if (rc == ENOENT) 342 return (rc); 343 goto fail2; 344 } 345 346 evvp->evv_length = length; 347 memcpy(evvp->evv_value, data + offset, length); 348 349 return (0); 350 351 fail2: 352 EFSYS_PROBE(fail2); 353 fail1: 354 EFSYS_PROBE1(fail1, efx_rc_t, rc); 355 356 return (rc); 357 } 358 359 __checkReturn efx_rc_t 360 ef10_vpd_set( 361 __in efx_nic_t *enp, 362 __in_bcount(size) caddr_t data, 363 __in size_t size, 364 __in efx_vpd_value_t *evvp) 365 { 366 efx_rc_t rc; 367 368 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 369 enp->en_family == EFX_FAMILY_MEDFORD || 370 enp->en_family == EFX_FAMILY_MEDFORD2); 371 372 /* If the provided (tag,keyword) exists in svpd, then it is readonly */ 373 if (enp->en_arch.ef10.ena_svpd_length > 0) { 374 unsigned int offset; 375 uint8_t length; 376 377 if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, 378 enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag, 379 evvp->evv_keyword, &offset, &length)) == 0) { 380 rc = EACCES; 381 goto fail1; 382 } 383 } 384 385 if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) 386 goto fail2; 387 388 return (0); 389 390 fail2: 391 EFSYS_PROBE(fail2); 392 fail1: 393 EFSYS_PROBE1(fail1, efx_rc_t, rc); 394 395 return (rc); 396 } 397 398 __checkReturn efx_rc_t 399 ef10_vpd_next( 400 __in efx_nic_t *enp, 401 __in_bcount(size) caddr_t data, 402 __in size_t size, 403 __out efx_vpd_value_t *evvp, 404 __inout unsigned int *contp) 405 { 406 _NOTE(ARGUNUSED(enp, data, size, evvp, contp)) 407 408 return (ENOTSUP); 409 } 410 411 __checkReturn efx_rc_t 412 ef10_vpd_write( 413 __in efx_nic_t *enp, 414 __in_bcount(size) caddr_t data, 415 __in size_t size) 416 { 417 size_t vpd_length; 418 uint32_t pci_pf; 419 uint32_t tag; 420 efx_rc_t rc; 421 422 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 423 enp->en_family == EFX_FAMILY_MEDFORD || 424 enp->en_family == EFX_FAMILY_MEDFORD2); 425 426 if (enp->en_nic_cfg.enc_vpd_is_global) { 427 tag = TLV_TAG_GLOBAL_DYNAMIC_VPD; 428 } else { 429 pci_pf = enp->en_nic_cfg.enc_pf; 430 tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf); 431 } 432 433 /* Determine total length of new dynamic VPD */ 434 if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) 435 goto fail1; 436 437 /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */ 438 if ((rc = ef10_nvram_partn_write_segment_tlv(enp, 439 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 440 tag, data, vpd_length, B_TRUE)) != 0) { 441 goto fail2; 442 } 443 444 return (0); 445 446 fail2: 447 EFSYS_PROBE(fail2); 448 449 fail1: 450 EFSYS_PROBE1(fail1, efx_rc_t, rc); 451 452 return (rc); 453 } 454 455 void 456 ef10_vpd_fini( 457 __in efx_nic_t *enp) 458 { 459 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 460 enp->en_family == EFX_FAMILY_MEDFORD || 461 enp->en_family == EFX_FAMILY_MEDFORD2); 462 463 if (enp->en_arch.ef10.ena_svpd_length > 0) { 464 EFSYS_KMEM_FREE(enp->en_esip, enp->en_arch.ef10.ena_svpd_length, 465 enp->en_arch.ef10.ena_svpd); 466 467 enp->en_arch.ef10.ena_svpd = NULL; 468 enp->en_arch.ef10.ena_svpd_length = 0; 469 } 470 } 471 472 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 473 474 #endif /* EFSYS_OPT_VPD */ 475