1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2023 Intel Corporation. 3 * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. 4 * All rights reserved. 5 */ 6 7 #include "spdk/accel.h" 8 #include "spdk/accel_module.h" 9 #include "spdk/thread.h" 10 11 static struct spdk_accel_module_if g_ex_module; 12 13 struct ex_accel_io_channel { 14 struct spdk_poller *completion_poller; 15 STAILQ_HEAD(, spdk_accel_task) tasks_to_complete; 16 }; 17 18 static int 19 ex_accel_copy_iovs(struct iovec *dst_iovs, uint32_t dst_iovcnt, 20 struct iovec *src_iovs, uint32_t src_iovcnt) 21 { 22 struct spdk_ioviter iter; 23 void *src, *dst; 24 size_t len; 25 26 for (len = spdk_ioviter_first(&iter, src_iovs, src_iovcnt, 27 dst_iovs, dst_iovcnt, &src, &dst); 28 len != 0; 29 len = spdk_ioviter_next(&iter, &src, &dst)) { 30 memcpy(dst, src, len); 31 } 32 33 return 0; 34 } 35 36 static int 37 ex_accel_compare(struct iovec *src_iovs, uint32_t src_iovcnt, 38 struct iovec *src2_iovs, uint32_t src2_iovcnt) 39 { 40 if (spdk_unlikely(src_iovcnt != 1 || src2_iovcnt != 1)) { 41 return -EINVAL; 42 } 43 44 if (spdk_unlikely(src_iovs[0].iov_len != src2_iovs[0].iov_len)) { 45 return -EINVAL; 46 } 47 48 return memcmp(src_iovs[0].iov_base, src2_iovs[0].iov_base, src_iovs[0].iov_len); 49 } 50 51 static int 52 ex_accel_fill(struct iovec *iovs, uint32_t iovcnt, uint8_t fill) 53 { 54 void *dst; 55 size_t nbytes; 56 57 if (spdk_unlikely(iovcnt != 1)) { 58 fprintf(stderr, "Unexpected number of iovs: %" PRIu32 "\n", iovcnt); 59 return -EINVAL; 60 } 61 62 dst = iovs[0].iov_base; 63 nbytes = iovs[0].iov_len; 64 65 memset(dst, fill, nbytes); 66 67 return 0; 68 } 69 70 static int 71 ex_accel_comp_poll(void *arg) 72 { 73 struct ex_accel_io_channel *ex_ch = arg; 74 STAILQ_HEAD(, spdk_accel_task) tasks_to_complete; 75 struct spdk_accel_task *accel_task; 76 77 if (STAILQ_EMPTY(&ex_ch->tasks_to_complete)) { 78 return SPDK_POLLER_IDLE; 79 } 80 81 STAILQ_INIT(&tasks_to_complete); 82 STAILQ_SWAP(&tasks_to_complete, &ex_ch->tasks_to_complete, spdk_accel_task); 83 84 while ((accel_task = STAILQ_FIRST(&tasks_to_complete))) { 85 STAILQ_REMOVE_HEAD(&tasks_to_complete, link); 86 spdk_accel_task_complete(accel_task, accel_task->status); 87 } 88 89 return SPDK_POLLER_BUSY; 90 } 91 92 static int 93 ex_accel_create_cb(void *io_device, void *ctx_buf) 94 { 95 struct ex_accel_io_channel *ex_ch = ctx_buf; 96 97 STAILQ_INIT(&ex_ch->tasks_to_complete); 98 ex_ch->completion_poller = SPDK_POLLER_REGISTER(ex_accel_comp_poll, ex_ch, 0); 99 100 return 0; 101 } 102 103 static void 104 ex_accel_destroy_cb(void *io_device, void *ctx_buf) 105 { 106 struct ex_accel_io_channel *ex_ch = ctx_buf; 107 108 spdk_poller_unregister(&ex_ch->completion_poller); 109 } 110 111 static int 112 ex_accel_module_init(void) 113 { 114 spdk_io_device_register(&g_ex_module, ex_accel_create_cb, ex_accel_destroy_cb, 115 sizeof(struct ex_accel_io_channel), "external_accel_module"); 116 117 return 0; 118 } 119 120 static void 121 ex_accel_module_fini(void *ctx) 122 { 123 spdk_io_device_unregister(&g_ex_module, NULL); 124 spdk_accel_module_finish(); 125 } 126 127 static size_t 128 ex_accel_module_get_ctx_size(void) 129 { 130 return sizeof(struct spdk_accel_task); 131 } 132 133 inline static void 134 add_to_comp_list(struct ex_accel_io_channel *ex_ch, struct spdk_accel_task *accel_task) 135 { 136 STAILQ_INSERT_TAIL(&ex_ch->tasks_to_complete, accel_task, link); 137 } 138 139 static bool 140 ex_accel_supports_opcode(enum spdk_accel_opcode opc) 141 { 142 switch (opc) { 143 case SPDK_ACCEL_OPC_COPY: 144 case SPDK_ACCEL_OPC_FILL: 145 case SPDK_ACCEL_OPC_COMPARE: 146 return true; 147 default: 148 return false; 149 } 150 } 151 152 static struct spdk_io_channel * 153 ex_accel_get_io_channel(void) 154 { 155 return spdk_get_io_channel(&g_ex_module); 156 } 157 158 static int 159 ex_accel_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *accel_task) 160 { 161 struct ex_accel_io_channel *ex_ch = spdk_io_channel_get_ctx(ch); 162 163 printf("Running on accel module task with code: %" PRIu8 "\n", accel_task->op_code); 164 switch (accel_task->op_code) { 165 case SPDK_ACCEL_OPC_COPY: 166 accel_task->status = ex_accel_copy_iovs(accel_task->d.iovs, accel_task->d.iovcnt, 167 accel_task->s.iovs, accel_task->s.iovcnt); 168 break; 169 case SPDK_ACCEL_OPC_FILL: 170 accel_task->status = ex_accel_fill(accel_task->d.iovs, accel_task->d.iovcnt, 171 accel_task->fill_pattern); 172 break; 173 case SPDK_ACCEL_OPC_COMPARE: 174 accel_task->status = ex_accel_compare(accel_task->s.iovs, accel_task->s.iovcnt, 175 accel_task->s2.iovs, accel_task->s2.iovcnt); 176 break; 177 default: 178 fprintf(stderr, "Unsupported accel opcode: %" PRIu8 "\n", accel_task->op_code); 179 accel_task->status = 1; 180 break; 181 } 182 183 add_to_comp_list(ex_ch, accel_task); 184 185 return accel_task->status; 186 } 187 188 static struct spdk_accel_module_if g_ex_module = { 189 .module_init = ex_accel_module_init, 190 .module_fini = ex_accel_module_fini, 191 .get_ctx_size = ex_accel_module_get_ctx_size, 192 .name = "external", 193 .supports_opcode = ex_accel_supports_opcode, 194 .get_io_channel = ex_accel_get_io_channel, 195 .submit_tasks = ex_accel_submit_tasks, 196 }; 197 198 SPDK_ACCEL_MODULE_REGISTER(external, &g_ex_module) 199