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