xref: /spdk/lib/idxd/idxd_kernel.c (revision 3b047a6162109bfc33ee7b078de706ebccf4fa3a)
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