Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2020 Intel Corporation. All rights reserved.
3 : : */
4 : :
5 : : /* VFIO transport extensions for spdk_nvme_ctrlr */
6 : :
7 : : #include "spdk/stdinc.h"
8 : : #include "spdk/env.h"
9 : : #include "spdk/likely.h"
10 : : #include "spdk/string.h"
11 : : #include "spdk/vfio_user_pci.h"
12 : : #include "nvme_internal.h"
13 : : #include "nvme_pcie_internal.h"
14 : :
15 : : #include <linux/vfio.h>
16 : :
17 : : #define NVME_MAX_XFER_SIZE (131072)
18 : : #define NVME_MAX_SGES (1)
19 : :
20 : : struct nvme_vfio_ctrlr {
21 : : struct nvme_pcie_ctrlr pctrlr;
22 : :
23 : : volatile uint32_t *doorbell_base;
24 : : struct vfio_device *dev;
25 : : };
26 : :
27 : : static inline struct nvme_vfio_ctrlr *
28 : 476 : nvme_vfio_ctrlr(struct spdk_nvme_ctrlr *ctrlr)
29 : : {
30 : 476 : struct nvme_pcie_ctrlr *pctrlr = nvme_pcie_ctrlr(ctrlr);
31 : :
32 : 476 : return SPDK_CONTAINEROF(pctrlr, struct nvme_vfio_ctrlr, pctrlr);
33 : : }
34 : :
35 : : static volatile struct spdk_nvme_registers *
36 : 0 : nvme_vfio_ctrlr_get_registers(struct spdk_nvme_ctrlr *ctrlr)
37 : : {
38 : 0 : struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
39 : :
40 : 0 : return vctrlr->pctrlr.regs;
41 : : }
42 : :
43 : : static int
44 : 102 : nvme_vfio_ctrlr_set_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t value)
45 : : {
46 : 102 : struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
47 : :
48 [ - + ]: 102 : assert(offset <= sizeof(struct spdk_nvme_registers) - 4);
49 [ - + + + ]: 102 : SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%x\n", ctrlr->trid.traddr, offset, value);
50 : :
51 : 102 : return spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
52 : : offset, 4, &value, true);
53 : : }
54 : :
55 : : static int
56 : 68 : nvme_vfio_ctrlr_set_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t value)
57 : : {
58 : 68 : struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
59 : :
60 [ - + ]: 68 : assert(offset <= sizeof(struct spdk_nvme_registers) - 8);
61 [ - + + + ]: 68 : SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%"PRIx64"\n", ctrlr->trid.traddr, offset,
62 : : value);
63 : :
64 : 68 : return spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
65 : : offset, 8, &value, true);
66 : : }
67 : :
68 : : static int
69 : 204 : nvme_vfio_ctrlr_get_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t *value)
70 : : {
71 : 204 : struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
72 : : int ret;
73 : :
74 [ - + ]: 204 : assert(offset <= sizeof(struct spdk_nvme_registers) - 4);
75 : :
76 : 204 : ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
77 : : offset, 4, value, false);
78 [ - + ]: 204 : if (ret != 0) {
79 : 0 : SPDK_ERRLOG("ctrlr %p, offset %x\n", ctrlr, offset);
80 : 0 : return ret;
81 : : }
82 : :
83 [ - + + + ]: 204 : SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%x\n", ctrlr->trid.traddr, offset, *value);
84 : :
85 : 204 : return 0;
86 : : }
87 : :
88 : : static int
89 : 68 : nvme_vfio_ctrlr_get_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t *value)
90 : : {
91 : 68 : struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
92 : : int ret;
93 : :
94 [ - + ]: 68 : assert(offset <= sizeof(struct spdk_nvme_registers) - 8);
95 : :
96 : 68 : ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
97 : : offset, 8, value, false);
98 [ - + ]: 68 : if (ret != 0) {
99 : 0 : SPDK_ERRLOG("ctrlr %p, offset %x\n", ctrlr, offset);
100 : 0 : return ret;
101 : : }
102 : :
103 [ - + + + ]: 68 : SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%"PRIx64"\n", ctrlr->trid.traddr, offset,
104 : : *value);
105 : :
106 : 68 : return 0;
107 : : }
108 : :
109 : : static int
110 : 34 : nvme_vfio_ctrlr_set_asq(struct spdk_nvme_ctrlr *ctrlr, uint64_t value)
111 : : {
112 : 34 : return nvme_vfio_ctrlr_set_reg_8(ctrlr, offsetof(struct spdk_nvme_registers, asq),
113 : : value);
114 : : }
115 : :
116 : : static int
117 : 34 : nvme_vfio_ctrlr_set_acq(struct spdk_nvme_ctrlr *ctrlr, uint64_t value)
118 : : {
119 : 34 : return nvme_vfio_ctrlr_set_reg_8(ctrlr, offsetof(struct spdk_nvme_registers, acq),
120 : : value);
121 : : }
122 : :
123 : : static int
124 : 34 : nvme_vfio_ctrlr_set_aqa(struct spdk_nvme_ctrlr *ctrlr, const union spdk_nvme_aqa_register *aqa)
125 : : {
126 : 68 : return nvme_vfio_ctrlr_set_reg_4(ctrlr, offsetof(struct spdk_nvme_registers, aqa.raw),
127 : 34 : aqa->raw);
128 : : }
129 : :
130 : : static int
131 : 34 : nvme_vfio_setup_bar0(struct nvme_vfio_ctrlr *vctrlr)
132 : : {
133 : : void *doorbell;
134 : :
135 : 34 : doorbell = spdk_vfio_user_get_bar_addr(vctrlr->dev, 0, 0x1000, 0x1000);
136 [ - + ]: 34 : if (!doorbell) {
137 : 0 : return -EINVAL;
138 : : }
139 : :
140 : 34 : vctrlr->doorbell_base = (volatile uint32_t *)doorbell;
141 : 34 : return 0;
142 : : }
143 : :
144 : : static struct spdk_nvme_ctrlr *
145 : 34 : nvme_vfio_ctrlr_construct(const struct spdk_nvme_transport_id *trid,
146 : : const struct spdk_nvme_ctrlr_opts *opts,
147 : : void *devhandle)
148 : : {
149 : : struct nvme_vfio_ctrlr *vctrlr;
150 : : struct nvme_pcie_ctrlr *pctrlr;
151 : 0 : uint16_t cmd_reg;
152 : 0 : union spdk_nvme_cap_register cap;
153 : : int ret;
154 : 0 : char ctrlr_path[PATH_MAX];
155 : :
156 [ - + ]: 34 : snprintf(ctrlr_path, sizeof(ctrlr_path), "%s/cntrl", trid->traddr);
157 [ - + ]: 34 : ret = access(ctrlr_path, F_OK);
158 [ - + ]: 34 : if (ret != 0) {
159 : 0 : SPDK_ERRLOG("Access path %s failed\n", ctrlr_path);
160 : 0 : return NULL;
161 : : }
162 : :
163 : 34 : vctrlr = calloc(1, sizeof(*vctrlr));
164 [ - + ]: 34 : if (!vctrlr) {
165 : 0 : return NULL;
166 : : }
167 : :
168 : 34 : vctrlr->dev = spdk_vfio_user_setup(ctrlr_path);
169 [ - + ]: 34 : if (!vctrlr->dev) {
170 : 0 : SPDK_ERRLOG("Error to setup vfio device\n");
171 : 0 : free(vctrlr);
172 : 0 : return NULL;
173 : : }
174 : :
175 : 34 : ret = nvme_vfio_setup_bar0(vctrlr);
176 [ - + ]: 34 : if (ret != 0) {
177 : 0 : SPDK_ERRLOG("Error to get device BAR0\n");
178 : 0 : goto exit;
179 : : }
180 : :
181 : 34 : pctrlr = &vctrlr->pctrlr;
182 : 34 : pctrlr->doorbell_base = vctrlr->doorbell_base;
183 : 34 : pctrlr->ctrlr.is_removed = false;
184 : 34 : pctrlr->ctrlr.opts = *opts;
185 : 34 : pctrlr->ctrlr.trid = *trid;
186 : 34 : pctrlr->ctrlr.opts.use_cmb_sqs = false;
187 : 34 : pctrlr->ctrlr.opts.admin_queue_size = spdk_max(pctrlr->ctrlr.opts.admin_queue_size,
188 : : NVME_PCIE_MIN_ADMIN_QUEUE_SIZE);
189 : :
190 : 34 : ret = nvme_ctrlr_construct(&pctrlr->ctrlr);
191 [ - + ]: 34 : if (ret != 0) {
192 : 0 : goto exit;
193 : : }
194 : :
195 : : /* Enable PCI busmaster and disable INTx */
196 : 34 : ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_CONFIG_REGION_INDEX, 4, 2,
197 : : &cmd_reg, false);
198 [ - + ]: 34 : if (ret != 0) {
199 : 0 : nvme_ctrlr_destruct(&pctrlr->ctrlr);
200 : 0 : SPDK_ERRLOG("Read PCI CMD REG failed\n");
201 : 0 : goto exit;
202 : : }
203 : 34 : cmd_reg |= 0x404;
204 : 34 : ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_CONFIG_REGION_INDEX, 4, 2,
205 : : &cmd_reg, true);
206 [ - + ]: 34 : if (ret != 0) {
207 : 0 : nvme_ctrlr_destruct(&pctrlr->ctrlr);
208 : 0 : SPDK_ERRLOG("Write PCI CMD REG failed\n");
209 : 0 : goto exit;
210 : : }
211 : :
212 [ - + ]: 34 : if (nvme_ctrlr_get_cap(&pctrlr->ctrlr, &cap)) {
213 : 0 : nvme_ctrlr_destruct(&pctrlr->ctrlr);
214 : 0 : SPDK_ERRLOG("get_cap() failed\n");
215 : 0 : goto exit;
216 : : }
217 : :
218 : : /* Doorbell stride is 2 ^ (dstrd + 2),
219 : : * but we want multiples of 4, so drop the + 2 */
220 [ - + ]: 34 : pctrlr->doorbell_stride_u32 = 1 << cap.bits.dstrd;
221 : :
222 : 34 : ret = nvme_pcie_ctrlr_construct_admin_qpair(&pctrlr->ctrlr, pctrlr->ctrlr.opts.admin_queue_size);
223 [ - + ]: 34 : if (ret != 0) {
224 : 0 : nvme_ctrlr_destruct(&pctrlr->ctrlr);
225 : 0 : goto exit;
226 : : }
227 : :
228 : : /* Construct the primary process properties */
229 : 34 : ret = nvme_ctrlr_add_process(&pctrlr->ctrlr, 0);
230 [ - + ]: 34 : if (ret != 0) {
231 : 0 : nvme_ctrlr_destruct(&pctrlr->ctrlr);
232 : 0 : goto exit;
233 : : }
234 : :
235 : 34 : return &pctrlr->ctrlr;
236 : :
237 : 0 : exit:
238 : 0 : spdk_vfio_user_release(vctrlr->dev);
239 : 0 : free(vctrlr);
240 : 0 : return NULL;
241 : : }
242 : :
243 : : static int
244 : 34 : nvme_vfio_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx,
245 : : bool direct_connect)
246 : : {
247 : : int ret;
248 : :
249 [ - + ]: 34 : if (probe_ctx->trid.trtype != SPDK_NVME_TRANSPORT_VFIOUSER) {
250 : 0 : SPDK_ERRLOG("Can only use SPDK_NVME_TRANSPORT_VFIOUSER");
251 : 0 : return -EINVAL;
252 : : }
253 : :
254 [ - + ]: 34 : ret = access(probe_ctx->trid.traddr, F_OK);
255 [ - + ]: 34 : if (ret != 0) {
256 : 0 : SPDK_ERRLOG("Error to access file %s\n", probe_ctx->trid.traddr);
257 : 0 : return ret;
258 : : }
259 [ - + + + ]: 34 : SPDK_DEBUGLOG(nvme_vfio, "Scan controller : %s\n", probe_ctx->trid.traddr);
260 : :
261 : 34 : return nvme_ctrlr_probe(&probe_ctx->trid, probe_ctx, NULL);
262 : : }
263 : :
264 : : static int
265 : 34 : nvme_vfio_ctrlr_enable(struct spdk_nvme_ctrlr *ctrlr)
266 : : {
267 : 34 : struct nvme_pcie_qpair *vadminq = nvme_pcie_qpair(ctrlr->adminq);
268 : 0 : union spdk_nvme_aqa_register aqa;
269 : :
270 [ - + ]: 34 : if (nvme_vfio_ctrlr_set_asq(ctrlr, vadminq->cmd_bus_addr)) {
271 : 0 : SPDK_ERRLOG("set_asq() failed\n");
272 : 0 : return -EIO;
273 : : }
274 : :
275 [ - + ]: 34 : if (nvme_vfio_ctrlr_set_acq(ctrlr, vadminq->cpl_bus_addr)) {
276 : 0 : SPDK_ERRLOG("set_acq() failed\n");
277 : 0 : return -EIO;
278 : : }
279 : :
280 : 34 : aqa.raw = 0;
281 : : /* acqs and asqs are 0-based. */
282 : 34 : aqa.bits.acqs = nvme_pcie_qpair(ctrlr->adminq)->num_entries - 1;
283 : 34 : aqa.bits.asqs = nvme_pcie_qpair(ctrlr->adminq)->num_entries - 1;
284 : :
285 [ - + ]: 34 : if (nvme_vfio_ctrlr_set_aqa(ctrlr, &aqa)) {
286 : 0 : SPDK_ERRLOG("set_aqa() failed\n");
287 : 0 : return -EIO;
288 : : }
289 : :
290 : 34 : return 0;
291 : : }
292 : :
293 : : static int
294 : 34 : nvme_vfio_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
295 : : {
296 : 34 : struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
297 : :
298 [ + - ]: 34 : if (ctrlr->adminq) {
299 : 34 : nvme_pcie_qpair_destroy(ctrlr->adminq);
300 : : }
301 : :
302 : 34 : nvme_ctrlr_destruct_finish(ctrlr);
303 : :
304 : 34 : spdk_vfio_user_release(vctrlr->dev);
305 : 34 : free(vctrlr);
306 : :
307 : 34 : return 0;
308 : : }
309 : :
310 : : static uint32_t
311 : 34 : nvme_vfio_ctrlr_get_max_xfer_size(struct spdk_nvme_ctrlr *ctrlr)
312 : : {
313 : 34 : return NVME_MAX_XFER_SIZE;
314 : : }
315 : :
316 : : static uint16_t
317 : 34 : nvme_vfio_ctrlr_get_max_sges(struct spdk_nvme_ctrlr *ctrlr)
318 : : {
319 : 34 : return NVME_MAX_SGES;
320 : : }
321 : :
322 : : const struct spdk_nvme_transport_ops vfio_ops = {
323 : : .name = "VFIOUSER",
324 : : .type = SPDK_NVME_TRANSPORT_VFIOUSER,
325 : : .ctrlr_construct = nvme_vfio_ctrlr_construct,
326 : : .ctrlr_scan = nvme_vfio_ctrlr_scan,
327 : : .ctrlr_destruct = nvme_vfio_ctrlr_destruct,
328 : : .ctrlr_enable = nvme_vfio_ctrlr_enable,
329 : :
330 : : .ctrlr_get_registers = nvme_vfio_ctrlr_get_registers,
331 : : .ctrlr_set_reg_4 = nvme_vfio_ctrlr_set_reg_4,
332 : : .ctrlr_set_reg_8 = nvme_vfio_ctrlr_set_reg_8,
333 : : .ctrlr_get_reg_4 = nvme_vfio_ctrlr_get_reg_4,
334 : : .ctrlr_get_reg_8 = nvme_vfio_ctrlr_get_reg_8,
335 : :
336 : : .ctrlr_get_max_xfer_size = nvme_vfio_ctrlr_get_max_xfer_size,
337 : : .ctrlr_get_max_sges = nvme_vfio_ctrlr_get_max_sges,
338 : :
339 : : .ctrlr_create_io_qpair = nvme_pcie_ctrlr_create_io_qpair,
340 : : .ctrlr_delete_io_qpair = nvme_pcie_ctrlr_delete_io_qpair,
341 : : .ctrlr_connect_qpair = nvme_pcie_ctrlr_connect_qpair,
342 : : .ctrlr_disconnect_qpair = nvme_pcie_ctrlr_disconnect_qpair,
343 : : .admin_qpair_abort_aers = nvme_pcie_admin_qpair_abort_aers,
344 : :
345 : : .qpair_reset = nvme_pcie_qpair_reset,
346 : : .qpair_abort_reqs = nvme_pcie_qpair_abort_reqs,
347 : : .qpair_submit_request = nvme_pcie_qpair_submit_request,
348 : : .qpair_process_completions = nvme_pcie_qpair_process_completions,
349 : :
350 : : .poll_group_create = nvme_pcie_poll_group_create,
351 : : .poll_group_connect_qpair = nvme_pcie_poll_group_connect_qpair,
352 : : .poll_group_disconnect_qpair = nvme_pcie_poll_group_disconnect_qpair,
353 : : .poll_group_add = nvme_pcie_poll_group_add,
354 : : .poll_group_remove = nvme_pcie_poll_group_remove,
355 : : .poll_group_process_completions = nvme_pcie_poll_group_process_completions,
356 : : .poll_group_destroy = nvme_pcie_poll_group_destroy,
357 : : .poll_group_get_stats = nvme_pcie_poll_group_get_stats,
358 : : .poll_group_free_stats = nvme_pcie_poll_group_free_stats
359 : : };
360 : :
361 : 2408 : SPDK_NVME_TRANSPORT_REGISTER(vfio, &vfio_ops);
362 : :
363 : 2408 : SPDK_LOG_REGISTER_COMPONENT(nvme_vfio)
|