The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sfxge/common/ef10_vpd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: f927a37f8f8b5e9b8536cc69db88612f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.