LCOV - code coverage report
Current view: top level - drivers/common/sfc_efx/base - ef10_mcdi.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 98 0.0 %
Date: 2024-02-14 00:53:57 Functions: 0 8 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 73 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *
       3                 :            :  * Copyright(c) 2019-2021 Xilinx, Inc.
       4                 :            :  * Copyright(c) 2012-2019 Solarflare Communications Inc.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "efx.h"
       8                 :            : #include "efx_impl.h"
       9                 :            : 
      10                 :            : 
      11                 :            : #if EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10()
      12                 :            : 
      13                 :            : #if EFSYS_OPT_MCDI
      14                 :            : 
      15                 :            : #ifndef WITH_MCDI_V2
      16                 :            : #error "WITH_MCDI_V2 required for EF10 MCDIv2 commands."
      17                 :            : #endif
      18                 :            : 
      19                 :            : 
      20                 :            :         __checkReturn   efx_rc_t
      21                 :          0 : ef10_mcdi_init(
      22                 :            :         __in            efx_nic_t *enp,
      23                 :            :         __in            const efx_mcdi_transport_t *emtp)
      24                 :            : {
      25                 :            :         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
      26                 :          0 :         efsys_mem_t *esmp = emtp->emt_dma_mem;
      27                 :            :         efx_dword_t dword;
      28                 :            :         efx_rc_t rc;
      29                 :            : 
      30         [ #  # ]:          0 :         EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
      31         [ #  # ]:          0 :         EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA);
      32                 :            : 
      33                 :            :         /*
      34                 :            :          * All EF10 firmware supports MCDIv2 and MCDIv1.
      35                 :            :          * Medford BootROM supports MCDIv2 and MCDIv1.
      36                 :            :          * Huntington BootROM supports MCDIv1 only.
      37                 :            :          */
      38                 :          0 :         emip->emi_max_version = 2;
      39                 :            : 
      40                 :            :         /* A host DMA buffer is required for EF10 MCDI */
      41         [ #  # ]:          0 :         if (esmp == NULL) {
      42                 :            :                 rc = EINVAL;
      43                 :          0 :                 goto fail1;
      44                 :            :         }
      45                 :            : 
      46                 :            :         /*
      47                 :            :          * Ensure that the MC doorbell is in a known state before issuing MCDI
      48                 :            :          * commands. The recovery algorithm requires that the MC command buffer
      49                 :            :          * must be 256 byte aligned. See bug24769.
      50                 :            :          */
      51         [ #  # ]:          0 :         if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) {
      52                 :            :                 rc = EINVAL;
      53                 :          0 :                 goto fail2;
      54                 :            :         }
      55                 :            :         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1);
      56         [ #  # ]:          0 :         switch (enp->en_family) {
      57                 :            : #if EFSYS_OPT_RIVERHEAD
      58                 :            :         case EFX_FAMILY_RIVERHEAD:
      59   [ #  #  #  # ]:          0 :                 EFX_BAR_FCW_WRITED(enp, ER_GZ_MC_DB_HWRD_REG, &dword);
      60                 :            :                 break;
      61                 :            : #endif  /* EFSYS_OPT_RIVERHEAD */
      62         [ #  # ]:          0 :         default:
      63         [ #  # ]:          0 :                 EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
      64                 :            :                 break;
      65                 :            :         }
      66                 :            : 
      67                 :            :         /* Save initial MC reboot status */
      68                 :          0 :         (void) ef10_mcdi_poll_reboot(enp);
      69                 :            : 
      70                 :            :         /* Start a new epoch (allow fresh MCDI requests to succeed) */
      71                 :          0 :         efx_mcdi_new_epoch(enp);
      72                 :            : 
      73                 :          0 :         return (0);
      74                 :            : 
      75                 :            : fail2:
      76                 :            :         EFSYS_PROBE(fail2);
      77                 :          0 : fail1:
      78                 :            :         EFSYS_PROBE1(fail1, efx_rc_t, rc);
      79                 :            : 
      80                 :            :         return (rc);
      81                 :            : }
      82                 :            : 
      83                 :            :                         void
      84                 :          0 : ef10_mcdi_fini(
      85                 :            :         __in            efx_nic_t *enp)
      86                 :            : {
      87                 :            :         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
      88                 :            : 
      89                 :          0 :         emip->emi_new_epoch = B_FALSE;
      90                 :          0 : }
      91                 :            : 
      92                 :            : /*
      93                 :            :  * In older firmware all commands are processed in a single thread, so a long
      94                 :            :  * running command for one PCIe function can block processing for another
      95                 :            :  * function (see bug 61269).
      96                 :            :  *
      97                 :            :  * In newer firmware that supports multithreaded MCDI processing, we can extend
      98                 :            :  * the timeout for long-running requests which we know firmware may choose to
      99                 :            :  * process in a background thread.
     100                 :            :  */
     101                 :            : #define EF10_MCDI_CMD_TIMEOUT_US        (10 * 1000 * 1000)
     102                 :            : #define EF10_MCDI_CMD_LONG_TIMEOUT_US   (60 * 1000 * 1000)
     103                 :            : 
     104                 :            :                         void
     105                 :          0 : ef10_mcdi_get_timeout(
     106                 :            :         __in            efx_nic_t *enp,
     107                 :            :         __in            efx_mcdi_req_t *emrp,
     108                 :            :         __out           uint32_t *timeoutp)
     109                 :            : {
     110                 :            :         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
     111                 :            : 
     112         [ #  # ]:          0 :         switch (emrp->emr_cmd) {
     113                 :          0 :         case MC_CMD_POLL_BIST:
     114                 :            :         case MC_CMD_NVRAM_ERASE:
     115                 :            :         case MC_CMD_LICENSING_V3:
     116                 :            :         case MC_CMD_NVRAM_UPDATE_FINISH:
     117         [ #  # ]:          0 :                 if (encp->enc_nvram_update_verify_result_supported != B_FALSE) {
     118                 :            :                         /*
     119                 :            :                          * Potentially longer running commands, which firmware
     120                 :            :                          * may choose to process in a background thread.
     121                 :            :                          */
     122                 :          0 :                         *timeoutp = EF10_MCDI_CMD_LONG_TIMEOUT_US;
     123                 :          0 :                         break;
     124                 :            :                 }
     125                 :            :                 /* FALLTHRU */
     126                 :            :         default:
     127                 :          0 :                 *timeoutp = EF10_MCDI_CMD_TIMEOUT_US;
     128                 :          0 :                 break;
     129                 :            :         }
     130                 :          0 : }
     131                 :            : 
     132                 :            :                         void
     133                 :          0 : ef10_mcdi_send_request(
     134                 :            :         __in                    efx_nic_t *enp,
     135                 :            :         __in_bcount(hdr_len)    void *hdrp,
     136                 :            :         __in                    size_t hdr_len,
     137                 :            :         __in_bcount(sdu_len)    void *sdup,
     138                 :            :         __in                    size_t sdu_len)
     139                 :            : {
     140                 :          0 :         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
     141                 :          0 :         efsys_mem_t *esmp = emtp->emt_dma_mem;
     142                 :            :         efx_dword_t dword;
     143                 :            :         unsigned int pos;
     144                 :            : 
     145         [ #  # ]:          0 :         EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
     146                 :            : 
     147                 :            :         /* Write the header */
     148         [ #  # ]:          0 :         for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) {
     149                 :          0 :                 dword = *(efx_dword_t *)((uint8_t *)hdrp + pos);
     150                 :          0 :                 EFSYS_MEM_WRITED(esmp, pos, &dword);
     151                 :            :         }
     152                 :            : 
     153                 :            :         /* Write the payload */
     154         [ #  # ]:          0 :         for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) {
     155                 :          0 :                 dword = *(efx_dword_t *)((uint8_t *)sdup + pos);
     156         [ #  # ]:          0 :                 EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword);
     157                 :            :         }
     158                 :            : 
     159                 :            :         /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */
     160                 :            :         EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len);
     161                 :          0 :         EFSYS_PIO_WRITE_BARRIER();
     162                 :            : 
     163                 :            :         /* Ring the doorbell to post the command DMA address to the MC */
     164                 :          0 :         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
     165                 :            :             EFSYS_MEM_ADDR(esmp) >> 32);
     166         [ #  # ]:          0 :         switch (enp->en_family) {
     167                 :            : #if EFSYS_OPT_RIVERHEAD
     168                 :            :         case EFX_FAMILY_RIVERHEAD:
     169   [ #  #  #  # ]:          0 :                 EFX_BAR_FCW_WRITED(enp, ER_GZ_MC_DB_LWRD_REG, &dword);
     170                 :            :                 break;
     171                 :            : #endif  /* EFSYS_OPT_RIVERHEAD */
     172         [ #  # ]:          0 :         default:
     173         [ #  # ]:          0 :                 EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE);
     174                 :            :                 break;
     175                 :            :         }
     176                 :            : 
     177                 :          0 :         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
     178                 :            :             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
     179         [ #  # ]:          0 :         switch (enp->en_family) {
     180                 :            : #if EFSYS_OPT_RIVERHEAD
     181                 :            :         case EFX_FAMILY_RIVERHEAD:
     182   [ #  #  #  # ]:          0 :                 EFX_BAR_FCW_WRITED(enp, ER_GZ_MC_DB_HWRD_REG, &dword);
     183                 :            :                 break;
     184                 :            : #endif  /* EFSYS_OPT_RIVERHEAD */
     185         [ #  # ]:          0 :         default:
     186         [ #  # ]:          0 :                 EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
     187                 :            :                 break;
     188                 :            :         }
     189                 :          0 : }
     190                 :            : 
     191                 :            :         __checkReturn   boolean_t
     192                 :          0 : ef10_mcdi_poll_response(
     193                 :            :         __in            efx_nic_t *enp)
     194                 :            : {
     195                 :          0 :         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
     196                 :          0 :         efsys_mem_t *esmp = emtp->emt_dma_mem;
     197                 :            :         efx_dword_t hdr;
     198                 :            : 
     199                 :          0 :         EFSYS_MEM_READD(esmp, 0, &hdr);
     200                 :            :         EFSYS_MEM_READ_BARRIER();
     201                 :            : 
     202                 :          0 :         return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
     203                 :            : }
     204                 :            : 
     205                 :            :                         void
     206                 :          0 : ef10_mcdi_read_response(
     207                 :            :         __in                    efx_nic_t *enp,
     208                 :            :         __out_bcount(length)    void *bufferp,
     209                 :            :         __in                    size_t offset,
     210                 :            :         __in                    size_t length)
     211                 :            : {
     212                 :          0 :         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
     213                 :          0 :         efsys_mem_t *esmp = emtp->emt_dma_mem;
     214                 :            :         unsigned int pos = 0;
     215                 :            :         efx_dword_t data;
     216                 :            :         size_t remaining = length;
     217                 :            : 
     218         [ #  # ]:          0 :         while (remaining > 0) {
     219                 :          0 :                 size_t chunk = MIN(remaining, sizeof (data));
     220                 :            : 
     221         [ #  # ]:          0 :                 EFSYS_MEM_READD(esmp, offset + pos, &data);
     222                 :          0 :                 memcpy((uint8_t *)bufferp + pos, &data, chunk);
     223                 :          0 :                 pos += chunk;
     224                 :          0 :                 remaining -= chunk;
     225                 :            :         }
     226                 :          0 : }
     227                 :            : 
     228                 :            :                         efx_rc_t
     229                 :          0 : ef10_mcdi_poll_reboot(
     230                 :            :         __in            efx_nic_t *enp)
     231                 :            : {
     232                 :            :         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
     233                 :            :         efx_dword_t dword;
     234                 :            :         uint32_t old_status;
     235                 :            :         uint32_t new_status;
     236                 :            :         efx_rc_t rc;
     237                 :            : 
     238                 :          0 :         old_status = emip->emi_mc_reboot_status;
     239                 :            : 
     240                 :            :         /* Update MC reboot status word */
     241         [ #  # ]:          0 :         switch (enp->en_family) {
     242                 :            : #if EFSYS_OPT_RIVERHEAD
     243                 :            :         case EFX_FAMILY_RIVERHEAD:
     244   [ #  #  #  # ]:          0 :                 EFX_BAR_FCW_READD(enp, ER_GZ_MC_SFT_STATUS, &dword);
     245                 :          0 :                 break;
     246                 :            : #endif  /* EFSYS_OPT_RIVERHEAD */
     247         [ #  # ]:          0 :         default:
     248         [ #  # ]:          0 :                 EFX_BAR_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG,
     249                 :            :                               &dword, B_FALSE);
     250                 :            :                 break;
     251                 :            :         }
     252                 :            :         new_status = dword.ed_u32[0];
     253                 :            : 
     254                 :            :         /* MC has rebooted if the value has changed */
     255         [ #  # ]:          0 :         if (new_status != old_status) {
     256                 :          0 :                 emip->emi_mc_reboot_status = new_status;
     257                 :            : 
     258                 :            :                 /*
     259                 :            :                  * FIXME: Ignore detected MC REBOOT for now.
     260                 :            :                  *
     261                 :            :                  * The Siena support for checking for MC reboot from status
     262                 :            :                  * flags is broken - see comments in siena_mcdi_poll_reboot().
     263                 :            :                  * As the generic MCDI code is shared the EF10 reboot
     264                 :            :                  * detection suffers similar problems.
     265                 :            :                  *
     266                 :            :                  * Do not report an error when the boot status changes until
     267                 :            :                  * this can be handled by common code drivers (and reworked to
     268                 :            :                  * support Siena too).
     269                 :            :                  */
     270                 :            :                 _NOTE(CONSTANTCONDITION)
     271                 :            :                 if (B_FALSE) {
     272                 :            :                         rc = EIO;
     273                 :            :                         goto fail1;
     274                 :            :                 }
     275                 :            :         }
     276                 :            : 
     277                 :            :         return (0);
     278                 :            : 
     279                 :            : fail1:
     280                 :            :         EFSYS_PROBE1(fail1, efx_rc_t, rc);
     281                 :            : 
     282                 :            :         return (rc);
     283                 :            : }
     284                 :            : 
     285                 :            :         __checkReturn   efx_rc_t
     286                 :          0 : ef10_mcdi_feature_supported(
     287                 :            :         __in            efx_nic_t *enp,
     288                 :            :         __in            efx_mcdi_feature_id_t id,
     289                 :            :         __out           boolean_t *supportedp)
     290                 :            : {
     291                 :            :         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
     292                 :          0 :         uint32_t privilege_mask = encp->enc_privilege_mask;
     293                 :            :         efx_rc_t rc;
     294                 :            : 
     295         [ #  # ]:          0 :         EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
     296                 :            : 
     297                 :            :         /*
     298                 :            :          * Use privilege mask state at MCDI attach.
     299                 :            :          */
     300                 :            : 
     301   [ #  #  #  #  :          0 :         switch (id) {
                      # ]
     302                 :          0 :         case EFX_MCDI_FEATURE_FW_UPDATE:
     303                 :            :                 /*
     304                 :            :                  * Admin privilege must be used prior to introduction of
     305                 :            :                  * specific flag.
     306                 :            :                  */
     307                 :          0 :                 *supportedp =
     308                 :          0 :                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
     309                 :          0 :                 break;
     310                 :          0 :         case EFX_MCDI_FEATURE_LINK_CONTROL:
     311                 :            :                 /*
     312                 :            :                  * Admin privilege used prior to introduction of
     313                 :            :                  * specific flag.
     314                 :            :                  */
     315                 :          0 :                 *supportedp =
     316                 :          0 :                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) ||
     317                 :            :                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
     318                 :          0 :                 break;
     319                 :          0 :         case EFX_MCDI_FEATURE_MACADDR_CHANGE:
     320                 :            :                 /*
     321                 :            :                  * Admin privilege must be used prior to introduction of
     322                 :            :                  * mac spoofing privilege (at v4.6), which is used up to
     323                 :            :                  * introduction of change mac spoofing privilege (at v4.7)
     324                 :            :                  */
     325                 :          0 :                 *supportedp =
     326                 :            :                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) ||
     327                 :          0 :                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
     328                 :            :                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
     329                 :          0 :                 break;
     330                 :          0 :         case EFX_MCDI_FEATURE_MAC_SPOOFING:
     331                 :            :                 /*
     332                 :            :                  * Admin privilege must be used prior to introduction of
     333                 :            :                  * mac spoofing privilege (at v4.6), which is used up to
     334                 :            :                  * introduction of mac spoofing TX privilege (at v4.7)
     335                 :            :                  */
     336                 :          0 :                 *supportedp =
     337                 :            :                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) ||
     338                 :          0 :                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
     339                 :            :                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
     340                 :          0 :                 break;
     341                 :          0 :         default:
     342                 :            :                 rc = ENOTSUP;
     343                 :          0 :                 goto fail1;
     344                 :            :         }
     345                 :            : 
     346                 :            :         return (0);
     347                 :            : 
     348                 :            : fail1:
     349                 :            :         EFSYS_PROBE1(fail1, efx_rc_t, rc);
     350                 :            : 
     351                 :          0 :         return (rc);
     352                 :            : }
     353                 :            : 
     354                 :            : #endif  /* EFSYS_OPT_MCDI */
     355                 :            : 
     356                 :            : #endif  /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */

Generated by: LCOV version 1.14