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/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" 15 16 #define XEN_HOST_PCI_MAX_EXT_CAP \ 17 ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4)) 18 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 24 25 /* 26 * from linux/ioport.h 27 * IO resources have these defined flags. 28 */ 29 #define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ 30 31 #define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */ 32 #define IORESOURCE_IO 0x00000100 33 #define IORESOURCE_MEM 0x00000200 34 35 #define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ 36 #define IORESOURCE_MEM_64 0x00100000 37 38 /* 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) 43 * 44 * We are always given the backend's BDF and need to lookup the appropriate 45 * local BDF for sysfs access. 46 */ 47 static void xen_host_pci_fill_local_addr(XenHostPCIDevice *d, Error **errp) 48 { 49 unsigned int num_devs, len, i; 50 unsigned int domain, bus, dev, func; 51 char *be_path = NULL; 52 char path[16]; 53 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; 58 } 59 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; 64 } 65 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; 72 } 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; 83 } 84 d->local_domain = domain; 85 d->local_bus = bus; 86 d->local_dev = dev; 87 d->local_func = func; 88 goto out; 89 } 90 error_setg(errp, "Failed to find PCI device %x:%x:%x.%x in xenstore", 91 d->domain, d->bus, d->dev, d->func); 92 93 out: 94 free(be_path); 95 } 96 97 static void xen_host_pci_sysfs_path(const XenHostPCIDevice *d, 98 const char *name, char *buf, ssize_t size) 99 { 100 int rc; 101 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); 106 } 107 108 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) 112 { 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; 119 120 xen_host_pci_sysfs_path(d, "resource", path, sizeof(path)); 121 122 fd = open(path, O_RDONLY); 123 if (fd == -1) { 124 error_setg_file_open(errp, errno, path); 125 return; 126 } 127 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; 133 } 134 } while (rc < 0); 135 buf[rc] = 0; 136 137 s = buf; 138 for (i = 0; i < PCI_NUM_REGIONS; i++) { 139 type = 0; 140 141 start = strtoll(s, &endptr, 16); 142 if (*endptr != ' ' || s == endptr) { 143 break; 144 } 145 s = endptr + 1; 146 end = strtoll(s, &endptr, 16); 147 if (*endptr != ' ' || s == endptr) { 148 break; 149 } 150 s = endptr + 1; 151 flags = strtoll(s, &endptr, 16); 152 if (*endptr != '\n' || s == endptr) { 153 break; 154 } 155 s = endptr + 1; 156 157 if (start) { 158 size = end - start + 1; 159 } else { 160 size = 0; 161 } 162 163 if (flags & IORESOURCE_IO) { 164 type |= XEN_HOST_PCI_REGION_TYPE_IO; 165 } 166 if (flags & IORESOURCE_MEM) { 167 type |= XEN_HOST_PCI_REGION_TYPE_MEM; 168 } 169 if (flags & IORESOURCE_PREFETCH) { 170 type |= XEN_HOST_PCI_REGION_TYPE_PREFETCH; 171 } 172 if (flags & IORESOURCE_MEM_64) { 173 type |= XEN_HOST_PCI_REGION_TYPE_MEM_64; 174 } 175 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; 186 } 187 } 188 189 if (i != PCI_NUM_REGIONS) { 190 error_setg(errp, "Invalid format or input too short: %s", buf); 191 } 192 193 out: 194 close(fd); 195 } 196 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) 201 { 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; 207 208 xen_host_pci_sysfs_path(d, name, path, sizeof(path)); 209 210 fd = open(path, O_RDONLY); 211 if (fd == -1) { 212 error_setg_file_open(errp, errno, path); 213 return; 214 } 215 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; 221 } 222 } while (rc < 0); 223 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); 231 } 232 233 out: 234 close(fd); 235 } 236 237 static inline void xen_host_pci_get_hex_value(XenHostPCIDevice *d, 238 const char *name, 239 unsigned int *pvalue, 240 Error **errp) 241 { 242 xen_host_pci_get_value(d, name, pvalue, 16, errp); 243 } 244 245 static inline void xen_host_pci_get_dec_value(XenHostPCIDevice *d, 246 const char *name, 247 unsigned int *pvalue, 248 Error **errp) 249 { 250 xen_host_pci_get_value(d, name, pvalue, 10, errp); 251 } 252 253 static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d) 254 { 255 char path[PATH_MAX]; 256 struct stat buf; 257 258 xen_host_pci_sysfs_path(d, "physfn", path, sizeof(path)); 259 260 return !stat(path, &buf); 261 } 262 263 static void xen_host_pci_config_open(XenHostPCIDevice *d, Error **errp) 264 { 265 char path[PATH_MAX]; 266 267 xen_host_pci_sysfs_path(d, "config", path, sizeof(path)); 268 269 d->config_fd = open(path, O_RDWR); 270 if (d->config_fd == -1) { 271 error_setg_file_open(errp, errno, path); 272 } 273 } 274 275 static int xen_host_pci_config_read(XenHostPCIDevice *d, 276 int pos, void *buf, int len) 277 { 278 int rc; 279 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; 285 } 286 return 0; 287 } 288 289 static int xen_host_pci_config_write(XenHostPCIDevice *d, 290 int pos, const void *buf, int len) 291 { 292 int rc; 293 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; 299 } 300 return 0; 301 } 302 303 304 int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p) 305 { 306 uint8_t buf; 307 int rc = xen_host_pci_config_read(d, pos, &buf, 1); 308 if (!rc) { 309 *p = buf; 310 } 311 return rc; 312 } 313 314 int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p) 315 { 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); 320 } 321 return rc; 322 } 323 324 int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p) 325 { 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); 330 } 331 return rc; 332 } 333 334 int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len) 335 { 336 return xen_host_pci_config_read(d, pos, buf, len); 337 } 338 339 int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data) 340 { 341 return xen_host_pci_config_write(d, pos, &data, 1); 342 } 343 344 int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data) 345 { 346 data = cpu_to_le16(data); 347 return xen_host_pci_config_write(d, pos, &data, 2); 348 } 349 350 int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data) 351 { 352 data = cpu_to_le32(data); 353 return xen_host_pci_config_write(d, pos, &data, 4); 354 } 355 356 int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len) 357 { 358 return xen_host_pci_config_write(d, pos, buf, len); 359 } 360 361 int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap) 362 { 363 uint32_t header = 0; 364 int max_cap = XEN_HOST_PCI_MAX_EXT_CAP; 365 int pos = PCI_CONFIG_SPACE_SIZE; 366 367 do { 368 if (xen_host_pci_get_long(d, pos, &header)) { 369 break; 370 } 371 /* 372 * If we have no capabilities, this is indicated by cap ID, 373 * cap version and next pointer all being 0. 374 */ 375 if (header == 0) { 376 break; 377 } 378 379 if (PCI_EXT_CAP_ID(header) == cap) { 380 return pos; 381 } 382 383 pos = PCI_EXT_CAP_NEXT(header); 384 if (pos < PCI_CONFIG_SPACE_SIZE) { 385 break; 386 } 387 388 max_cap--; 389 } while (max_cap > 0); 390 391 return -1; 392 } 393 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) 397 { 398 ERRP_GUARD(); 399 unsigned int v; 400 401 d->config_fd = -1; 402 d->domain = domain; 403 d->bus = bus; 404 d->dev = dev; 405 d->func = func; 406 407 if (xen_is_stubdomain) { 408 xen_host_pci_fill_local_addr(d, errp); 409 if (*errp) { 410 goto error; 411 } 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; 417 } 418 419 xen_host_pci_config_open(d, errp); 420 if (*errp) { 421 goto error; 422 } 423 424 xen_host_pci_get_resource(d, errp); 425 if (*errp) { 426 goto error; 427 } 428 429 xen_host_pci_get_hex_value(d, "vendor", &v, errp); 430 if (*errp) { 431 goto error; 432 } 433 d->vendor_id = v; 434 435 xen_host_pci_get_hex_value(d, "device", &v, errp); 436 if (*errp) { 437 goto error; 438 } 439 d->device_id = v; 440 441 xen_host_pci_get_dec_value(d, "irq", &v, errp); 442 if (*errp) { 443 goto error; 444 } 445 d->irq = v; 446 447 xen_host_pci_get_hex_value(d, "class", &v, errp); 448 if (*errp) { 449 goto error; 450 } 451 d->class_code = v; 452 453 d->is_virtfn = xen_host_pci_dev_is_virtfn(d); 454 455 return; 456 457 error: 458 459 if (d->config_fd >= 0) { 460 close(d->config_fd); 461 d->config_fd = -1; 462 } 463 } 464 465 bool xen_host_pci_device_closed(XenHostPCIDevice *d) 466 { 467 return d->config_fd == -1; 468 } 469 470 void xen_host_pci_device_put(XenHostPCIDevice *d) 471 { 472 if (d->config_fd >= 0) { 473 close(d->config_fd); 474 d->config_fd = -1; 475 } 476 } 477