Merge tag 'v9.1.0'
[qemu/ar7.git] / hw / xen / xen-host-pci-device.c
blobeaf32f27107b68dc0bd8e0e732d6d0c7fc812671
1 /*
2 * Copyright (C) 2011 Citrix Ltd.
4 * This work is licensed under the terms of the GNU GPL, version 2. See
5 * the COPYING file in the top-level directory.
7 */
9 #include "qemu/osdep.h"
10 #include "qapi/error.h"
11 #include "qemu/cutils.h"
12 #include "hw/xen/xen-legacy-backend.h"
13 #include "hw/xen/xen-bus-helper.h"
14 #include "xen-host-pci-device.h"
16 #define XEN_HOST_PCI_MAX_EXT_CAP \
17 ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4))
19 #ifdef XEN_HOST_PCI_DEVICE_DEBUG
20 # define XEN_HOST_PCI_LOG(f, a...) fprintf(stderr, "%s: " f, __func__, ##a)
21 #else
22 # define XEN_HOST_PCI_LOG(f, a...) (void)0
23 #endif
26 * from linux/ioport.h
27 * IO resources have these defined flags.
29 #define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
31 #define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */
32 #define IORESOURCE_IO 0x00000100
33 #define IORESOURCE_MEM 0x00000200
35 #define IORESOURCE_PREFETCH 0x00001000 /* No side effects */
36 #define IORESOURCE_MEM_64 0x00100000
39 * Non-passthrough (dom0) accesses are local PCI devices and use the given BDF
40 * Passthough (stubdom) accesses are through PV frontend PCI device. Those
41 * either have a BDF identical to the backend's BDF (xen-backend.passthrough=1)
42 * or a local virtual BDF (xen-backend.passthrough=0)
44 * We are always given the backend's BDF and need to lookup the appropriate
45 * local BDF for sysfs access.
47 static void xen_host_pci_fill_local_addr(XenHostPCIDevice *d, Error **errp)
49 unsigned int num_devs, len, i;
50 unsigned int domain, bus, dev, func;
51 char *be_path = NULL;
52 char path[16];
54 be_path = qemu_xen_xs_read(xenstore, 0, "device/pci/0/backend", &len);
55 if (!be_path) {
56 error_setg(errp, "Failed to read device/pci/0/backend");
57 goto out;
60 if (xs_node_scanf(xenstore, 0, be_path, "num_devs", NULL,
61 "%d", &num_devs) != 1) {
62 error_setg(errp, "Failed to read or parse %s/num_devs", be_path);
63 goto out;
66 for (i = 0; i < num_devs; i++) {
67 snprintf(path, sizeof(path), "dev-%d", i);
68 if (xs_node_scanf(xenstore, 0, be_path, path, NULL,
69 "%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
70 error_setg(errp, "Failed to read or parse %s/%s", be_path, path);
71 goto out;
73 if (domain != d->domain ||
74 bus != d->bus ||
75 dev != d->dev ||
76 func != d->func)
77 continue;
78 snprintf(path, sizeof(path), "vdev-%d", i);
79 if (xs_node_scanf(xenstore, 0, be_path, path, NULL,
80 "%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
81 error_setg(errp, "Failed to read or parse %s/%s", be_path, path);
82 goto out;
84 d->local_domain = domain;
85 d->local_bus = bus;
86 d->local_dev = dev;
87 d->local_func = func;
88 goto out;
90 error_setg(errp, "Failed to find PCI device %x:%x:%x.%x in xenstore",
91 d->domain, d->bus, d->dev, d->func);
93 out:
94 free(be_path);
97 static void xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
98 const char *name, char *buf, ssize_t size)
100 int rc;
102 rc = snprintf(buf, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
103 d->local_domain, d->local_bus, d->local_dev, d->local_func,
104 name);
105 assert(rc >= 0 && rc < size);
109 /* This size should be enough to read the first 7 lines of a resource file */
110 #define XEN_HOST_PCI_RESOURCE_BUFFER_SIZE 400
111 static void xen_host_pci_get_resource(XenHostPCIDevice *d, Error **errp)
113 int i, rc, fd;
114 char path[PATH_MAX];
115 char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE];
116 unsigned long long start, end, flags, size;
117 char *endptr, *s;
118 uint8_t type;
120 xen_host_pci_sysfs_path(d, "resource", path, sizeof(path));
122 fd = open(path, O_RDONLY);
123 if (fd == -1) {
124 error_setg_file_open(errp, errno, path);
125 return;
128 do {
129 rc = read(fd, &buf, sizeof(buf) - 1);
130 if (rc < 0 && errno != EINTR) {
131 error_setg_errno(errp, errno, "read err");
132 goto out;
134 } while (rc < 0);
135 buf[rc] = 0;
137 s = buf;
138 for (i = 0; i < PCI_NUM_REGIONS; i++) {
139 type = 0;
141 start = strtoll(s, &endptr, 16);
142 if (*endptr != ' ' || s == endptr) {
143 break;
145 s = endptr + 1;
146 end = strtoll(s, &endptr, 16);
147 if (*endptr != ' ' || s == endptr) {
148 break;
150 s = endptr + 1;
151 flags = strtoll(s, &endptr, 16);
152 if (*endptr != '\n' || s == endptr) {
153 break;
155 s = endptr + 1;
157 if (start) {
158 size = end - start + 1;
159 } else {
160 size = 0;
163 if (flags & IORESOURCE_IO) {
164 type |= XEN_HOST_PCI_REGION_TYPE_IO;
166 if (flags & IORESOURCE_MEM) {
167 type |= XEN_HOST_PCI_REGION_TYPE_MEM;
169 if (flags & IORESOURCE_PREFETCH) {
170 type |= XEN_HOST_PCI_REGION_TYPE_PREFETCH;
172 if (flags & IORESOURCE_MEM_64) {
173 type |= XEN_HOST_PCI_REGION_TYPE_MEM_64;
176 if (i < PCI_ROM_SLOT) {
177 d->io_regions[i].base_addr = start;
178 d->io_regions[i].size = size;
179 d->io_regions[i].type = type;
180 d->io_regions[i].bus_flags = flags & IORESOURCE_BITS;
181 } else {
182 d->rom.base_addr = start;
183 d->rom.size = size;
184 d->rom.type = type;
185 d->rom.bus_flags = flags & IORESOURCE_BITS;
189 if (i != PCI_NUM_REGIONS) {
190 error_setg(errp, "Invalid format or input too short: %s", buf);
193 out:
194 close(fd);
197 /* This size should be enough to read a long from a file */
198 #define XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE 22
199 static void xen_host_pci_get_value(XenHostPCIDevice *d, const char *name,
200 unsigned int *pvalue, int base, Error **errp)
202 char path[PATH_MAX];
203 char buf[XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE];
204 int fd, rc;
205 unsigned long value;
206 const char *endptr;
208 xen_host_pci_sysfs_path(d, name, path, sizeof(path));
210 fd = open(path, O_RDONLY);
211 if (fd == -1) {
212 error_setg_file_open(errp, errno, path);
213 return;
216 do {
217 rc = read(fd, &buf, sizeof(buf) - 1);
218 if (rc < 0 && errno != EINTR) {
219 error_setg_errno(errp, errno, "read err");
220 goto out;
222 } while (rc < 0);
224 buf[rc] = 0;
225 rc = qemu_strtoul(buf, &endptr, base, &value);
226 if (!rc) {
227 assert(value <= UINT_MAX);
228 *pvalue = value;
229 } else {
230 error_setg_errno(errp, -rc, "failed to parse value '%s'", buf);
233 out:
234 close(fd);
237 static inline void xen_host_pci_get_hex_value(XenHostPCIDevice *d,
238 const char *name,
239 unsigned int *pvalue,
240 Error **errp)
242 xen_host_pci_get_value(d, name, pvalue, 16, errp);
245 static inline void xen_host_pci_get_dec_value(XenHostPCIDevice *d,
246 const char *name,
247 unsigned int *pvalue,
248 Error **errp)
250 xen_host_pci_get_value(d, name, pvalue, 10, errp);
253 static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d)
255 char path[PATH_MAX];
256 struct stat buf;
258 xen_host_pci_sysfs_path(d, "physfn", path, sizeof(path));
260 return !stat(path, &buf);
263 static void xen_host_pci_config_open(XenHostPCIDevice *d, Error **errp)
265 char path[PATH_MAX];
267 xen_host_pci_sysfs_path(d, "config", path, sizeof(path));
269 d->config_fd = open(path, O_RDWR);
270 if (d->config_fd == -1) {
271 error_setg_file_open(errp, errno, path);
275 static int xen_host_pci_config_read(XenHostPCIDevice *d,
276 int pos, void *buf, int len)
278 int rc;
280 do {
281 rc = pread(d->config_fd, buf, len, pos);
282 } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
283 if (rc != len) {
284 return -errno;
286 return 0;
289 static int xen_host_pci_config_write(XenHostPCIDevice *d,
290 int pos, const void *buf, int len)
292 int rc;
294 do {
295 rc = pwrite(d->config_fd, buf, len, pos);
296 } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
297 if (rc != len) {
298 return -errno;
300 return 0;
304 int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p)
306 uint8_t buf;
307 int rc = xen_host_pci_config_read(d, pos, &buf, 1);
308 if (!rc) {
309 *p = buf;
311 return rc;
314 int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p)
316 uint16_t buf;
317 int rc = xen_host_pci_config_read(d, pos, &buf, 2);
318 if (!rc) {
319 *p = le16_to_cpu(buf);
321 return rc;
324 int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p)
326 uint32_t buf;
327 int rc = xen_host_pci_config_read(d, pos, &buf, 4);
328 if (!rc) {
329 *p = le32_to_cpu(buf);
331 return rc;
334 int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
336 return xen_host_pci_config_read(d, pos, buf, len);
339 int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data)
341 return xen_host_pci_config_write(d, pos, &data, 1);
344 int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data)
346 data = cpu_to_le16(data);
347 return xen_host_pci_config_write(d, pos, &data, 2);
350 int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data)
352 data = cpu_to_le32(data);
353 return xen_host_pci_config_write(d, pos, &data, 4);
356 int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
358 return xen_host_pci_config_write(d, pos, buf, len);
361 int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap)
363 uint32_t header = 0;
364 int max_cap = XEN_HOST_PCI_MAX_EXT_CAP;
365 int pos = PCI_CONFIG_SPACE_SIZE;
367 do {
368 if (xen_host_pci_get_long(d, pos, &header)) {
369 break;
372 * If we have no capabilities, this is indicated by cap ID,
373 * cap version and next pointer all being 0.
375 if (header == 0) {
376 break;
379 if (PCI_EXT_CAP_ID(header) == cap) {
380 return pos;
383 pos = PCI_EXT_CAP_NEXT(header);
384 if (pos < PCI_CONFIG_SPACE_SIZE) {
385 break;
388 max_cap--;
389 } while (max_cap > 0);
391 return -1;
394 void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
395 uint8_t bus, uint8_t dev, uint8_t func,
396 Error **errp)
398 ERRP_GUARD();
399 unsigned int v;
401 d->config_fd = -1;
402 d->domain = domain;
403 d->bus = bus;
404 d->dev = dev;
405 d->func = func;
407 if (xen_is_stubdomain) {
408 xen_host_pci_fill_local_addr(d, errp);
409 if (*errp) {
410 goto error;
412 } else {
413 d->local_domain = d->domain;
414 d->local_bus = d->bus;
415 d->local_dev = d->dev;
416 d->local_func = d->func;
419 xen_host_pci_config_open(d, errp);
420 if (*errp) {
421 goto error;
424 xen_host_pci_get_resource(d, errp);
425 if (*errp) {
426 goto error;
429 xen_host_pci_get_hex_value(d, "vendor", &v, errp);
430 if (*errp) {
431 goto error;
433 d->vendor_id = v;
435 xen_host_pci_get_hex_value(d, "device", &v, errp);
436 if (*errp) {
437 goto error;
439 d->device_id = v;
441 xen_host_pci_get_dec_value(d, "irq", &v, errp);
442 if (*errp) {
443 goto error;
445 d->irq = v;
447 xen_host_pci_get_hex_value(d, "class", &v, errp);
448 if (*errp) {
449 goto error;
451 d->class_code = v;
453 d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
455 return;
457 error:
459 if (d->config_fd >= 0) {
460 close(d->config_fd);
461 d->config_fd = -1;
465 bool xen_host_pci_device_closed(XenHostPCIDevice *d)
467 return d->config_fd == -1;
470 void xen_host_pci_device_put(XenHostPCIDevice *d)
472 if (d->config_fd >= 0) {
473 close(d->config_fd);
474 d->config_fd = -1;