xref: /spdk/lib/nvme/nvme_vfio_user.c (revision 7bf78abb5cd310089ef77499275f8ae270e87e9b)
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