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