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