1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * * Neither the name of Intel Corporation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include "spdk/stdinc.h" 36 37 #include <accel-config/libaccel_config.h> 38 39 #include "spdk/env.h" 40 #include "spdk/util.h" 41 #include "spdk/memory.h" 42 #include "spdk/likely.h" 43 44 #include "spdk/log.h" 45 #include "spdk_internal/idxd.h" 46 47 #include "idxd.h" 48 49 struct spdk_kernel_idxd_device { 50 struct spdk_idxd_device idxd; 51 struct accfg_ctx *ctx; 52 53 unsigned int max_batch_size; 54 unsigned int max_xfer_size; 55 unsigned int max_xfer_bits; 56 57 /* We only use a single WQ */ 58 struct accfg_wq *wq; 59 int fd; 60 void *portal; 61 }; 62 63 #define __kernel_idxd(idxd) SPDK_CONTAINEROF(idxd, struct spdk_kernel_idxd_device, idxd) 64 65 static void 66 kernel_idxd_device_destruct(struct spdk_idxd_device *idxd) 67 { 68 struct spdk_kernel_idxd_device *kernel_idxd = __kernel_idxd(idxd); 69 70 if (kernel_idxd->portal != NULL) { 71 munmap(kernel_idxd->portal, 0x1000); 72 } 73 74 if (kernel_idxd->fd >= 0) { 75 close(kernel_idxd->fd); 76 } 77 78 accfg_unref(kernel_idxd->ctx); 79 free(kernel_idxd); 80 } 81 82 static int 83 kernel_idxd_probe(void *cb_ctx, spdk_idxd_attach_cb attach_cb) 84 { 85 int rc; 86 struct accfg_ctx *ctx; 87 struct accfg_device *device; 88 89 rc = accfg_new(&ctx); 90 if (rc < 0) { 91 SPDK_ERRLOG("Unable to allocate accel-config context\n"); 92 return rc; 93 } 94 95 /* Loop over each IDXD device */ 96 accfg_device_foreach(ctx, device) { 97 enum accfg_device_state dstate; 98 struct spdk_kernel_idxd_device *kernel_idxd; 99 struct accfg_wq *wq; 100 101 /* Make sure that the device is enabled */ 102 dstate = accfg_device_get_state(device); 103 if (dstate != ACCFG_DEVICE_ENABLED) { 104 continue; 105 } 106 107 kernel_idxd = calloc(1, sizeof(struct spdk_kernel_idxd_device)); 108 if (kernel_idxd == NULL) { 109 SPDK_ERRLOG("Failed to allocate memory for kernel_idxd device.\n"); 110 /* TODO: Goto error cleanup */ 111 return -ENOMEM; 112 } 113 114 kernel_idxd->max_batch_size = accfg_device_get_max_batch_size(device); 115 kernel_idxd->max_xfer_size = accfg_device_get_max_transfer_size(device); 116 kernel_idxd->idxd.socket_id = accfg_device_get_numa_node(device); 117 kernel_idxd->fd = -1; 118 119 accfg_wq_foreach(device, wq) { 120 enum accfg_wq_state wstate; 121 enum accfg_wq_mode mode; 122 enum accfg_wq_type type; 123 int major, minor; 124 char path[1024]; 125 126 wstate = accfg_wq_get_state(wq); 127 if (wstate != ACCFG_WQ_ENABLED) { 128 continue; 129 } 130 131 type = accfg_wq_get_type(wq); 132 if (type != ACCFG_WQT_USER) { 133 continue; 134 } 135 136 /* TODO: For now, only support dedicated WQ */ 137 mode = accfg_wq_get_mode(wq); 138 if (mode != ACCFG_WQ_DEDICATED) { 139 continue; 140 } 141 142 major = accfg_device_get_cdev_major(device); 143 if (major < 0) { 144 continue; 145 } 146 147 minor = accfg_wq_get_cdev_minor(wq); 148 if (minor < 0) { 149 continue; 150 } 151 152 /* Map the portal */ 153 snprintf(path, sizeof(path), "/dev/char/%u:%u", major, minor); 154 kernel_idxd->fd = open(path, O_RDWR); 155 if (kernel_idxd->fd < 0) { 156 SPDK_ERRLOG("Can not open the WQ file descriptor on path=%s\n", 157 path); 158 continue; 159 } 160 161 kernel_idxd->portal = mmap(NULL, 0x1000, PROT_WRITE, 162 MAP_SHARED | MAP_POPULATE, kernel_idxd->fd, 0); 163 if (kernel_idxd->portal == MAP_FAILED) { 164 perror("mmap"); 165 continue; 166 } 167 168 kernel_idxd->wq = wq; 169 170 /* Since we only use a single WQ, the total size is the size of this WQ */ 171 kernel_idxd->idxd.total_wq_size = accfg_wq_get_size(wq); 172 kernel_idxd->idxd.chan_per_device = (kernel_idxd->idxd.total_wq_size >= 128) ? 8 : 4; 173 /* TODO: Handle BOF when we add support for shared WQ */ 174 /* wq_ctx->bof = accfg_wq_get_block_on_fault(wq); */ 175 176 /* We only use a single WQ, so once we've found one we can stop looking. */ 177 break; 178 } 179 180 if (kernel_idxd->idxd.total_wq_size > 0) { 181 /* This device has at least 1 WQ available, so ask the user if they want to use it. */ 182 attach_cb(cb_ctx, &kernel_idxd->idxd); 183 } else { 184 kernel_idxd_device_destruct(&kernel_idxd->idxd); 185 } 186 } 187 188 return 0; 189 } 190 191 static void 192 kernel_idxd_dump_sw_error(struct spdk_idxd_device *idxd, void *portal) 193 { 194 /* Need to be enhanced later */ 195 } 196 197 static char * 198 kernel_idxd_portal_get_addr(struct spdk_idxd_device *idxd) 199 { 200 struct spdk_kernel_idxd_device *kernel_idxd = __kernel_idxd(idxd); 201 202 return kernel_idxd->portal; 203 } 204 205 static struct spdk_idxd_impl g_kernel_idxd_impl = { 206 .name = "kernel", 207 .probe = kernel_idxd_probe, 208 .destruct = kernel_idxd_device_destruct, 209 .dump_sw_error = kernel_idxd_dump_sw_error, 210 .portal_get_addr = kernel_idxd_portal_get_addr, 211 }; 212 213 SPDK_IDXD_IMPL_REGISTER(kernel, &g_kernel_idxd_impl); 214