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