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 void 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 assert(rc >= 0 && rc < size); 42 } 43 44 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 47 static void xen_host_pci_get_resource(XenHostPCIDevice *d, Error **errp) 48 { 49 int i, rc, fd; 50 char path[PATH_MAX]; 51 char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE]; 52 unsigned long long start, end, flags, size; 53 char *endptr, *s; 54 uint8_t type; 55 56 xen_host_pci_sysfs_path(d, "resource", path, sizeof(path)); 57 58 fd = open(path, O_RDONLY); 59 if (fd == -1) { 60 error_setg_file_open(errp, errno, path); 61 return; 62 } 63 64 do { 65 rc = read(fd, &buf, sizeof(buf) - 1); 66 if (rc < 0 && errno != EINTR) { 67 error_setg_errno(errp, errno, "read err"); 68 goto out; 69 } 70 } while (rc < 0); 71 buf[rc] = 0; 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 } 124 125 if (i != PCI_NUM_REGIONS) { 126 error_setg(errp, "Invalid format or input too short: %s", buf); 127 } 128 129 out: 130 close(fd); 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 135 static void xen_host_pci_get_value(XenHostPCIDevice *d, const char *name, 136 unsigned int *pvalue, int base, Error **errp) 137 { 138 char path[PATH_MAX]; 139 char buf[XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE]; 140 int fd, rc; 141 unsigned long value; 142 const char *endptr; 143 144 xen_host_pci_sysfs_path(d, name, path, sizeof(path)); 145 146 fd = open(path, O_RDONLY); 147 if (fd == -1) { 148 error_setg_file_open(errp, errno, path); 149 return; 150 } 151 152 do { 153 rc = read(fd, &buf, sizeof(buf) - 1); 154 if (rc < 0 && errno != EINTR) { 155 error_setg_errno(errp, errno, "read err"); 156 goto out; 157 } 158 } while (rc < 0); 159 160 buf[rc] = 0; 161 rc = qemu_strtoul(buf, &endptr, base, &value); 162 if (!rc) { 163 assert(value <= UINT_MAX); 164 *pvalue = value; 165 } else { 166 error_setg_errno(errp, -rc, "failed to parse value '%s'", buf); 167 } 168 169 out: 170 close(fd); 171 } 172 173 static inline void xen_host_pci_get_hex_value(XenHostPCIDevice *d, 174 const char *name, 175 unsigned int *pvalue, 176 Error **errp) 177 { 178 xen_host_pci_get_value(d, name, pvalue, 16, errp); 179 } 180 181 static inline void xen_host_pci_get_dec_value(XenHostPCIDevice *d, 182 const char *name, 183 unsigned int *pvalue, 184 Error **errp) 185 { 186 xen_host_pci_get_value(d, name, pvalue, 10, errp); 187 } 188 189 static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d) 190 { 191 char path[PATH_MAX]; 192 struct stat buf; 193 194 xen_host_pci_sysfs_path(d, "physfn", path, sizeof(path)); 195 196 return !stat(path, &buf); 197 } 198 199 static void xen_host_pci_config_open(XenHostPCIDevice *d, Error **errp) 200 { 201 char path[PATH_MAX]; 202 203 xen_host_pci_sysfs_path(d, "config", path, sizeof(path)); 204 205 d->config_fd = open(path, O_RDWR); 206 if (d->config_fd == -1) { 207 error_setg_file_open(errp, errno, path); 208 } 209 } 210 211 static 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 225 static 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 240 int 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 250 int 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 260 int 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 270 int 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 275 int 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 280 int 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 286 int 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 292 int 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 297 int 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 330 void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain, 331 uint8_t bus, uint8_t dev, uint8_t func, 332 Error **errp) 333 { 334 unsigned int v; 335 Error *err = NULL; 336 337 d->config_fd = -1; 338 d->domain = domain; 339 d->bus = bus; 340 d->dev = dev; 341 d->func = func; 342 343 xen_host_pci_config_open(d, &err); 344 if (err) { 345 goto error; 346 } 347 348 xen_host_pci_get_resource(d, &err); 349 if (err) { 350 goto error; 351 } 352 353 xen_host_pci_get_hex_value(d, "vendor", &v, &err); 354 if (err) { 355 goto error; 356 } 357 d->vendor_id = v; 358 359 xen_host_pci_get_hex_value(d, "device", &v, &err); 360 if (err) { 361 goto error; 362 } 363 d->device_id = v; 364 365 xen_host_pci_get_dec_value(d, "irq", &v, &err); 366 if (err) { 367 goto error; 368 } 369 d->irq = v; 370 371 xen_host_pci_get_hex_value(d, "class", &v, &err); 372 if (err) { 373 goto error; 374 } 375 d->class_code = v; 376 377 d->is_virtfn = xen_host_pci_dev_is_virtfn(d); 378 379 return; 380 381 error: 382 error_propagate(errp, err); 383 384 if (d->config_fd >= 0) { 385 close(d->config_fd); 386 d->config_fd = -1; 387 } 388 } 389 390 bool xen_host_pci_device_closed(XenHostPCIDevice *d) 391 { 392 return d->config_fd == -1; 393 } 394 395 void 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 } 402