LCOV - code coverage report
Current view: top level - spdk/module/accel/ioat - accel_ioat.c (source / functions) Hit Total Coverage
Test: Combined Lines: 121 140 86.4 %
Date: 2024-07-16 00:47:24 Functions: 20 20 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 42 73 57.5 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2020 Intel Corporation.
       3                 :            :  *   Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES.
       4                 :            :  *   All rights reserved.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "accel_ioat.h"
       8                 :            : 
       9                 :            : #include "spdk/stdinc.h"
      10                 :            : 
      11                 :            : #include "spdk/accel_module.h"
      12                 :            : #include "spdk/log.h"
      13                 :            : #include "spdk/likely.h"
      14                 :            : 
      15                 :            : #include "spdk/env.h"
      16                 :            : #include "spdk/event.h"
      17                 :            : #include "spdk/thread.h"
      18                 :            : #include "spdk/ioat.h"
      19                 :            : #include "spdk/json.h"
      20                 :            : 
      21                 :            : static bool g_ioat_enable = false;
      22                 :            : static bool g_ioat_initialized = false;
      23                 :            : 
      24                 :            : struct ioat_device {
      25                 :            :         struct spdk_ioat_chan *ioat;
      26                 :            :         bool is_allocated;
      27                 :            :         /** linked list pointer for device list */
      28                 :            :         TAILQ_ENTRY(ioat_device) tailq;
      29                 :            : };
      30                 :            : 
      31                 :            : struct pci_device {
      32                 :            :         struct spdk_pci_device *pci_dev;
      33                 :            :         TAILQ_ENTRY(pci_device) tailq;
      34                 :            : };
      35                 :            : 
      36                 :            : static TAILQ_HEAD(, ioat_device) g_devices = TAILQ_HEAD_INITIALIZER(g_devices);
      37                 :            : static pthread_mutex_t g_ioat_mutex = PTHREAD_MUTEX_INITIALIZER;
      38                 :            : 
      39                 :            : static TAILQ_HEAD(, pci_device) g_pci_devices = TAILQ_HEAD_INITIALIZER(g_pci_devices);
      40                 :            : 
      41                 :            : struct ioat_io_channel {
      42                 :            :         struct spdk_ioat_chan           *ioat_ch;
      43                 :            :         struct ioat_device              *ioat_dev;
      44                 :            :         struct spdk_poller              *poller;
      45                 :            : };
      46                 :            : 
      47                 :            : static struct ioat_device *
      48                 :         36 : ioat_allocate_device(void)
      49                 :            : {
      50                 :            :         struct ioat_device *dev;
      51                 :            : 
      52         [ -  + ]:         36 :         pthread_mutex_lock(&g_ioat_mutex);
      53         [ +  - ]:         65 :         TAILQ_FOREACH(dev, &g_devices, tailq) {
      54   [ -  +  +  + ]:         65 :                 if (!dev->is_allocated) {
      55                 :         36 :                         dev->is_allocated = true;
      56         [ -  + ]:         36 :                         pthread_mutex_unlock(&g_ioat_mutex);
      57                 :         36 :                         return dev;
      58                 :            :                 }
      59                 :            :         }
      60         [ #  # ]:          0 :         pthread_mutex_unlock(&g_ioat_mutex);
      61                 :            : 
      62                 :          0 :         return NULL;
      63                 :            : }
      64                 :            : 
      65                 :            : static void
      66                 :         36 : ioat_free_device(struct ioat_device *dev)
      67                 :            : {
      68         [ -  + ]:         36 :         pthread_mutex_lock(&g_ioat_mutex);
      69                 :         36 :         dev->is_allocated = false;
      70         [ -  + ]:         36 :         pthread_mutex_unlock(&g_ioat_mutex);
      71                 :         36 : }
      72                 :            : 
      73                 :            : static int accel_ioat_init(void);
      74                 :            : static void accel_ioat_exit(void *ctx);
      75                 :            : static void accel_ioat_write_config_json(struct spdk_json_write_ctx *w);
      76                 :            : static bool ioat_supports_opcode(enum spdk_accel_opcode opc);
      77                 :            : static struct spdk_io_channel *ioat_get_io_channel(void);
      78                 :            : static int ioat_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *accel_task);
      79                 :            : 
      80                 :            : static size_t
      81                 :         24 : accel_ioat_get_ctx_size(void)
      82                 :            : {
      83                 :         24 :         return sizeof(struct spdk_accel_task);
      84                 :            : }
      85                 :            : 
      86                 :            : static struct spdk_accel_module_if g_ioat_module = {
      87                 :            :         .module_init = accel_ioat_init,
      88                 :            :         .module_fini = accel_ioat_exit,
      89                 :            :         .write_config_json = accel_ioat_write_config_json,
      90                 :            :         .get_ctx_size = accel_ioat_get_ctx_size,
      91                 :            :         .name                   = "ioat",
      92                 :            :         .supports_opcode        = ioat_supports_opcode,
      93                 :            :         .get_io_channel         = ioat_get_io_channel,
      94                 :            :         .submit_tasks           = ioat_submit_tasks
      95                 :            : };
      96                 :            : 
      97                 :            : static void
      98                 :     530336 : ioat_done(void *cb_arg)
      99                 :            : {
     100                 :     530336 :         struct spdk_accel_task *accel_task = cb_arg;
     101                 :            : 
     102                 :     530336 :         spdk_accel_task_complete(accel_task, 0);
     103                 :     530336 : }
     104                 :            : 
     105                 :            : static int
     106                 :     107470 : ioat_poll(void *arg)
     107                 :            : {
     108                 :     107470 :         struct spdk_ioat_chan *chan = arg;
     109                 :            : 
     110                 :     107470 :         return spdk_ioat_process_events(chan) != 0 ? SPDK_POLLER_BUSY :
     111                 :            :                SPDK_POLLER_IDLE;
     112                 :            : }
     113                 :            : 
     114                 :            : static struct spdk_io_channel *ioat_get_io_channel(void);
     115                 :            : 
     116                 :            : static bool
     117                 :        360 : ioat_supports_opcode(enum spdk_accel_opcode opc)
     118                 :            : {
     119   [ -  +  -  + ]:        360 :         if (!g_ioat_initialized) {
     120                 :          0 :                 assert(0);
     121                 :            :                 return false;
     122                 :            :         }
     123                 :            : 
     124         [ +  + ]:        360 :         switch (opc) {
     125                 :         48 :         case SPDK_ACCEL_OPC_COPY:
     126                 :            :         case SPDK_ACCEL_OPC_FILL:
     127                 :         48 :                 return true;
     128                 :        312 :         default:
     129                 :        312 :                 return false;
     130                 :            :         }
     131                 :            : }
     132                 :            : 
     133                 :            : static int
     134                 :     278208 : ioat_submit_fill(struct ioat_io_channel *ioat_ch, struct spdk_accel_task *task)
     135                 :            : {
     136         [ -  + ]:     278208 :         if (spdk_unlikely(task->d.iovcnt != 1)) {
     137                 :          0 :                 return -EINVAL;
     138                 :            :         }
     139                 :            : 
     140                 :     556416 :         return spdk_ioat_build_fill(ioat_ch->ioat_ch, task, ioat_done,
     141                 :     278208 :                                     task->d.iovs[0].iov_base, task->fill_pattern,
     142                 :     278208 :                                     task->d.iovs[0].iov_len);
     143                 :            : }
     144                 :            : 
     145                 :            : static int
     146                 :     252128 : ioat_submit_copy(struct ioat_io_channel *ioat_ch, struct spdk_accel_task *task)
     147                 :            : {
     148   [ +  -  -  + ]:     252128 :         if (spdk_unlikely(task->d.iovcnt != 1 || task->s.iovcnt != 1)) {
     149                 :          0 :                 return -EINVAL;
     150                 :            :         }
     151                 :            : 
     152         [ -  + ]:     252128 :         if (spdk_unlikely(task->d.iovs[0].iov_len != task->s.iovs[0].iov_len)) {
     153                 :          0 :                 return -EINVAL;
     154                 :            :         }
     155                 :            : 
     156                 :     504256 :         return spdk_ioat_build_copy(ioat_ch->ioat_ch, task, ioat_done,
     157                 :     252128 :                                     task->d.iovs[0].iov_base, task->s.iovs[0].iov_base,
     158                 :     252128 :                                     task->d.iovs[0].iov_len);
     159                 :            : }
     160                 :            : 
     161                 :            : static int
     162                 :     530336 : ioat_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *accel_task)
     163                 :            : {
     164                 :     530336 :         struct ioat_io_channel *ioat_ch = spdk_io_channel_get_ctx(ch);
     165                 :            :         struct spdk_accel_task *tmp;
     166                 :     530336 :         int rc = 0;
     167                 :            : 
     168                 :            :         do {
     169      [ +  +  - ]:     530336 :                 switch (accel_task->op_code) {
     170                 :     278208 :                 case SPDK_ACCEL_OPC_FILL:
     171                 :     278208 :                         rc = ioat_submit_fill(ioat_ch,  accel_task);
     172                 :     278208 :                         break;
     173                 :     252128 :                 case SPDK_ACCEL_OPC_COPY:
     174                 :     252128 :                         rc = ioat_submit_copy(ioat_ch, accel_task);
     175                 :     252128 :                         break;
     176                 :          0 :                 default:
     177                 :          0 :                         assert(false);
     178                 :            :                         break;
     179                 :            :                 }
     180                 :            : 
     181                 :     530336 :                 tmp = STAILQ_NEXT(accel_task, link);
     182                 :            : 
     183                 :            :                 /* Report any build errors via the callback now. */
     184         [ -  + ]:     530336 :                 if (rc) {
     185                 :          0 :                         spdk_accel_task_complete(accel_task, rc);
     186                 :            :                 }
     187                 :            : 
     188                 :     530336 :                 accel_task = tmp;
     189         [ -  + ]:     530336 :         } while (accel_task);
     190                 :            : 
     191                 :     530336 :         spdk_ioat_flush(ioat_ch->ioat_ch);
     192                 :            : 
     193                 :     530336 :         return 0;
     194                 :            : }
     195                 :            : 
     196                 :            : static int
     197                 :         36 : ioat_create_cb(void *io_device, void *ctx_buf)
     198                 :            : {
     199                 :         36 :         struct ioat_io_channel *ch = ctx_buf;
     200                 :            :         struct ioat_device *ioat_dev;
     201                 :            : 
     202                 :         36 :         ioat_dev = ioat_allocate_device();
     203         [ -  + ]:         36 :         if (ioat_dev == NULL) {
     204                 :          0 :                 return -1;
     205                 :            :         }
     206                 :            : 
     207                 :         36 :         ch->ioat_dev = ioat_dev;
     208                 :         36 :         ch->ioat_ch = ioat_dev->ioat;
     209                 :         36 :         ch->poller = SPDK_POLLER_REGISTER(ioat_poll, ch->ioat_ch, 0);
     210                 :            : 
     211                 :         36 :         return 0;
     212                 :            : }
     213                 :            : 
     214                 :            : static void
     215                 :         36 : ioat_destroy_cb(void *io_device, void *ctx_buf)
     216                 :            : {
     217                 :         36 :         struct ioat_io_channel *ch = ctx_buf;
     218                 :            : 
     219                 :         36 :         ioat_free_device(ch->ioat_dev);
     220                 :         36 :         spdk_poller_unregister(&ch->poller);
     221                 :         36 : }
     222                 :            : 
     223                 :            : static struct spdk_io_channel *
     224                 :         72 : ioat_get_io_channel(void)
     225                 :            : {
     226                 :         72 :         return spdk_get_io_channel(&g_ioat_module);
     227                 :            : }
     228                 :            : 
     229                 :            : static bool
     230                 :        384 : probe_cb(void *cb_ctx, struct spdk_pci_device *pci_dev)
     231                 :            : {
     232                 :        384 :         struct spdk_pci_addr pci_addr = spdk_pci_device_get_addr(pci_dev);
     233                 :            :         struct pci_device *pdev;
     234                 :            : 
     235   [ -  +  -  + ]:        384 :         SPDK_INFOLOG(accel_ioat,
     236                 :            :                      " Found matching device at %04x:%02x:%02x.%x vendor:0x%04x device:0x%04x\n",
     237                 :            :                      pci_addr.domain,
     238                 :            :                      pci_addr.bus,
     239                 :            :                      pci_addr.dev,
     240                 :            :                      pci_addr.func,
     241                 :            :                      spdk_pci_device_get_vendor_id(pci_dev),
     242                 :            :                      spdk_pci_device_get_device_id(pci_dev));
     243                 :            : 
     244                 :        384 :         pdev = calloc(1, sizeof(*pdev));
     245         [ -  + ]:        384 :         if (pdev == NULL) {
     246                 :          0 :                 return false;
     247                 :            :         }
     248                 :        384 :         pdev->pci_dev = pci_dev;
     249                 :        384 :         TAILQ_INSERT_TAIL(&g_pci_devices, pdev, tailq);
     250                 :            : 
     251                 :            :         /* Claim the device in case conflict with other process */
     252         [ -  + ]:        384 :         if (spdk_pci_device_claim(pci_dev) < 0) {
     253                 :          0 :                 return false;
     254                 :            :         }
     255                 :            : 
     256                 :        384 :         return true;
     257                 :            : }
     258                 :            : 
     259                 :            : static void
     260                 :        384 : attach_cb(void *cb_ctx, struct spdk_pci_device *pci_dev, struct spdk_ioat_chan *ioat)
     261                 :            : {
     262                 :            :         struct ioat_device *dev;
     263                 :            : 
     264                 :        384 :         dev = calloc(1, sizeof(*dev));
     265         [ -  + ]:        384 :         if (dev == NULL) {
     266                 :          0 :                 SPDK_ERRLOG("Failed to allocate device struct\n");
     267                 :          0 :                 return;
     268                 :            :         }
     269                 :            : 
     270                 :        384 :         dev->ioat = ioat;
     271                 :        384 :         TAILQ_INSERT_TAIL(&g_devices, dev, tailq);
     272                 :            : }
     273                 :            : 
     274                 :            : void
     275                 :         24 : accel_ioat_enable_probe(void)
     276                 :            : {
     277                 :         24 :         g_ioat_enable = true;
     278                 :         24 :         spdk_accel_module_list_add(&g_ioat_module);
     279                 :         24 : }
     280                 :            : 
     281                 :            : static int
     282                 :         24 : accel_ioat_init(void)
     283                 :            : {
     284   [ -  +  -  + ]:         24 :         if (!g_ioat_enable) {
     285                 :          0 :                 assert(0);
     286                 :            :                 return 0;
     287                 :            :         }
     288                 :            : 
     289         [ -  + ]:         24 :         if (spdk_ioat_probe(NULL, probe_cb, attach_cb) != 0) {
     290                 :          0 :                 SPDK_ERRLOG("spdk_ioat_probe() failed\n");
     291                 :          0 :                 return -1;
     292                 :            :         }
     293                 :            : 
     294         [ -  + ]:         24 :         if (TAILQ_EMPTY(&g_devices)) {
     295                 :          0 :                 return -ENODEV;
     296                 :            :         }
     297                 :            : 
     298                 :         24 :         g_ioat_initialized = true;
     299                 :         24 :         spdk_io_device_register(&g_ioat_module, ioat_create_cb, ioat_destroy_cb,
     300                 :            :                                 sizeof(struct ioat_io_channel), "ioat_accel_module");
     301                 :         24 :         return 0;
     302                 :            : }
     303                 :            : 
     304                 :            : static void
     305                 :         24 : _device_unregister_cb(void *io_device)
     306                 :            : {
     307                 :         24 :         struct ioat_device *dev = io_device;
     308                 :            :         struct pci_device *pci_dev;
     309                 :            : 
     310         [ +  + ]:        408 :         while (!TAILQ_EMPTY(&g_devices)) {
     311                 :        384 :                 dev = TAILQ_FIRST(&g_devices);
     312         [ +  + ]:        384 :                 TAILQ_REMOVE(&g_devices, dev, tailq);
     313                 :        384 :                 spdk_ioat_detach(dev->ioat);
     314                 :        384 :                 free(dev);
     315                 :            :         }
     316                 :            : 
     317         [ +  + ]:        408 :         while (!TAILQ_EMPTY(&g_pci_devices)) {
     318                 :        384 :                 pci_dev = TAILQ_FIRST(&g_pci_devices);
     319         [ +  + ]:        384 :                 TAILQ_REMOVE(&g_pci_devices, pci_dev, tailq);
     320                 :        384 :                 spdk_pci_device_detach(pci_dev->pci_dev);
     321                 :        384 :                 free(pci_dev);
     322                 :            :         }
     323                 :            : 
     324                 :         24 :         g_ioat_initialized = false;
     325                 :            : 
     326                 :         24 :         spdk_accel_module_finish();
     327                 :         24 : }
     328                 :            : 
     329                 :            : static void
     330                 :         24 : accel_ioat_exit(void *ctx)
     331                 :            : {
     332   [ -  +  +  - ]:         24 :         if (g_ioat_initialized) {
     333                 :         24 :                 spdk_io_device_unregister(&g_ioat_module, _device_unregister_cb);
     334                 :            :         } else {
     335                 :          0 :                 spdk_accel_module_finish();
     336                 :            :         }
     337                 :         24 : }
     338                 :            : 
     339                 :            : static void
     340                 :          1 : accel_ioat_write_config_json(struct spdk_json_write_ctx *w)
     341                 :            : {
     342   [ -  +  +  - ]:          1 :         if (g_ioat_enable) {
     343                 :          1 :                 spdk_json_write_object_begin(w);
     344                 :          1 :                 spdk_json_write_named_string(w, "method", "ioat_scan_accel_module");
     345                 :          1 :                 spdk_json_write_object_end(w);
     346                 :            :         }
     347                 :          1 : }
     348                 :            : 
     349                 :       2576 : SPDK_LOG_REGISTER_COMPONENT(accel_ioat)

Generated by: LCOV version 1.14