Signed-off-by: Elena Ufimtseva <elena.ufimts...@oracle.com> --- include/hw/remote/proxy.h | 1 + hw/remote/proxy.c | 66 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 4 deletions(-)
diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h index 741def71f1..9efef0b935 100644 --- a/include/hw/remote/proxy.h +++ b/include/hw/remote/proxy.h @@ -29,6 +29,7 @@ struct PCIProxyDev { PCIDevice parent_dev; char *fd; + char *ioregfd; /* * Mutex used to protect the QIOChannel fd from * the concurrent access by the VCPUs since proxy diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index bad164299d..ba1aa20d78 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -146,6 +146,33 @@ static void pci_proxy_dev_exit(PCIDevice *pdev) event_notifier_cleanup(&dev->resample); } +static void config_get_ioregionfd_info(PCIProxyDev *pdev, uint32_t reg_num, + uint32_t *val, bool memory) +{ + MPQemuMsg msg = { 0 }; + Error *local_err = NULL; + uint64_t ret = -EINVAL; + + memset(&msg, 0, sizeof(MPQemuMsg)); + msg.cmd = MPQEMU_CMD_BAR_INFO; + msg.num_fds = 0; + msg.data.u64 = (uint64_t)reg_num & MAKE_64BIT_MASK(0, 32); + + msg.data.u64 |= memory ? (1ULL << 32) : 0; + msg.size = sizeof(msg.data.u64); + + ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); + if (local_err) { + error_report_err(local_err); + error_report("Error while receiving reply from remote about fd"); + } + if (ret == UINT64_MAX) { + error_report("Failed to request bar info for %d", reg_num); + } + + *val = (uint32_t)ret; +} + static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val, int len, unsigned int op) { @@ -198,6 +225,7 @@ static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t val, static Property proxy_properties[] = { DEFINE_PROP_STRING("fd", PCIProxyDev, fd), + DEFINE_PROP_STRING("ioregfd", PCIProxyDev, ioregfd), DEFINE_PROP_END_OF_LIST(), }; @@ -297,7 +325,7 @@ const MemoryRegionOps proxy_mr_ops = { static void probe_pci_info(PCIDevice *dev, Error **errp) { PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); - uint32_t orig_val, new_val, base_class, val; + uint32_t orig_val, new_val, base_class, val, ioregionfd_bar; PCIProxyDev *pdev = PCI_PROXY_DEV(dev); DeviceClass *dc = DEVICE_CLASS(pc); uint8_t type; @@ -342,6 +370,9 @@ static void probe_pci_info(PCIDevice *dev, Error **errp) } for (i = 0; i < PCI_NUM_REGIONS; i++) { + bool init_ioregionfd = false; + int fd = -1; + config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &orig_val, 4, MPQEMU_CMD_PCI_CFGREAD); new_val = 0xffffffff; @@ -362,9 +393,36 @@ static void probe_pci_info(PCIDevice *dev, Error **errp) if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) { pdev->region[i].memory = true; } - memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev), - &proxy_mr_ops, &pdev->region[i], - name, size); +#ifdef CONFIG_IOREGIONFD + /* + * Currently, only one fd per device is supported. + * TODO: Drop this limit. + */ + if (pdev->ioregfd) { + fd = monitor_fd_param(monitor_cur(), pdev->ioregfd, errp); + if (fd == -1) { + error_prepend(errp, "Could not parse ioregionfd fd %s:", + pdev->ioregfd); + } + + config_get_ioregionfd_info(pdev, i, &ioregionfd_bar, + pdev->region[i].memory); + if (ioregionfd_bar == i) { + init_ioregionfd = true; + } + } +#endif + if (init_ioregionfd) { + memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev), + NULL, &pdev->region[i], + name, size); + memory_region_add_ioregionfd(&pdev->region[i].mr, 0, size, i, + fd, false); + } else { + memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev), + &proxy_mr_ops, &pdev->region[i], + name, size); + } pci_register_bar(dev, i, type, &pdev->region[i].mr); } } -- 2.25.1