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