root / hw / xen-host-pci-device.c @ c06aaf01
History | View | Annotate | Download (9.6 kB)
1 | 396af688 | Anthony PERARD | /*
|
---|---|---|---|
2 | 396af688 | Anthony PERARD | * Copyright (C) 2011 Citrix Ltd.
|
3 | 396af688 | Anthony PERARD | *
|
4 | 396af688 | Anthony PERARD | * This work is licensed under the terms of the GNU GPL, version 2. See
|
5 | 396af688 | Anthony PERARD | * the COPYING file in the top-level directory.
|
6 | 396af688 | Anthony PERARD | *
|
7 | 396af688 | Anthony PERARD | */
|
8 | 396af688 | Anthony PERARD | |
9 | 396af688 | Anthony PERARD | #include "qemu-common.h" |
10 | 396af688 | Anthony PERARD | #include "xen-host-pci-device.h" |
11 | 396af688 | Anthony PERARD | |
12 | 396af688 | Anthony PERARD | #define XEN_HOST_PCI_MAX_EXT_CAP \
|
13 | 396af688 | Anthony PERARD | ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4))
|
14 | 396af688 | Anthony PERARD | |
15 | 396af688 | Anthony PERARD | #ifdef XEN_HOST_PCI_DEVICE_DEBUG
|
16 | 396af688 | Anthony PERARD | # define XEN_HOST_PCI_LOG(f, a...) fprintf(stderr, "%s: " f, __func__, ##a) |
17 | 396af688 | Anthony PERARD | #else
|
18 | 396af688 | Anthony PERARD | # define XEN_HOST_PCI_LOG(f, a...) (void)0 |
19 | 396af688 | Anthony PERARD | #endif
|
20 | 396af688 | Anthony PERARD | |
21 | 396af688 | Anthony PERARD | /*
|
22 | 396af688 | Anthony PERARD | * from linux/ioport.h
|
23 | 396af688 | Anthony PERARD | * IO resources have these defined flags.
|
24 | 396af688 | Anthony PERARD | */
|
25 | 396af688 | Anthony PERARD | #define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ |
26 | 396af688 | Anthony PERARD | |
27 | 396af688 | Anthony PERARD | #define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */ |
28 | 396af688 | Anthony PERARD | #define IORESOURCE_IO 0x00000100 |
29 | 396af688 | Anthony PERARD | #define IORESOURCE_MEM 0x00000200 |
30 | 396af688 | Anthony PERARD | |
31 | 396af688 | Anthony PERARD | #define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ |
32 | 396af688 | Anthony PERARD | #define IORESOURCE_MEM_64 0x00100000 |
33 | 396af688 | Anthony PERARD | |
34 | 396af688 | Anthony PERARD | static int xen_host_pci_sysfs_path(const XenHostPCIDevice *d, |
35 | 396af688 | Anthony PERARD | const char *name, char *buf, ssize_t size) |
36 | 396af688 | Anthony PERARD | { |
37 | 396af688 | Anthony PERARD | int rc;
|
38 | 396af688 | Anthony PERARD | |
39 | 396af688 | Anthony PERARD | rc = snprintf(buf, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
|
40 | 396af688 | Anthony PERARD | d->domain, d->bus, d->dev, d->func, name); |
41 | 396af688 | Anthony PERARD | |
42 | 396af688 | Anthony PERARD | if (rc >= size || rc < 0) { |
43 | 396af688 | Anthony PERARD | /* The ouput is truncated or an other error is encountered */
|
44 | 396af688 | Anthony PERARD | return -ENODEV;
|
45 | 396af688 | Anthony PERARD | } |
46 | 396af688 | Anthony PERARD | return 0; |
47 | 396af688 | Anthony PERARD | } |
48 | 396af688 | Anthony PERARD | |
49 | 396af688 | Anthony PERARD | |
50 | 396af688 | Anthony PERARD | /* This size should be enough to read the first 7 lines of a ressource file */
|
51 | 396af688 | Anthony PERARD | #define XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE 400 |
52 | 396af688 | Anthony PERARD | static int xen_host_pci_get_resource(XenHostPCIDevice *d) |
53 | 396af688 | Anthony PERARD | { |
54 | 396af688 | Anthony PERARD | int i, rc, fd;
|
55 | 396af688 | Anthony PERARD | char path[PATH_MAX];
|
56 | 396af688 | Anthony PERARD | char buf[XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE];
|
57 | 396af688 | Anthony PERARD | unsigned long long start, end, flags, size; |
58 | 396af688 | Anthony PERARD | char *endptr, *s;
|
59 | 396af688 | Anthony PERARD | uint8_t type; |
60 | 396af688 | Anthony PERARD | |
61 | 396af688 | Anthony PERARD | rc = xen_host_pci_sysfs_path(d, "resource", path, sizeof (path)); |
62 | 396af688 | Anthony PERARD | if (rc) {
|
63 | 396af688 | Anthony PERARD | return rc;
|
64 | 396af688 | Anthony PERARD | } |
65 | 396af688 | Anthony PERARD | fd = open(path, O_RDONLY); |
66 | 396af688 | Anthony PERARD | if (fd == -1) { |
67 | 396af688 | Anthony PERARD | XEN_HOST_PCI_LOG("Error: Can't open %s: %s\n", path, strerror(errno));
|
68 | 396af688 | Anthony PERARD | return -errno;
|
69 | 396af688 | Anthony PERARD | } |
70 | 396af688 | Anthony PERARD | |
71 | 396af688 | Anthony PERARD | do {
|
72 | 396af688 | Anthony PERARD | rc = read(fd, &buf, sizeof (buf) - 1); |
73 | 396af688 | Anthony PERARD | if (rc < 0 && errno != EINTR) { |
74 | 396af688 | Anthony PERARD | rc = -errno; |
75 | 396af688 | Anthony PERARD | goto out;
|
76 | 396af688 | Anthony PERARD | } |
77 | 396af688 | Anthony PERARD | } while (rc < 0); |
78 | 396af688 | Anthony PERARD | buf[rc] = 0;
|
79 | 396af688 | Anthony PERARD | rc = 0;
|
80 | 396af688 | Anthony PERARD | |
81 | 396af688 | Anthony PERARD | s = buf; |
82 | 396af688 | Anthony PERARD | for (i = 0; i < PCI_NUM_REGIONS; i++) { |
83 | 396af688 | Anthony PERARD | type = 0;
|
84 | 396af688 | Anthony PERARD | |
85 | 396af688 | Anthony PERARD | start = strtoll(s, &endptr, 16);
|
86 | 396af688 | Anthony PERARD | if (*endptr != ' ' || s == endptr) { |
87 | 396af688 | Anthony PERARD | break;
|
88 | 396af688 | Anthony PERARD | } |
89 | 396af688 | Anthony PERARD | s = endptr + 1;
|
90 | 396af688 | Anthony PERARD | end = strtoll(s, &endptr, 16);
|
91 | 396af688 | Anthony PERARD | if (*endptr != ' ' || s == endptr) { |
92 | 396af688 | Anthony PERARD | break;
|
93 | 396af688 | Anthony PERARD | } |
94 | 396af688 | Anthony PERARD | s = endptr + 1;
|
95 | 396af688 | Anthony PERARD | flags = strtoll(s, &endptr, 16);
|
96 | 396af688 | Anthony PERARD | if (*endptr != '\n' || s == endptr) { |
97 | 396af688 | Anthony PERARD | break;
|
98 | 396af688 | Anthony PERARD | } |
99 | 396af688 | Anthony PERARD | s = endptr + 1;
|
100 | 396af688 | Anthony PERARD | |
101 | 396af688 | Anthony PERARD | if (start) {
|
102 | 396af688 | Anthony PERARD | size = end - start + 1;
|
103 | 396af688 | Anthony PERARD | } else {
|
104 | 396af688 | Anthony PERARD | size = 0;
|
105 | 396af688 | Anthony PERARD | } |
106 | 396af688 | Anthony PERARD | |
107 | 396af688 | Anthony PERARD | if (flags & IORESOURCE_IO) {
|
108 | 396af688 | Anthony PERARD | type |= XEN_HOST_PCI_REGION_TYPE_IO; |
109 | 396af688 | Anthony PERARD | } |
110 | 396af688 | Anthony PERARD | if (flags & IORESOURCE_MEM) {
|
111 | 396af688 | Anthony PERARD | type |= XEN_HOST_PCI_REGION_TYPE_MEM; |
112 | 396af688 | Anthony PERARD | } |
113 | 396af688 | Anthony PERARD | if (flags & IORESOURCE_PREFETCH) {
|
114 | 396af688 | Anthony PERARD | type |= XEN_HOST_PCI_REGION_TYPE_PREFETCH; |
115 | 396af688 | Anthony PERARD | } |
116 | 396af688 | Anthony PERARD | if (flags & IORESOURCE_MEM_64) {
|
117 | 396af688 | Anthony PERARD | type |= XEN_HOST_PCI_REGION_TYPE_MEM_64; |
118 | 396af688 | Anthony PERARD | } |
119 | 396af688 | Anthony PERARD | |
120 | 396af688 | Anthony PERARD | if (i < PCI_ROM_SLOT) {
|
121 | 396af688 | Anthony PERARD | d->io_regions[i].base_addr = start; |
122 | 396af688 | Anthony PERARD | d->io_regions[i].size = size; |
123 | 396af688 | Anthony PERARD | d->io_regions[i].type = type; |
124 | 396af688 | Anthony PERARD | d->io_regions[i].bus_flags = flags & IORESOURCE_BITS; |
125 | 396af688 | Anthony PERARD | } else {
|
126 | 396af688 | Anthony PERARD | d->rom.base_addr = start; |
127 | 396af688 | Anthony PERARD | d->rom.size = size; |
128 | 396af688 | Anthony PERARD | d->rom.type = type; |
129 | 396af688 | Anthony PERARD | d->rom.bus_flags = flags & IORESOURCE_BITS; |
130 | 396af688 | Anthony PERARD | } |
131 | 396af688 | Anthony PERARD | } |
132 | 396af688 | Anthony PERARD | if (i != PCI_NUM_REGIONS) {
|
133 | 396af688 | Anthony PERARD | /* Invalid format or input to short */
|
134 | 396af688 | Anthony PERARD | rc = -ENODEV; |
135 | 396af688 | Anthony PERARD | } |
136 | 396af688 | Anthony PERARD | |
137 | 396af688 | Anthony PERARD | out:
|
138 | 396af688 | Anthony PERARD | close(fd); |
139 | 396af688 | Anthony PERARD | return rc;
|
140 | 396af688 | Anthony PERARD | } |
141 | 396af688 | Anthony PERARD | |
142 | 396af688 | Anthony PERARD | /* This size should be enough to read a long from a file */
|
143 | 396af688 | Anthony PERARD | #define XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE 22 |
144 | 396af688 | Anthony PERARD | static int xen_host_pci_get_value(XenHostPCIDevice *d, const char *name, |
145 | 396af688 | Anthony PERARD | unsigned int *pvalue, int base) |
146 | 396af688 | Anthony PERARD | { |
147 | 396af688 | Anthony PERARD | char path[PATH_MAX];
|
148 | 396af688 | Anthony PERARD | char buf[XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE];
|
149 | 396af688 | Anthony PERARD | int fd, rc;
|
150 | 396af688 | Anthony PERARD | unsigned long value; |
151 | 396af688 | Anthony PERARD | char *endptr;
|
152 | 396af688 | Anthony PERARD | |
153 | 396af688 | Anthony PERARD | rc = xen_host_pci_sysfs_path(d, name, path, sizeof (path));
|
154 | 396af688 | Anthony PERARD | if (rc) {
|
155 | 396af688 | Anthony PERARD | return rc;
|
156 | 396af688 | Anthony PERARD | } |
157 | 396af688 | Anthony PERARD | fd = open(path, O_RDONLY); |
158 | 396af688 | Anthony PERARD | if (fd == -1) { |
159 | 396af688 | Anthony PERARD | XEN_HOST_PCI_LOG("Error: Can't open %s: %s\n", path, strerror(errno));
|
160 | 396af688 | Anthony PERARD | return -errno;
|
161 | 396af688 | Anthony PERARD | } |
162 | 396af688 | Anthony PERARD | do {
|
163 | 396af688 | Anthony PERARD | rc = read(fd, &buf, sizeof (buf) - 1); |
164 | 396af688 | Anthony PERARD | if (rc < 0 && errno != EINTR) { |
165 | 396af688 | Anthony PERARD | rc = -errno; |
166 | 396af688 | Anthony PERARD | goto out;
|
167 | 396af688 | Anthony PERARD | } |
168 | 396af688 | Anthony PERARD | } while (rc < 0); |
169 | 396af688 | Anthony PERARD | buf[rc] = 0;
|
170 | 396af688 | Anthony PERARD | value = strtol(buf, &endptr, base); |
171 | 396af688 | Anthony PERARD | if (endptr == buf || *endptr != '\n') { |
172 | 396af688 | Anthony PERARD | rc = -1;
|
173 | 396af688 | Anthony PERARD | } else if ((value == LONG_MIN || value == LONG_MAX) && errno == ERANGE) { |
174 | 396af688 | Anthony PERARD | rc = -errno; |
175 | 396af688 | Anthony PERARD | } else {
|
176 | 396af688 | Anthony PERARD | rc = 0;
|
177 | 396af688 | Anthony PERARD | *pvalue = value; |
178 | 396af688 | Anthony PERARD | } |
179 | 396af688 | Anthony PERARD | out:
|
180 | 396af688 | Anthony PERARD | close(fd); |
181 | 396af688 | Anthony PERARD | return rc;
|
182 | 396af688 | Anthony PERARD | } |
183 | 396af688 | Anthony PERARD | |
184 | 396af688 | Anthony PERARD | static inline int xen_host_pci_get_hex_value(XenHostPCIDevice *d, |
185 | 396af688 | Anthony PERARD | const char *name, |
186 | 396af688 | Anthony PERARD | unsigned int *pvalue) |
187 | 396af688 | Anthony PERARD | { |
188 | 396af688 | Anthony PERARD | return xen_host_pci_get_value(d, name, pvalue, 16); |
189 | 396af688 | Anthony PERARD | } |
190 | 396af688 | Anthony PERARD | |
191 | 396af688 | Anthony PERARD | static inline int xen_host_pci_get_dec_value(XenHostPCIDevice *d, |
192 | 396af688 | Anthony PERARD | const char *name, |
193 | 396af688 | Anthony PERARD | unsigned int *pvalue) |
194 | 396af688 | Anthony PERARD | { |
195 | 396af688 | Anthony PERARD | return xen_host_pci_get_value(d, name, pvalue, 10); |
196 | 396af688 | Anthony PERARD | } |
197 | 396af688 | Anthony PERARD | |
198 | 396af688 | Anthony PERARD | static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d) |
199 | 396af688 | Anthony PERARD | { |
200 | 396af688 | Anthony PERARD | char path[PATH_MAX];
|
201 | 396af688 | Anthony PERARD | struct stat buf;
|
202 | 396af688 | Anthony PERARD | |
203 | 396af688 | Anthony PERARD | if (xen_host_pci_sysfs_path(d, "physfn", path, sizeof (path))) { |
204 | 396af688 | Anthony PERARD | return false; |
205 | 396af688 | Anthony PERARD | } |
206 | 396af688 | Anthony PERARD | return !stat(path, &buf);
|
207 | 396af688 | Anthony PERARD | } |
208 | 396af688 | Anthony PERARD | |
209 | 396af688 | Anthony PERARD | static int xen_host_pci_config_open(XenHostPCIDevice *d) |
210 | 396af688 | Anthony PERARD | { |
211 | 396af688 | Anthony PERARD | char path[PATH_MAX];
|
212 | 396af688 | Anthony PERARD | int rc;
|
213 | 396af688 | Anthony PERARD | |
214 | 396af688 | Anthony PERARD | rc = xen_host_pci_sysfs_path(d, "config", path, sizeof (path)); |
215 | 396af688 | Anthony PERARD | if (rc) {
|
216 | 396af688 | Anthony PERARD | return rc;
|
217 | 396af688 | Anthony PERARD | } |
218 | 396af688 | Anthony PERARD | d->config_fd = open(path, O_RDWR); |
219 | 396af688 | Anthony PERARD | if (d->config_fd < 0) { |
220 | 396af688 | Anthony PERARD | return -errno;
|
221 | 396af688 | Anthony PERARD | } |
222 | 396af688 | Anthony PERARD | return 0; |
223 | 396af688 | Anthony PERARD | } |
224 | 396af688 | Anthony PERARD | |
225 | 396af688 | Anthony PERARD | static int xen_host_pci_config_read(XenHostPCIDevice *d, |
226 | 396af688 | Anthony PERARD | int pos, void *buf, int len) |
227 | 396af688 | Anthony PERARD | { |
228 | 396af688 | Anthony PERARD | int rc;
|
229 | 396af688 | Anthony PERARD | |
230 | 396af688 | Anthony PERARD | do {
|
231 | 396af688 | Anthony PERARD | rc = pread(d->config_fd, buf, len, pos); |
232 | 396af688 | Anthony PERARD | } while (rc < 0 && (errno == EINTR || errno == EAGAIN)); |
233 | 396af688 | Anthony PERARD | if (rc != len) {
|
234 | 396af688 | Anthony PERARD | return -errno;
|
235 | 396af688 | Anthony PERARD | } |
236 | 396af688 | Anthony PERARD | return 0; |
237 | 396af688 | Anthony PERARD | } |
238 | 396af688 | Anthony PERARD | |
239 | 396af688 | Anthony PERARD | static int xen_host_pci_config_write(XenHostPCIDevice *d, |
240 | 396af688 | Anthony PERARD | int pos, const void *buf, int len) |
241 | 396af688 | Anthony PERARD | { |
242 | 396af688 | Anthony PERARD | int rc;
|
243 | 396af688 | Anthony PERARD | |
244 | 396af688 | Anthony PERARD | do {
|
245 | 396af688 | Anthony PERARD | rc = pwrite(d->config_fd, buf, len, pos); |
246 | 396af688 | Anthony PERARD | } while (rc < 0 && (errno == EINTR || errno == EAGAIN)); |
247 | 396af688 | Anthony PERARD | if (rc != len) {
|
248 | 396af688 | Anthony PERARD | return -errno;
|
249 | 396af688 | Anthony PERARD | } |
250 | 396af688 | Anthony PERARD | return 0; |
251 | 396af688 | Anthony PERARD | } |
252 | 396af688 | Anthony PERARD | |
253 | 396af688 | Anthony PERARD | |
254 | 396af688 | Anthony PERARD | int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p) |
255 | 396af688 | Anthony PERARD | { |
256 | 396af688 | Anthony PERARD | uint8_t buf; |
257 | 396af688 | Anthony PERARD | int rc = xen_host_pci_config_read(d, pos, &buf, 1); |
258 | 396af688 | Anthony PERARD | if (!rc) {
|
259 | 396af688 | Anthony PERARD | *p = buf; |
260 | 396af688 | Anthony PERARD | } |
261 | 396af688 | Anthony PERARD | return rc;
|
262 | 396af688 | Anthony PERARD | } |
263 | 396af688 | Anthony PERARD | |
264 | 396af688 | Anthony PERARD | int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p) |
265 | 396af688 | Anthony PERARD | { |
266 | 396af688 | Anthony PERARD | uint16_t buf; |
267 | 396af688 | Anthony PERARD | int rc = xen_host_pci_config_read(d, pos, &buf, 2); |
268 | 396af688 | Anthony PERARD | if (!rc) {
|
269 | 396af688 | Anthony PERARD | *p = le16_to_cpu(buf); |
270 | 396af688 | Anthony PERARD | } |
271 | 396af688 | Anthony PERARD | return rc;
|
272 | 396af688 | Anthony PERARD | } |
273 | 396af688 | Anthony PERARD | |
274 | 396af688 | Anthony PERARD | int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p) |
275 | 396af688 | Anthony PERARD | { |
276 | 396af688 | Anthony PERARD | uint32_t buf; |
277 | 396af688 | Anthony PERARD | int rc = xen_host_pci_config_read(d, pos, &buf, 4); |
278 | 396af688 | Anthony PERARD | if (!rc) {
|
279 | 396af688 | Anthony PERARD | *p = le32_to_cpu(buf); |
280 | 396af688 | Anthony PERARD | } |
281 | 396af688 | Anthony PERARD | return rc;
|
282 | 396af688 | Anthony PERARD | } |
283 | 396af688 | Anthony PERARD | |
284 | 396af688 | Anthony PERARD | int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len) |
285 | 396af688 | Anthony PERARD | { |
286 | 396af688 | Anthony PERARD | return xen_host_pci_config_read(d, pos, buf, len);
|
287 | 396af688 | Anthony PERARD | } |
288 | 396af688 | Anthony PERARD | |
289 | 396af688 | Anthony PERARD | int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data) |
290 | 396af688 | Anthony PERARD | { |
291 | 396af688 | Anthony PERARD | return xen_host_pci_config_write(d, pos, &data, 1); |
292 | 396af688 | Anthony PERARD | } |
293 | 396af688 | Anthony PERARD | |
294 | 396af688 | Anthony PERARD | int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data) |
295 | 396af688 | Anthony PERARD | { |
296 | 396af688 | Anthony PERARD | data = cpu_to_le16(data); |
297 | 396af688 | Anthony PERARD | return xen_host_pci_config_write(d, pos, &data, 2); |
298 | 396af688 | Anthony PERARD | } |
299 | 396af688 | Anthony PERARD | |
300 | 396af688 | Anthony PERARD | int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data) |
301 | 396af688 | Anthony PERARD | { |
302 | 396af688 | Anthony PERARD | data = cpu_to_le32(data); |
303 | 396af688 | Anthony PERARD | return xen_host_pci_config_write(d, pos, &data, 4); |
304 | 396af688 | Anthony PERARD | } |
305 | 396af688 | Anthony PERARD | |
306 | 396af688 | Anthony PERARD | int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len) |
307 | 396af688 | Anthony PERARD | { |
308 | 396af688 | Anthony PERARD | return xen_host_pci_config_write(d, pos, buf, len);
|
309 | 396af688 | Anthony PERARD | } |
310 | 396af688 | Anthony PERARD | |
311 | 396af688 | Anthony PERARD | int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap)
|
312 | 396af688 | Anthony PERARD | { |
313 | 396af688 | Anthony PERARD | uint32_t header = 0;
|
314 | 396af688 | Anthony PERARD | int max_cap = XEN_HOST_PCI_MAX_EXT_CAP;
|
315 | 396af688 | Anthony PERARD | int pos = PCI_CONFIG_SPACE_SIZE;
|
316 | 396af688 | Anthony PERARD | |
317 | 396af688 | Anthony PERARD | do {
|
318 | 396af688 | Anthony PERARD | if (xen_host_pci_get_long(d, pos, &header)) {
|
319 | 396af688 | Anthony PERARD | break;
|
320 | 396af688 | Anthony PERARD | } |
321 | 396af688 | Anthony PERARD | /*
|
322 | 396af688 | Anthony PERARD | * If we have no capabilities, this is indicated by cap ID,
|
323 | 396af688 | Anthony PERARD | * cap version and next pointer all being 0.
|
324 | 396af688 | Anthony PERARD | */
|
325 | 396af688 | Anthony PERARD | if (header == 0) { |
326 | 396af688 | Anthony PERARD | break;
|
327 | 396af688 | Anthony PERARD | } |
328 | 396af688 | Anthony PERARD | |
329 | 396af688 | Anthony PERARD | if (PCI_EXT_CAP_ID(header) == cap) {
|
330 | 396af688 | Anthony PERARD | return pos;
|
331 | 396af688 | Anthony PERARD | } |
332 | 396af688 | Anthony PERARD | |
333 | 396af688 | Anthony PERARD | pos = PCI_EXT_CAP_NEXT(header); |
334 | 396af688 | Anthony PERARD | if (pos < PCI_CONFIG_SPACE_SIZE) {
|
335 | 396af688 | Anthony PERARD | break;
|
336 | 396af688 | Anthony PERARD | } |
337 | 396af688 | Anthony PERARD | |
338 | 396af688 | Anthony PERARD | max_cap--; |
339 | 396af688 | Anthony PERARD | } while (max_cap > 0); |
340 | 396af688 | Anthony PERARD | |
341 | 396af688 | Anthony PERARD | return -1; |
342 | 396af688 | Anthony PERARD | } |
343 | 396af688 | Anthony PERARD | |
344 | 396af688 | Anthony PERARD | int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
|
345 | 396af688 | Anthony PERARD | uint8_t bus, uint8_t dev, uint8_t func) |
346 | 396af688 | Anthony PERARD | { |
347 | 396af688 | Anthony PERARD | unsigned int v; |
348 | 396af688 | Anthony PERARD | int rc = 0; |
349 | 396af688 | Anthony PERARD | |
350 | 396af688 | Anthony PERARD | d->config_fd = -1;
|
351 | 396af688 | Anthony PERARD | d->domain = domain; |
352 | 396af688 | Anthony PERARD | d->bus = bus; |
353 | 396af688 | Anthony PERARD | d->dev = dev; |
354 | 396af688 | Anthony PERARD | d->func = func; |
355 | 396af688 | Anthony PERARD | |
356 | 396af688 | Anthony PERARD | rc = xen_host_pci_config_open(d); |
357 | 396af688 | Anthony PERARD | if (rc) {
|
358 | 396af688 | Anthony PERARD | goto error;
|
359 | 396af688 | Anthony PERARD | } |
360 | 396af688 | Anthony PERARD | rc = xen_host_pci_get_resource(d); |
361 | 396af688 | Anthony PERARD | if (rc) {
|
362 | 396af688 | Anthony PERARD | goto error;
|
363 | 396af688 | Anthony PERARD | } |
364 | 396af688 | Anthony PERARD | rc = xen_host_pci_get_hex_value(d, "vendor", &v);
|
365 | 396af688 | Anthony PERARD | if (rc) {
|
366 | 396af688 | Anthony PERARD | goto error;
|
367 | 396af688 | Anthony PERARD | } |
368 | 396af688 | Anthony PERARD | d->vendor_id = v; |
369 | 396af688 | Anthony PERARD | rc = xen_host_pci_get_hex_value(d, "device", &v);
|
370 | 396af688 | Anthony PERARD | if (rc) {
|
371 | 396af688 | Anthony PERARD | goto error;
|
372 | 396af688 | Anthony PERARD | } |
373 | 396af688 | Anthony PERARD | d->device_id = v; |
374 | 396af688 | Anthony PERARD | rc = xen_host_pci_get_dec_value(d, "irq", &v);
|
375 | 396af688 | Anthony PERARD | if (rc) {
|
376 | 396af688 | Anthony PERARD | goto error;
|
377 | 396af688 | Anthony PERARD | } |
378 | 396af688 | Anthony PERARD | d->irq = v; |
379 | 396af688 | Anthony PERARD | d->is_virtfn = xen_host_pci_dev_is_virtfn(d); |
380 | 396af688 | Anthony PERARD | |
381 | 396af688 | Anthony PERARD | return 0; |
382 | 396af688 | Anthony PERARD | error:
|
383 | 396af688 | Anthony PERARD | if (d->config_fd >= 0) { |
384 | 396af688 | Anthony PERARD | close(d->config_fd); |
385 | 396af688 | Anthony PERARD | d->config_fd = -1;
|
386 | 396af688 | Anthony PERARD | } |
387 | 396af688 | Anthony PERARD | return rc;
|
388 | 396af688 | Anthony PERARD | } |
389 | 396af688 | Anthony PERARD | |
390 | 396af688 | Anthony PERARD | void xen_host_pci_device_put(XenHostPCIDevice *d)
|
391 | 396af688 | Anthony PERARD | { |
392 | 396af688 | Anthony PERARD | if (d->config_fd >= 0) { |
393 | 396af688 | Anthony PERARD | close(d->config_fd); |
394 | 396af688 | Anthony PERARD | d->config_fd = -1;
|
395 | 396af688 | Anthony PERARD | } |
396 | 396af688 | Anthony PERARD | } |