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