xref: /spdk/lib/env_dpdk/pci.c (revision 65e5bbdc059f740cbbe8271ddec0929ea9b9624e)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "env_internal.h"
35 
36 #include "spdk/env.h"
37 
38 #define SYSFS_PCI_DRIVERS	"/sys/bus/pci/drivers"
39 
40 #define PCI_CFG_SIZE		256
41 #define PCI_EXT_CAP_ID_SN	0x03
42 
43 int
44 spdk_pci_device_init(struct rte_pci_driver *driver,
45 		     struct rte_pci_device *device)
46 {
47 	struct spdk_pci_enum_ctx *ctx = (struct spdk_pci_enum_ctx *)driver;
48 	int rc;
49 
50 	if (!ctx->cb_fn) {
51 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4)
52 		rte_pci_unmap_device(device);
53 #elif RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0)
54 		rte_eal_pci_unmap_device(device);
55 #endif
56 
57 		/* Return a positive value to indicate that this device does not belong to this driver, but
58 		 * this isn't an error. */
59 		return 1;
60 	}
61 
62 	rc = ctx->cb_fn(ctx->cb_arg, (struct spdk_pci_device *)device);
63 	if (rc != 0) {
64 		return rc;
65 	}
66 
67 	spdk_vtophys_pci_device_added(device);
68 	return 0;
69 }
70 
71 int
72 spdk_pci_device_fini(struct rte_pci_device *device)
73 {
74 	spdk_vtophys_pci_device_removed(device);
75 	return 0;
76 }
77 
78 void
79 spdk_pci_device_detach(struct spdk_pci_device *device)
80 {
81 #if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0)
82 #if RTE_VERSION < RTE_VERSION_NUM(17, 05, 0, 0)
83 	rte_eal_device_remove(&device->device);
84 #endif
85 #endif
86 
87 #if RTE_VERSION >= RTE_VERSION_NUM(17, 11, 0, 3)
88 	struct spdk_pci_addr	addr;
89 	char			bdf[32];
90 
91 	addr.domain = device->addr.domain;
92 	addr.bus = device->addr.bus;
93 	addr.dev = device->addr.devid;
94 	addr.func = device->addr.function;
95 
96 	spdk_pci_addr_fmt(bdf, sizeof(bdf), &addr);
97 	if (rte_eal_dev_detach(&device->device) < 0) {
98 		fprintf(stderr, "Failed to detach PCI device %s (device already removed?).\n", bdf);
99 	}
100 #elif RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4)
101 	rte_pci_detach(&device->addr);
102 #else
103 	rte_eal_pci_detach(&device->addr);
104 #endif
105 }
106 
107 int
108 spdk_pci_device_attach(struct spdk_pci_enum_ctx *ctx,
109 		       spdk_pci_enum_cb enum_cb,
110 		       void *enum_ctx, struct spdk_pci_addr *pci_address)
111 {
112 #if RTE_VERSION >= RTE_VERSION_NUM(17, 11, 0, 3)
113 	char				bdf[32];
114 
115 	spdk_pci_addr_fmt(bdf, sizeof(bdf), pci_address);
116 #else
117 	struct rte_pci_addr		addr;
118 
119 	addr.domain = pci_address->domain;
120 	addr.bus = pci_address->bus;
121 	addr.devid = pci_address->dev;
122 	addr.function = pci_address->func;
123 #endif
124 
125 	pthread_mutex_lock(&ctx->mtx);
126 
127 	if (!ctx->is_registered) {
128 		ctx->is_registered = true;
129 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4)
130 		rte_pci_register(&ctx->driver);
131 #else
132 		rte_eal_pci_register(&ctx->driver);
133 #endif
134 	}
135 
136 	ctx->cb_fn = enum_cb;
137 	ctx->cb_arg = enum_ctx;
138 
139 #if RTE_VERSION >= RTE_VERSION_NUM(17, 11, 0, 3)
140 	if (rte_eal_dev_attach(bdf, "") != 0) {
141 #elif RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4)
142 	if (rte_pci_probe_one(&addr) != 0) {
143 #else
144 	if (rte_eal_pci_probe_one(&addr) != 0) {
145 #endif
146 		ctx->cb_arg = NULL;
147 		ctx->cb_fn = NULL;
148 		pthread_mutex_unlock(&ctx->mtx);
149 		return -1;
150 	}
151 
152 	ctx->cb_arg = NULL;
153 	ctx->cb_fn = NULL;
154 	pthread_mutex_unlock(&ctx->mtx);
155 
156 	return 0;
157 }
158 
159 /* Note: You can call spdk_pci_enumerate from more than one thread
160  *       simultaneously safely, but you cannot call spdk_pci_enumerate
161  *       and rte_eal_pci_probe simultaneously.
162  */
163 int
164 spdk_pci_enumerate(struct spdk_pci_enum_ctx *ctx,
165 		   spdk_pci_enum_cb enum_cb,
166 		   void *enum_ctx)
167 {
168 	pthread_mutex_lock(&ctx->mtx);
169 
170 	if (!ctx->is_registered) {
171 		ctx->is_registered = true;
172 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4)
173 		rte_pci_register(&ctx->driver);
174 #else
175 		rte_eal_pci_register(&ctx->driver);
176 #endif
177 	}
178 
179 	ctx->cb_fn = enum_cb;
180 	ctx->cb_arg = enum_ctx;
181 
182 #if RTE_VERSION >= RTE_VERSION_NUM(17, 11, 0, 3)
183 	if (rte_bus_probe() != 0) {
184 #elif RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4)
185 	if (rte_pci_probe() != 0) {
186 #else
187 	if (rte_eal_pci_probe() != 0) {
188 #endif
189 		ctx->cb_arg = NULL;
190 		ctx->cb_fn = NULL;
191 		pthread_mutex_unlock(&ctx->mtx);
192 		return -1;
193 	}
194 
195 	ctx->cb_arg = NULL;
196 	ctx->cb_fn = NULL;
197 	pthread_mutex_unlock(&ctx->mtx);
198 
199 	return 0;
200 }
201 
202 int
203 spdk_pci_device_map_bar(struct spdk_pci_device *device, uint32_t bar,
204 			void **mapped_addr, uint64_t *phys_addr, uint64_t *size)
205 {
206 	struct rte_pci_device *dev = device;
207 
208 	*mapped_addr = dev->mem_resource[bar].addr;
209 	*phys_addr = (uint64_t)dev->mem_resource[bar].phys_addr;
210 	*size = (uint64_t)dev->mem_resource[bar].len;
211 
212 	return 0;
213 }
214 
215 int
216 spdk_pci_device_unmap_bar(struct spdk_pci_device *device, uint32_t bar, void *addr)
217 {
218 	return 0;
219 }
220 
221 uint32_t
222 spdk_pci_device_get_domain(struct spdk_pci_device *dev)
223 {
224 	return dev->addr.domain;
225 }
226 
227 uint8_t
228 spdk_pci_device_get_bus(struct spdk_pci_device *dev)
229 {
230 	return dev->addr.bus;
231 }
232 
233 uint8_t
234 spdk_pci_device_get_dev(struct spdk_pci_device *dev)
235 {
236 	return dev->addr.devid;
237 }
238 
239 uint8_t
240 spdk_pci_device_get_func(struct spdk_pci_device *dev)
241 {
242 	return dev->addr.function;
243 }
244 
245 uint16_t
246 spdk_pci_device_get_vendor_id(struct spdk_pci_device *dev)
247 {
248 	return dev->id.vendor_id;
249 }
250 
251 uint16_t
252 spdk_pci_device_get_device_id(struct spdk_pci_device *dev)
253 {
254 	return dev->id.device_id;
255 }
256 
257 uint16_t
258 spdk_pci_device_get_subvendor_id(struct spdk_pci_device *dev)
259 {
260 	return dev->id.subsystem_vendor_id;
261 }
262 
263 uint16_t
264 spdk_pci_device_get_subdevice_id(struct spdk_pci_device *dev)
265 {
266 	return dev->id.subsystem_device_id;
267 }
268 
269 struct spdk_pci_id
270 spdk_pci_device_get_id(struct spdk_pci_device *pci_dev)
271 {
272 	struct spdk_pci_id pci_id;
273 
274 	pci_id.vendor_id = spdk_pci_device_get_vendor_id(pci_dev);
275 	pci_id.device_id = spdk_pci_device_get_device_id(pci_dev);
276 	pci_id.subvendor_id = spdk_pci_device_get_subvendor_id(pci_dev);
277 	pci_id.subdevice_id = spdk_pci_device_get_subdevice_id(pci_dev);
278 
279 	return pci_id;
280 }
281 
282 int
283 spdk_pci_device_get_socket_id(struct spdk_pci_device *pci_dev)
284 {
285 #if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0)
286 	return pci_dev->device.numa_node;
287 #else
288 	return pci_dev->numa_node;
289 #endif
290 }
291 
292 int
293 spdk_pci_device_cfg_read(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset)
294 {
295 	int rc;
296 
297 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4)
298 	rc = rte_pci_read_config(dev, value, len, offset);
299 #else
300 	rc = rte_eal_pci_read_config(dev, value, len, offset);
301 #endif
302 	return (rc > 0 && (uint32_t) rc == len) ? 0 : -1;
303 }
304 
305 int
306 spdk_pci_device_cfg_write(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset)
307 {
308 	int rc;
309 
310 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4)
311 	rc = rte_pci_write_config(dev, value, len, offset);
312 #else
313 	rc = rte_eal_pci_write_config(dev, value, len, offset);
314 #endif
315 	return (rc > 0 && (uint32_t) rc == len) ? 0 : -1;
316 }
317 
318 int
319 spdk_pci_device_cfg_read8(struct spdk_pci_device *dev, uint8_t *value, uint32_t offset)
320 {
321 	return spdk_pci_device_cfg_read(dev, value, 1, offset);
322 }
323 
324 int
325 spdk_pci_device_cfg_write8(struct spdk_pci_device *dev, uint8_t value, uint32_t offset)
326 {
327 	return spdk_pci_device_cfg_write(dev, &value, 1, offset);
328 }
329 
330 int
331 spdk_pci_device_cfg_read16(struct spdk_pci_device *dev, uint16_t *value, uint32_t offset)
332 {
333 	return spdk_pci_device_cfg_read(dev, value, 2, offset);
334 }
335 
336 int
337 spdk_pci_device_cfg_write16(struct spdk_pci_device *dev, uint16_t value, uint32_t offset)
338 {
339 	return spdk_pci_device_cfg_write(dev, &value, 2, offset);
340 }
341 
342 int
343 spdk_pci_device_cfg_read32(struct spdk_pci_device *dev, uint32_t *value, uint32_t offset)
344 {
345 	return spdk_pci_device_cfg_read(dev, value, 4, offset);
346 }
347 
348 int
349 spdk_pci_device_cfg_write32(struct spdk_pci_device *dev, uint32_t value, uint32_t offset)
350 {
351 	return spdk_pci_device_cfg_write(dev, &value, 4, offset);
352 }
353 
354 int
355 spdk_pci_device_get_serial_number(struct spdk_pci_device *dev, char *sn, size_t len)
356 {
357 	int err;
358 	uint32_t pos, header = 0;
359 	uint32_t i, buf[2];
360 
361 	if (len < 17) {
362 		return -1;
363 	}
364 
365 	err = spdk_pci_device_cfg_read32(dev, &header, PCI_CFG_SIZE);
366 	if (err || !header) {
367 		return -1;
368 	}
369 
370 	pos = PCI_CFG_SIZE;
371 	while (1) {
372 		if ((header & 0x0000ffff) == PCI_EXT_CAP_ID_SN) {
373 			if (pos) {
374 				/* skip the header */
375 				pos += 4;
376 				for (i = 0; i < 2; i++) {
377 					err = spdk_pci_device_cfg_read32(dev, &buf[i], pos + 4 * i);
378 					if (err) {
379 						return -1;
380 					}
381 				}
382 				snprintf(sn, len, "%08x%08x", buf[1], buf[0]);
383 				return 0;
384 			}
385 		}
386 		pos = (header >> 20) & 0xffc;
387 		/* 0 if no other items exist */
388 		if (pos < PCI_CFG_SIZE) {
389 			return -1;
390 		}
391 		err = spdk_pci_device_cfg_read32(dev, &header, pos);
392 		if (err) {
393 			return -1;
394 		}
395 	}
396 	return -1;
397 }
398 
399 struct spdk_pci_addr
400 spdk_pci_device_get_addr(struct spdk_pci_device *pci_dev)
401 {
402 	struct spdk_pci_addr pci_addr;
403 
404 	pci_addr.domain = spdk_pci_device_get_domain(pci_dev);
405 	pci_addr.bus = spdk_pci_device_get_bus(pci_dev);
406 	pci_addr.dev = spdk_pci_device_get_dev(pci_dev);
407 	pci_addr.func = spdk_pci_device_get_func(pci_dev);
408 
409 	return pci_addr;
410 }
411 
412 int
413 spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr *a2)
414 {
415 	if (a1->domain > a2->domain) {
416 		return 1;
417 	} else if (a1->domain < a2->domain) {
418 		return -1;
419 	} else if (a1->bus > a2->bus) {
420 		return 1;
421 	} else if (a1->bus < a2->bus) {
422 		return -1;
423 	} else if (a1->dev > a2->dev) {
424 		return 1;
425 	} else if (a1->dev < a2->dev) {
426 		return -1;
427 	} else if (a1->func > a2->func) {
428 		return 1;
429 	} else if (a1->func < a2->func) {
430 		return -1;
431 	}
432 
433 	return 0;
434 }
435 
436 #ifdef __linux__
437 int
438 spdk_pci_device_claim(const struct spdk_pci_addr *pci_addr)
439 {
440 	int dev_fd;
441 	char dev_name[64];
442 	int pid;
443 	void *dev_map;
444 	struct flock pcidev_lock = {
445 		.l_type = F_WRLCK,
446 		.l_whence = SEEK_SET,
447 		.l_start = 0,
448 		.l_len = 0,
449 	};
450 
451 	snprintf(dev_name, sizeof(dev_name), "/tmp/spdk_pci_lock_%04x:%02x:%02x.%x", pci_addr->domain,
452 		 pci_addr->bus,
453 		 pci_addr->dev, pci_addr->func);
454 
455 	dev_fd = open(dev_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
456 	if (dev_fd == -1) {
457 		fprintf(stderr, "could not open %s\n", dev_name);
458 		return -1;
459 	}
460 
461 	if (ftruncate(dev_fd, sizeof(int)) != 0) {
462 		fprintf(stderr, "could not truncate %s\n", dev_name);
463 		close(dev_fd);
464 		return -1;
465 	}
466 
467 	dev_map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,
468 		       MAP_SHARED, dev_fd, 0);
469 	if (dev_map == MAP_FAILED) {
470 		fprintf(stderr, "could not mmap dev %s (%d)\n", dev_name, errno);
471 		close(dev_fd);
472 		return -1;
473 	}
474 
475 	if (fcntl(dev_fd, F_SETLK, &pcidev_lock) != 0) {
476 		pid = *(int *)dev_map;
477 		fprintf(stderr, "Cannot create lock on device %s, probably"
478 			" process %d has claimed it\n", dev_name, pid);
479 		munmap(dev_map, sizeof(int));
480 		close(dev_fd);
481 		return -1;
482 	}
483 
484 	*(int *)dev_map = (int)getpid();
485 	munmap(dev_map, sizeof(int));
486 	/* Keep dev_fd open to maintain the lock. */
487 	return dev_fd;
488 }
489 #endif /* __linux__ */
490 
491 #ifdef __FreeBSD__
492 int
493 spdk_pci_device_claim(const struct spdk_pci_addr *pci_addr)
494 {
495 	/* TODO */
496 	return 0;
497 }
498 #endif /* __FreeBSD__ */
499 
500 int
501 spdk_pci_addr_parse(struct spdk_pci_addr *addr, const char *bdf)
502 {
503 	unsigned domain, bus, dev, func;
504 
505 	if (addr == NULL || bdf == NULL) {
506 		return -EINVAL;
507 	}
508 
509 	if ((sscanf(bdf, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) ||
510 	    (sscanf(bdf, "%x.%x.%x.%x", &domain, &bus, &dev, &func) == 4)) {
511 		/* Matched a full address - all variables are initialized */
512 	} else if (sscanf(bdf, "%x:%x:%x", &domain, &bus, &dev) == 3) {
513 		func = 0;
514 	} else if ((sscanf(bdf, "%x:%x.%x", &bus, &dev, &func) == 3) ||
515 		   (sscanf(bdf, "%x.%x.%x", &bus, &dev, &func) == 3)) {
516 		domain = 0;
517 	} else if ((sscanf(bdf, "%x:%x", &bus, &dev) == 2) ||
518 		   (sscanf(bdf, "%x.%x", &bus, &dev) == 2)) {
519 		domain = 0;
520 		func = 0;
521 	} else {
522 		return -EINVAL;
523 	}
524 
525 	if (bus > 0xFF || dev > 0x1F || func > 7) {
526 		return -EINVAL;
527 	}
528 
529 	addr->domain = domain;
530 	addr->bus = bus;
531 	addr->dev = dev;
532 	addr->func = func;
533 
534 	return 0;
535 }
536 
537 int
538 spdk_pci_addr_fmt(char *bdf, size_t sz, const struct spdk_pci_addr *addr)
539 {
540 	int rc;
541 
542 	rc = snprintf(bdf, sz, "%04x:%02x:%02x.%x",
543 		      addr->domain, addr->bus,
544 		      addr->dev, addr->func);
545 
546 	if (rc > 0 && (size_t)rc < sz) {
547 		return 0;
548 	}
549 
550 	return -1;
551 }
552