0160fc1eb8aa9eb829cd1d7e504a90d069727e29
[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         errno = 0;
63         val = strtoul(in, &end, 16);
64         if (errno != 0 || end[0] != dlm || val > UINT8_MAX) {
65                 errno = errno ? errno : EINVAL;
66                 return NULL;
67         }
68         *u8 = (uint8_t)val;
69         return end + 1;
70 }
71
72 static int
73 pci_bdf_parse(const char *input, struct rte_pci_addr *dev_addr)
74 {
75         const char *in = input;
76
77         dev_addr->domain = 0;
78         in = get_u8_pciaddr_field(in, &dev_addr->bus, ':');
79         if (in == NULL)
80                 return -EINVAL;
81         in = get_u8_pciaddr_field(in, &dev_addr->devid, '.');
82         if (in == NULL)
83                 return -EINVAL;
84         in = get_u8_pciaddr_field(in, &dev_addr->function, '\0');
85         if (in == NULL)
86                 return -EINVAL;
87         return 0;
88 }
89
90 static int
91 pci_dbdf_parse(const char *input, struct rte_pci_addr *dev_addr)
92 {
93         const char *in = input;
94         unsigned long val;
95         char *end;
96
97         errno = 0;
98         val = strtoul(in, &end, 16);
99         if (errno != 0 || end[0] != ':' || val > UINT16_MAX)
100                 return -EINVAL;
101         dev_addr->domain = (uint16_t)val;
102         in = end + 1;
103         in = get_u8_pciaddr_field(in, &dev_addr->bus, ':');
104         if (in == NULL)
105                 return -EINVAL;
106         in = get_u8_pciaddr_field(in, &dev_addr->devid, '.');
107         if (in == NULL)
108                 return -EINVAL;
109         in = get_u8_pciaddr_field(in, &dev_addr->function, '\0');
110         if (in == NULL)
111                 return -EINVAL;
112         return 0;
113 }
114
115 int
116 eal_parse_pci_BDF(const char *input, struct rte_pci_addr *dev_addr)
117 {
118         return pci_bdf_parse(input, dev_addr);
119 }
120
121 int
122 eal_parse_pci_DomBDF(const char *input, struct rte_pci_addr *dev_addr)
123 {
124         return pci_dbdf_parse(input, dev_addr);
125 }
126
127 void
128 rte_pci_device_name(const struct rte_pci_addr *addr,
129                 char *output, size_t size)
130 {
131         RTE_VERIFY(size >= PCI_PRI_STR_SIZE);
132         RTE_VERIFY(snprintf(output, size, PCI_PRI_FMT,
133                             addr->domain, addr->bus,
134                             addr->devid, addr->function) >= 0);
135 }
136
137 int
138 rte_eal_compare_pci_addr(const struct rte_pci_addr *addr,
139                          const struct rte_pci_addr *addr2)
140 {
141         return rte_pci_addr_cmp(addr, addr2);
142 }
143
144 int
145 rte_pci_addr_cmp(const struct rte_pci_addr *addr,
146              const struct rte_pci_addr *addr2)
147 {
148         uint64_t dev_addr, dev_addr2;
149
150         if ((addr == NULL) || (addr2 == NULL))
151                 return -1;
152
153         dev_addr = ((uint64_t)addr->domain << 24) |
154                 (addr->bus << 16) | (addr->devid << 8) | addr->function;
155         dev_addr2 = ((uint64_t)addr2->domain << 24) |
156                 (addr2->bus << 16) | (addr2->devid << 8) | addr2->function;
157
158         if (dev_addr > dev_addr2)
159                 return 1;
160         else if (dev_addr < dev_addr2)
161                 return -1;
162         else
163                 return 0;
164 }
165
166 int
167 rte_pci_addr_parse(const char *str, struct rte_pci_addr *addr)
168 {
169         if (pci_bdf_parse(str, addr) == 0 ||
170             pci_dbdf_parse(str, addr) == 0)
171                 return 0;
172         return -1;
173 }
174
175
176 /* map a particular resource from a file */
177 void *
178 pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
179                  int additional_flags)
180 {
181         void *mapaddr;
182
183         /* Map the PCI memory resource of device */
184         mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE,
185                         MAP_SHARED | additional_flags, fd, offset);
186         if (mapaddr == MAP_FAILED) {
187                 RTE_LOG(ERR, EAL, "%s(): cannot mmap(%d, %p, 0x%lx, 0x%lx): %s (%p)\n",
188                         __func__, fd, requested_addr,
189                         (unsigned long)size, (unsigned long)offset,
190                         strerror(errno), mapaddr);
191         } else
192                 RTE_LOG(DEBUG, EAL, "  PCI memory mapped at %p\n", mapaddr);
193
194         return mapaddr;
195 }
196
197 /* unmap a particular resource */
198 void
199 pci_unmap_resource(void *requested_addr, size_t size)
200 {
201         if (requested_addr == NULL)
202                 return;
203
204         /* Unmap the PCI memory resource of device */
205         if (munmap(requested_addr, size)) {
206                 RTE_LOG(ERR, EAL, "%s(): cannot munmap(%p, 0x%lx): %s\n",
207                         __func__, requested_addr, (unsigned long)size,
208                         strerror(errno));
209         } else
210                 RTE_LOG(DEBUG, EAL, "  PCI memory unmapped at %p\n",
211                                 requested_addr);
212 }