From mboxrd@z Thu Jan 1 00:00:00 1970 From: Gerd Hoffmann Subject: [PATCH v4 6/8] igd: revamp host config read Date: Tue, 8 Mar 2016 15:27:25 +0100 Message-ID: <1457447247-4865-7-git-send-email-kraxel@redhat.com> References: <1457447247-4865-1-git-send-email-kraxel@redhat.com> Return-path: In-Reply-To: <1457447247-4865-1-git-send-email-kraxel@redhat.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+gceq-qemu-devel=gmane.org@nongnu.org Sender: qemu-devel-bounces+gceq-qemu-devel=gmane.org@nongnu.org To: kevin.tian@intel.com, Alex Williamson , Stefano Stabellini Cc: igvt-g@ml01.01.org, xen-devel@lists.xensource.com, Gerd Hoffmann , "open list:All patches CC here" List-Id: xen-devel@lists.xenproject.org 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 --- 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