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