xen-host-pci-device.c 12 KB

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