xref: /dpdk/drivers/bus/pci/pci_common_uio.c (revision 847d78fb9530fff401bf167298aad22766a1f04a)
15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
25566a3e3SBruce Richardson  * Copyright(c) 2010-2015 Intel Corporation
3c752998bSGaetan Rivet  */
4c752998bSGaetan Rivet 
5c752998bSGaetan Rivet #include <fcntl.h>
6c752998bSGaetan Rivet #include <string.h>
7c752998bSGaetan Rivet #include <unistd.h>
8c752998bSGaetan Rivet #include <sys/types.h>
9c752998bSGaetan Rivet #include <sys/stat.h>
10c752998bSGaetan Rivet #include <sys/mman.h>
11c752998bSGaetan Rivet 
12c752998bSGaetan Rivet #include <rte_eal.h>
13c752998bSGaetan Rivet #include <rte_pci.h>
14c752998bSGaetan Rivet #include <rte_bus_pci.h>
15c752998bSGaetan Rivet #include <rte_tailq.h>
16c752998bSGaetan Rivet #include <rte_log.h>
17c752998bSGaetan Rivet #include <rte_malloc.h>
18c752998bSGaetan Rivet 
19c752998bSGaetan Rivet #include "private.h"
20c752998bSGaetan Rivet 
21c752998bSGaetan Rivet static struct rte_tailq_elem rte_uio_tailq = {
22c752998bSGaetan Rivet 	.name = "UIO_RESOURCE_LIST",
23c752998bSGaetan Rivet };
24c752998bSGaetan Rivet EAL_REGISTER_TAILQ(rte_uio_tailq)
25c752998bSGaetan Rivet 
26c752998bSGaetan Rivet static int
27c752998bSGaetan Rivet pci_uio_map_secondary(struct rte_pci_device *dev)
28c752998bSGaetan Rivet {
299e0a0e38SZerun Fu 	int fd, i = 0, j, res_idx;
30c752998bSGaetan Rivet 	struct mapped_pci_resource *uio_res;
31c752998bSGaetan Rivet 	struct mapped_pci_res_list *uio_res_list =
32c752998bSGaetan Rivet 			RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list);
33c752998bSGaetan Rivet 
34c752998bSGaetan Rivet 	TAILQ_FOREACH(uio_res, uio_res_list, next) {
35c752998bSGaetan Rivet 
36c752998bSGaetan Rivet 		/* skip this element if it doesn't match our PCI address */
370e3ef055SGaetan Rivet 		if (rte_pci_addr_cmp(&uio_res->pci_addr, &dev->addr))
38c752998bSGaetan Rivet 			continue;
39c752998bSGaetan Rivet 
409e0a0e38SZerun Fu 		/* Map all BARs */
419e0a0e38SZerun Fu 		for (res_idx = 0; res_idx != PCI_MAX_RESOURCE; res_idx++) {
429e0a0e38SZerun Fu 			/* skip empty BAR */
439e0a0e38SZerun Fu 			if (dev->mem_resource[res_idx].phys_addr == 0)
449e0a0e38SZerun Fu 				continue;
459e0a0e38SZerun Fu 
469e0a0e38SZerun Fu 			if (i >= uio_res->nb_maps)
479e0a0e38SZerun Fu 				return -1;
489e0a0e38SZerun Fu 
49c752998bSGaetan Rivet 			/*
50c752998bSGaetan Rivet 			 * open devname, to mmap it
51c752998bSGaetan Rivet 			 */
52c752998bSGaetan Rivet 			fd = open(uio_res->maps[i].path, O_RDWR);
53c752998bSGaetan Rivet 			if (fd < 0) {
54849f773bSDavid Marchand 				PCI_LOG(ERR, "Cannot open %s: %s",
55c752998bSGaetan Rivet 					uio_res->maps[i].path, strerror(errno));
56c752998bSGaetan Rivet 				return -1;
57c752998bSGaetan Rivet 			}
58c752998bSGaetan Rivet 
59c752998bSGaetan Rivet 			void *mapaddr = pci_map_resource(uio_res->maps[i].addr,
60c752998bSGaetan Rivet 					fd, (off_t)uio_res->maps[i].offset,
61c752998bSGaetan Rivet 					(size_t)uio_res->maps[i].size, 0);
6220b6fd65SStephen Hemminger 
6320b6fd65SStephen Hemminger 			/* fd is not needed in secondary process, close it */
64c752998bSGaetan Rivet 			close(fd);
65c752998bSGaetan Rivet 			if (mapaddr != uio_res->maps[i].addr) {
66849f773bSDavid Marchand 				PCI_LOG(ERR, "Cannot mmap device resource file %s to address: %p",
67c752998bSGaetan Rivet 					uio_res->maps[i].path,
68c752998bSGaetan Rivet 					uio_res->maps[i].addr);
69e200535cSDavid Marchand 				if (mapaddr != NULL) {
70c752998bSGaetan Rivet 					/* unmap addrs correctly mapped */
71c752998bSGaetan Rivet 					for (j = 0; j < i; j++)
72c752998bSGaetan Rivet 						pci_unmap_resource(
73c752998bSGaetan Rivet 							uio_res->maps[j].addr,
74c752998bSGaetan Rivet 							(size_t)uio_res->maps[j].size);
75c752998bSGaetan Rivet 					/* unmap addr wrongly mapped */
76c752998bSGaetan Rivet 					pci_unmap_resource(mapaddr,
77c752998bSGaetan Rivet 						(size_t)uio_res->maps[i].size);
78c752998bSGaetan Rivet 				}
79c752998bSGaetan Rivet 				return -1;
80c752998bSGaetan Rivet 			}
819e0a0e38SZerun Fu 			dev->mem_resource[res_idx].addr = mapaddr;
829e0a0e38SZerun Fu 
839e0a0e38SZerun Fu 			i++;
84c752998bSGaetan Rivet 		}
85c752998bSGaetan Rivet 		return 0;
86c752998bSGaetan Rivet 	}
87c752998bSGaetan Rivet 
88849f773bSDavid Marchand 	PCI_LOG(ERR, "Cannot find resource for device");
89c752998bSGaetan Rivet 	return 1;
90c752998bSGaetan Rivet }
91c752998bSGaetan Rivet 
92c752998bSGaetan Rivet /* map the PCI resource of a PCI device in virtual memory */
93c752998bSGaetan Rivet int
94c752998bSGaetan Rivet pci_uio_map_resource(struct rte_pci_device *dev)
95c752998bSGaetan Rivet {
96c752998bSGaetan Rivet 	int i, map_idx = 0, ret;
97c752998bSGaetan Rivet 	uint64_t phaddr;
98c752998bSGaetan Rivet 	struct mapped_pci_resource *uio_res = NULL;
99c752998bSGaetan Rivet 	struct mapped_pci_res_list *uio_res_list =
100c752998bSGaetan Rivet 		RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list);
101c752998bSGaetan Rivet 
102d61138d4SHarman Kalra 	if (rte_intr_fd_set(dev->intr_handle, -1))
103d61138d4SHarman Kalra 		return -1;
104d61138d4SHarman Kalra 
105d61138d4SHarman Kalra 	if (rte_intr_dev_fd_set(dev->intr_handle, -1))
106d61138d4SHarman Kalra 		return -1;
107c752998bSGaetan Rivet 
108c752998bSGaetan Rivet 	/* allocate uio resource */
109c752998bSGaetan Rivet 	ret = pci_uio_alloc_resource(dev, &uio_res);
110c752998bSGaetan Rivet 	if (ret)
111c752998bSGaetan Rivet 		return ret;
112c752998bSGaetan Rivet 
113*847d78fbSZerun Fu 	/* secondary processes - use already recorded details */
114*847d78fbSZerun Fu 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
115*847d78fbSZerun Fu 		return pci_uio_map_secondary(dev);
116*847d78fbSZerun Fu 
117c752998bSGaetan Rivet 	/* Map all BARs */
118c752998bSGaetan Rivet 	for (i = 0; i != PCI_MAX_RESOURCE; i++) {
119c752998bSGaetan Rivet 		/* skip empty BAR */
120c752998bSGaetan Rivet 		phaddr = dev->mem_resource[i].phys_addr;
121c752998bSGaetan Rivet 		if (phaddr == 0)
122c752998bSGaetan Rivet 			continue;
123c752998bSGaetan Rivet 
124c752998bSGaetan Rivet 		ret = pci_uio_map_resource_by_index(dev, i,
125c752998bSGaetan Rivet 				uio_res, map_idx);
126c752998bSGaetan Rivet 		if (ret)
127c752998bSGaetan Rivet 			goto error;
128c752998bSGaetan Rivet 
129c752998bSGaetan Rivet 		map_idx++;
130c752998bSGaetan Rivet 	}
131c752998bSGaetan Rivet 
132c752998bSGaetan Rivet 	uio_res->nb_maps = map_idx;
133c752998bSGaetan Rivet 
134c752998bSGaetan Rivet 	TAILQ_INSERT_TAIL(uio_res_list, uio_res, next);
135c752998bSGaetan Rivet 
136c752998bSGaetan Rivet 	return 0;
137c752998bSGaetan Rivet error:
138c752998bSGaetan Rivet 	for (i = 0; i < map_idx; i++) {
139c752998bSGaetan Rivet 		pci_unmap_resource(uio_res->maps[i].addr,
140c752998bSGaetan Rivet 				(size_t)uio_res->maps[i].size);
141c752998bSGaetan Rivet 		rte_free(uio_res->maps[i].path);
142c752998bSGaetan Rivet 	}
143c752998bSGaetan Rivet 	pci_uio_free_resource(dev, uio_res);
144c752998bSGaetan Rivet 	return -1;
145c752998bSGaetan Rivet }
146c752998bSGaetan Rivet 
147c752998bSGaetan Rivet static void
148c752998bSGaetan Rivet pci_uio_unmap(struct mapped_pci_resource *uio_res)
149c752998bSGaetan Rivet {
150c752998bSGaetan Rivet 	int i;
151c752998bSGaetan Rivet 
152c752998bSGaetan Rivet 	if (uio_res == NULL)
153c752998bSGaetan Rivet 		return;
154c752998bSGaetan Rivet 
155c752998bSGaetan Rivet 	for (i = 0; i != uio_res->nb_maps; i++) {
156c752998bSGaetan Rivet 		pci_unmap_resource(uio_res->maps[i].addr,
157c752998bSGaetan Rivet 				(size_t)uio_res->maps[i].size);
158c752998bSGaetan Rivet 		if (rte_eal_process_type() == RTE_PROC_PRIMARY)
159c752998bSGaetan Rivet 			rte_free(uio_res->maps[i].path);
160c752998bSGaetan Rivet 	}
161c752998bSGaetan Rivet }
162c752998bSGaetan Rivet 
163b01dc3daSJeff Guo /* remap the PCI resource of a PCI device in anonymous virtual memory */
164b01dc3daSJeff Guo int
165b01dc3daSJeff Guo pci_uio_remap_resource(struct rte_pci_device *dev)
166b01dc3daSJeff Guo {
167b01dc3daSJeff Guo 	int i;
168b01dc3daSJeff Guo 	void *map_address;
169b01dc3daSJeff Guo 
170b01dc3daSJeff Guo 	if (dev == NULL)
171b01dc3daSJeff Guo 		return -1;
172b01dc3daSJeff Guo 
173b01dc3daSJeff Guo 	/* Remap all BARs */
174b01dc3daSJeff Guo 	for (i = 0; i != PCI_MAX_RESOURCE; i++) {
175b01dc3daSJeff Guo 		/* skip empty BAR */
176b01dc3daSJeff Guo 		if (dev->mem_resource[i].phys_addr == 0)
177b01dc3daSJeff Guo 			continue;
178b01dc3daSJeff Guo 		map_address = mmap(dev->mem_resource[i].addr,
179b01dc3daSJeff Guo 				(size_t)dev->mem_resource[i].len,
180b01dc3daSJeff Guo 				PROT_READ | PROT_WRITE,
181b01dc3daSJeff Guo 				MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
182b01dc3daSJeff Guo 		if (map_address == MAP_FAILED) {
183849f773bSDavid Marchand 			PCI_LOG(ERR, "Cannot remap resource for device %s", dev->name);
184b01dc3daSJeff Guo 			return -1;
185b01dc3daSJeff Guo 		}
186849f773bSDavid Marchand 		PCI_LOG(INFO, "Successful remap resource for device %s", dev->name);
187b01dc3daSJeff Guo 	}
188b01dc3daSJeff Guo 
189b01dc3daSJeff Guo 	return 0;
190b01dc3daSJeff Guo }
191b01dc3daSJeff Guo 
192c752998bSGaetan Rivet static struct mapped_pci_resource *
193c752998bSGaetan Rivet pci_uio_find_resource(struct rte_pci_device *dev)
194c752998bSGaetan Rivet {
195c752998bSGaetan Rivet 	struct mapped_pci_resource *uio_res;
196c752998bSGaetan Rivet 	struct mapped_pci_res_list *uio_res_list =
197c752998bSGaetan Rivet 			RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list);
198c752998bSGaetan Rivet 
199c752998bSGaetan Rivet 	if (dev == NULL)
200c752998bSGaetan Rivet 		return NULL;
201c752998bSGaetan Rivet 
202c752998bSGaetan Rivet 	TAILQ_FOREACH(uio_res, uio_res_list, next) {
203c752998bSGaetan Rivet 
204c752998bSGaetan Rivet 		/* skip this element if it doesn't match our PCI address */
2050e3ef055SGaetan Rivet 		if (!rte_pci_addr_cmp(&uio_res->pci_addr, &dev->addr))
206c752998bSGaetan Rivet 			return uio_res;
207c752998bSGaetan Rivet 	}
208c752998bSGaetan Rivet 	return NULL;
209c752998bSGaetan Rivet }
210c752998bSGaetan Rivet 
211c752998bSGaetan Rivet /* unmap the PCI resource of a PCI device in virtual memory */
212c752998bSGaetan Rivet void
213c752998bSGaetan Rivet pci_uio_unmap_resource(struct rte_pci_device *dev)
214c752998bSGaetan Rivet {
215c752998bSGaetan Rivet 	struct mapped_pci_resource *uio_res;
216c752998bSGaetan Rivet 	struct mapped_pci_res_list *uio_res_list =
217c752998bSGaetan Rivet 			RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list);
218d61138d4SHarman Kalra 	int uio_cfg_fd;
219c752998bSGaetan Rivet 
220c752998bSGaetan Rivet 	if (dev == NULL)
221c752998bSGaetan Rivet 		return;
222c752998bSGaetan Rivet 
223c752998bSGaetan Rivet 	/* find an entry for the device */
224c752998bSGaetan Rivet 	uio_res = pci_uio_find_resource(dev);
225c752998bSGaetan Rivet 	if (uio_res == NULL)
226c752998bSGaetan Rivet 		return;
227c752998bSGaetan Rivet 
228*847d78fbSZerun Fu 	/* close fd */
229*847d78fbSZerun Fu 	if (rte_intr_fd_get(dev->intr_handle) >= 0)
230*847d78fbSZerun Fu 		close(rte_intr_fd_get(dev->intr_handle));
231*847d78fbSZerun Fu 	uio_cfg_fd = rte_intr_dev_fd_get(dev->intr_handle);
232*847d78fbSZerun Fu 	if (uio_cfg_fd >= 0) {
233*847d78fbSZerun Fu 		close(uio_cfg_fd);
234*847d78fbSZerun Fu 		rte_intr_dev_fd_set(dev->intr_handle, -1);
235*847d78fbSZerun Fu 	}
236*847d78fbSZerun Fu 
237*847d78fbSZerun Fu 	rte_intr_fd_set(dev->intr_handle, -1);
238*847d78fbSZerun Fu 	rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
239*847d78fbSZerun Fu 
240c752998bSGaetan Rivet 	/* secondary processes - just free maps */
241c752998bSGaetan Rivet 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
242c752998bSGaetan Rivet 		return pci_uio_unmap(uio_res);
243c752998bSGaetan Rivet 
244c752998bSGaetan Rivet 	TAILQ_REMOVE(uio_res_list, uio_res, next);
245c752998bSGaetan Rivet 
246c752998bSGaetan Rivet 	/* unmap all resources */
247c752998bSGaetan Rivet 	pci_uio_unmap(uio_res);
248c752998bSGaetan Rivet 
249c752998bSGaetan Rivet 	/* free uio resource */
250c752998bSGaetan Rivet 	rte_free(uio_res);
251c752998bSGaetan Rivet }
252