LCOV - code coverage report
Current view: top level - drivers/common/sfc_efx - sfc_efx_mcdi.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 111 0.0 %
Date: 2024-01-22 15:35:40 Functions: 0 10 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 58 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) 2016-2019 Solarflare Communications Inc.
       5                 :            :  *
       6                 :            :  * This software was jointly developed between OKTET Labs (under contract
       7                 :            :  * for Solarflare) and Solarflare Communications, Inc.
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <rte_cycles.h>
      11                 :            : 
      12                 :            : #include "efx.h"
      13                 :            : #include "efx_mcdi.h"
      14                 :            : #include "efx_regs_mcdi.h"
      15                 :            : 
      16                 :            : #include "sfc_efx_mcdi.h"
      17                 :            : #include "sfc_efx_debug.h"
      18                 :            : 
      19                 :            : #define SFC_EFX_MCDI_POLL_INTERVAL_MIN_US       10              /* 10us */
      20                 :            : #define SFC_EFX_MCDI_POLL_INTERVAL_MAX_US       (US_PER_S / 10) /* 100ms */
      21                 :            : #define SFC_EFX_MCDI_WATCHDOG_INTERVAL_US       (10 * US_PER_S) /* 10s */
      22                 :            : 
      23                 :            : #define sfc_efx_mcdi_log(mcdi, level, ...) \
      24                 :            :         do {                                                            \
      25                 :            :                 const struct sfc_efx_mcdi *_mcdi = (mcdi);              \
      26                 :            :                                                                         \
      27                 :            :                 rte_log(level, _mcdi->logtype,                               \
      28                 :            :                         RTE_FMT("%s" RTE_FMT_HEAD(__VA_ARGS__ ,) "\n",      \
      29                 :            :                                 _mcdi->log_prefix,                   \
      30                 :            :                                 RTE_FMT_TAIL(__VA_ARGS__,)));           \
      31                 :            :         } while (0)
      32                 :            : 
      33                 :            : #define sfc_efx_mcdi_crit(mcdi, ...) \
      34                 :            :         sfc_efx_mcdi_log(mcdi, RTE_LOG_CRIT, __VA_ARGS__)
      35                 :            : 
      36                 :            : #define sfc_efx_mcdi_err(mcdi, ...) \
      37                 :            :         sfc_efx_mcdi_log(mcdi, RTE_LOG_ERR, __VA_ARGS__)
      38                 :            : 
      39                 :            : #define sfc_efx_mcdi_warn(mcdi, ...) \
      40                 :            :         sfc_efx_mcdi_log(mcdi, RTE_LOG_WARNING, __VA_ARGS__)
      41                 :            : 
      42                 :            : #define sfc_efx_mcdi_info(mcdi, ...) \
      43                 :            :         sfc_efx_mcdi_log(mcdi, RTE_LOG_INFO, __VA_ARGS__)
      44                 :            : 
      45                 :            : /** Level value used by MCDI log statements */
      46                 :            : #define SFC_EFX_LOG_LEVEL_MCDI  RTE_LOG_INFO
      47                 :            : 
      48                 :            : #define sfc_efx_log_mcdi(mcdi, ...) \
      49                 :            :         sfc_efx_mcdi_log(mcdi, SFC_EFX_LOG_LEVEL_MCDI, __VA_ARGS__)
      50                 :            : 
      51                 :            : static void
      52                 :          0 : sfc_efx_mcdi_timeout(struct sfc_efx_mcdi *mcdi)
      53                 :            : {
      54                 :          0 :         sfc_efx_mcdi_warn(mcdi, "MC TIMEOUT");
      55                 :            : 
      56                 :          0 :         sfc_efx_mcdi_crit(mcdi, "MCDI timeout handling is not implemented");
      57                 :          0 :         sfc_efx_mcdi_crit(mcdi, "NIC is unusable");
      58                 :          0 :         mcdi->state = SFC_EFX_MCDI_DEAD;
      59                 :          0 : }
      60                 :            : 
      61                 :            : static inline boolean_t
      62                 :            : sfc_efx_mcdi_proxy_event_available(struct sfc_efx_mcdi *mcdi)
      63                 :            : {
      64                 :          0 :         mcdi->proxy_handle = 0;
      65                 :          0 :         mcdi->proxy_result = ETIMEDOUT;
      66                 :          0 :         mcdi->ops->mgmt_evq_poll(mcdi->ops_cookie);
      67         [ #  # ]:          0 :         if (mcdi->proxy_result != ETIMEDOUT)
      68                 :            :                 return B_TRUE;
      69                 :            : 
      70                 :            :         return B_FALSE;
      71                 :            : }
      72                 :            : 
      73                 :            : static void
      74                 :          0 : sfc_efx_mcdi_poll(struct sfc_efx_mcdi *mcdi, boolean_t proxy)
      75                 :            : {
      76                 :            :         efx_nic_t *enp;
      77                 :            :         unsigned int delay_total;
      78                 :            :         unsigned int delay_us;
      79                 :            :         boolean_t aborted __rte_unused;
      80                 :            : 
      81                 :            :         delay_total = 0;
      82                 :            :         delay_us = SFC_EFX_MCDI_POLL_INTERVAL_MIN_US;
      83                 :          0 :         enp = mcdi->nic;
      84                 :            : 
      85                 :            :         do {
      86                 :            :                 boolean_t poll_completed;
      87                 :            : 
      88                 :            :                 poll_completed = (proxy) ?
      89         [ #  # ]:          0 :                                 sfc_efx_mcdi_proxy_event_available(mcdi) :
      90                 :          0 :                                 efx_mcdi_request_poll(enp);
      91         [ #  # ]:          0 :                 if (poll_completed)
      92                 :          0 :                         return;
      93                 :            : 
      94         [ #  # ]:          0 :                 if (delay_total > SFC_EFX_MCDI_WATCHDOG_INTERVAL_US) {
      95         [ #  # ]:          0 :                         if (!proxy) {
      96                 :          0 :                                 aborted = efx_mcdi_request_abort(enp);
      97         [ #  # ]:          0 :                                 SFC_EFX_ASSERT(aborted);
      98                 :          0 :                                 sfc_efx_mcdi_timeout(mcdi);
      99                 :            :                         }
     100                 :            : 
     101                 :          0 :                         return;
     102                 :            :                 }
     103                 :            : 
     104                 :          0 :                 rte_delay_us(delay_us);
     105                 :            : 
     106                 :          0 :                 delay_total += delay_us;
     107                 :            : 
     108                 :            :                 /* Exponentially back off the poll frequency */
     109                 :            :                 RTE_BUILD_BUG_ON(SFC_EFX_MCDI_POLL_INTERVAL_MAX_US >
     110                 :            :                                  UINT_MAX / 2);
     111                 :          0 :                 delay_us *= 2;
     112                 :            :                 if (delay_us > SFC_EFX_MCDI_POLL_INTERVAL_MAX_US)
     113                 :            :                         delay_us = SFC_EFX_MCDI_POLL_INTERVAL_MAX_US;
     114                 :            : 
     115                 :            :         } while (1);
     116                 :            : }
     117                 :            : 
     118                 :            : static void
     119                 :          0 : sfc_efx_mcdi_execute(void *arg, efx_mcdi_req_t *emrp)
     120                 :            : {
     121                 :            :         struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
     122                 :            :         uint32_t proxy_handle;
     123                 :            : 
     124         [ #  # ]:          0 :         if (mcdi->state == SFC_EFX_MCDI_DEAD) {
     125                 :          0 :                 emrp->emr_rc = ENOEXEC;
     126                 :          0 :                 return;
     127                 :            :         }
     128                 :            : 
     129                 :          0 :         rte_spinlock_lock(&mcdi->lock);
     130                 :            : 
     131         [ #  # ]:          0 :         SFC_EFX_ASSERT(mcdi->state == SFC_EFX_MCDI_INITIALIZED);
     132                 :            : 
     133                 :          0 :         efx_mcdi_request_start(mcdi->nic, emrp, B_FALSE);
     134                 :          0 :         sfc_efx_mcdi_poll(mcdi, B_FALSE);
     135                 :            : 
     136         [ #  # ]:          0 :         if (efx_mcdi_get_proxy_handle(mcdi->nic, emrp, &proxy_handle) == 0) {
     137                 :            :                 /*
     138                 :            :                  * Authorization is required for the MCDI request;
     139                 :            :                  * wait for an MCDI proxy response event to bring
     140                 :            :                  * a non-zero proxy handle (should be the same as
     141                 :            :                  * the value obtained above) and operation status
     142                 :            :                  */
     143                 :          0 :                 sfc_efx_mcdi_poll(mcdi, B_TRUE);
     144                 :            : 
     145         [ #  # ]:          0 :                 if ((mcdi->proxy_handle != 0) &&
     146         [ #  # ]:          0 :                     (mcdi->proxy_handle != proxy_handle)) {
     147                 :          0 :                         sfc_efx_mcdi_err(mcdi, "Unexpected MCDI proxy event");
     148                 :          0 :                         emrp->emr_rc = EFAULT;
     149         [ #  # ]:          0 :                 } else if (mcdi->proxy_result == 0) {
     150                 :            :                         /*
     151                 :            :                          * Authorization succeeded; re-issue the original
     152                 :            :                          * request and poll for an ordinary MCDI response
     153                 :            :                          */
     154                 :          0 :                         efx_mcdi_request_start(mcdi->nic, emrp, B_FALSE);
     155                 :          0 :                         sfc_efx_mcdi_poll(mcdi, B_FALSE);
     156                 :            :                 } else {
     157                 :          0 :                         emrp->emr_rc = mcdi->proxy_result;
     158                 :          0 :                         sfc_efx_mcdi_err(mcdi,
     159                 :            :                                 "MCDI proxy authorization failed (handle=%08x, result=%d)",
     160                 :            :                                 proxy_handle, mcdi->proxy_result);
     161                 :            :                 }
     162                 :            :         }
     163                 :            : 
     164                 :            :         rte_spinlock_unlock(&mcdi->lock);
     165                 :            : }
     166                 :            : 
     167                 :            : static void
     168                 :          0 : sfc_efx_mcdi_ev_cpl(void *arg)
     169                 :            : {
     170                 :            :         struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
     171                 :            : 
     172                 :            :         RTE_SET_USED(mcdi);
     173         [ #  # ]:          0 :         SFC_EFX_ASSERT(mcdi->state == SFC_EFX_MCDI_INITIALIZED);
     174                 :            : 
     175                 :            :         /* MCDI is polled, completions are not expected */
     176                 :          0 :         SFC_EFX_ASSERT(0);
     177                 :            : }
     178                 :            : 
     179                 :            : static void
     180                 :          0 : sfc_efx_mcdi_exception(void *arg, efx_mcdi_exception_t eme)
     181                 :            : {
     182                 :            :         struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
     183                 :            : 
     184   [ #  #  #  # ]:          0 :         sfc_efx_mcdi_warn(mcdi, "MC %s",
     185                 :            :             (eme == EFX_MCDI_EXCEPTION_MC_REBOOT) ? "REBOOT" :
     186                 :            :             (eme == EFX_MCDI_EXCEPTION_MC_BADASSERT) ? "BADASSERT" : "UNKNOWN");
     187                 :            : 
     188                 :          0 :         mcdi->ops->sched_restart(mcdi->ops_cookie);
     189                 :          0 : }
     190                 :            : 
     191                 :            : #define SFC_MCDI_LOG_BUF_SIZE   128
     192                 :            : 
     193                 :            : static size_t
     194                 :          0 : sfc_efx_mcdi_do_log(const struct sfc_efx_mcdi *mcdi,
     195                 :            :                 char *buffer, void *data, size_t data_size,
     196                 :            :                 size_t pfxsize, size_t position)
     197                 :            : {
     198                 :            :         uint32_t *words = data;
     199                 :            :         /* Space separator plus 2 characters per byte */
     200                 :            :         const size_t word_str_space = 1 + 2 * sizeof(*words);
     201                 :            :         size_t i;
     202                 :            : 
     203         [ #  # ]:          0 :         for (i = 0; i < data_size; i += sizeof(*words)) {
     204         [ #  # ]:          0 :                 if (position + word_str_space >=
     205                 :            :                     SFC_MCDI_LOG_BUF_SIZE) {
     206                 :            :                         /* Flush at SFC_MCDI_LOG_BUF_SIZE with backslash
     207                 :            :                          * at the end which is required by netlogdecode.
     208                 :            :                          */
     209                 :          0 :                         buffer[position] = '\0';
     210                 :          0 :                         sfc_efx_log_mcdi(mcdi, "%s \\", buffer);
     211                 :            :                         /* Preserve prefix for the next log message */
     212                 :            :                         position = pfxsize;
     213                 :            :                 }
     214                 :          0 :                 position += snprintf(buffer + position,
     215                 :            :                                      SFC_MCDI_LOG_BUF_SIZE - position,
     216                 :            :                                      " %08x", *words);
     217                 :          0 :                 words++;
     218                 :            :         }
     219                 :          0 :         return position;
     220                 :            : }
     221                 :            : 
     222                 :            : static void
     223                 :          0 : sfc_efx_mcdi_logger(void *arg, efx_log_msg_t type,
     224                 :            :                 void *header, size_t header_size,
     225                 :            :                 void *data, size_t data_size)
     226                 :            : {
     227                 :            :         struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
     228                 :            :         char buffer[SFC_MCDI_LOG_BUF_SIZE];
     229                 :            :         size_t pfxsize;
     230                 :            :         size_t start;
     231                 :            : 
     232                 :            :         /*
     233                 :            :          * Unlike the other cases, MCDI logging implies more onerous work
     234                 :            :          * needed to produce a message. If the dynamic log level prevents
     235                 :            :          * the end result from being printed, the CPU time will be wasted.
     236                 :            :          *
     237                 :            :          * To avoid wasting time, the actual level is examined in advance.
     238                 :            :          */
     239         [ #  # ]:          0 :         if (rte_log_get_level(mcdi->logtype) < (int)SFC_EFX_LOG_LEVEL_MCDI)
     240                 :          0 :                 return;
     241                 :            : 
     242                 :            :         /* The format including prefix added by sfc_efx_log_mcdi() is the
     243                 :            :          * format consumed by the Solarflare netlogdecode tool.
     244                 :            :          */
     245         [ #  # ]:          0 :         pfxsize = snprintf(buffer, sizeof(buffer), "MCDI RPC %s:",
     246                 :            :                            type == EFX_LOG_MCDI_REQUEST ? "REQ" :
     247         [ #  # ]:          0 :                            type == EFX_LOG_MCDI_RESPONSE ? "RESP" : "???");
     248                 :          0 :         start = sfc_efx_mcdi_do_log(mcdi, buffer, header, header_size,
     249                 :            :                                     pfxsize, pfxsize);
     250                 :          0 :         start = sfc_efx_mcdi_do_log(mcdi, buffer, data, data_size,
     251                 :            :                                     pfxsize, start);
     252         [ #  # ]:          0 :         if (start != pfxsize) {
     253                 :          0 :                 buffer[start] = '\0';
     254                 :          0 :                 sfc_efx_log_mcdi(mcdi, "%s", buffer);
     255                 :            :         }
     256                 :            : }
     257                 :            : 
     258                 :            : static void
     259                 :          0 : sfc_efx_mcdi_ev_proxy_response(void *arg, uint32_t handle, efx_rc_t result)
     260                 :            : {
     261                 :            :         struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
     262                 :            : 
     263                 :          0 :         mcdi->proxy_handle = handle;
     264                 :          0 :         mcdi->proxy_result = result;
     265                 :          0 : }
     266                 :            : 
     267                 :            : int
     268                 :          0 : sfc_efx_mcdi_init(struct sfc_efx_mcdi *mcdi,
     269                 :            :                   uint32_t logtype, const char *log_prefix, efx_nic_t *nic,
     270                 :            :                   const struct sfc_efx_mcdi_ops *ops, void *ops_cookie)
     271                 :            : {
     272                 :            :         size_t max_msg_size;
     273                 :            :         efx_mcdi_transport_t *emtp;
     274                 :            :         int rc;
     275                 :            : 
     276   [ #  #  #  # ]:          0 :         if (ops->dma_alloc == NULL || ops->dma_free == NULL ||
     277   [ #  #  #  # ]:          0 :             ops->sched_restart == NULL || ops->mgmt_evq_poll == NULL)
     278                 :            :                 return EINVAL;
     279                 :            : 
     280         [ #  # ]:          0 :         SFC_EFX_ASSERT(mcdi->state == SFC_EFX_MCDI_UNINITIALIZED);
     281                 :            : 
     282                 :            :         rte_spinlock_init(&mcdi->lock);
     283                 :            : 
     284                 :          0 :         mcdi->ops = ops;
     285                 :          0 :         mcdi->ops_cookie = ops_cookie;
     286                 :          0 :         mcdi->nic = nic;
     287                 :            : 
     288                 :          0 :         mcdi->state = SFC_EFX_MCDI_INITIALIZED;
     289                 :            : 
     290                 :          0 :         mcdi->logtype = logtype;
     291                 :          0 :         mcdi->log_prefix = log_prefix;
     292                 :            : 
     293                 :            :         max_msg_size = sizeof(uint32_t) + MCDI_CTL_SDU_LEN_MAX_V2;
     294                 :          0 :         rc = ops->dma_alloc(ops_cookie, "mcdi", max_msg_size, &mcdi->mem);
     295         [ #  # ]:          0 :         if (rc != 0)
     296                 :          0 :                 goto fail_dma_alloc;
     297                 :            : 
     298                 :          0 :         emtp = &mcdi->transport;
     299                 :          0 :         emtp->emt_context = mcdi;
     300                 :          0 :         emtp->emt_dma_mem = &mcdi->mem;
     301                 :          0 :         emtp->emt_execute = sfc_efx_mcdi_execute;
     302                 :          0 :         emtp->emt_ev_cpl = sfc_efx_mcdi_ev_cpl;
     303                 :          0 :         emtp->emt_exception = sfc_efx_mcdi_exception;
     304                 :          0 :         emtp->emt_logger = sfc_efx_mcdi_logger;
     305                 :          0 :         emtp->emt_ev_proxy_response = sfc_efx_mcdi_ev_proxy_response;
     306                 :            : 
     307                 :          0 :         sfc_efx_mcdi_info(mcdi, "init MCDI");
     308                 :          0 :         rc = efx_mcdi_init(mcdi->nic, emtp);
     309         [ #  # ]:          0 :         if (rc != 0)
     310                 :          0 :                 goto fail_mcdi_init;
     311                 :            : 
     312                 :            :         return 0;
     313                 :            : 
     314                 :            : fail_mcdi_init:
     315                 :            :         memset(emtp, 0, sizeof(*emtp));
     316                 :          0 :         ops->dma_free(ops_cookie, &mcdi->mem);
     317                 :            : 
     318                 :          0 : fail_dma_alloc:
     319                 :          0 :         mcdi->state = SFC_EFX_MCDI_UNINITIALIZED;
     320                 :          0 :         return rc;
     321                 :            : }
     322                 :            : 
     323                 :            : void
     324                 :          0 : sfc_efx_mcdi_fini(struct sfc_efx_mcdi *mcdi)
     325                 :            : {
     326                 :            :         efx_mcdi_transport_t *emtp;
     327                 :            : 
     328                 :          0 :         emtp = &mcdi->transport;
     329                 :            : 
     330                 :          0 :         rte_spinlock_lock(&mcdi->lock);
     331                 :            : 
     332         [ #  # ]:          0 :         SFC_EFX_ASSERT(mcdi->state == SFC_EFX_MCDI_INITIALIZED ||
     333                 :            :                        mcdi->state == SFC_EFX_MCDI_DEAD);
     334                 :          0 :         mcdi->state = SFC_EFX_MCDI_UNINITIALIZED;
     335                 :            : 
     336                 :          0 :         sfc_efx_mcdi_info(mcdi, "fini MCDI");
     337                 :          0 :         efx_mcdi_fini(mcdi->nic);
     338                 :            :         memset(emtp, 0, sizeof(*emtp));
     339                 :            : 
     340                 :            :         rte_spinlock_unlock(&mcdi->lock);
     341                 :            : 
     342                 :          0 :         mcdi->ops->dma_free(mcdi->ops_cookie, &mcdi->mem);
     343                 :          0 : }

Generated by: LCOV version 1.14