LCOV - code coverage report
Current view: top level - drivers/net/sfc - sfc_nic_dma.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 94 0.0 %
Date: 2024-12-01 18:57:19 Functions: 0 8 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 47 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2021 Xilinx, Inc.
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <rte_mempool.h>
       6                 :            : #include <rte_memzone.h>
       7                 :            : 
       8                 :            : #include "efx.h"
       9                 :            : 
      10                 :            : #include "sfc_log.h"
      11                 :            : #include "sfc.h"
      12                 :            : #include "sfc_nic_dma.h"
      13                 :            : 
      14                 :            : static int
      15                 :            : sfc_nic_dma_add_region(struct sfc_nic_dma_info *nic_dma_info,
      16                 :            :                        rte_iova_t nic_base, rte_iova_t trgt_base,
      17                 :            :                        size_t map_len)
      18                 :            : {
      19                 :            :         struct sfc_nic_dma_region *region;
      20                 :            : 
      21         [ #  # ]:          0 :         if (nic_dma_info->nb_regions >= RTE_DIM(nic_dma_info->regions))
      22                 :            :                 return ENOMEM;
      23                 :            : 
      24                 :            :         region = &nic_dma_info->regions[nic_dma_info->nb_regions];
      25                 :          0 :         region->nic_base = nic_base;
      26                 :          0 :         region->trgt_base = trgt_base;
      27                 :          0 :         region->trgt_end = trgt_base + map_len;
      28                 :            : 
      29                 :          0 :         nic_dma_info->nb_regions++;
      30                 :            :         return 0;
      31                 :            : }
      32                 :            : 
      33                 :            : /*
      34                 :            :  * Register mapping for all IOVA mempools at the time of creation to
      35                 :            :  * have mapping for all mbufs.
      36                 :            :  */
      37                 :            : 
      38                 :            : struct sfc_nic_dma_register_mempool_data {
      39                 :            :         struct sfc_adapter              *sa;
      40                 :            :         int                             rc;
      41                 :            : };
      42                 :            : 
      43                 :            : static void
      44                 :          0 : sfc_nic_dma_register_mempool_chunk(struct rte_mempool *mp __rte_unused,
      45                 :            :                                    void *opaque,
      46                 :            :                                    struct rte_mempool_memhdr *memhdr,
      47                 :            :                                    unsigned mem_idx __rte_unused)
      48                 :            : {
      49                 :            :         struct sfc_nic_dma_register_mempool_data *register_data = opaque;
      50         [ #  # ]:          0 :         struct sfc_adapter *sa = register_data->sa;
      51                 :            :         struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
      52                 :            :         efsys_dma_addr_t nic_base;
      53                 :            :         efsys_dma_addr_t trgt_base;
      54                 :            :         size_t map_len;
      55                 :            :         int rc;
      56                 :            : 
      57         [ #  # ]:          0 :         if (memhdr->iova == RTE_BAD_IOVA)
      58                 :          0 :                 return;
      59                 :            : 
      60                 :            :         /*
      61                 :            :          * Check if the memory chunk is mapped already. In that case, there's
      62                 :            :          * nothing left to do.
      63                 :            :          */
      64                 :          0 :         nic_base = sfc_nic_dma_map(&sas->nic_dma_info, memhdr->iova,
      65                 :            :                                    memhdr->len);
      66         [ #  # ]:          0 :         if (nic_base != RTE_BAD_IOVA)
      67                 :            :                 return;
      68                 :            : 
      69                 :          0 :         rc = efx_nic_dma_config_add(sa->nic, memhdr->iova, memhdr->len,
      70                 :            :                                     &nic_base, &trgt_base, &map_len);
      71         [ #  # ]:          0 :         if (rc != 0) {
      72                 :          0 :                 sfc_err(sa,
      73                 :            :                         "cannot handle memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
      74                 :            :                         memhdr->addr, (uint64_t)memhdr->iova, memhdr->len,
      75                 :            :                         rte_strerror(rc));
      76                 :          0 :                 register_data->rc = rc;
      77                 :          0 :                 return;
      78                 :            :         }
      79                 :            : 
      80                 :          0 :         sfc_info(sa,
      81                 :            :                  "registered memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 " -> NIC_BASE=%" PRIx64 " TRGT_BASE=%" PRIx64 " MAP_LEN=%" PRIx64,
      82                 :            :                  memhdr->addr, (uint64_t)memhdr->iova, memhdr->len,
      83                 :            :                  (uint64_t)nic_base, (uint64_t)trgt_base, (uint64_t)map_len);
      84                 :            : 
      85         [ #  # ]:          0 :         rc = sfc_nic_dma_add_region(&sas->nic_dma_info, nic_base, trgt_base,
      86                 :            :                                     map_len);
      87                 :            :         if (rc != 0) {
      88                 :          0 :                 sfc_err(sa, "failed to add regioned NIC DMA mapping: %s",
      89                 :            :                         rte_strerror(rc));
      90                 :          0 :                 register_data->rc = rc;
      91                 :            :         }
      92                 :            : }
      93                 :            : 
      94                 :            : static int
      95                 :          0 : sfc_nic_dma_register_mempool(struct sfc_adapter *sa, struct rte_mempool *mp)
      96                 :            : {
      97                 :          0 :         struct sfc_nic_dma_register_mempool_data register_data = {
      98                 :            :                 .sa = sa,
      99                 :            :         };
     100                 :            :         uint32_t iters;
     101                 :            :         int result = 0;
     102                 :            :         int rc;
     103                 :            : 
     104                 :            :         SFC_ASSERT(sfc_adapter_is_locked(sa));
     105                 :            : 
     106         [ #  # ]:          0 :         if (mp->flags & RTE_MEMPOOL_F_NON_IO)
     107                 :            :                 return 0;
     108                 :            : 
     109                 :          0 :         iters = rte_mempool_mem_iter(mp, sfc_nic_dma_register_mempool_chunk,
     110                 :            :                                      &register_data);
     111         [ #  # ]:          0 :         if (iters != mp->nb_mem_chunks) {
     112                 :          0 :                 sfc_err(sa,
     113                 :            :                         "failed to iterate over memory chunks, some mbufs may be unusable");
     114                 :            :                 result = EFAULT;
     115                 :            :                 /*
     116                 :            :                  * Return an error, but try to continue if error is
     117                 :            :                  * async and cannot be handled properly.
     118                 :            :                  */
     119                 :            :         }
     120                 :            : 
     121         [ #  # ]:          0 :         if (register_data.rc != 0) {
     122                 :          0 :                 sfc_err(sa,
     123                 :            :                         "failed to map some memory chunks (%s), some mbufs may be unusable",
     124                 :            :                         rte_strerror(register_data.rc));
     125                 :          0 :                 result = register_data.rc;
     126                 :            :                 /* Try to continue */
     127                 :            :         }
     128                 :            : 
     129                 :            :         /*
     130                 :            :          * There is no point to apply mapping changes triggered by mempool
     131                 :            :          * registration. Configuration will be propagated on start and
     132                 :            :          * mbufs mapping is required in started state only.
     133                 :            :          */
     134         [ #  # ]:          0 :         if (sa->state == SFC_ETHDEV_STARTED) {
     135                 :            :                 /*
     136                 :            :                  * It's safe to reconfigure the DMA mapping even if no changes
     137                 :            :                  * have been made during memory chunks iteration. In that case,
     138                 :            :                  * this operation will not change anything either.
     139                 :            :                  */
     140                 :          0 :                 rc = efx_nic_dma_reconfigure(sa->nic);
     141         [ #  # ]:          0 :                 if (rc != 0) {
     142                 :          0 :                         sfc_err(sa, "cannot reconfigure NIC DMA: %s",
     143                 :            :                                 rte_strerror(rc));
     144                 :            :                         result = rc;
     145                 :            :                 }
     146                 :            :         }
     147                 :            : 
     148                 :            :         return result;
     149                 :            : }
     150                 :            : 
     151                 :            : static void
     152                 :          0 : sfc_mempool_event_cb(enum rte_mempool_event event, struct rte_mempool *mp,
     153                 :            :                      void *user_data)
     154                 :            : {
     155                 :            :         struct sfc_adapter *sa = user_data;
     156                 :            : 
     157         [ #  # ]:          0 :         if (event != RTE_MEMPOOL_EVENT_READY)
     158                 :            :                 return;
     159                 :            : 
     160                 :          0 :         sfc_adapter_lock(sa);
     161                 :            : 
     162                 :          0 :         (void)sfc_nic_dma_register_mempool(sa, mp);
     163                 :            : 
     164                 :            :         sfc_adapter_unlock(sa);
     165                 :            : }
     166                 :            : 
     167                 :            : struct sfc_mempool_walk_data {
     168                 :            :         struct sfc_adapter              *sa;
     169                 :            :         int                             rc;
     170                 :            : };
     171                 :            : 
     172                 :            : static void
     173                 :          0 : sfc_mempool_walk_cb(struct rte_mempool *mp, void *arg)
     174                 :            : {
     175                 :            :         struct sfc_mempool_walk_data *walk_data = arg;
     176                 :            :         int rc;
     177                 :            : 
     178                 :          0 :         rc = sfc_nic_dma_register_mempool(walk_data->sa, mp);
     179         [ #  # ]:          0 :         if (rc != 0)
     180                 :          0 :                 walk_data->rc = rc;
     181                 :          0 : }
     182                 :            : 
     183                 :            : static int
     184                 :          0 : sfc_nic_dma_attach_regioned(struct sfc_adapter *sa)
     185                 :            : {
     186                 :            :         struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
     187                 :          0 :         struct sfc_mempool_walk_data walk_data = {
     188                 :            :                 .sa = sa,
     189                 :            :         };
     190                 :            :         int rc;
     191                 :            : 
     192                 :          0 :         rc = rte_mempool_event_callback_register(sfc_mempool_event_cb, sa);
     193         [ #  # ]:          0 :         if (rc != 0) {
     194                 :          0 :                 sfc_err(sa, "failed to register mempool event callback");
     195                 :            :                 rc = EFAULT;
     196                 :          0 :                 goto fail_mempool_event_callback_register;
     197                 :            :         }
     198                 :            : 
     199                 :          0 :         rte_mempool_walk(sfc_mempool_walk_cb, &walk_data);
     200         [ #  # ]:          0 :         if (walk_data.rc != 0) {
     201                 :            :                 rc = walk_data.rc;
     202                 :          0 :                 goto fail_mempool_walk;
     203                 :            :         }
     204                 :            : 
     205                 :            :         return 0;
     206                 :            : 
     207                 :            : fail_mempool_walk:
     208                 :          0 :         rte_mempool_event_callback_unregister(sfc_mempool_event_cb, sa);
     209                 :          0 :         sas->nic_dma_info.nb_regions = 0;
     210                 :            : 
     211                 :            : fail_mempool_event_callback_register:
     212                 :            :         return rc;
     213                 :            : }
     214                 :            : 
     215                 :            : static void
     216                 :            : sfc_nic_dma_detach_regioned(struct sfc_adapter *sa)
     217                 :            : {
     218                 :            :         struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
     219                 :            : 
     220                 :          0 :         rte_mempool_event_callback_unregister(sfc_mempool_event_cb, sa);
     221                 :          0 :         sas->nic_dma_info.nb_regions = 0;
     222                 :          0 : }
     223                 :            : 
     224                 :            : int
     225                 :          0 : sfc_nic_dma_attach(struct sfc_adapter *sa)
     226                 :            : {
     227                 :          0 :         const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
     228                 :            :         int rc;
     229                 :            : 
     230                 :          0 :         sfc_log_init(sa, "dma_mapping_type=%u", encp->enc_dma_mapping);
     231                 :            : 
     232      [ #  #  # ]:          0 :         switch (encp->enc_dma_mapping) {
     233                 :            :         case EFX_NIC_DMA_MAPPING_FLAT:
     234                 :            :                 /* No mapping required */
     235                 :            :                 rc = 0;
     236                 :            :                 break;
     237                 :          0 :         case EFX_NIC_DMA_MAPPING_REGIONED:
     238                 :          0 :                 rc = sfc_nic_dma_attach_regioned(sa);
     239                 :          0 :                 break;
     240                 :          0 :         default:
     241                 :            :                 rc = ENOTSUP;
     242                 :          0 :                 break;
     243                 :            :         }
     244                 :            : 
     245                 :          0 :         sfc_log_init(sa, "done: %s", rte_strerror(rc));
     246                 :          0 :         return rc;
     247                 :            : }
     248                 :            : 
     249                 :            : void
     250                 :          0 : sfc_nic_dma_detach(struct sfc_adapter *sa)
     251                 :            : {
     252                 :          0 :         const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
     253                 :            : 
     254                 :          0 :         sfc_log_init(sa, "dma_mapping_type=%u", encp->enc_dma_mapping);
     255                 :            : 
     256         [ #  # ]:          0 :         switch (encp->enc_dma_mapping) {
     257                 :            :         case EFX_NIC_DMA_MAPPING_FLAT:
     258                 :            :                 /* Nothing to do here */
     259                 :            :                 break;
     260                 :            :         case EFX_NIC_DMA_MAPPING_REGIONED:
     261                 :            :                 sfc_nic_dma_detach_regioned(sa);
     262                 :            :                 break;
     263                 :            :         default:
     264                 :            :                 break;
     265                 :            :         }
     266                 :            : 
     267                 :          0 :         sfc_log_init(sa, "done");
     268                 :          0 : }
     269                 :            : 
     270                 :            : int
     271                 :          0 : sfc_nic_dma_mz_map(struct sfc_adapter *sa, const struct rte_memzone *mz,
     272                 :            :                    efx_nic_dma_addr_type_t addr_type,
     273                 :            :                    efsys_dma_addr_t *dma_addr)
     274                 :            : {
     275                 :            :         efsys_dma_addr_t nic_base;
     276                 :            :         efsys_dma_addr_t trgt_base;
     277                 :            :         size_t map_len;
     278                 :            :         int rc;
     279                 :            : 
     280                 :            :         /*
     281                 :            :          * Check if the memzone can be mapped already without changing the DMA
     282                 :            :          * configuration.
     283                 :            :          * libefx is used instead of the driver cache since it can take the type
     284                 :            :          * of the buffer into account and make a better decision when it comes
     285                 :            :          * to buffers that are mapped by the FW itself.
     286                 :            :          */
     287                 :          0 :         rc = efx_nic_dma_map(sa->nic, addr_type, mz->iova, mz->len, dma_addr);
     288         [ #  # ]:          0 :         if (rc == 0)
     289                 :            :                 return 0;
     290                 :            : 
     291         [ #  # ]:          0 :         if (rc != ENOENT) {
     292                 :          0 :                 sfc_err(sa,
     293                 :            :                         "failed to map memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
     294                 :            :                         mz->addr, (uint64_t)mz->iova, mz->len,
     295                 :            :                         rte_strerror(rc));
     296                 :          0 :                 return rc;
     297                 :            :         }
     298                 :            : 
     299                 :          0 :         rc = efx_nic_dma_config_add(sa->nic, mz->iova, mz->len,
     300                 :            :                                     &nic_base, &trgt_base, &map_len);
     301         [ #  # ]:          0 :         if (rc != 0) {
     302                 :          0 :                 sfc_err(sa,
     303                 :            :                         "cannot handle memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
     304                 :            :                         mz->addr, (uint64_t)mz->iova, mz->len,
     305                 :            :                         rte_strerror(rc));
     306                 :          0 :                 return EFAULT;
     307                 :            :         }
     308                 :            : 
     309         [ #  # ]:          0 :         rc = sfc_nic_dma_add_region(&sfc_sa2shared(sa)->nic_dma_info,
     310                 :            :                                     nic_base, trgt_base, map_len);
     311                 :            :         if (rc != 0) {
     312                 :          0 :                 sfc_err(sa,
     313                 :            :                         "failed to add DMA region VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
     314                 :            :                         mz->addr, (uint64_t)mz->iova, mz->len,
     315                 :            :                         rte_strerror(rc));
     316                 :          0 :                 return rc;
     317                 :            :         }
     318                 :            : 
     319                 :          0 :         rc = efx_nic_dma_reconfigure(sa->nic);
     320         [ #  # ]:          0 :         if (rc != 0) {
     321                 :          0 :                 sfc_err(sa, "failed to reconfigure DMA");
     322                 :          0 :                 return rc;
     323                 :            :         }
     324                 :            : 
     325                 :          0 :         rc = efx_nic_dma_map(sa->nic, addr_type, mz->iova, mz->len, dma_addr);
     326         [ #  # ]:          0 :         if (rc != 0) {
     327                 :          0 :                 sfc_err(sa,
     328                 :            :                         "failed to map memory buffer VA=%p IOVA=%" PRIx64 " length=0x%" PRIx64 ": %s",
     329                 :            :                         mz->addr, (uint64_t)mz->iova, mz->len,
     330                 :            :                         rte_strerror(rc));
     331                 :          0 :                 return rc;
     332                 :            :         }
     333                 :            : 
     334                 :            :         return 0;
     335                 :            : }

Generated by: LCOV version 1.14