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 *
nvme_vfio_ctrlr(struct spdk_nvme_ctrlr * ctrlr)28 nvme_vfio_ctrlr(struct spdk_nvme_ctrlr *ctrlr)
29 {
30 struct nvme_pcie_ctrlr *pctrlr = nvme_pcie_ctrlr(ctrlr);
31
32 return SPDK_CONTAINEROF(pctrlr, struct nvme_vfio_ctrlr, pctrlr);
33 }
34
35 static volatile struct spdk_nvme_registers *
nvme_vfio_ctrlr_get_registers(struct spdk_nvme_ctrlr * ctrlr)36 nvme_vfio_ctrlr_get_registers(struct spdk_nvme_ctrlr *ctrlr)
37 {
38 struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
39
40 return vctrlr->pctrlr.regs;
41 }
42
43 static int
nvme_vfio_ctrlr_set_reg_4(struct spdk_nvme_ctrlr * ctrlr,uint32_t offset,uint32_t value)44 nvme_vfio_ctrlr_set_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t value)
45 {
46 struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
47
48 assert(offset <= sizeof(struct spdk_nvme_registers) - 4);
49 SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%x\n", ctrlr->trid.traddr, offset, value);
50
51 return spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
52 offset, 4, &value, true);
53 }
54
55 static int
nvme_vfio_ctrlr_set_reg_8(struct spdk_nvme_ctrlr * ctrlr,uint32_t offset,uint64_t value)56 nvme_vfio_ctrlr_set_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t value)
57 {
58 struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
59
60 assert(offset <= sizeof(struct spdk_nvme_registers) - 8);
61 SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%"PRIx64"\n", ctrlr->trid.traddr, offset,
62 value);
63
64 return spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
65 offset, 8, &value, true);
66 }
67
68 static int
nvme_vfio_ctrlr_get_reg_4(struct spdk_nvme_ctrlr * ctrlr,uint32_t offset,uint32_t * value)69 nvme_vfio_ctrlr_get_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t *value)
70 {
71 struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
72 int ret;
73
74 assert(offset <= sizeof(struct spdk_nvme_registers) - 4);
75
76 ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
77 offset, 4, value, false);
78 if (ret != 0) {
79 SPDK_ERRLOG("ctrlr %p, offset %x\n", ctrlr, offset);
80 return ret;
81 }
82
83 SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%x\n", ctrlr->trid.traddr, offset, *value);
84
85 return 0;
86 }
87
88 static int
nvme_vfio_ctrlr_get_reg_8(struct spdk_nvme_ctrlr * ctrlr,uint32_t offset,uint64_t * value)89 nvme_vfio_ctrlr_get_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t *value)
90 {
91 struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
92 int ret;
93
94 assert(offset <= sizeof(struct spdk_nvme_registers) - 8);
95
96 ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
97 offset, 8, value, false);
98 if (ret != 0) {
99 SPDK_ERRLOG("ctrlr %p, offset %x\n", ctrlr, offset);
100 return ret;
101 }
102
103 SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%"PRIx64"\n", ctrlr->trid.traddr, offset,
104 *value);
105
106 return 0;
107 }
108
109 static int
nvme_vfio_ctrlr_set_asq(struct spdk_nvme_ctrlr * ctrlr,uint64_t value)110 nvme_vfio_ctrlr_set_asq(struct spdk_nvme_ctrlr *ctrlr, uint64_t value)
111 {
112 return nvme_vfio_ctrlr_set_reg_8(ctrlr, offsetof(struct spdk_nvme_registers, asq),
113 value);
114 }
115
116 static int
nvme_vfio_ctrlr_set_acq(struct spdk_nvme_ctrlr * ctrlr,uint64_t value)117 nvme_vfio_ctrlr_set_acq(struct spdk_nvme_ctrlr *ctrlr, uint64_t value)
118 {
119 return nvme_vfio_ctrlr_set_reg_8(ctrlr, offsetof(struct spdk_nvme_registers, acq),
120 value);
121 }
122
123 static int
nvme_vfio_ctrlr_set_aqa(struct spdk_nvme_ctrlr * ctrlr,const union spdk_nvme_aqa_register * aqa)124 nvme_vfio_ctrlr_set_aqa(struct spdk_nvme_ctrlr *ctrlr, const union spdk_nvme_aqa_register *aqa)
125 {
126 return nvme_vfio_ctrlr_set_reg_4(ctrlr, offsetof(struct spdk_nvme_registers, aqa.raw),
127 aqa->raw);
128 }
129
130 static int
nvme_vfio_setup_bar0(struct nvme_vfio_ctrlr * vctrlr)131 nvme_vfio_setup_bar0(struct nvme_vfio_ctrlr *vctrlr)
132 {
133 void *doorbell;
134
135 doorbell = spdk_vfio_user_get_bar_addr(vctrlr->dev, 0, 0x1000, 0x1000);
136 if (!doorbell) {
137 return -EINVAL;
138 }
139
140 vctrlr->doorbell_base = (volatile uint32_t *)doorbell;
141 return 0;
142 }
143
144 static struct spdk_nvme_ctrlr *
nvme_vfio_ctrlr_construct(const struct spdk_nvme_transport_id * trid,const struct spdk_nvme_ctrlr_opts * opts,void * devhandle)145 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 uint16_t cmd_reg;
152 union spdk_nvme_cap_register cap;
153 int ret;
154 char ctrlr_path[PATH_MAX];
155
156 snprintf(ctrlr_path, sizeof(ctrlr_path), "%s/cntrl", trid->traddr);
157 ret = access(ctrlr_path, F_OK);
158 if (ret != 0) {
159 SPDK_ERRLOG("Access path %s failed\n", ctrlr_path);
160 return NULL;
161 }
162
163 vctrlr = calloc(1, sizeof(*vctrlr));
164 if (!vctrlr) {
165 return NULL;
166 }
167
168 vctrlr->dev = spdk_vfio_user_setup(ctrlr_path);
169 if (!vctrlr->dev) {
170 SPDK_ERRLOG("Error to setup vfio device\n");
171 free(vctrlr);
172 return NULL;
173 }
174
175 ret = nvme_vfio_setup_bar0(vctrlr);
176 if (ret != 0) {
177 SPDK_ERRLOG("Error to get device BAR0\n");
178 goto exit;
179 }
180
181 pctrlr = &vctrlr->pctrlr;
182 pctrlr->doorbell_base = vctrlr->doorbell_base;
183 pctrlr->ctrlr.is_removed = false;
184 pctrlr->ctrlr.opts = *opts;
185 pctrlr->ctrlr.trid = *trid;
186 pctrlr->ctrlr.opts.use_cmb_sqs = false;
187 pctrlr->ctrlr.opts.admin_queue_size = spdk_max(pctrlr->ctrlr.opts.admin_queue_size,
188 NVME_PCIE_MIN_ADMIN_QUEUE_SIZE);
189
190 ret = nvme_ctrlr_construct(&pctrlr->ctrlr);
191 if (ret != 0) {
192 goto exit;
193 }
194
195 /* Enable PCI busmaster and disable INTx */
196 ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_CONFIG_REGION_INDEX, 4, 2,
197 &cmd_reg, false);
198 if (ret != 0) {
199 nvme_ctrlr_destruct(&pctrlr->ctrlr);
200 SPDK_ERRLOG("Read PCI CMD REG failed\n");
201 goto exit;
202 }
203 cmd_reg |= 0x404;
204 ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_CONFIG_REGION_INDEX, 4, 2,
205 &cmd_reg, true);
206 if (ret != 0) {
207 nvme_ctrlr_destruct(&pctrlr->ctrlr);
208 SPDK_ERRLOG("Write PCI CMD REG failed\n");
209 goto exit;
210 }
211
212 if (nvme_ctrlr_get_cap(&pctrlr->ctrlr, &cap)) {
213 nvme_ctrlr_destruct(&pctrlr->ctrlr);
214 SPDK_ERRLOG("get_cap() failed\n");
215 goto exit;
216 }
217
218 /* Doorbell stride is 2 ^ (dstrd + 2),
219 * but we want multiples of 4, so drop the + 2 */
220 pctrlr->doorbell_stride_u32 = 1 << cap.bits.dstrd;
221
222 ret = nvme_pcie_ctrlr_construct_admin_qpair(&pctrlr->ctrlr, pctrlr->ctrlr.opts.admin_queue_size);
223 if (ret != 0) {
224 nvme_ctrlr_destruct(&pctrlr->ctrlr);
225 goto exit;
226 }
227
228 /* Construct the primary process properties */
229 ret = nvme_ctrlr_add_process(&pctrlr->ctrlr, 0);
230 if (ret != 0) {
231 nvme_ctrlr_destruct(&pctrlr->ctrlr);
232 goto exit;
233 }
234
235 return &pctrlr->ctrlr;
236
237 exit:
238 spdk_vfio_user_release(vctrlr->dev);
239 free(vctrlr);
240 return NULL;
241 }
242
243 static int
nvme_vfio_ctrlr_scan(struct spdk_nvme_probe_ctx * probe_ctx,bool direct_connect)244 nvme_vfio_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx,
245 bool direct_connect)
246 {
247 int ret;
248
249 if (probe_ctx->trid.trtype != SPDK_NVME_TRANSPORT_VFIOUSER) {
250 SPDK_ERRLOG("Can only use SPDK_NVME_TRANSPORT_VFIOUSER");
251 return -EINVAL;
252 }
253
254 ret = access(probe_ctx->trid.traddr, F_OK);
255 if (ret != 0) {
256 SPDK_ERRLOG("Error to access file %s\n", probe_ctx->trid.traddr);
257 return ret;
258 }
259 SPDK_DEBUGLOG(nvme_vfio, "Scan controller : %s\n", probe_ctx->trid.traddr);
260
261 return nvme_ctrlr_probe(&probe_ctx->trid, probe_ctx, NULL);
262 }
263
264 static int
nvme_vfio_ctrlr_enable(struct spdk_nvme_ctrlr * ctrlr)265 nvme_vfio_ctrlr_enable(struct spdk_nvme_ctrlr *ctrlr)
266 {
267 struct nvme_pcie_qpair *vadminq = nvme_pcie_qpair(ctrlr->adminq);
268 union spdk_nvme_aqa_register aqa;
269
270 if (nvme_vfio_ctrlr_set_asq(ctrlr, vadminq->cmd_bus_addr)) {
271 SPDK_ERRLOG("set_asq() failed\n");
272 return -EIO;
273 }
274
275 if (nvme_vfio_ctrlr_set_acq(ctrlr, vadminq->cpl_bus_addr)) {
276 SPDK_ERRLOG("set_acq() failed\n");
277 return -EIO;
278 }
279
280 aqa.raw = 0;
281 /* acqs and asqs are 0-based. */
282 aqa.bits.acqs = nvme_pcie_qpair(ctrlr->adminq)->num_entries - 1;
283 aqa.bits.asqs = nvme_pcie_qpair(ctrlr->adminq)->num_entries - 1;
284
285 if (nvme_vfio_ctrlr_set_aqa(ctrlr, &aqa)) {
286 SPDK_ERRLOG("set_aqa() failed\n");
287 return -EIO;
288 }
289
290 return 0;
291 }
292
293 static int
nvme_vfio_ctrlr_destruct(struct spdk_nvme_ctrlr * ctrlr)294 nvme_vfio_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
295 {
296 struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
297
298 if (ctrlr->adminq) {
299 nvme_pcie_qpair_destroy(ctrlr->adminq);
300 }
301
302 nvme_ctrlr_destruct_finish(ctrlr);
303
304 spdk_vfio_user_release(vctrlr->dev);
305 free(vctrlr);
306
307 return 0;
308 }
309
310 static uint32_t
nvme_vfio_ctrlr_get_max_xfer_size(struct spdk_nvme_ctrlr * ctrlr)311 nvme_vfio_ctrlr_get_max_xfer_size(struct spdk_nvme_ctrlr *ctrlr)
312 {
313 return NVME_MAX_XFER_SIZE;
314 }
315
316 static uint16_t
nvme_vfio_ctrlr_get_max_sges(struct spdk_nvme_ctrlr * ctrlr)317 nvme_vfio_ctrlr_get_max_sges(struct spdk_nvme_ctrlr *ctrlr)
318 {
319 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 SPDK_NVME_TRANSPORT_REGISTER(vfio, &vfio_ops);
362
363 SPDK_LOG_REGISTER_COMPONENT(nvme_vfio)
364