1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 * 5 */ 6 7 #include "spdk/stdinc.h" 8 9 #include <accel-config/libaccel_config.h> 10 11 #include "spdk/env.h" 12 #include "spdk/util.h" 13 #include "spdk/memory.h" 14 #include "spdk/likely.h" 15 16 #include "spdk/log.h" 17 #include "spdk_internal/idxd.h" 18 19 #include "idxd_internal.h" 20 21 struct spdk_kernel_idxd_device { 22 struct spdk_idxd_device idxd; 23 struct accfg_ctx *ctx; 24 25 unsigned int max_batch_size; 26 unsigned int max_xfer_size; 27 unsigned int max_xfer_bits; 28 29 /* We only use a single WQ */ 30 struct accfg_wq *wq; 31 int fd; 32 void *portal; 33 }; 34 35 #define __kernel_idxd(idxd) SPDK_CONTAINEROF(idxd, struct spdk_kernel_idxd_device, idxd) 36 37 static void 38 kernel_idxd_device_destruct(struct spdk_idxd_device *idxd) 39 { 40 struct spdk_kernel_idxd_device *kernel_idxd = __kernel_idxd(idxd); 41 42 if (kernel_idxd->portal != NULL) { 43 munmap(kernel_idxd->portal, 0x1000); 44 } 45 46 if (kernel_idxd->fd >= 0) { 47 close(kernel_idxd->fd); 48 } 49 50 accfg_unref(kernel_idxd->ctx); 51 free(kernel_idxd); 52 } 53 54 static struct spdk_idxd_impl g_kernel_idxd_impl; 55 56 static int 57 kernel_idxd_probe(void *cb_ctx, spdk_idxd_attach_cb attach_cb, spdk_idxd_probe_cb probe_cb) 58 { 59 int rc; 60 struct accfg_ctx *ctx; 61 struct accfg_device *device; 62 63 rc = accfg_new(&ctx); 64 if (rc < 0) { 65 SPDK_ERRLOG("Unable to allocate accel-config context\n"); 66 return rc; 67 } 68 69 /* Loop over each IDXD device */ 70 accfg_device_foreach(ctx, device) { 71 enum accfg_device_state dstate; 72 struct spdk_kernel_idxd_device *kernel_idxd; 73 struct accfg_wq *wq; 74 75 /* Make sure that the device is enabled */ 76 dstate = accfg_device_get_state(device); 77 if (dstate != ACCFG_DEVICE_ENABLED) { 78 continue; 79 } 80 81 kernel_idxd = calloc(1, sizeof(struct spdk_kernel_idxd_device)); 82 if (kernel_idxd == NULL) { 83 SPDK_ERRLOG("Failed to allocate memory for kernel_idxd device.\n"); 84 /* TODO: Goto error cleanup */ 85 return -ENOMEM; 86 } 87 88 kernel_idxd->max_batch_size = accfg_device_get_max_batch_size(device); 89 kernel_idxd->max_xfer_size = accfg_device_get_max_transfer_size(device); 90 kernel_idxd->idxd.socket_id = accfg_device_get_numa_node(device); 91 kernel_idxd->idxd.impl = &g_kernel_idxd_impl; 92 kernel_idxd->fd = -1; 93 kernel_idxd->idxd.version = accfg_device_get_version(device); 94 95 accfg_wq_foreach(device, wq) { 96 enum accfg_wq_state wstate; 97 enum accfg_wq_mode mode; 98 enum accfg_wq_type type; 99 int major, minor; 100 char path[1024]; 101 102 wstate = accfg_wq_get_state(wq); 103 if (wstate != ACCFG_WQ_ENABLED) { 104 continue; 105 } 106 107 type = accfg_wq_get_type(wq); 108 if (type != ACCFG_WQT_USER) { 109 continue; 110 } 111 112 /* TODO: For now, only support dedicated WQ */ 113 mode = accfg_wq_get_mode(wq); 114 if (mode != ACCFG_WQ_DEDICATED) { 115 continue; 116 } 117 118 major = accfg_device_get_cdev_major(device); 119 if (major < 0) { 120 continue; 121 } 122 123 minor = accfg_wq_get_cdev_minor(wq); 124 if (minor < 0) { 125 continue; 126 } 127 128 /* Map the portal */ 129 snprintf(path, sizeof(path), "/dev/char/%u:%u", major, minor); 130 kernel_idxd->fd = open(path, O_RDWR); 131 if (kernel_idxd->fd < 0) { 132 SPDK_ERRLOG("Can not open the WQ file descriptor on path=%s\n", 133 path); 134 continue; 135 } 136 137 kernel_idxd->portal = mmap(NULL, 0x1000, PROT_WRITE, 138 MAP_SHARED | MAP_POPULATE, kernel_idxd->fd, 0); 139 if (kernel_idxd->portal == MAP_FAILED) { 140 perror("mmap"); 141 continue; 142 } 143 144 kernel_idxd->wq = wq; 145 146 /* Since we only use a single WQ, the total size is the size of this WQ */ 147 kernel_idxd->idxd.total_wq_size = accfg_wq_get_size(wq); 148 kernel_idxd->idxd.chan_per_device = (kernel_idxd->idxd.total_wq_size >= 128) ? 8 : 4; 149 /* TODO: Handle BOF when we add support for shared WQ */ 150 /* wq_ctx->bof = accfg_wq_get_block_on_fault(wq); */ 151 152 /* We only use a single WQ, so once we've found one we can stop looking. */ 153 break; 154 } 155 156 if (kernel_idxd->idxd.total_wq_size > 0) { 157 /* This device has at least 1 WQ available, so ask the user if they want to use it. */ 158 attach_cb(cb_ctx, &kernel_idxd->idxd); 159 } else { 160 kernel_idxd_device_destruct(&kernel_idxd->idxd); 161 } 162 } 163 164 return 0; 165 } 166 167 static void 168 kernel_idxd_dump_sw_error(struct spdk_idxd_device *idxd, void *portal) 169 { 170 /* Need to be enhanced later */ 171 } 172 173 static char * 174 kernel_idxd_portal_get_addr(struct spdk_idxd_device *idxd) 175 { 176 struct spdk_kernel_idxd_device *kernel_idxd = __kernel_idxd(idxd); 177 178 return kernel_idxd->portal; 179 } 180 181 static struct spdk_idxd_impl g_kernel_idxd_impl = { 182 .name = "kernel", 183 .probe = kernel_idxd_probe, 184 .destruct = kernel_idxd_device_destruct, 185 .dump_sw_error = kernel_idxd_dump_sw_error, 186 .portal_get_addr = kernel_idxd_portal_get_addr, 187 }; 188 189 SPDK_IDXD_IMPL_REGISTER(kernel, &g_kernel_idxd_impl); 190