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