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