LCOV - code coverage report
Current view: top level - drivers/dma/ioat - ioat_dmadev.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 2 298 0.7 %
Date: 2025-01-02 22:41:34 Functions: 2 25 8.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 1 128 0.8 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2021 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <bus_pci_driver.h>
       6                 :            : #include <rte_dmadev_pmd.h>
       7                 :            : #include <rte_malloc.h>
       8                 :            : #include <rte_prefetch.h>
       9                 :            : #include <rte_errno.h>
      10                 :            : 
      11                 :            : #include "ioat_internal.h"
      12                 :            : 
      13                 :            : static struct rte_pci_driver ioat_pmd_drv;
      14                 :            : 
      15         [ -  + ]:        251 : RTE_LOG_REGISTER_DEFAULT(ioat_pmd_logtype, INFO);
      16                 :            : 
      17                 :            : #define DESC_SZ sizeof(struct ioat_dma_hw_desc)
      18                 :            : 
      19                 :            : #define IOAT_PMD_NAME dmadev_ioat
      20                 :            : #define IOAT_PMD_NAME_STR RTE_STR(IOAT_PMD_NAME)
      21                 :            : 
      22                 :            : /* IOAT operations. */
      23                 :            : enum rte_ioat_ops {
      24                 :            :         ioat_op_copy = 0,       /* Standard DMA Operation */
      25                 :            :         ioat_op_fill            /* Block Fill */
      26                 :            : };
      27                 :            : 
      28                 :            : /* Configure a device. */
      29                 :            : static int
      30                 :          0 : ioat_dev_configure(struct rte_dma_dev *dev __rte_unused, const struct rte_dma_conf *dev_conf,
      31                 :            :                 uint32_t conf_sz)
      32                 :            : {
      33         [ #  # ]:          0 :         if (sizeof(struct rte_dma_conf) != conf_sz)
      34                 :            :                 return -EINVAL;
      35                 :            : 
      36         [ #  # ]:          0 :         if (dev_conf->nb_vchans != 1)
      37                 :          0 :                 return -EINVAL;
      38                 :            : 
      39                 :            :         return 0;
      40                 :            : }
      41                 :            : 
      42                 :            : /* Setup a virtual channel for IOAT, only 1 vchan is supported. */
      43                 :            : static int
      44                 :          0 : ioat_vchan_setup(struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
      45                 :            :                 const struct rte_dma_vchan_conf *qconf, uint32_t qconf_sz)
      46                 :            : {
      47                 :          0 :         struct ioat_dmadev *ioat = dev->fp_obj->dev_private;
      48                 :          0 :         uint16_t max_desc = qconf->nb_desc;
      49                 :            :         int i;
      50                 :            : 
      51         [ #  # ]:          0 :         if (sizeof(struct rte_dma_vchan_conf) != qconf_sz)
      52                 :            :                 return -EINVAL;
      53                 :            : 
      54                 :          0 :         ioat->qcfg = *qconf;
      55                 :            : 
      56         [ #  # ]:          0 :         if (!rte_is_power_of_2(max_desc)) {
      57                 :          0 :                 max_desc = rte_align32pow2(max_desc);
      58                 :          0 :                 IOAT_PMD_DEBUG("DMA dev %u using %u descriptors", dev->data->dev_id, max_desc);
      59                 :          0 :                 ioat->qcfg.nb_desc = max_desc;
      60                 :            :         }
      61                 :            : 
      62                 :            :         /* In case we are reconfiguring a device, free any existing memory. */
      63                 :          0 :         rte_free(ioat->desc_ring);
      64                 :            : 
      65                 :          0 :         ioat->desc_ring = rte_zmalloc(NULL, sizeof(*ioat->desc_ring) * max_desc, 0);
      66         [ #  # ]:          0 :         if (ioat->desc_ring == NULL)
      67                 :            :                 return -ENOMEM;
      68                 :            : 
      69                 :          0 :         ioat->ring_addr = rte_mem_virt2iova(ioat->desc_ring);
      70                 :            : 
      71                 :          0 :         ioat->status_addr = rte_mem_virt2iova(ioat) + offsetof(struct ioat_dmadev, status);
      72                 :            : 
      73                 :            :         /* Ensure all counters are reset, if reconfiguring/restarting device. */
      74                 :          0 :         ioat->next_read = 0;
      75                 :          0 :         ioat->next_write = 0;
      76                 :          0 :         ioat->last_write = 0;
      77                 :          0 :         ioat->offset = 0;
      78                 :          0 :         ioat->failure = 0;
      79                 :            : 
      80                 :            :         /* Reset Stats. */
      81                 :          0 :         ioat->stats = (struct rte_dma_stats){0};
      82                 :            : 
      83                 :            :         /* Configure descriptor ring - each one points to next. */
      84         [ #  # ]:          0 :         for (i = 0; i < ioat->qcfg.nb_desc; i++) {
      85                 :          0 :                 ioat->desc_ring[i].next = ioat->ring_addr +
      86                 :          0 :                                 (((i + 1) % ioat->qcfg.nb_desc) * DESC_SZ);
      87                 :            :         }
      88                 :            : 
      89                 :            :         return 0;
      90                 :            : }
      91                 :            : 
      92                 :            : /* Recover IOAT device. */
      93                 :            : static inline int
      94                 :          0 : __ioat_recover(struct ioat_dmadev *ioat)
      95                 :            : {
      96                 :            :         uint32_t chanerr, retry = 0;
      97                 :          0 :         uint16_t mask = ioat->qcfg.nb_desc - 1;
      98                 :            : 
      99                 :            :         /* Clear any channel errors. Reading and writing to chanerr does this. */
     100                 :          0 :         chanerr = ioat->regs->chanerr;
     101                 :          0 :         ioat->regs->chanerr = chanerr;
     102                 :            : 
     103                 :            :         /* Reset Channel. */
     104                 :          0 :         ioat->regs->chancmd = IOAT_CHANCMD_RESET;
     105                 :            : 
     106                 :            :         /* Write new chain address to trigger state change. */
     107                 :          0 :         ioat->regs->chainaddr = ioat->desc_ring[(ioat->next_read - 1) & mask].next;
     108                 :            :         /* Ensure channel control and status addr are correct. */
     109                 :          0 :         ioat->regs->chanctrl = IOAT_CHANCTRL_ANY_ERR_ABORT_EN |
     110                 :            :                         IOAT_CHANCTRL_ERR_COMPLETION_EN;
     111                 :          0 :         ioat->regs->chancmp = ioat->status_addr;
     112                 :            : 
     113                 :            :         /* Allow HW time to move to the ARMED state. */
     114                 :            :         do {
     115                 :            :                 rte_pause();
     116                 :          0 :                 retry++;
     117   [ #  #  #  # ]:          0 :         } while (ioat->regs->chansts != IOAT_CHANSTS_ARMED && retry < 200);
     118                 :            : 
     119                 :            :         /* Exit as failure if device is still HALTED. */
     120         [ #  # ]:          0 :         if (ioat->regs->chansts != IOAT_CHANSTS_ARMED)
     121                 :            :                 return -1;
     122                 :            : 
     123                 :            :         /* Store next write as offset as recover will move HW and SW ring out of sync. */
     124                 :          0 :         ioat->offset = ioat->next_read;
     125                 :            : 
     126                 :            :         /* Prime status register with previous address. */
     127                 :          0 :         ioat->status = ioat->desc_ring[(ioat->next_read - 2) & mask].next;
     128                 :            : 
     129                 :          0 :         return 0;
     130                 :            : }
     131                 :            : 
     132                 :            : /* Start a configured device. */
     133                 :            : static int
     134                 :          0 : ioat_dev_start(struct rte_dma_dev *dev)
     135                 :            : {
     136                 :          0 :         struct ioat_dmadev *ioat = dev->fp_obj->dev_private;
     137                 :            : 
     138   [ #  #  #  # ]:          0 :         if (ioat->qcfg.nb_desc == 0 || ioat->desc_ring == NULL)
     139                 :            :                 return -EBUSY;
     140                 :            : 
     141                 :            :         /* Inform hardware of where the descriptor ring is. */
     142                 :          0 :         ioat->regs->chainaddr = ioat->ring_addr;
     143                 :            :         /* Inform hardware of where to write the status/completions. */
     144                 :          0 :         ioat->regs->chancmp = ioat->status_addr;
     145                 :            :         /* Ensure channel control is set to abort on error, so we get status writeback. */
     146                 :          0 :         ioat->regs->chanctrl = IOAT_CHANCTRL_ANY_ERR_ABORT_EN |
     147                 :            :                         IOAT_CHANCTRL_ERR_COMPLETION_EN;
     148                 :            : 
     149                 :            :         /* Prime the status register to be set to the last element. */
     150                 :          0 :         ioat->status = ioat->ring_addr + ((ioat->qcfg.nb_desc - 1) * DESC_SZ);
     151                 :            : 
     152                 :            :         /* reset all counters */
     153                 :          0 :         ioat->next_read = 0;
     154                 :          0 :         ioat->next_write = 0;
     155                 :          0 :         ioat->last_write = 0;
     156                 :          0 :         ioat->offset = 0;
     157                 :          0 :         ioat->failure = 0;
     158                 :            : 
     159                 :          0 :         IOAT_PMD_DEBUG("channel status - %s [0x%"PRIx64"]",
     160                 :            :                         chansts_readable[ioat->status & IOAT_CHANSTS_STATUS],
     161                 :            :                         ioat->status);
     162                 :            : 
     163         [ #  # ]:          0 :         if ((ioat->regs->chansts & IOAT_CHANSTS_STATUS) == IOAT_CHANSTS_HALTED) {
     164                 :          0 :                 IOAT_PMD_WARN("Device HALTED on start, attempting to recover");
     165         [ #  # ]:          0 :                 if (__ioat_recover(ioat) != 0) {
     166                 :          0 :                         IOAT_PMD_ERR("Device couldn't be recovered");
     167                 :          0 :                         return -1;
     168                 :            :                 }
     169                 :            :         }
     170                 :            : 
     171                 :            :         return 0;
     172                 :            : }
     173                 :            : 
     174                 :            : /* Stop a configured device. */
     175                 :            : static int
     176                 :          0 : ioat_dev_stop(struct rte_dma_dev *dev)
     177                 :            : {
     178                 :          0 :         struct ioat_dmadev *ioat = dev->fp_obj->dev_private;
     179                 :            :         unsigned int chansts;
     180                 :            :         uint32_t retry = 0;
     181                 :            : 
     182                 :          0 :         chansts = (unsigned int)(ioat->regs->chansts & IOAT_CHANSTS_STATUS);
     183         [ #  # ]:          0 :         if (chansts == IOAT_CHANSTS_ACTIVE || chansts == IOAT_CHANSTS_IDLE)
     184                 :          0 :                 ioat->regs->chancmd = IOAT_CHANCMD_SUSPEND;
     185                 :            :         else
     186                 :          0 :                 ioat->regs->chancmd = IOAT_CHANCMD_RESET;
     187                 :            : 
     188                 :            :         do {
     189                 :            :                 rte_pause();
     190                 :          0 :                 retry++;
     191                 :          0 :                 chansts = (unsigned int)(ioat->regs->chansts & IOAT_CHANSTS_STATUS);
     192                 :          0 :         } while (chansts != IOAT_CHANSTS_SUSPENDED &&
     193   [ #  #  #  # ]:          0 :                         chansts != IOAT_CHANSTS_HALTED && retry < 200);
     194                 :            : 
     195         [ #  # ]:          0 :         if (chansts == IOAT_CHANSTS_SUSPENDED || chansts == IOAT_CHANSTS_HALTED)
     196                 :            :                 return 0;
     197                 :            : 
     198                 :          0 :         IOAT_PMD_WARN("Channel could not be suspended on stop. (chansts = %u [%s])",
     199                 :            :                         chansts, chansts_readable[chansts]);
     200                 :          0 :         return -1;
     201                 :            : }
     202                 :            : 
     203                 :            : /* Get device information of a device. */
     204                 :            : static int
     205                 :          0 : ioat_dev_info_get(const struct rte_dma_dev *dev, struct rte_dma_info *info, uint32_t size)
     206                 :            : {
     207                 :          0 :         struct ioat_dmadev *ioat = dev->fp_obj->dev_private;
     208         [ #  # ]:          0 :         if (size < sizeof(*info))
     209                 :            :                 return -EINVAL;
     210                 :          0 :         info->dev_capa = RTE_DMA_CAPA_MEM_TO_MEM |
     211                 :            :                         RTE_DMA_CAPA_OPS_COPY |
     212                 :            :                         RTE_DMA_CAPA_OPS_FILL;
     213         [ #  # ]:          0 :         if (ioat->version >= IOAT_VER_3_4)
     214                 :          0 :                 info->dev_capa |= RTE_DMA_CAPA_HANDLES_ERRORS;
     215                 :          0 :         info->max_vchans = 1;
     216                 :          0 :         info->min_desc = 32;
     217                 :          0 :         info->max_desc = 4096;
     218                 :          0 :         return 0;
     219                 :            : }
     220                 :            : 
     221                 :            : /* Close a configured device. */
     222                 :            : static int
     223                 :          0 : ioat_dev_close(struct rte_dma_dev *dev)
     224                 :            : {
     225                 :            :         struct ioat_dmadev *ioat;
     226                 :            : 
     227         [ #  # ]:          0 :         if (!dev) {
     228                 :          0 :                 IOAT_PMD_ERR("Invalid device");
     229                 :          0 :                 return -EINVAL;
     230                 :            :         }
     231                 :            : 
     232                 :          0 :         ioat = dev->fp_obj->dev_private;
     233         [ #  # ]:          0 :         if (!ioat) {
     234                 :          0 :                 IOAT_PMD_ERR("Error getting dev_private");
     235                 :          0 :                 return -EINVAL;
     236                 :            :         }
     237                 :            : 
     238                 :          0 :         rte_free(ioat->desc_ring);
     239                 :            : 
     240                 :          0 :         return 0;
     241                 :            : }
     242                 :            : 
     243                 :            : /* Trigger hardware to begin performing enqueued operations. */
     244                 :            : static inline void
     245                 :            : __submit(struct ioat_dmadev *ioat)
     246                 :            : {
     247                 :          0 :         *ioat->doorbell = ioat->next_write - ioat->offset;
     248                 :            : 
     249                 :          0 :         ioat->stats.submitted += (uint16_t)(ioat->next_write - ioat->last_write);
     250                 :            : 
     251                 :          0 :         ioat->last_write = ioat->next_write;
     252                 :          0 : }
     253                 :            : 
     254                 :            : /* External submit function wrapper. */
     255                 :            : static int
     256                 :          0 : ioat_submit(void *dev_private, uint16_t qid __rte_unused)
     257                 :            : {
     258                 :            :         struct ioat_dmadev *ioat = dev_private;
     259                 :            : 
     260                 :            :         __submit(ioat);
     261                 :            : 
     262                 :          0 :         return 0;
     263                 :            : }
     264                 :            : 
     265                 :            : /* Write descriptor for enqueue. */
     266                 :            : static inline int
     267                 :          0 : __write_desc(void *dev_private, uint32_t op, uint64_t src, phys_addr_t dst,
     268                 :            :                 unsigned int length, uint64_t flags)
     269                 :            : {
     270                 :            :         struct ioat_dmadev *ioat = dev_private;
     271                 :            :         uint16_t ret;
     272                 :          0 :         const unsigned short mask = ioat->qcfg.nb_desc - 1;
     273                 :          0 :         const unsigned short read = ioat->next_read;
     274                 :          0 :         unsigned short write = ioat->next_write;
     275                 :          0 :         const unsigned short space = mask + read - write;
     276                 :            :         struct ioat_dma_hw_desc *desc;
     277                 :            : 
     278         [ #  # ]:          0 :         if (space == 0)
     279                 :            :                 return -ENOSPC;
     280                 :            : 
     281                 :          0 :         ioat->next_write = write + 1;
     282                 :          0 :         write &= mask;
     283                 :            : 
     284                 :          0 :         desc = &ioat->desc_ring[write];
     285                 :          0 :         desc->size = length;
     286                 :          0 :         desc->u.control_raw = (uint32_t)((op << IOAT_CMD_OP_SHIFT) |
     287                 :            :                         (1 << IOAT_COMP_UPDATE_SHIFT));
     288                 :            : 
     289                 :            :         /* In IOAT the fence ensures that all operations including the current one
     290                 :            :          * are completed before moving on, DMAdev assumes that the fence ensures
     291                 :            :          * all operations before the current one are completed before starting
     292                 :            :          * the current one, so in IOAT we set the fence for the previous descriptor.
     293                 :            :          */
     294         [ #  # ]:          0 :         if (flags & RTE_DMA_OP_FLAG_FENCE)
     295                 :          0 :                 ioat->desc_ring[(write - 1) & mask].u.control.fence = 1;
     296                 :            : 
     297                 :          0 :         desc->src_addr = src;
     298                 :          0 :         desc->dest_addr = dst;
     299                 :            : 
     300                 :          0 :         rte_prefetch0(&ioat->desc_ring[ioat->next_write & mask]);
     301                 :            : 
     302                 :            :         ret = (uint16_t)(ioat->next_write - 1);
     303                 :            : 
     304         [ #  # ]:          0 :         if (flags & RTE_DMA_OP_FLAG_SUBMIT)
     305                 :            :                 __submit(ioat);
     306                 :            : 
     307                 :          0 :         return ret;
     308                 :            : }
     309                 :            : 
     310                 :            : /* Enqueue a fill operation onto the ioat device. */
     311                 :            : static int
     312                 :          0 : ioat_enqueue_fill(void *dev_private, uint16_t qid __rte_unused, uint64_t pattern,
     313                 :            :                 rte_iova_t dst, unsigned int length, uint64_t flags)
     314                 :            : {
     315                 :          0 :         return __write_desc(dev_private, ioat_op_fill, pattern, dst, length, flags);
     316                 :            : }
     317                 :            : 
     318                 :            : /* Enqueue a copy operation onto the ioat device. */
     319                 :            : static int
     320                 :          0 : ioat_enqueue_copy(void *dev_private, uint16_t qid __rte_unused, rte_iova_t src,
     321                 :            :                 rte_iova_t dst, unsigned int length, uint64_t flags)
     322                 :            : {
     323                 :          0 :         return __write_desc(dev_private, ioat_op_copy, src, dst, length, flags);
     324                 :            : }
     325                 :            : 
     326                 :            : /* Dump DMA device info. */
     327                 :            : static int
     328                 :          0 : __dev_dump(void *dev_private, FILE *f)
     329                 :            : {
     330                 :            :         struct ioat_dmadev *ioat = dev_private;
     331                 :          0 :         uint64_t chansts_masked = ioat->regs->chansts & IOAT_CHANSTS_STATUS;
     332                 :          0 :         uint32_t chanerr = ioat->regs->chanerr;
     333                 :          0 :         uint64_t mask = (ioat->qcfg.nb_desc - 1);
     334                 :          0 :         char ver = ioat->version;
     335                 :            :         fprintf(f, "========= IOAT =========\n");
     336                 :          0 :         fprintf(f, "  IOAT version: %d.%d\n", ver >> 4, ver & 0xF);
     337                 :          0 :         fprintf(f, "  Channel status: %s [0x%"PRIx64"]\n",
     338                 :            :                         chansts_readable[chansts_masked], chansts_masked);
     339                 :          0 :         fprintf(f, "  ChainADDR: 0x%"PRIu64"\n", ioat->regs->chainaddr);
     340         [ #  # ]:          0 :         if (chanerr == 0) {
     341                 :            :                 fprintf(f, "  No Channel Errors\n");
     342                 :            :         } else {
     343                 :            :                 fprintf(f, "  ChanERR: 0x%"PRIu32"\n", chanerr);
     344         [ #  # ]:          0 :                 if (chanerr & IOAT_CHANERR_INVALID_SRC_ADDR_MASK)
     345                 :            :                         fprintf(f, "    Invalid Source Address\n");
     346         [ #  # ]:          0 :                 if (chanerr & IOAT_CHANERR_INVALID_DST_ADDR_MASK)
     347                 :            :                         fprintf(f, "    Invalid Destination Address\n");
     348         [ #  # ]:          0 :                 if (chanerr & IOAT_CHANERR_INVALID_LENGTH_MASK)
     349                 :            :                         fprintf(f, "    Invalid Descriptor Length\n");
     350         [ #  # ]:          0 :                 if (chanerr & IOAT_CHANERR_DESCRIPTOR_READ_ERROR_MASK)
     351                 :            :                         fprintf(f, "    Descriptor Read Error\n");
     352         [ #  # ]:          0 :                 if ((chanerr & ~(IOAT_CHANERR_INVALID_SRC_ADDR_MASK |
     353                 :            :                                 IOAT_CHANERR_INVALID_DST_ADDR_MASK |
     354                 :            :                                 IOAT_CHANERR_INVALID_LENGTH_MASK |
     355                 :            :                                 IOAT_CHANERR_DESCRIPTOR_READ_ERROR_MASK)) != 0)
     356                 :            :                         fprintf(f, "    Unknown Error(s)\n");
     357                 :            :         }
     358                 :            :         fprintf(f, "== Private Data ==\n");
     359                 :          0 :         fprintf(f, "  Config: { ring_size: %u }\n", ioat->qcfg.nb_desc);
     360                 :          0 :         fprintf(f, "  Status: 0x%"PRIx64"\n", ioat->status);
     361                 :          0 :         fprintf(f, "  Status IOVA: 0x%"PRIx64"\n", ioat->status_addr);
     362                 :          0 :         fprintf(f, "  Status ADDR: %p\n", &ioat->status);
     363                 :          0 :         fprintf(f, "  Ring IOVA: 0x%"PRIx64"\n", ioat->ring_addr);
     364                 :          0 :         fprintf(f, "  Ring ADDR: 0x%"PRIx64"\n", ioat->desc_ring[0].next-64);
     365                 :          0 :         fprintf(f, "  Next write: %"PRIu16"\n", ioat->next_write);
     366                 :          0 :         fprintf(f, "  Next read: %"PRIu16"\n", ioat->next_read);
     367                 :          0 :         struct ioat_dma_hw_desc *desc_ring = &ioat->desc_ring[(ioat->next_write - 1) & mask];
     368                 :            :         fprintf(f, "  Last Descriptor Written {\n");
     369                 :          0 :         fprintf(f, "    Size: %"PRIu32"\n", desc_ring->size);
     370                 :          0 :         fprintf(f, "    Control: 0x%"PRIx32"\n", desc_ring->u.control_raw);
     371                 :          0 :         fprintf(f, "    Src: 0x%"PRIx64"\n", desc_ring->src_addr);
     372                 :          0 :         fprintf(f, "    Dest: 0x%"PRIx64"\n", desc_ring->dest_addr);
     373                 :          0 :         fprintf(f, "    Next: 0x%"PRIx64"\n", desc_ring->next);
     374                 :            :         fprintf(f, "  }\n");
     375                 :            :         fprintf(f, "  Next Descriptor {\n");
     376                 :          0 :         fprintf(f, "    Size: %"PRIu32"\n", ioat->desc_ring[ioat->next_read & mask].size);
     377                 :          0 :         fprintf(f, "    Src: 0x%"PRIx64"\n", ioat->desc_ring[ioat->next_read & mask].src_addr);
     378                 :          0 :         fprintf(f, "    Dest: 0x%"PRIx64"\n", ioat->desc_ring[ioat->next_read & mask].dest_addr);
     379                 :          0 :         fprintf(f, "    Next: 0x%"PRIx64"\n", ioat->desc_ring[ioat->next_read & mask].next);
     380                 :            :         fprintf(f, "  }\n");
     381                 :          0 :         fprintf(f, "  Key Stats { submitted: %"PRIu64", comp: %"PRIu64", failed: %"PRIu64" }\n",
     382                 :            :                         ioat->stats.submitted,
     383                 :            :                         ioat->stats.completed,
     384                 :            :                         ioat->stats.errors);
     385                 :            : 
     386                 :          0 :         return 0;
     387                 :            : }
     388                 :            : 
     389                 :            : /* Public wrapper for dump. */
     390                 :            : static int
     391                 :          0 : ioat_dev_dump(const struct rte_dma_dev *dev, FILE *f)
     392                 :            : {
     393                 :          0 :         return __dev_dump(dev->fp_obj->dev_private, f);
     394                 :            : }
     395                 :            : 
     396                 :            : /* Returns the index of the last completed operation. */
     397                 :            : static inline uint16_t
     398                 :            : __get_last_completed(const struct ioat_dmadev *ioat, int *state)
     399                 :            : {
     400                 :            :         /* Status register contains the address of the completed operation */
     401                 :          0 :         uint64_t status = ioat->status;
     402                 :            : 
     403                 :            :         /* lower 3 bits indicate "transfer status" : active, idle, halted.
     404                 :            :          * We can ignore bit 0.
     405                 :            :          */
     406                 :          0 :         *state = status & IOAT_CHANSTS_STATUS;
     407                 :            : 
     408                 :            :         /* If we are just after recovering from an error the address returned by
     409                 :            :          * status will be 0, in this case we return the offset - 1 as the last
     410                 :            :          * completed. If not return the status value minus the chainaddr which
     411                 :            :          * gives us an offset into the ring. Right shifting by 6 (divide by 64)
     412                 :            :          * gives the index of the completion from the HW point of view and adding
     413                 :            :          * the offset translates the ring index from HW to SW point of view.
     414                 :            :          */
     415         [ #  # ]:          0 :         if ((status & ~IOAT_CHANSTS_STATUS) == 0)
     416                 :          0 :                 return ioat->offset - 1;
     417                 :            : 
     418                 :          0 :         return (status - ioat->ring_addr) >> 6;
     419                 :            : }
     420                 :            : 
     421                 :            : /* Translates IOAT ChanERRs to DMA error codes. */
     422                 :            : static inline enum rte_dma_status_code
     423                 :            : __translate_status_ioat_to_dma(uint32_t chanerr)
     424                 :            : {
     425         [ #  # ]:          0 :         if (chanerr & IOAT_CHANERR_INVALID_SRC_ADDR_MASK)
     426                 :            :                 return RTE_DMA_STATUS_INVALID_SRC_ADDR;
     427   [ #  #  #  # ]:          0 :         else if (chanerr & IOAT_CHANERR_INVALID_DST_ADDR_MASK)
     428                 :            :                 return RTE_DMA_STATUS_INVALID_DST_ADDR;
     429   [ #  #  #  # ]:          0 :         else if (chanerr & IOAT_CHANERR_INVALID_LENGTH_MASK)
     430                 :            :                 return RTE_DMA_STATUS_INVALID_LENGTH;
     431   [ #  #  #  # ]:          0 :         else if (chanerr & IOAT_CHANERR_DESCRIPTOR_READ_ERROR_MASK)
     432                 :            :                 return RTE_DMA_STATUS_DESCRIPTOR_READ_ERROR;
     433                 :            :         else
     434                 :          0 :                 return RTE_DMA_STATUS_ERROR_UNKNOWN;
     435                 :            : }
     436                 :            : 
     437                 :            : /* Returns details of operations that have been completed. */
     438                 :            : static uint16_t
     439                 :          0 : ioat_completed(void *dev_private, uint16_t qid __rte_unused, const uint16_t max_ops,
     440                 :            :                 uint16_t *last_idx, bool *has_error)
     441                 :            : {
     442                 :            :         struct ioat_dmadev *ioat = dev_private;
     443                 :            : 
     444                 :          0 :         const unsigned short mask = (ioat->qcfg.nb_desc - 1);
     445                 :          0 :         const unsigned short read = ioat->next_read;
     446                 :            :         unsigned short last_completed, count;
     447                 :            :         int state, fails = 0;
     448                 :            : 
     449                 :            :         /* Do not do any work if there is an uncleared error. */
     450         [ #  # ]:          0 :         if (ioat->failure != 0) {
     451                 :          0 :                 *has_error = true;
     452                 :          0 :                 *last_idx = ioat->next_read - 2;
     453                 :          0 :                 return 0;
     454                 :            :         }
     455                 :            : 
     456                 :            :         last_completed = __get_last_completed(ioat, &state);
     457                 :          0 :         count = (last_completed + 1 - read) & mask;
     458                 :            : 
     459                 :            :         /* Cap count at max_ops or set as last run in batch. */
     460                 :            :         if (count > max_ops)
     461                 :            :                 count = max_ops;
     462                 :            : 
     463   [ #  #  #  # ]:          0 :         if (count == max_ops || state != IOAT_CHANSTS_HALTED) {
     464                 :          0 :                 ioat->next_read = read + count;
     465                 :          0 :                 *last_idx = ioat->next_read - 1;
     466                 :            :         } else {
     467                 :          0 :                 *has_error = true;
     468                 :          0 :                 rte_errno = EIO;
     469                 :          0 :                 ioat->failure = ioat->regs->chanerr;
     470                 :          0 :                 ioat->next_read = read + count + 1;
     471         [ #  # ]:          0 :                 if (__ioat_recover(ioat) != 0) {
     472                 :          0 :                         IOAT_PMD_ERR("Device HALTED and could not be recovered");
     473                 :          0 :                         __dev_dump(dev_private, stdout);
     474                 :          0 :                         return 0;
     475                 :            :                 }
     476                 :            :                 __submit(ioat);
     477                 :            :                 fails++;
     478                 :          0 :                 *last_idx = ioat->next_read - 2;
     479                 :            :         }
     480                 :            : 
     481                 :          0 :         ioat->stats.completed += count;
     482                 :          0 :         ioat->stats.errors += fails;
     483                 :            : 
     484                 :          0 :         return count;
     485                 :            : }
     486                 :            : 
     487                 :            : /* Returns detailed status information about operations that have been completed. */
     488                 :            : static uint16_t
     489                 :          0 : ioat_completed_status(void *dev_private, uint16_t qid __rte_unused,
     490                 :            :                 uint16_t max_ops, uint16_t *last_idx, enum rte_dma_status_code *status)
     491                 :            : {
     492                 :            :         struct ioat_dmadev *ioat = dev_private;
     493                 :            : 
     494                 :          0 :         const unsigned short mask = (ioat->qcfg.nb_desc - 1);
     495         [ #  # ]:          0 :         const unsigned short read = ioat->next_read;
     496                 :            :         unsigned short count, last_completed;
     497                 :            :         uint64_t fails = 0;
     498                 :            :         int state, i;
     499                 :            : 
     500                 :            :         last_completed = __get_last_completed(ioat, &state);
     501                 :          0 :         count = (last_completed + 1 - read) & mask;
     502                 :            : 
     503         [ #  # ]:          0 :         for (i = 0; i < RTE_MIN(count + 1, max_ops); i++)
     504                 :          0 :                 status[i] = RTE_DMA_STATUS_SUCCESSFUL;
     505                 :            : 
     506                 :            :         /* Cap count at max_ops or set as last run in batch. */
     507                 :            :         if (count > max_ops)
     508                 :            :                 count = max_ops;
     509                 :            : 
     510   [ #  #  #  # ]:          0 :         if (count == max_ops || state != IOAT_CHANSTS_HALTED)
     511                 :          0 :                 ioat->next_read = read + count;
     512                 :            :         else {
     513                 :          0 :                 rte_errno = EIO;
     514         [ #  # ]:          0 :                 status[count] = __translate_status_ioat_to_dma(ioat->regs->chanerr);
     515                 :          0 :                 count++;
     516                 :          0 :                 ioat->next_read = read + count;
     517         [ #  # ]:          0 :                 if (__ioat_recover(ioat) != 0) {
     518                 :          0 :                         IOAT_PMD_ERR("Device HALTED and could not be recovered");
     519                 :          0 :                         __dev_dump(dev_private, stdout);
     520                 :          0 :                         return 0;
     521                 :            :                 }
     522                 :            :                 __submit(ioat);
     523                 :            :                 fails++;
     524                 :            :         }
     525                 :            : 
     526         [ #  # ]:          0 :         if (ioat->failure > 0) {
     527                 :          0 :                 status[0] = __translate_status_ioat_to_dma(ioat->failure);
     528                 :          0 :                 count = RTE_MIN(count + 1, max_ops);
     529                 :          0 :                 ioat->failure = 0;
     530                 :            :         }
     531                 :            : 
     532                 :          0 :         *last_idx = ioat->next_read - 1;
     533                 :            : 
     534                 :          0 :         ioat->stats.completed += count;
     535                 :          0 :         ioat->stats.errors += fails;
     536                 :            : 
     537                 :          0 :         return count;
     538                 :            : }
     539                 :            : 
     540                 :            : /* Get the remaining capacity of the ring. */
     541                 :            : static uint16_t
     542                 :          0 : ioat_burst_capacity(const void *dev_private, uint16_t vchan __rte_unused)
     543                 :            : {
     544                 :            :         const struct ioat_dmadev *ioat = dev_private;
     545                 :          0 :         unsigned short size = ioat->qcfg.nb_desc - 1;
     546                 :          0 :         unsigned short read = ioat->next_read;
     547                 :          0 :         unsigned short write = ioat->next_write;
     548                 :          0 :         unsigned short space = size - (write - read);
     549                 :            : 
     550                 :          0 :         return space;
     551                 :            : }
     552                 :            : 
     553                 :            : /* Retrieve the generic stats of a DMA device. */
     554                 :            : static int
     555                 :          0 : ioat_stats_get(const struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
     556                 :            :                 struct rte_dma_stats *rte_stats, uint32_t size)
     557                 :            : {
     558                 :          0 :         struct rte_dma_stats *stats = (&((struct ioat_dmadev *)dev->fp_obj->dev_private)->stats);
     559                 :            : 
     560         [ #  # ]:          0 :         if (size < sizeof(rte_stats))
     561                 :            :                 return -EINVAL;
     562         [ #  # ]:          0 :         if (rte_stats == NULL)
     563                 :            :                 return -EINVAL;
     564                 :            : 
     565                 :          0 :         *rte_stats = *stats;
     566                 :          0 :         return 0;
     567                 :            : }
     568                 :            : 
     569                 :            : /* Reset the generic stat counters for the DMA device. */
     570                 :            : static int
     571                 :          0 : ioat_stats_reset(struct rte_dma_dev *dev, uint16_t vchan __rte_unused)
     572                 :            : {
     573                 :          0 :         struct ioat_dmadev *ioat = dev->fp_obj->dev_private;
     574                 :            : 
     575                 :          0 :         ioat->stats = (struct rte_dma_stats){0};
     576                 :          0 :         return 0;
     577                 :            : }
     578                 :            : 
     579                 :            : /* Check if the IOAT device is idle. */
     580                 :            : static int
     581                 :          0 : ioat_vchan_status(const struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
     582                 :            :                 enum rte_dma_vchan_status *status)
     583                 :            : {
     584                 :            :         int state = 0;
     585                 :          0 :         const struct ioat_dmadev *ioat = dev->fp_obj->dev_private;
     586         [ #  # ]:          0 :         const uint16_t mask = ioat->qcfg.nb_desc - 1;
     587                 :            :         const uint16_t last = __get_last_completed(ioat, &state);
     588                 :            : 
     589         [ #  # ]:          0 :         if (state == IOAT_CHANSTS_HALTED || state == IOAT_CHANSTS_SUSPENDED)
     590                 :          0 :                 *status = RTE_DMA_VCHAN_HALTED_ERROR;
     591         [ #  # ]:          0 :         else if (last == ((ioat->next_write - 1) & mask))
     592                 :          0 :                 *status = RTE_DMA_VCHAN_IDLE;
     593                 :            :         else
     594                 :          0 :                 *status = RTE_DMA_VCHAN_ACTIVE;
     595                 :            : 
     596                 :          0 :         return 0;
     597                 :            : }
     598                 :            : 
     599                 :            : /* Create a DMA device. */
     600                 :            : static int
     601                 :          0 : ioat_dmadev_create(const char *name, struct rte_pci_device *dev)
     602                 :            : {
     603                 :            :         static const struct rte_dma_dev_ops ioat_dmadev_ops = {
     604                 :            :                 .dev_close = ioat_dev_close,
     605                 :            :                 .dev_configure = ioat_dev_configure,
     606                 :            :                 .dev_dump = ioat_dev_dump,
     607                 :            :                 .dev_info_get = ioat_dev_info_get,
     608                 :            :                 .dev_start = ioat_dev_start,
     609                 :            :                 .dev_stop = ioat_dev_stop,
     610                 :            :                 .stats_get = ioat_stats_get,
     611                 :            :                 .stats_reset = ioat_stats_reset,
     612                 :            :                 .vchan_status = ioat_vchan_status,
     613                 :            :                 .vchan_setup = ioat_vchan_setup,
     614                 :            :         };
     615                 :            : 
     616                 :            :         struct rte_dma_dev *dmadev = NULL;
     617                 :            :         struct ioat_dmadev *ioat = NULL;
     618                 :            :         int retry = 0;
     619                 :            : 
     620         [ #  # ]:          0 :         if (!name) {
     621                 :          0 :                 IOAT_PMD_ERR("Invalid name of the device!");
     622                 :          0 :                 return -EINVAL;
     623                 :            :         }
     624                 :            : 
     625                 :            :         /* Allocate device structure. */
     626                 :          0 :         dmadev = rte_dma_pmd_allocate(name, dev->device.numa_node, sizeof(struct ioat_dmadev));
     627         [ #  # ]:          0 :         if (dmadev == NULL) {
     628                 :          0 :                 IOAT_PMD_ERR("Unable to allocate dma device");
     629                 :          0 :                 return -ENOMEM;
     630                 :            :         }
     631                 :            : 
     632                 :          0 :         dmadev->device = &dev->device;
     633                 :            : 
     634                 :          0 :         dmadev->fp_obj->dev_private = dmadev->data->dev_private;
     635                 :            : 
     636                 :          0 :         dmadev->dev_ops = &ioat_dmadev_ops;
     637                 :            : 
     638                 :          0 :         dmadev->fp_obj->burst_capacity = ioat_burst_capacity;
     639                 :          0 :         dmadev->fp_obj->completed = ioat_completed;
     640                 :          0 :         dmadev->fp_obj->completed_status = ioat_completed_status;
     641                 :          0 :         dmadev->fp_obj->copy = ioat_enqueue_copy;
     642                 :          0 :         dmadev->fp_obj->fill = ioat_enqueue_fill;
     643                 :          0 :         dmadev->fp_obj->submit = ioat_submit;
     644                 :            : 
     645                 :            :         ioat = dmadev->data->dev_private;
     646                 :          0 :         ioat->dmadev = dmadev;
     647                 :          0 :         ioat->regs = dev->mem_resource[0].addr;
     648                 :          0 :         ioat->doorbell = &ioat->regs->dmacount;
     649                 :          0 :         ioat->qcfg.nb_desc = 0;
     650                 :          0 :         ioat->desc_ring = NULL;
     651                 :          0 :         ioat->version = ioat->regs->cbver;
     652                 :            : 
     653                 :            :         /* Do device initialization - reset and set error behaviour. */
     654         [ #  # ]:          0 :         if (ioat->regs->chancnt != 1)
     655                 :          0 :                 IOAT_PMD_WARN("%s: Channel count == %d", __func__,
     656                 :            :                                 ioat->regs->chancnt);
     657                 :            : 
     658                 :            :         /* Locked by someone else. */
     659         [ #  # ]:          0 :         if (ioat->regs->chanctrl & IOAT_CHANCTRL_CHANNEL_IN_USE) {
     660                 :          0 :                 IOAT_PMD_WARN("%s: Channel appears locked", __func__);
     661                 :          0 :                 ioat->regs->chanctrl = 0;
     662                 :            :         }
     663                 :            : 
     664                 :            :         /* clear any previous errors */
     665         [ #  # ]:          0 :         if (ioat->regs->chanerr != 0) {
     666                 :          0 :                 uint32_t val = ioat->regs->chanerr;
     667                 :          0 :                 ioat->regs->chanerr = val;
     668                 :            :         }
     669                 :            : 
     670                 :          0 :         ioat->regs->chancmd = IOAT_CHANCMD_SUSPEND;
     671                 :            :         rte_delay_ms(1);
     672                 :          0 :         ioat->regs->chancmd = IOAT_CHANCMD_RESET;
     673                 :            :         rte_delay_ms(1);
     674         [ #  # ]:          0 :         while (ioat->regs->chancmd & IOAT_CHANCMD_RESET) {
     675                 :          0 :                 ioat->regs->chainaddr = 0;
     676                 :            :                 rte_delay_ms(1);
     677         [ #  # ]:          0 :                 if (++retry >= 200) {
     678                 :          0 :                         IOAT_PMD_ERR("%s: cannot reset device. CHANCMD=%#"PRIx8
     679                 :            :                                         ", CHANSTS=%#"PRIx64", CHANERR=%#"PRIx32,
     680                 :            :                                         __func__,
     681                 :            :                                         ioat->regs->chancmd,
     682                 :            :                                         ioat->regs->chansts,
     683                 :            :                                         ioat->regs->chanerr);
     684                 :          0 :                         rte_dma_pmd_release(name);
     685                 :          0 :                         return -EIO;
     686                 :            :                 }
     687                 :            :         }
     688                 :            : 
     689                 :          0 :         dmadev->fp_obj->dev_private = ioat;
     690                 :            : 
     691                 :          0 :         dmadev->state = RTE_DMA_DEV_READY;
     692                 :            : 
     693                 :          0 :         return 0;
     694                 :            : 
     695                 :            : }
     696                 :            : 
     697                 :            : /* Destroy a DMA device. */
     698                 :            : static int
     699                 :          0 : ioat_dmadev_destroy(const char *name)
     700                 :            : {
     701                 :            :         int ret;
     702                 :            : 
     703         [ #  # ]:          0 :         if (!name) {
     704                 :          0 :                 IOAT_PMD_ERR("Invalid device name");
     705                 :          0 :                 return -EINVAL;
     706                 :            :         }
     707                 :            : 
     708                 :          0 :         ret = rte_dma_pmd_release(name);
     709         [ #  # ]:          0 :         if (ret)
     710                 :          0 :                 IOAT_PMD_DEBUG("Device cleanup failed");
     711                 :            : 
     712                 :            :         return 0;
     713                 :            : }
     714                 :            : 
     715                 :            : /* Probe DMA device. */
     716                 :            : static int
     717                 :          0 : ioat_dmadev_probe(struct rte_pci_driver *drv, struct rte_pci_device *dev)
     718                 :            : {
     719                 :            :         char name[32];
     720                 :            : 
     721                 :          0 :         rte_pci_device_name(&dev->addr, name, sizeof(name));
     722                 :          0 :         IOAT_PMD_INFO("Init %s on NUMA node %d", name, dev->device.numa_node);
     723                 :            : 
     724                 :          0 :         dev->device.driver = &drv->driver;
     725                 :          0 :         return ioat_dmadev_create(name, dev);
     726                 :            : }
     727                 :            : 
     728                 :            : /* Remove DMA device. */
     729                 :            : static int
     730                 :          0 : ioat_dmadev_remove(struct rte_pci_device *dev)
     731                 :            : {
     732                 :            :         char name[32];
     733                 :            : 
     734                 :          0 :         rte_pci_device_name(&dev->addr, name, sizeof(name));
     735                 :            : 
     736                 :          0 :         IOAT_PMD_INFO("Closing %s on NUMA node %d",
     737                 :            :                         name, dev->device.numa_node);
     738                 :            : 
     739                 :          0 :         return ioat_dmadev_destroy(name);
     740                 :            : }
     741                 :            : 
     742                 :            : static const struct rte_pci_id pci_id_ioat_map[] = {
     743                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_SKX) },
     744                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDX0) },
     745                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDX1) },
     746                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDX2) },
     747                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDX3) },
     748                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDX4) },
     749                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDX5) },
     750                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDX6) },
     751                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDX7) },
     752                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDXE) },
     753                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_BDXF) },
     754                 :            :         { RTE_PCI_DEVICE(IOAT_VENDOR_ID, IOAT_DEVICE_ID_ICX) },
     755                 :            :         { .vendor_id = 0, /* sentinel */ },
     756                 :            : };
     757                 :            : 
     758                 :            : static struct rte_pci_driver ioat_pmd_drv = {
     759                 :            :         .id_table = pci_id_ioat_map,
     760                 :            :         .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
     761                 :            :         .probe = ioat_dmadev_probe,
     762                 :            :         .remove = ioat_dmadev_remove,
     763                 :            : };
     764                 :            : 
     765                 :        251 : RTE_PMD_REGISTER_PCI(IOAT_PMD_NAME, ioat_pmd_drv);
     766                 :            : RTE_PMD_REGISTER_PCI_TABLE(IOAT_PMD_NAME, pci_id_ioat_map);
     767                 :            : RTE_PMD_REGISTER_KMOD_DEP(IOAT_PMD_NAME, "* igb_uio | uio_pci_generic | vfio-pci");

Generated by: LCOV version 1.14