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