LCOV - code coverage report
Current view: top level - spdk/lib/ioat - ioat.c (source / functions) Hit Total Coverage
Test: Combined Lines: 272 347 78.4 %
Date: 2024-07-15 19:44:11 Functions: 32 33 97.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 77 148 52.0 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2015 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "ioat_internal.h"
       9                 :            : 
      10                 :            : #include "spdk/env.h"
      11                 :            : #include "spdk/util.h"
      12                 :            : #include "spdk/memory.h"
      13                 :            : 
      14                 :            : #include "spdk/log.h"
      15                 :            : 
      16                 :            : struct ioat_driver {
      17                 :            :         pthread_mutex_t                 lock;
      18                 :            :         TAILQ_HEAD(, spdk_ioat_chan)    attached_chans;
      19                 :            : };
      20                 :            : 
      21                 :            : static struct ioat_driver g_ioat_driver = {
      22                 :            :         .lock = PTHREAD_MUTEX_INITIALIZER,
      23                 :            :         .attached_chans = TAILQ_HEAD_INITIALIZER(g_ioat_driver.attached_chans),
      24                 :            : };
      25                 :            : 
      26                 :            : static uint64_t
      27                 :       1216 : ioat_get_chansts(struct spdk_ioat_chan *ioat)
      28                 :            : {
      29                 :       1216 :         return spdk_mmio_read_8(&ioat->regs->chansts);
      30                 :            : }
      31                 :            : 
      32                 :            : static void
      33                 :        416 : ioat_write_chancmp(struct spdk_ioat_chan *ioat, uint64_t addr)
      34                 :            : {
      35                 :        416 :         spdk_mmio_write_8(&ioat->regs->chancmp, addr);
      36                 :        416 : }
      37                 :            : 
      38                 :            : static void
      39                 :        416 : ioat_write_chainaddr(struct spdk_ioat_chan *ioat, uint64_t addr)
      40                 :            : {
      41                 :        416 :         spdk_mmio_write_8(&ioat->regs->chainaddr, addr);
      42                 :        416 : }
      43                 :            : 
      44                 :            : static inline void
      45                 :        384 : ioat_suspend(struct spdk_ioat_chan *ioat)
      46                 :            : {
      47                 :        384 :         ioat->regs->chancmd = SPDK_IOAT_CHANCMD_SUSPEND;
      48                 :        384 : }
      49                 :            : 
      50                 :            : static inline void
      51                 :        416 : ioat_reset(struct spdk_ioat_chan *ioat)
      52                 :            : {
      53                 :        416 :         ioat->regs->chancmd = SPDK_IOAT_CHANCMD_RESET;
      54                 :        416 : }
      55                 :            : 
      56                 :            : static inline uint32_t
      57                 :        416 : ioat_reset_pending(struct spdk_ioat_chan *ioat)
      58                 :            : {
      59                 :            :         uint8_t cmd;
      60                 :            : 
      61                 :        416 :         cmd = ioat->regs->chancmd;
      62                 :        416 :         return (cmd & SPDK_IOAT_CHANCMD_RESET) == SPDK_IOAT_CHANCMD_RESET;
      63                 :            : }
      64                 :            : 
      65                 :            : static int
      66                 :        416 : ioat_map_pci_bar(struct spdk_ioat_chan *ioat)
      67                 :            : {
      68                 :            :         int regs_bar, rc;
      69                 :          0 :         void *addr;
      70                 :          0 :         uint64_t phys_addr, size;
      71                 :            : 
      72                 :        416 :         regs_bar = 0;
      73                 :        416 :         rc = spdk_pci_device_map_bar(ioat->device, regs_bar, &addr, &phys_addr, &size);
      74   [ +  -  -  + ]:        416 :         if (rc != 0 || addr == NULL) {
      75                 :          0 :                 SPDK_ERRLOG("pci_device_map_range failed with error code %d\n",
      76                 :            :                             rc);
      77                 :          0 :                 return -1;
      78                 :            :         }
      79                 :            : 
      80                 :        416 :         ioat->regs = (volatile struct spdk_ioat_registers *)addr;
      81                 :            : 
      82                 :        416 :         return 0;
      83                 :            : }
      84                 :            : 
      85                 :            : static int
      86                 :        401 : ioat_unmap_pci_bar(struct spdk_ioat_chan *ioat)
      87                 :            : {
      88                 :        401 :         int rc = 0;
      89                 :        401 :         void *addr = (void *)ioat->regs;
      90                 :            : 
      91         [ +  - ]:        401 :         if (addr) {
      92                 :        401 :                 rc = spdk_pci_device_unmap_bar(ioat->device, 0, addr);
      93                 :            :         }
      94                 :        401 :         return rc;
      95                 :            : }
      96                 :            : 
      97                 :            : 
      98                 :            : static inline uint32_t
      99                 :    1208063 : ioat_get_active(struct spdk_ioat_chan *ioat)
     100                 :            : {
     101         [ -  + ]:    1208063 :         return (ioat->head - ioat->tail) & ((1 << ioat->ring_size_order) - 1);
     102                 :            : }
     103                 :            : 
     104                 :            : static inline uint32_t
     105                 :    1208063 : ioat_get_ring_space(struct spdk_ioat_chan *ioat)
     106                 :            : {
     107         [ -  + ]:    1208063 :         return (1 << ioat->ring_size_order) - ioat_get_active(ioat) - 1;
     108                 :            : }
     109                 :            : 
     110                 :            : static uint32_t
     111                 :   16570259 : ioat_get_ring_index(struct spdk_ioat_chan *ioat, uint32_t index)
     112                 :            : {
     113         [ -  + ]:   16570259 :         return index & ((1 << ioat->ring_size_order) - 1);
     114                 :            : }
     115                 :            : 
     116                 :            : static void
     117                 :    1208063 : ioat_get_ring_entry(struct spdk_ioat_chan *ioat, uint32_t index,
     118                 :            :                     struct ioat_descriptor **desc,
     119                 :            :                     union spdk_ioat_hw_desc **hw_desc)
     120                 :            : {
     121                 :    1208063 :         uint32_t i = ioat_get_ring_index(ioat, index);
     122                 :            : 
     123                 :    1208063 :         *desc = &ioat->ring[i];
     124                 :    1208063 :         *hw_desc = &ioat->hw_ring[i];
     125                 :    1208063 : }
     126                 :            : 
     127                 :            : static void
     128                 :    1208063 : ioat_submit_single(struct spdk_ioat_chan *ioat)
     129                 :            : {
     130                 :    1208063 :         ioat->head++;
     131                 :    1208063 : }
     132                 :            : 
     133                 :            : void
     134                 :     522645 : spdk_ioat_flush(struct spdk_ioat_chan *ioat)
     135                 :            : {
     136                 :     522645 :         uint32_t index = ioat_get_ring_index(ioat, ioat->head - 1);
     137                 :            :         union spdk_ioat_hw_desc *hw_desc;
     138                 :            : 
     139                 :     522645 :         hw_desc = &ioat->hw_ring[index];
     140                 :     522645 :         hw_desc->dma.u.control.completion_update = 1;
     141                 :     522645 :         ioat->regs->dmacount = (uint16_t)ioat->head;
     142                 :     522645 : }
     143                 :            : 
     144                 :            : static struct ioat_descriptor *
     145                 :        416 : ioat_prep_null(struct spdk_ioat_chan *ioat)
     146                 :            : {
     147                 :          0 :         struct ioat_descriptor *desc;
     148                 :          0 :         union spdk_ioat_hw_desc *hw_desc;
     149                 :            : 
     150         [ -  + ]:        416 :         if (ioat_get_ring_space(ioat) < 1) {
     151                 :          0 :                 return NULL;
     152                 :            :         }
     153                 :            : 
     154                 :        416 :         ioat_get_ring_entry(ioat, ioat->head, &desc, &hw_desc);
     155                 :            : 
     156                 :        416 :         hw_desc->dma.u.control_raw = 0;
     157                 :        416 :         hw_desc->dma.u.control.op = SPDK_IOAT_OP_COPY;
     158                 :        416 :         hw_desc->dma.u.control.null = 1;
     159                 :            : 
     160                 :        416 :         hw_desc->dma.size = 8;
     161                 :        416 :         hw_desc->dma.src_addr = 0;
     162                 :        416 :         hw_desc->dma.dest_addr = 0;
     163                 :            : 
     164                 :        416 :         desc->callback_fn = NULL;
     165                 :        416 :         desc->callback_arg = NULL;
     166                 :            : 
     167                 :        416 :         ioat_submit_single(ioat);
     168                 :            : 
     169                 :        416 :         return desc;
     170                 :            : }
     171                 :            : 
     172                 :            : static struct ioat_descriptor *
     173                 :     937151 : ioat_prep_copy(struct spdk_ioat_chan *ioat, uint64_t dst,
     174                 :            :                uint64_t src, uint32_t len)
     175                 :            : {
     176                 :          0 :         struct ioat_descriptor *desc;
     177                 :          0 :         union spdk_ioat_hw_desc *hw_desc;
     178                 :            : 
     179         [ -  + ]:     937151 :         assert(len <= ioat->max_xfer_size);
     180                 :            : 
     181         [ -  + ]:     937151 :         if (ioat_get_ring_space(ioat) < 1) {
     182                 :          0 :                 return NULL;
     183                 :            :         }
     184                 :            : 
     185                 :     937151 :         ioat_get_ring_entry(ioat, ioat->head, &desc, &hw_desc);
     186                 :            : 
     187                 :     937151 :         hw_desc->dma.u.control_raw = 0;
     188                 :     937151 :         hw_desc->dma.u.control.op = SPDK_IOAT_OP_COPY;
     189                 :            : 
     190                 :     937151 :         hw_desc->dma.size = len;
     191                 :     937151 :         hw_desc->dma.src_addr = src;
     192                 :     937151 :         hw_desc->dma.dest_addr = dst;
     193                 :            : 
     194                 :     937151 :         desc->callback_fn = NULL;
     195                 :     937151 :         desc->callback_arg = NULL;
     196                 :            : 
     197                 :     937151 :         ioat_submit_single(ioat);
     198                 :            : 
     199                 :     937151 :         return desc;
     200                 :            : }
     201                 :            : 
     202                 :            : static struct ioat_descriptor *
     203                 :     270496 : ioat_prep_fill(struct spdk_ioat_chan *ioat, uint64_t dst,
     204                 :            :                uint64_t fill_pattern, uint32_t len)
     205                 :            : {
     206                 :          0 :         struct ioat_descriptor *desc;
     207                 :          0 :         union spdk_ioat_hw_desc *hw_desc;
     208                 :            : 
     209         [ -  + ]:     270496 :         assert(len <= ioat->max_xfer_size);
     210                 :            : 
     211         [ -  + ]:     270496 :         if (ioat_get_ring_space(ioat) < 1) {
     212                 :          0 :                 return NULL;
     213                 :            :         }
     214                 :            : 
     215                 :     270496 :         ioat_get_ring_entry(ioat, ioat->head, &desc, &hw_desc);
     216                 :            : 
     217                 :     270496 :         hw_desc->fill.u.control_raw = 0;
     218                 :     270496 :         hw_desc->fill.u.control.op = SPDK_IOAT_OP_FILL;
     219                 :            : 
     220                 :     270496 :         hw_desc->fill.size = len;
     221                 :     270496 :         hw_desc->fill.src_data = fill_pattern;
     222                 :     270496 :         hw_desc->fill.dest_addr = dst;
     223                 :            : 
     224                 :     270496 :         desc->callback_fn = NULL;
     225                 :     270496 :         desc->callback_arg = NULL;
     226                 :            : 
     227                 :     270496 :         ioat_submit_single(ioat);
     228                 :            : 
     229                 :     270496 :         return desc;
     230                 :            : }
     231                 :            : 
     232                 :            : static int
     233                 :        416 : ioat_reset_hw(struct spdk_ioat_chan *ioat)
     234                 :            : {
     235                 :            :         int timeout;
     236                 :            :         uint64_t status;
     237                 :          0 :         uint32_t chanerr;
     238                 :            :         int rc;
     239                 :            : 
     240                 :        416 :         status = ioat_get_chansts(ioat);
     241   [ +  -  +  + ]:        416 :         if (is_ioat_active(status) || is_ioat_idle(status)) {
     242                 :        384 :                 ioat_suspend(ioat);
     243                 :            :         }
     244                 :            : 
     245                 :        416 :         timeout = 20; /* in milliseconds */
     246   [ -  +  +  + ]:        800 :         while (is_ioat_active(status) || is_ioat_idle(status)) {
     247                 :        384 :                 spdk_delay_us(1000);
     248                 :        384 :                 timeout--;
     249         [ -  + ]:        384 :                 if (timeout == 0) {
     250                 :          0 :                         SPDK_ERRLOG("timed out waiting for suspend\n");
     251                 :          0 :                         return -1;
     252                 :            :                 }
     253                 :        384 :                 status = ioat_get_chansts(ioat);
     254                 :            :         }
     255                 :            : 
     256                 :            :         /*
     257                 :            :          * Clear any outstanding errors.
     258                 :            :          * CHANERR is write-1-to-clear, so write the current CHANERR bits back to reset everything.
     259                 :            :          */
     260                 :        416 :         chanerr = ioat->regs->chanerr;
     261                 :        416 :         ioat->regs->chanerr = chanerr;
     262                 :            : 
     263         [ -  + ]:        416 :         if (ioat->regs->cbver < SPDK_IOAT_VER_3_3) {
     264                 :          0 :                 rc = spdk_pci_device_cfg_read32(ioat->device, &chanerr,
     265                 :            :                                                 SPDK_IOAT_PCI_CHANERR_INT_OFFSET);
     266         [ #  # ]:          0 :                 if (rc) {
     267                 :          0 :                         SPDK_ERRLOG("failed to read the internal channel error register\n");
     268                 :          0 :                         return -1;
     269                 :            :                 }
     270                 :            : 
     271                 :          0 :                 spdk_pci_device_cfg_write32(ioat->device, chanerr,
     272                 :            :                                             SPDK_IOAT_PCI_CHANERR_INT_OFFSET);
     273                 :            :         }
     274                 :            : 
     275                 :        416 :         ioat_reset(ioat);
     276                 :            : 
     277                 :        416 :         timeout = 20;
     278         [ -  + ]:        416 :         while (ioat_reset_pending(ioat)) {
     279                 :          0 :                 spdk_delay_us(1000);
     280                 :          0 :                 timeout--;
     281         [ #  # ]:          0 :                 if (timeout == 0) {
     282                 :          0 :                         SPDK_ERRLOG("timed out waiting for reset\n");
     283                 :          0 :                         return -1;
     284                 :            :                 }
     285                 :            :         }
     286                 :            : 
     287                 :        416 :         return 0;
     288                 :            : }
     289                 :            : 
     290                 :            : static int
     291                 :     110137 : ioat_process_channel_events(struct spdk_ioat_chan *ioat)
     292                 :            : {
     293                 :            :         struct ioat_descriptor *desc;
     294                 :     110137 :         uint64_t status, completed_descriptor, hw_desc_phys_addr, events_count = 0;
     295                 :            :         uint32_t tail;
     296                 :            : 
     297         [ +  + ]:     110137 :         if (ioat->head == ioat->tail) {
     298                 :      92389 :                 return 0;
     299                 :            :         }
     300                 :            : 
     301                 :      17748 :         status = *ioat->comp_update;
     302                 :      17748 :         completed_descriptor = status & SPDK_IOAT_CHANSTS_COMPLETED_DESCRIPTOR_MASK;
     303                 :            : 
     304         [ -  + ]:      17748 :         if (is_ioat_halted(status)) {
     305                 :          0 :                 SPDK_ERRLOG("Channel halted (%x)\n", ioat->regs->chanerr);
     306                 :          0 :                 return -1;
     307                 :            :         }
     308                 :            : 
     309         [ -  + ]:      17748 :         if (completed_descriptor == ioat->last_seen) {
     310                 :          0 :                 return 0;
     311                 :            :         }
     312                 :            : 
     313                 :            :         do {
     314                 :    1208063 :                 tail = ioat_get_ring_index(ioat, ioat->tail);
     315                 :    1208063 :                 desc = &ioat->ring[tail];
     316                 :            : 
     317         [ +  + ]:    1208063 :                 if (desc->callback_fn) {
     318                 :    1207647 :                         desc->callback_fn(desc->callback_arg);
     319                 :            :                 }
     320                 :            : 
     321                 :    1208063 :                 hw_desc_phys_addr = desc->phys_addr;
     322                 :    1208063 :                 ioat->tail++;
     323                 :    1208063 :                 events_count++;
     324         [ +  + ]:    1208063 :         } while (hw_desc_phys_addr != completed_descriptor);
     325                 :            : 
     326                 :      17748 :         ioat->last_seen = hw_desc_phys_addr;
     327                 :            : 
     328                 :      17748 :         return events_count;
     329                 :            : }
     330                 :            : 
     331                 :            : static void
     332                 :        401 : ioat_channel_destruct(struct spdk_ioat_chan *ioat)
     333                 :            : {
     334                 :        401 :         ioat_unmap_pci_bar(ioat);
     335                 :            : 
     336         [ +  - ]:        401 :         if (ioat->ring) {
     337                 :        401 :                 free(ioat->ring);
     338                 :            :         }
     339                 :            : 
     340         [ +  - ]:        401 :         if (ioat->hw_ring) {
     341                 :        401 :                 spdk_free(ioat->hw_ring);
     342                 :            :         }
     343                 :            : 
     344         [ +  - ]:        401 :         if (ioat->comp_update) {
     345                 :        401 :                 spdk_free((void *)ioat->comp_update);
     346                 :        401 :                 ioat->comp_update = NULL;
     347                 :            :         }
     348                 :        401 : }
     349                 :            : 
     350                 :            : uint32_t
     351                 :          0 : spdk_ioat_get_max_descriptors(struct spdk_ioat_chan *ioat)
     352                 :            : {
     353         [ #  # ]:          0 :         return 1 << ioat->ring_size_order;
     354                 :            : }
     355                 :            : 
     356                 :            : static int
     357                 :        416 : ioat_channel_start(struct spdk_ioat_chan *ioat)
     358                 :            : {
     359                 :            :         uint8_t xfercap, version;
     360                 :        416 :         uint64_t status = 0;
     361                 :            :         int i, num_descriptors;
     362                 :        416 :         uint64_t comp_update_bus_addr = 0;
     363                 :            :         uint64_t phys_addr;
     364                 :            : 
     365         [ -  + ]:        416 :         if (ioat_map_pci_bar(ioat) != 0) {
     366                 :          0 :                 SPDK_ERRLOG("ioat_map_pci_bar() failed\n");
     367                 :          0 :                 return -1;
     368                 :            :         }
     369                 :            : 
     370                 :        416 :         version = ioat->regs->cbver;
     371         [ -  + ]:        416 :         if (version < SPDK_IOAT_VER_3_0) {
     372                 :          0 :                 SPDK_ERRLOG(" unsupported IOAT version %u.%u\n",
     373                 :            :                             version >> 4, version & 0xF);
     374                 :          0 :                 return -1;
     375                 :            :         }
     376                 :            : 
     377                 :            :         /* Always support DMA copy */
     378                 :        416 :         ioat->dma_capabilities = SPDK_IOAT_ENGINE_COPY_SUPPORTED;
     379         [ +  - ]:        416 :         if (ioat->regs->dmacapability & SPDK_IOAT_DMACAP_BFILL) {
     380                 :        416 :                 ioat->dma_capabilities |= SPDK_IOAT_ENGINE_FILL_SUPPORTED;
     381                 :            :         }
     382                 :        416 :         xfercap = ioat->regs->xfercap;
     383                 :            : 
     384                 :            :         /* Only bits [4:0] are valid. */
     385                 :        416 :         xfercap &= 0x1f;
     386         [ -  + ]:        416 :         if (xfercap == 0) {
     387                 :            :                 /* 0 means 4 GB max transfer size. */
     388                 :          0 :                 ioat->max_xfer_size = 1ULL << 32;
     389         [ -  + ]:        416 :         } else if (xfercap < 12) {
     390                 :            :                 /* XFERCAP must be at least 12 (4 KB) according to the spec. */
     391                 :          0 :                 SPDK_ERRLOG("invalid XFERCAP value %u\n", xfercap);
     392                 :          0 :                 return -1;
     393                 :            :         } else {
     394         [ -  + ]:        416 :                 ioat->max_xfer_size = 1U << xfercap;
     395                 :            :         }
     396                 :            : 
     397                 :        416 :         ioat->comp_update = spdk_zmalloc(sizeof(*ioat->comp_update), SPDK_IOAT_CHANCMP_ALIGN,
     398                 :            :                                          NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     399         [ -  + ]:        416 :         if (ioat->comp_update == NULL) {
     400                 :          0 :                 return -1;
     401                 :            :         }
     402                 :            : 
     403                 :        416 :         comp_update_bus_addr = spdk_vtophys((void *)ioat->comp_update, NULL);
     404         [ -  + ]:        416 :         if (comp_update_bus_addr == SPDK_VTOPHYS_ERROR) {
     405                 :          0 :                 return -1;
     406                 :            :         }
     407                 :            : 
     408                 :        416 :         ioat->ring_size_order = IOAT_DEFAULT_ORDER;
     409                 :            : 
     410         [ -  + ]:        416 :         num_descriptors = 1 << ioat->ring_size_order;
     411                 :            : 
     412                 :        416 :         ioat->ring = calloc(num_descriptors, sizeof(struct ioat_descriptor));
     413         [ -  + ]:        416 :         if (!ioat->ring) {
     414                 :          0 :                 return -1;
     415                 :            :         }
     416                 :            : 
     417                 :        416 :         ioat->hw_ring = spdk_zmalloc(num_descriptors * sizeof(union spdk_ioat_hw_desc), 64,
     418                 :            :                                      NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     419         [ -  + ]:        416 :         if (!ioat->hw_ring) {
     420                 :          0 :                 return -1;
     421                 :            :         }
     422                 :            : 
     423         [ +  + ]:   13631904 :         for (i = 0; i < num_descriptors; i++) {
     424                 :   13631488 :                 phys_addr = spdk_vtophys(&ioat->hw_ring[i], NULL);
     425         [ -  + ]:   13631488 :                 if (phys_addr == SPDK_VTOPHYS_ERROR) {
     426                 :          0 :                         SPDK_ERRLOG("Failed to translate descriptor %u to physical address\n", i);
     427                 :          0 :                         return -1;
     428                 :            :                 }
     429                 :            : 
     430                 :   13631488 :                 ioat->ring[i].phys_addr = phys_addr;
     431                 :   13631488 :                 ioat->hw_ring[ioat_get_ring_index(ioat, i - 1)].generic.next = phys_addr;
     432                 :            :         }
     433                 :            : 
     434                 :        416 :         ioat->head = 0;
     435                 :        416 :         ioat->tail = 0;
     436                 :        416 :         ioat->last_seen = 0;
     437                 :            : 
     438                 :        416 :         ioat_reset_hw(ioat);
     439                 :            : 
     440                 :        416 :         ioat->regs->chanctrl = SPDK_IOAT_CHANCTRL_ANY_ERR_ABORT_EN;
     441                 :        416 :         ioat_write_chancmp(ioat, comp_update_bus_addr);
     442                 :        416 :         ioat_write_chainaddr(ioat, ioat->ring[0].phys_addr);
     443                 :            : 
     444                 :        416 :         ioat_prep_null(ioat);
     445                 :        416 :         spdk_ioat_flush(ioat);
     446                 :            : 
     447                 :        416 :         i = 100;
     448         [ +  - ]:        416 :         while (i-- > 0) {
     449                 :        416 :                 spdk_delay_us(100);
     450                 :        416 :                 status = ioat_get_chansts(ioat);
     451         [ +  - ]:        416 :                 if (is_ioat_idle(status)) {
     452                 :        416 :                         break;
     453                 :            :                 }
     454                 :            :         }
     455                 :            : 
     456         [ +  - ]:        416 :         if (is_ioat_idle(status)) {
     457                 :        416 :                 ioat_process_channel_events(ioat);
     458                 :            :         } else {
     459                 :          0 :                 SPDK_ERRLOG("could not start channel: status = %p\n error = %#x\n",
     460                 :            :                             (void *)status, ioat->regs->chanerr);
     461                 :          0 :                 return -1;
     462                 :            :         }
     463                 :            : 
     464                 :        416 :         return 0;
     465                 :            : }
     466                 :            : 
     467                 :            : /* Caller must hold g_ioat_driver.lock */
     468                 :            : static struct spdk_ioat_chan *
     469                 :        416 : ioat_attach(struct spdk_pci_device *device)
     470                 :            : {
     471                 :            :         struct spdk_ioat_chan *ioat;
     472                 :          0 :         uint32_t cmd_reg;
     473                 :            : 
     474                 :        416 :         ioat = calloc(1, sizeof(struct spdk_ioat_chan));
     475         [ -  + ]:        416 :         if (ioat == NULL) {
     476                 :          0 :                 return NULL;
     477                 :            :         }
     478                 :            : 
     479                 :            :         /* Enable PCI busmaster. */
     480                 :        416 :         spdk_pci_device_cfg_read32(device, &cmd_reg, 4);
     481                 :        416 :         cmd_reg |= 0x4;
     482                 :        416 :         spdk_pci_device_cfg_write32(device, cmd_reg, 4);
     483                 :            : 
     484                 :        416 :         ioat->device = device;
     485                 :            : 
     486         [ -  + ]:        416 :         if (ioat_channel_start(ioat) != 0) {
     487                 :          0 :                 ioat_channel_destruct(ioat);
     488                 :          0 :                 free(ioat);
     489                 :          0 :                 return NULL;
     490                 :            :         }
     491                 :            : 
     492                 :        416 :         return ioat;
     493                 :            : }
     494                 :            : 
     495                 :            : struct ioat_enum_ctx {
     496                 :            :         spdk_ioat_probe_cb probe_cb;
     497                 :            :         spdk_ioat_attach_cb attach_cb;
     498                 :            :         void *cb_ctx;
     499                 :            : };
     500                 :            : 
     501                 :            : /* This function must only be called while holding g_ioat_driver.lock */
     502                 :            : static int
     503                 :        416 : ioat_enum_cb(void *ctx, struct spdk_pci_device *pci_dev)
     504                 :            : {
     505                 :        416 :         struct ioat_enum_ctx *enum_ctx = ctx;
     506                 :            :         struct spdk_ioat_chan *ioat;
     507                 :            : 
     508                 :            :         /* Verify that this device is not already attached */
     509         [ +  + ]:       3536 :         TAILQ_FOREACH(ioat, &g_ioat_driver.attached_chans, tailq) {
     510                 :            :                 /*
     511                 :            :                  * NOTE: This assumes that the PCI abstraction layer will use the same device handle
     512                 :            :                  *  across enumerations; we could compare by BDF instead if this is not true.
     513                 :            :                  */
     514         [ -  + ]:       3120 :                 if (pci_dev == ioat->device) {
     515                 :          0 :                         return 0;
     516                 :            :                 }
     517                 :            :         }
     518                 :            : 
     519         [ +  - ]:        416 :         if (enum_ctx->probe_cb(enum_ctx->cb_ctx, pci_dev)) {
     520                 :            :                 /*
     521                 :            :                  * Since I/OAT init is relatively quick, just perform the full init during probing.
     522                 :            :                  *  If this turns out to be a bottleneck later, this can be changed to work like
     523                 :            :                  *  NVMe with a list of devices to initialize in parallel.
     524                 :            :                  */
     525                 :        416 :                 ioat = ioat_attach(pci_dev);
     526         [ -  + ]:        416 :                 if (ioat == NULL) {
     527                 :          0 :                         SPDK_ERRLOG("ioat_attach() failed\n");
     528                 :          0 :                         return -1;
     529                 :            :                 }
     530                 :            : 
     531                 :        416 :                 TAILQ_INSERT_TAIL(&g_ioat_driver.attached_chans, ioat, tailq);
     532                 :            : 
     533                 :        416 :                 enum_ctx->attach_cb(enum_ctx->cb_ctx, pci_dev, ioat);
     534                 :            :         }
     535                 :            : 
     536                 :        416 :         return 0;
     537                 :            : }
     538                 :            : 
     539                 :            : int
     540                 :         26 : spdk_ioat_probe(void *cb_ctx, spdk_ioat_probe_cb probe_cb, spdk_ioat_attach_cb attach_cb)
     541                 :            : {
     542                 :            :         int rc;
     543                 :          0 :         struct ioat_enum_ctx enum_ctx;
     544                 :            : 
     545         [ -  + ]:         26 :         pthread_mutex_lock(&g_ioat_driver.lock);
     546                 :            : 
     547                 :         26 :         enum_ctx.probe_cb = probe_cb;
     548                 :         26 :         enum_ctx.attach_cb = attach_cb;
     549                 :         26 :         enum_ctx.cb_ctx = cb_ctx;
     550                 :            : 
     551                 :         26 :         rc = spdk_pci_enumerate(spdk_pci_ioat_get_driver(), ioat_enum_cb, &enum_ctx);
     552                 :            : 
     553         [ -  + ]:         26 :         pthread_mutex_unlock(&g_ioat_driver.lock);
     554                 :            : 
     555                 :         26 :         return rc;
     556                 :            : }
     557                 :            : 
     558                 :            : void
     559                 :        401 : spdk_ioat_detach(struct spdk_ioat_chan *ioat)
     560                 :            : {
     561                 :        401 :         struct ioat_driver      *driver = &g_ioat_driver;
     562                 :            : 
     563                 :            :         /* ioat should be in the free list (not registered to a thread)
     564                 :            :          * when calling ioat_detach().
     565                 :            :          */
     566         [ -  + ]:        401 :         pthread_mutex_lock(&driver->lock);
     567         [ +  + ]:        401 :         TAILQ_REMOVE(&driver->attached_chans, ioat, tailq);
     568         [ -  + ]:        401 :         pthread_mutex_unlock(&driver->lock);
     569                 :            : 
     570                 :        401 :         ioat_channel_destruct(ioat);
     571                 :        401 :         free(ioat);
     572                 :        401 : }
     573                 :            : 
     574                 :            : int
     575                 :     937151 : spdk_ioat_build_copy(struct spdk_ioat_chan *ioat, void *cb_arg, spdk_ioat_req_cb cb_fn,
     576                 :            :                      void *dst, const void *src, uint64_t nbytes)
     577                 :            : {
     578                 :            :         struct ioat_descriptor  *last_desc;
     579                 :            :         uint64_t        remaining, op_size;
     580                 :            :         uint64_t        vdst, vsrc;
     581                 :          0 :         uint64_t        pdst_addr, psrc_addr, dst_len, src_len;
     582                 :            :         uint32_t        orig_head;
     583                 :            : 
     584         [ -  + ]:     937151 :         if (!ioat) {
     585                 :          0 :                 return -EINVAL;
     586                 :            :         }
     587                 :            : 
     588                 :     937151 :         orig_head = ioat->head;
     589                 :            : 
     590                 :     937151 :         vdst = (uint64_t)dst;
     591                 :     937151 :         vsrc = (uint64_t)src;
     592                 :            : 
     593                 :     937151 :         remaining = nbytes;
     594         [ +  - ]:     937151 :         while (remaining) {
     595                 :     937151 :                 src_len = dst_len = remaining;
     596                 :            : 
     597                 :     937151 :                 psrc_addr = spdk_vtophys((void *)vsrc, &src_len);
     598         [ -  + ]:     937151 :                 if (psrc_addr == SPDK_VTOPHYS_ERROR) {
     599                 :          0 :                         return -EINVAL;
     600                 :            :                 }
     601                 :     937151 :                 pdst_addr = spdk_vtophys((void *)vdst, &dst_len);
     602         [ -  + ]:     937151 :                 if (pdst_addr == SPDK_VTOPHYS_ERROR) {
     603                 :          0 :                         return -EINVAL;
     604                 :            :                 }
     605                 :            : 
     606                 :     937151 :                 op_size = spdk_min(dst_len, src_len);
     607                 :     937151 :                 op_size = spdk_min(op_size, ioat->max_xfer_size);
     608                 :     937151 :                 remaining -= op_size;
     609                 :            : 
     610                 :     937151 :                 last_desc = ioat_prep_copy(ioat, pdst_addr, psrc_addr, op_size);
     611                 :            : 
     612   [ -  +  -  - ]:     937151 :                 if (remaining == 0 || last_desc == NULL) {
     613                 :            :                         break;
     614                 :            :                 }
     615                 :            : 
     616                 :          0 :                 vsrc += op_size;
     617                 :          0 :                 vdst += op_size;
     618                 :            : 
     619                 :            :         }
     620                 :            :         /* Issue null descriptor for null transfer */
     621         [ -  + ]:     937151 :         if (nbytes == 0) {
     622                 :          0 :                 last_desc = ioat_prep_null(ioat);
     623                 :            :         }
     624                 :            : 
     625         [ +  - ]:     937151 :         if (last_desc) {
     626                 :     937151 :                 last_desc->callback_fn = cb_fn;
     627                 :     937151 :                 last_desc->callback_arg = cb_arg;
     628                 :            :         } else {
     629                 :            :                 /*
     630                 :            :                  * Ran out of descriptors in the ring - reset head to leave things as they were
     631                 :            :                  * in case we managed to fill out any descriptors.
     632                 :            :                  */
     633                 :          0 :                 ioat->head = orig_head;
     634                 :          0 :                 return -ENOMEM;
     635                 :            :         }
     636                 :            : 
     637                 :     937151 :         return 0;
     638                 :            : }
     639                 :            : 
     640                 :            : int
     641                 :        543 : spdk_ioat_submit_copy(struct spdk_ioat_chan *ioat, void *cb_arg, spdk_ioat_req_cb cb_fn,
     642                 :            :                       void *dst, const void *src, uint64_t nbytes)
     643                 :            : {
     644                 :            :         int rc;
     645                 :            : 
     646                 :        543 :         rc = spdk_ioat_build_copy(ioat, cb_arg, cb_fn, dst, src, nbytes);
     647         [ -  + ]:        543 :         if (rc != 0) {
     648                 :          0 :                 return rc;
     649                 :            :         }
     650                 :            : 
     651                 :        543 :         spdk_ioat_flush(ioat);
     652                 :        543 :         return 0;
     653                 :            : }
     654                 :            : 
     655                 :            : int
     656                 :     270496 : spdk_ioat_build_fill(struct spdk_ioat_chan *ioat, void *cb_arg, spdk_ioat_req_cb cb_fn,
     657                 :            :                      void *dst, uint64_t fill_pattern, uint64_t nbytes)
     658                 :            : {
     659                 :     270496 :         struct ioat_descriptor  *last_desc = NULL;
     660                 :            :         uint64_t        remaining, op_size;
     661                 :            :         uint64_t        vdst;
     662                 :          0 :         uint64_t        pdst_addr, dst_len;
     663                 :            :         uint32_t        orig_head;
     664                 :            : 
     665         [ -  + ]:     270496 :         if (!ioat) {
     666                 :          0 :                 return -EINVAL;
     667                 :            :         }
     668                 :            : 
     669         [ -  + ]:     270496 :         if (!(ioat->dma_capabilities & SPDK_IOAT_ENGINE_FILL_SUPPORTED)) {
     670                 :          0 :                 SPDK_ERRLOG("Channel does not support memory fill\n");
     671                 :          0 :                 return -1;
     672                 :            :         }
     673                 :            : 
     674                 :     270496 :         orig_head = ioat->head;
     675                 :            : 
     676                 :     270496 :         vdst = (uint64_t)dst;
     677                 :     270496 :         remaining = nbytes;
     678                 :            : 
     679         [ +  - ]:     270496 :         while (remaining) {
     680                 :     270496 :                 dst_len = remaining;
     681                 :     270496 :                 pdst_addr = spdk_vtophys((void *)vdst, &dst_len);
     682         [ -  + ]:     270496 :                 if (pdst_addr == SPDK_VTOPHYS_ERROR) {
     683                 :          0 :                         return -EINVAL;
     684                 :            :                 }
     685                 :            : 
     686                 :     270496 :                 op_size = spdk_min(dst_len, ioat->max_xfer_size);
     687                 :     270496 :                 remaining -= op_size;
     688                 :            : 
     689                 :     270496 :                 last_desc = ioat_prep_fill(ioat, pdst_addr, fill_pattern, op_size);
     690                 :            : 
     691   [ -  +  -  - ]:     270496 :                 if (remaining == 0 || last_desc == NULL) {
     692                 :            :                         break;
     693                 :            :                 }
     694                 :            : 
     695                 :          0 :                 vdst += op_size;
     696                 :            :         }
     697                 :            : 
     698         [ +  - ]:     270496 :         if (last_desc) {
     699                 :     270496 :                 last_desc->callback_fn = cb_fn;
     700                 :     270496 :                 last_desc->callback_arg = cb_arg;
     701                 :            :         } else {
     702                 :            :                 /*
     703                 :            :                  * Ran out of descriptors in the ring - reset head to leave things as they were
     704                 :            :                  * in case we managed to fill out any descriptors.
     705                 :            :                  */
     706                 :          0 :                 ioat->head = orig_head;
     707                 :          0 :                 return -ENOMEM;
     708                 :            :         }
     709                 :            : 
     710                 :     270496 :         return 0;
     711                 :            : }
     712                 :            : 
     713                 :            : int
     714                 :        544 : spdk_ioat_submit_fill(struct spdk_ioat_chan *ioat, void *cb_arg, spdk_ioat_req_cb cb_fn,
     715                 :            :                       void *dst, uint64_t fill_pattern, uint64_t nbytes)
     716                 :            : {
     717                 :            :         int rc;
     718                 :            : 
     719                 :        544 :         rc = spdk_ioat_build_fill(ioat, cb_arg, cb_fn, dst, fill_pattern, nbytes);
     720         [ -  + ]:        544 :         if (rc != 0) {
     721                 :          0 :                 return rc;
     722                 :            :         }
     723                 :            : 
     724                 :        544 :         spdk_ioat_flush(ioat);
     725                 :        544 :         return 0;
     726                 :            : }
     727                 :            : 
     728                 :            : uint32_t
     729                 :         32 : spdk_ioat_get_dma_capabilities(struct spdk_ioat_chan *ioat)
     730                 :            : {
     731         [ -  + ]:         32 :         if (!ioat) {
     732                 :          0 :                 return 0;
     733                 :            :         }
     734                 :         32 :         return ioat->dma_capabilities;
     735                 :            : }
     736                 :            : 
     737                 :            : int
     738                 :     109721 : spdk_ioat_process_events(struct spdk_ioat_chan *ioat)
     739                 :            : {
     740                 :     109721 :         return ioat_process_channel_events(ioat);
     741                 :            : }
     742                 :            : 
     743                 :       3086 : SPDK_LOG_REGISTER_COMPONENT(ioat)

Generated by: LCOV version 1.14