New upstream version 17.11.5
[deb_dpdk.git] / lib / librte_pci / rte_pci.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   Copyright 2013-2014 6WIND S.A.
6  *   All rights reserved.
7  *
8  *   Redistribution and use in source and binary forms, with or without
9  *   modification, are permitted provided that the following conditions
10  *   are met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in
16  *       the documentation and/or other materials provided with the
17  *       distribution.
18  *     * Neither the name of Intel Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <string.h>
36 #include <inttypes.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <sys/queue.h>
41 #include <sys/mman.h>
42
43 #include <rte_errno.h>
44 #include <rte_interrupts.h>
45 #include <rte_log.h>
46 #include <rte_bus.h>
47 #include <rte_per_lcore.h>
48 #include <rte_memory.h>
49 #include <rte_eal.h>
50 #include <rte_string_fns.h>
51 #include <rte_common.h>
52
53 #include "rte_pci.h"
54
55 static inline const char *
56 get_u8_pciaddr_field(const char *in, void *_u8, char dlm)
57 {
58         unsigned long val;
59         uint8_t *u8 = _u8;
60         char *end;
61
62         /* empty string is an error though strtoul() returns 0 */
63         if (*in == '\0')
64                 return NULL;
65
66         errno = 0;
67         val = strtoul(in, &end, 16);
68         if (errno != 0 || end[0] != dlm || val > UINT8_MAX) {
69                 errno = errno ? errno : EINVAL;
70                 return NULL;
71         }
72         *u8 = (uint8_t)val;
73         return end + 1;
74 }
75
76 static int
77 pci_bdf_parse(const char *input, struct rte_pci_addr *dev_addr)
78 {
79         const char *in = input;
80
81         dev_addr->domain = 0;
82         in = get_u8_pciaddr_field(in, &dev_addr->bus, ':');
83         if (in == NULL)
84                 return -EINVAL;
85         in = get_u8_pciaddr_field(in, &dev_addr->devid, '.');
86         if (in == NULL)
87                 return -EINVAL;
88         in = get_u8_pciaddr_field(in, &dev_addr->function, '\0');
89         if (in == NULL)
90                 return -EINVAL;
91         return 0;
92 }
93
94 static int
95 pci_dbdf_parse(const char *input, struct rte_pci_addr *dev_addr)
96 {
97         const char *in = input;
98         unsigned long val;
99         char *end;
100
101         errno = 0;
102         val = strtoul(in, &end, 16);
103         if (errno != 0 || end[0] != ':' || val > UINT16_MAX)
104                 return -EINVAL;
105         dev_addr->domain = (uint16_t)val;
106         in = end + 1;
107         in = get_u8_pciaddr_field(in, &dev_addr->bus, ':');
108         if (in == NULL)
109                 return -EINVAL;
110         in = get_u8_pciaddr_field(in, &dev_addr->devid, '.');
111         if (in == NULL)
112                 return -EINVAL;
113         in = get_u8_pciaddr_field(in, &dev_addr->function, '\0');
114         if (in == NULL)
115                 return -EINVAL;
116         return 0;
117 }
118
119 int
120 eal_parse_pci_BDF(const char *input, struct rte_pci_addr *dev_addr)
121 {
122         return pci_bdf_parse(input, dev_addr);
123 }
124
125 int
126 eal_parse_pci_DomBDF(const char *input, struct rte_pci_addr *dev_addr)
127 {
128         return pci_dbdf_parse(input, dev_addr);
129 }
130
131 void
132 rte_pci_device_name(const struct rte_pci_addr *addr,
133                 char *output, size_t size)
134 {
135         RTE_VERIFY(size >= PCI_PRI_STR_SIZE);
136         RTE_VERIFY(snprintf(output, size, PCI_PRI_FMT,
137                             addr->domain, addr->bus,
138                             addr->devid, addr->function) >= 0);
139 }
140
141 int
142 rte_eal_compare_pci_addr(const struct rte_pci_addr *addr,
143                          const struct rte_pci_addr *addr2)
144 {
145         return rte_pci_addr_cmp(addr, addr2);
146 }
147
148 int
149 rte_pci_addr_cmp(const struct rte_pci_addr *addr,
150              const struct rte_pci_addr *addr2)
151 {
152         uint64_t dev_addr, dev_addr2;
153
154         if ((addr == NULL) || (addr2 == NULL))
155                 return -1;
156
157         dev_addr = ((uint64_t)addr->domain << 24) |
158                 (addr->bus << 16) | (addr->devid << 8) | addr->function;
159         dev_addr2 = ((uint64_t)addr2->domain << 24) |
160                 (addr2->bus << 16) | (addr2->devid << 8) | addr2->function;
161
162         if (dev_addr > dev_addr2)
163                 return 1;
164         else if (dev_addr < dev_addr2)
165                 return -1;
166         else
167                 return 0;
168 }
169
170 int
171 rte_pci_addr_parse(const char *str, struct rte_pci_addr *addr)
172 {
173         if (pci_bdf_parse(str, addr) == 0 ||
174             pci_dbdf_parse(str, addr) == 0)
175                 return 0;
176         return -1;
177 }
178
179
180 /* map a particular resource from a file */
181 void *
182 pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
183                  int additional_flags)
184 {
185         void *mapaddr;
186
187         /* Map the PCI memory resource of device */
188         mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE,
189                         MAP_SHARED | additional_flags, fd, offset);
190         if (mapaddr == MAP_FAILED) {
191                 RTE_LOG(ERR, EAL, "%s(): cannot mmap(%d, %p, 0x%lx, 0x%lx): %s (%p)\n",
192                         __func__, fd, requested_addr,
193                         (unsigned long)size, (unsigned long)offset,
194                         strerror(errno), mapaddr);
195         } else
196                 RTE_LOG(DEBUG, EAL, "  PCI memory mapped at %p\n", mapaddr);
197
198         return mapaddr;
199 }
200
201 /* unmap a particular resource */
202 void
203 pci_unmap_resource(void *requested_addr, size_t size)
204 {
205         if (requested_addr == NULL)
206                 return;
207
208         /* Unmap the PCI memory resource of device */
209         if (munmap(requested_addr, size)) {
210                 RTE_LOG(ERR, EAL, "%s(): cannot munmap(%p, 0x%lx): %s\n",
211                         __func__, requested_addr, (unsigned long)size,
212                         strerror(errno));
213         } else
214                 RTE_LOG(DEBUG, EAL, "  PCI memory unmapped at %p\n",
215                                 requested_addr);
216 }