Move all work to the host_pci_config_copy helper function, which we can easily reuse when adding q35 support. Open sysfs file only once for all values. Use pread. Proper error handling.
Fix bug: Update config space directly (writing via pci_default_write_config only works for registers whitelisted in wmask). Hmm, this code can hardly ever worked before, /me wonders what test coverage it had. With this patch in place igd-passthru=on actually works, although it still requires root priviledges because linux refuses to allow non-root users access pci config space above offset 0x50. Signed-off-by: Gerd Hoffmann <kra...@redhat.com> --- hw/pci-host/igd.c | 65 ++++++++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/hw/pci-host/igd.c b/hw/pci-host/igd.c index 8a8b37b..5c4a008 100644 --- a/hw/pci-host/igd.c +++ b/hw/pci-host/igd.c @@ -20,40 +20,33 @@ static const IGDHostInfo igd_host_bridge_infos[] = { {0xa8, 4}, /* SNB: base of GTT stolen memory */ }; -static int host_pci_config_read(int pos, int len, uint32_t *val) +static void host_pci_config_copy(PCIDevice *guest, const char *host, + const IGDHostInfo *list, int len, Error **errp) { - char path[PATH_MAX]; - int config_fd; - ssize_t size = sizeof(path); - /* Access real host bridge. */ - int rc = snprintf(path, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s", - 0, 0, 0, 0, "config"); - int ret = 0; + char *path; + int config_fd, rc, i; - if (rc >= size || rc < 0) { - return -ENODEV; - } - - config_fd = open(path, O_RDWR); + path = g_strdup_printf("/sys/bus/pci/devices/%s/config", host); + config_fd = open(path, O_RDONLY); if (config_fd < 0) { - return -ENODEV; + error_setg_file_open(errp, errno, path); + goto out_free; } - if (lseek(config_fd, pos, SEEK_SET) != pos) { - ret = -errno; - goto out; + for (i = 0; i < len; i++) { + rc = pread(config_fd, guest->config + list[i].offset, + list[i].len, list[i].offset); + if (rc != list[i].len) { + error_setg_errno(errp, errno, "read %s, offset 0x%x", + path, list[i].offset); + goto out_close; + } } - do { - rc = read(config_fd, (uint8_t *)val, len); - } while (rc < 0 && (errno == EINTR || errno == EAGAIN)); - if (rc != len) { - ret = -errno; - } - -out: +out_close: close(config_fd); - return ret; +out_free: + g_free(path); } #define IGD_PT_I440FX_CLASS(class) \ @@ -72,9 +65,6 @@ static void igd_pt_i440fx_realize(PCIDevice *pci_dev, Error **errp) { IGDPtI440fxClass *k = IGD_PT_I440FX_GET_CLASS(pci_dev); Error *err = NULL; - uint32_t val = 0; - int rc, i, num; - int pos, len; k->parent_realize(pci_dev, &err); if (err != NULL) { @@ -82,16 +72,13 @@ static void igd_pt_i440fx_realize(PCIDevice *pci_dev, Error **errp) return; } - num = ARRAY_SIZE(igd_host_bridge_infos); - for (i = 0; i < num; i++) { - pos = igd_host_bridge_infos[i].offset; - len = igd_host_bridge_infos[i].len; - rc = host_pci_config_read(pos, len, &val); - if (rc) { - error_setg(errp, "failed to read host config"); - return; - } - pci_default_write_config(pci_dev, pos, val, len); + host_pci_config_copy(pci_dev, "0000:00:00.0", + igd_host_bridge_infos, + ARRAY_SIZE(igd_host_bridge_infos), + &err); + if (err != NULL) { + error_propagate(errp, err); + return; } } -- 1.8.3.1 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel