xref: /spdk/lib/idxd/idxd_kernel.c (revision efc07e370cc603049203469057e3fd8fb8ca639c)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2021 Intel Corporation.
32ed914f8SZiye Yang  *   All rights reserved.
42ed914f8SZiye Yang  */
52ed914f8SZiye Yang 
62ed914f8SZiye Yang #include "spdk/stdinc.h"
72ed914f8SZiye Yang 
82ed914f8SZiye Yang #include <accel-config/libaccel_config.h>
92ed914f8SZiye Yang 
102ed914f8SZiye Yang #include "spdk/env.h"
112ed914f8SZiye Yang #include "spdk/util.h"
122ed914f8SZiye Yang #include "spdk/memory.h"
132ed914f8SZiye Yang #include "spdk/likely.h"
142ed914f8SZiye Yang 
152ed914f8SZiye Yang #include "spdk/log.h"
162ed914f8SZiye Yang #include "spdk_internal/idxd.h"
172ed914f8SZiye Yang 
1879c9b1e5SJim Harris #include "idxd_internal.h"
192ed914f8SZiye Yang 
20de732691SBen Walker struct spdk_kernel_idxd_device {
21de732691SBen Walker 	struct spdk_idxd_device	idxd;
22de732691SBen Walker 	struct accfg_ctx	*ctx;
232ed914f8SZiye Yang 
242ed914f8SZiye Yang 	unsigned int		max_batch_size;
252ed914f8SZiye Yang 	unsigned int		max_xfer_size;
262ed914f8SZiye Yang 	unsigned int		max_xfer_bits;
272ed914f8SZiye Yang 
28de732691SBen Walker 	/* We only use a single WQ */
29de732691SBen Walker 	struct accfg_wq		*wq;
302ed914f8SZiye Yang 	int			fd;
31de732691SBen Walker 	void			*portal;
322ed914f8SZiye Yang };
332ed914f8SZiye Yang 
342ed914f8SZiye Yang #define __kernel_idxd(idxd) SPDK_CONTAINEROF(idxd, struct spdk_kernel_idxd_device, idxd)
352ed914f8SZiye Yang 
36de732691SBen Walker static void
kernel_idxd_device_destruct(struct spdk_idxd_device * idxd)37de732691SBen Walker kernel_idxd_device_destruct(struct spdk_idxd_device *idxd)
382ed914f8SZiye Yang {
39de732691SBen Walker 	struct spdk_kernel_idxd_device *kernel_idxd = __kernel_idxd(idxd);
402ed914f8SZiye Yang 
41de732691SBen Walker 	if (kernel_idxd->portal != NULL) {
42de732691SBen Walker 		munmap(kernel_idxd->portal, 0x1000);
43de732691SBen Walker 	}
44de732691SBen Walker 
45de732691SBen Walker 	if (kernel_idxd->fd >= 0) {
46de732691SBen Walker 		close(kernel_idxd->fd);
47de732691SBen Walker 	}
48de732691SBen Walker 
49de732691SBen Walker 	accfg_unref(kernel_idxd->ctx);
50de732691SBen Walker 	free(kernel_idxd);
512ed914f8SZiye Yang }
522ed914f8SZiye Yang 
5326f503b0SBen Walker static struct spdk_idxd_impl g_kernel_idxd_impl;
5426f503b0SBen Walker 
552ed914f8SZiye Yang static int
kernel_idxd_probe(void * cb_ctx,spdk_idxd_attach_cb attach_cb,spdk_idxd_probe_cb probe_cb)56ecaa8e10Spaul luse kernel_idxd_probe(void *cb_ctx, spdk_idxd_attach_cb attach_cb, spdk_idxd_probe_cb probe_cb)
572ed914f8SZiye Yang {
582ed914f8SZiye Yang 	int rc;
59de732691SBen Walker 	struct accfg_ctx *ctx;
60de732691SBen Walker 	struct accfg_device *device;
612ed914f8SZiye Yang 
62b217432fSTomasz Zawadzki 	/* Create a configuration context, incrementing the reference count. */
63de732691SBen Walker 	rc = accfg_new(&ctx);
64de732691SBen Walker 	if (rc < 0) {
65de732691SBen Walker 		SPDK_ERRLOG("Unable to allocate accel-config context\n");
66de732691SBen Walker 		return rc;
67de732691SBen Walker 	}
68de732691SBen Walker 
69de732691SBen Walker 	/* Loop over each IDXD device */
70de732691SBen Walker 	accfg_device_foreach(ctx, device) {
712ed914f8SZiye Yang 		enum accfg_device_state dstate;
72de732691SBen Walker 		struct spdk_kernel_idxd_device *kernel_idxd;
73de732691SBen Walker 		struct accfg_wq *wq;
742371a070SBen Walker 		bool pasid_enabled;
752ed914f8SZiye Yang 
762ed914f8SZiye Yang 		/* Make sure that the device is enabled */
772ed914f8SZiye Yang 		dstate = accfg_device_get_state(device);
782ed914f8SZiye Yang 		if (dstate != ACCFG_DEVICE_ENABLED) {
792ed914f8SZiye Yang 			continue;
802ed914f8SZiye Yang 		}
812ed914f8SZiye Yang 
822371a070SBen Walker 		pasid_enabled = accfg_device_get_pasid_enabled(device);
832371a070SBen Walker 		if (!pasid_enabled && spdk_iommu_is_enabled()) {
842371a070SBen Walker 			/*
852371a070SBen Walker 			 * If the IOMMU is enabled but shared memory mode is not on,
862371a070SBen Walker 			 * then we have no way to get the IOVA from userspace to use this
872371a070SBen Walker 			 * device or any kernel device. Return an error.
882371a070SBen Walker 			 */
892371a070SBen Walker 			SPDK_ERRLOG("Found kernel IDXD device, but cannot use it when IOMMU is enabled but SM is disabled\n");
902371a070SBen Walker 			return -ENOTSUP;
912371a070SBen Walker 		}
922371a070SBen Walker 
93de732691SBen Walker 		kernel_idxd = calloc(1, sizeof(struct spdk_kernel_idxd_device));
94de732691SBen Walker 		if (kernel_idxd == NULL) {
95de732691SBen Walker 			SPDK_ERRLOG("Failed to allocate memory for kernel_idxd device.\n");
96de732691SBen Walker 			/* TODO: Goto error cleanup */
97de732691SBen Walker 			return -ENOMEM;
982ed914f8SZiye Yang 		}
992ed914f8SZiye Yang 
100de732691SBen Walker 		kernel_idxd->max_batch_size = accfg_device_get_max_batch_size(device);
101de732691SBen Walker 		kernel_idxd->max_xfer_size = accfg_device_get_max_transfer_size(device);
102de732691SBen Walker 		kernel_idxd->idxd.socket_id = accfg_device_get_numa_node(device);
10326f503b0SBen Walker 		kernel_idxd->idxd.impl = &g_kernel_idxd_impl;
104de732691SBen Walker 		kernel_idxd->fd = -1;
10561631dadSpaul luse 		kernel_idxd->idxd.version = accfg_device_get_version(device);
1062371a070SBen Walker 		kernel_idxd->idxd.pasid_enabled = pasid_enabled;
107de732691SBen Walker 
108b217432fSTomasz Zawadzki 		/* Increment configuration context reference for each device. */
109b217432fSTomasz Zawadzki 		kernel_idxd->ctx = accfg_ref(kernel_idxd->ctx);
110b217432fSTomasz Zawadzki 
1112ed914f8SZiye Yang 		accfg_wq_foreach(device, wq) {
1122ed914f8SZiye Yang 			enum accfg_wq_state wstate;
1132ed914f8SZiye Yang 			enum accfg_wq_mode mode;
1142ed914f8SZiye Yang 			enum accfg_wq_type type;
115de732691SBen Walker 			int major, minor;
116de732691SBen Walker 			char path[1024];
1172ed914f8SZiye Yang 
1182ed914f8SZiye Yang 			wstate = accfg_wq_get_state(wq);
1192ed914f8SZiye Yang 			if (wstate != ACCFG_WQ_ENABLED) {
1202ed914f8SZiye Yang 				continue;
1212ed914f8SZiye Yang 			}
1222ed914f8SZiye Yang 
1232ed914f8SZiye Yang 			type = accfg_wq_get_type(wq);
1242ed914f8SZiye Yang 			if (type != ACCFG_WQT_USER) {
1252ed914f8SZiye Yang 				continue;
1262ed914f8SZiye Yang 			}
1272ed914f8SZiye Yang 
128de732691SBen Walker 			/* TODO: For now, only support dedicated WQ */
1292ed914f8SZiye Yang 			mode = accfg_wq_get_mode(wq);
130de732691SBen Walker 			if (mode != ACCFG_WQ_DEDICATED) {
1312ed914f8SZiye Yang 				continue;
1322ed914f8SZiye Yang 			}
1332ed914f8SZiye Yang 
134de732691SBen Walker 			major = accfg_device_get_cdev_major(device);
135de732691SBen Walker 			if (major < 0) {
136de732691SBen Walker 				continue;
137de732691SBen Walker 			}
138de732691SBen Walker 
139de732691SBen Walker 			minor = accfg_wq_get_cdev_minor(wq);
140de732691SBen Walker 			if (minor < 0) {
141de732691SBen Walker 				continue;
142de732691SBen Walker 			}
143de732691SBen Walker 
144de732691SBen Walker 			/* Map the portal */
145de732691SBen Walker 			snprintf(path, sizeof(path), "/dev/char/%u:%u", major, minor);
146de732691SBen Walker 			kernel_idxd->fd = open(path, O_RDWR);
147de732691SBen Walker 			if (kernel_idxd->fd < 0) {
148de732691SBen Walker 				SPDK_ERRLOG("Can not open the WQ file descriptor on path=%s\n",
149de732691SBen Walker 					    path);
150de732691SBen Walker 				continue;
151de732691SBen Walker 			}
152de732691SBen Walker 
153de732691SBen Walker 			kernel_idxd->portal = mmap(NULL, 0x1000, PROT_WRITE,
154de732691SBen Walker 						   MAP_SHARED | MAP_POPULATE, kernel_idxd->fd, 0);
155de732691SBen Walker 			if (kernel_idxd->portal == MAP_FAILED) {
156*efc07e37SSlawomir Ptak 				if (errno == EPERM) {
157*efc07e37SSlawomir Ptak 					SPDK_ERRLOG("CAP_SYS_RAWIO capabilities required to mmap the portal\n");
158*efc07e37SSlawomir Ptak 				}
159de732691SBen Walker 				perror("mmap");
160de732691SBen Walker 				continue;
161de732691SBen Walker 			}
162de732691SBen Walker 
163de732691SBen Walker 			kernel_idxd->wq = wq;
164de732691SBen Walker 
165de732691SBen Walker 			/* Since we only use a single WQ, the total size is the size of this WQ */
166de732691SBen Walker 			kernel_idxd->idxd.total_wq_size = accfg_wq_get_size(wq);
167de732691SBen Walker 			kernel_idxd->idxd.chan_per_device = (kernel_idxd->idxd.total_wq_size >= 128) ? 8 : 4;
168de732691SBen Walker 
16906472fb6STomasz Zawadzki 			kernel_idxd->idxd.batch_size = accfg_wq_get_max_batch_size(wq);
17006472fb6STomasz Zawadzki 
171de732691SBen Walker 			/* We only use a single WQ, so once we've found one we can stop looking. */
1722ed914f8SZiye Yang 			break;
1732ed914f8SZiye Yang 		}
1742ed914f8SZiye Yang 
175de732691SBen Walker 		if (kernel_idxd->idxd.total_wq_size > 0) {
176de732691SBen Walker 			/* This device has at least 1 WQ available, so ask the user if they want to use it. */
177de732691SBen Walker 			attach_cb(cb_ctx, &kernel_idxd->idxd);
178de732691SBen Walker 		} else {
179de732691SBen Walker 			kernel_idxd_device_destruct(&kernel_idxd->idxd);
1802ed914f8SZiye Yang 		}
1812ed914f8SZiye Yang 	}
182f0bf4e75SBen Walker 
183b217432fSTomasz Zawadzki 	/* Release the reference used for configuration. */
184b217432fSTomasz Zawadzki 	accfg_unref(ctx);
185b217432fSTomasz Zawadzki 
186f0bf4e75SBen Walker 	return 0;
187f0bf4e75SBen Walker }
188f0bf4e75SBen Walker 
189f0bf4e75SBen Walker static void
kernel_idxd_dump_sw_error(struct spdk_idxd_device * idxd,void * portal)190f0bf4e75SBen Walker kernel_idxd_dump_sw_error(struct spdk_idxd_device *idxd, void *portal)
191f0bf4e75SBen Walker {
192f0bf4e75SBen Walker 	/* Need to be enhanced later */
193f0bf4e75SBen Walker }
194f0bf4e75SBen Walker 
195f0bf4e75SBen Walker static char *
kernel_idxd_portal_get_addr(struct spdk_idxd_device * idxd)196f0bf4e75SBen Walker kernel_idxd_portal_get_addr(struct spdk_idxd_device *idxd)
197f0bf4e75SBen Walker {
198f0bf4e75SBen Walker 	struct spdk_kernel_idxd_device *kernel_idxd = __kernel_idxd(idxd);
199de732691SBen Walker 
200de732691SBen Walker 	return kernel_idxd->portal;
201f0bf4e75SBen Walker }
202f0bf4e75SBen Walker 
203f0bf4e75SBen Walker static struct spdk_idxd_impl g_kernel_idxd_impl = {
204f0bf4e75SBen Walker 	.name			= "kernel",
205f0bf4e75SBen Walker 	.probe			= kernel_idxd_probe,
206f0bf4e75SBen Walker 	.destruct		= kernel_idxd_device_destruct,
207f0bf4e75SBen Walker 	.dump_sw_error		= kernel_idxd_dump_sw_error,
208f0bf4e75SBen Walker 	.portal_get_addr	= kernel_idxd_portal_get_addr,
209f0bf4e75SBen Walker };
210f0bf4e75SBen Walker 
2112ed914f8SZiye Yang SPDK_IDXD_IMPL_REGISTER(kernel, &g_kernel_idxd_impl);
212