ac50e13fc2d46de84c968dc2930ff44a702d52f4
[dpdk.git] / lib / librte_eal / linuxapp / eal / eal_pci_uio.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
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 <string.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <dirent.h>
38 #include <sys/stat.h>
39 #include <sys/mman.h>
40 #include <linux/pci_regs.h>
41
42 #include <rte_log.h>
43 #include <rte_pci.h>
44 #include <rte_eal_memconfig.h>
45 #include <rte_common.h>
46 #include <rte_malloc.h>
47
48 #include "eal_filesystem.h"
49 #include "eal_pci_init.h"
50
51 void *pci_map_addr = NULL;
52
53 #define OFF_MAX              ((uint64_t)(off_t)-1)
54
55 int
56 pci_uio_read_config(const struct rte_intr_handle *intr_handle,
57                     void *buf, size_t len, off_t offset)
58 {
59         return pread(intr_handle->uio_cfg_fd, buf, len, offset);
60 }
61
62 int
63 pci_uio_write_config(const struct rte_intr_handle *intr_handle,
64                      const void *buf, size_t len, off_t offset)
65 {
66         return pwrite(intr_handle->uio_cfg_fd, buf, len, offset);
67 }
68
69 static int
70 pci_uio_set_bus_master(int dev_fd)
71 {
72         uint16_t reg;
73         int ret;
74
75         ret = pread(dev_fd, &reg, sizeof(reg), PCI_COMMAND);
76         if (ret != sizeof(reg)) {
77                 RTE_LOG(ERR, EAL,
78                         "Cannot read command from PCI config space!\n");
79                 return -1;
80         }
81
82         /* return if bus mastering is already on */
83         if (reg & PCI_COMMAND_MASTER)
84                 return 0;
85
86         reg |= PCI_COMMAND_MASTER;
87
88         ret = pwrite(dev_fd, &reg, sizeof(reg), PCI_COMMAND);
89         if (ret != sizeof(reg)) {
90                 RTE_LOG(ERR, EAL,
91                         "Cannot write command to PCI config space!\n");
92                 return -1;
93         }
94
95         return 0;
96 }
97
98 static int
99 pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
100 {
101         FILE *f;
102         char filename[PATH_MAX];
103         int ret;
104         unsigned major, minor;
105         dev_t dev;
106
107         /* get the name of the sysfs file that contains the major and minor
108          * of the uio device and read its content */
109         snprintf(filename, sizeof(filename), "%s/dev", sysfs_uio_path);
110
111         f = fopen(filename, "r");
112         if (f == NULL) {
113                 RTE_LOG(ERR, EAL, "%s(): cannot open sysfs to get major:minor\n",
114                         __func__);
115                 return -1;
116         }
117
118         ret = fscanf(f, "%u:%u", &major, &minor);
119         if (ret != 2) {
120                 RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs to get major:minor\n",
121                         __func__);
122                 fclose(f);
123                 return -1;
124         }
125         fclose(f);
126
127         /* create the char device "mknod /dev/uioX c major minor" */
128         snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
129         dev = makedev(major, minor);
130         ret = mknod(filename, S_IFCHR | S_IRUSR | S_IWUSR, dev);
131         if (f == NULL) {
132                 RTE_LOG(ERR, EAL, "%s(): mknod() failed %s\n",
133                         __func__, strerror(errno));
134                 return -1;
135         }
136
137         return ret;
138 }
139
140 /*
141  * Return the uioX char device used for a pci device. On success, return
142  * the UIO number and fill dstbuf string with the path of the device in
143  * sysfs. On error, return a negative value. In this case dstbuf is
144  * invalid.
145  */
146 static int
147 pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
148                            unsigned int buflen)
149 {
150         struct rte_pci_addr *loc = &dev->addr;
151         unsigned int uio_num;
152         struct dirent *e;
153         DIR *dir;
154         char dirname[PATH_MAX];
155
156         /* depending on kernel version, uio can be located in uio/uioX
157          * or uio:uioX */
158
159         snprintf(dirname, sizeof(dirname),
160                         SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio",
161                         loc->domain, loc->bus, loc->devid, loc->function);
162
163         dir = opendir(dirname);
164         if (dir == NULL) {
165                 /* retry with the parent directory */
166                 snprintf(dirname, sizeof(dirname),
167                                 SYSFS_PCI_DEVICES "/" PCI_PRI_FMT,
168                                 loc->domain, loc->bus, loc->devid, loc->function);
169                 dir = opendir(dirname);
170
171                 if (dir == NULL) {
172                         RTE_LOG(ERR, EAL, "Cannot opendir %s\n", dirname);
173                         return -1;
174                 }
175         }
176
177         /* take the first file starting with "uio" */
178         while ((e = readdir(dir)) != NULL) {
179                 /* format could be uio%d ...*/
180                 int shortprefix_len = sizeof("uio") - 1;
181                 /* ... or uio:uio%d */
182                 int longprefix_len = sizeof("uio:uio") - 1;
183                 char *endptr;
184
185                 if (strncmp(e->d_name, "uio", 3) != 0)
186                         continue;
187
188                 /* first try uio%d */
189                 errno = 0;
190                 uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
191                 if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
192                         snprintf(dstbuf, buflen, "%s/uio%u", dirname, uio_num);
193                         break;
194                 }
195
196                 /* then try uio:uio%d */
197                 errno = 0;
198                 uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
199                 if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
200                         snprintf(dstbuf, buflen, "%s/uio:uio%u", dirname, uio_num);
201                         break;
202                 }
203         }
204         closedir(dir);
205
206         /* No uio resource found */
207         if (e == NULL)
208                 return -1;
209
210         /* create uio device if we've been asked to */
211         if (internal_config.create_uio_dev &&
212                         pci_mknod_uio_dev(dstbuf, uio_num) < 0)
213                 RTE_LOG(WARNING, EAL, "Cannot create /dev/uio%u\n", uio_num);
214
215         return uio_num;
216 }
217
218 void
219 pci_uio_free_resource(struct rte_pci_device *dev,
220                 struct mapped_pci_resource *uio_res)
221 {
222         rte_free(uio_res);
223
224         if (dev->intr_handle.uio_cfg_fd >= 0) {
225                 close(dev->intr_handle.uio_cfg_fd);
226                 dev->intr_handle.uio_cfg_fd = -1;
227         }
228         if (dev->intr_handle.fd) {
229                 close(dev->intr_handle.fd);
230                 dev->intr_handle.fd = -1;
231                 dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
232         }
233 }
234
235 int
236 pci_uio_alloc_resource(struct rte_pci_device *dev,
237                 struct mapped_pci_resource **uio_res)
238 {
239         char dirname[PATH_MAX];
240         char cfgname[PATH_MAX];
241         char devname[PATH_MAX]; /* contains the /dev/uioX */
242         int uio_num;
243         struct rte_pci_addr *loc;
244
245         loc = &dev->addr;
246
247         /* find uio resource */
248         uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname));
249         if (uio_num < 0) {
250                 RTE_LOG(WARNING, EAL, "  "PCI_PRI_FMT" not managed by UIO driver, "
251                                 "skipping\n", loc->domain, loc->bus, loc->devid, loc->function);
252                 return 1;
253         }
254         snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num);
255
256         /* save fd if in primary process */
257         dev->intr_handle.fd = open(devname, O_RDWR);
258         if (dev->intr_handle.fd < 0) {
259                 RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
260                         devname, strerror(errno));
261                 goto error;
262         }
263
264         snprintf(cfgname, sizeof(cfgname),
265                         "/sys/class/uio/uio%u/device/config", uio_num);
266         dev->intr_handle.uio_cfg_fd = open(cfgname, O_RDWR);
267         if (dev->intr_handle.uio_cfg_fd < 0) {
268                 RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
269                         cfgname, strerror(errno));
270                 goto error;
271         }
272
273         if (dev->kdrv == RTE_KDRV_IGB_UIO)
274                 dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
275         else {
276                 dev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX;
277
278                 /* set bus master that is not done by uio_pci_generic */
279                 if (pci_uio_set_bus_master(dev->intr_handle.uio_cfg_fd)) {
280                         RTE_LOG(ERR, EAL, "Cannot set up bus mastering!\n");
281                         goto error;
282                 }
283         }
284
285         /* allocate the mapping details for secondary processes*/
286         *uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0);
287         if (*uio_res == NULL) {
288                 RTE_LOG(ERR, EAL,
289                         "%s(): cannot store uio mmap details\n", __func__);
290                 goto error;
291         }
292
293         snprintf((*uio_res)->path, sizeof((*uio_res)->path), "%s", devname);
294         memcpy(&(*uio_res)->pci_addr, &dev->addr, sizeof((*uio_res)->pci_addr));
295
296         return 0;
297
298 error:
299         pci_uio_free_resource(dev, *uio_res);
300         return -1;
301 }
302
303 int
304 pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
305                 struct mapped_pci_resource *uio_res, int map_idx)
306 {
307         int fd;
308         char devname[PATH_MAX]; /* contains the /dev/uioX */
309         void *mapaddr;
310         struct rte_pci_addr *loc;
311         struct pci_map *maps;
312
313         loc = &dev->addr;
314         maps = uio_res->maps;
315
316         /* update devname for mmap  */
317         snprintf(devname, sizeof(devname),
318                         SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/resource%d",
319                         loc->domain, loc->bus, loc->devid,
320                         loc->function, res_idx);
321
322         /* allocate memory to keep path */
323         maps[map_idx].path = rte_malloc(NULL, strlen(devname) + 1, 0);
324         if (maps[map_idx].path == NULL) {
325                 RTE_LOG(ERR, EAL, "Cannot allocate memory for path: %s\n",
326                                 strerror(errno));
327                 return -1;
328         }
329
330         /*
331          * open resource file, to mmap it
332          */
333         fd = open(devname, O_RDWR);
334         if (fd < 0) {
335                 RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
336                                 devname, strerror(errno));
337                 goto error;
338         }
339
340         /* try mapping somewhere close to the end of hugepages */
341         if (pci_map_addr == NULL)
342                 pci_map_addr = pci_find_max_end_va();
343
344         mapaddr = pci_map_resource(pci_map_addr, fd, 0,
345                         (size_t)dev->mem_resource[res_idx].len, 0);
346         close(fd);
347         if (mapaddr == MAP_FAILED)
348                 goto error;
349
350         pci_map_addr = RTE_PTR_ADD(mapaddr,
351                         (size_t)dev->mem_resource[res_idx].len);
352
353         maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr;
354         maps[map_idx].size = dev->mem_resource[res_idx].len;
355         maps[map_idx].addr = mapaddr;
356         maps[map_idx].offset = 0;
357         strcpy(maps[map_idx].path, devname);
358         dev->mem_resource[res_idx].addr = mapaddr;
359
360         return 0;
361
362 error:
363         rte_free(maps[map_idx].path);
364         return -1;
365 }