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