19f811207SElena Ufimtseva /* 29f811207SElena Ufimtseva * Copyright © 2018, 2021 Oracle and/or its affiliates. 39f811207SElena Ufimtseva * 49f811207SElena Ufimtseva * This work is licensed under the terms of the GNU GPL, version 2 or later. 59f811207SElena Ufimtseva * See the COPYING file in the top-level directory. 69f811207SElena Ufimtseva * 79f811207SElena Ufimtseva */ 89f811207SElena Ufimtseva 99f811207SElena Ufimtseva #include "qemu/osdep.h" 109f811207SElena Ufimtseva #include "qemu-common.h" 119f811207SElena Ufimtseva 129f811207SElena Ufimtseva #include "hw/remote/proxy.h" 139f811207SElena Ufimtseva #include "hw/pci/pci.h" 149f811207SElena Ufimtseva #include "qapi/error.h" 159f811207SElena Ufimtseva #include "io/channel-util.h" 169f811207SElena Ufimtseva #include "hw/qdev-properties.h" 179f811207SElena Ufimtseva #include "monitor/monitor.h" 189f811207SElena Ufimtseva #include "migration/blocker.h" 199f811207SElena Ufimtseva #include "qemu/sockets.h" 2011ab8725SElena Ufimtseva #include "hw/remote/mpqemu-link.h" 2111ab8725SElena Ufimtseva #include "qemu/error-report.h" 22*c746b74aSJagannathan Raman #include "hw/remote/proxy-memory-listener.h" 23*c746b74aSJagannathan Raman #include "qom/object.h" 249f811207SElena Ufimtseva 259f811207SElena Ufimtseva static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) 269f811207SElena Ufimtseva { 279f811207SElena Ufimtseva ERRP_GUARD(); 289f811207SElena Ufimtseva PCIProxyDev *dev = PCI_PROXY_DEV(device); 299f811207SElena Ufimtseva int fd; 309f811207SElena Ufimtseva 319f811207SElena Ufimtseva if (!dev->fd) { 329f811207SElena Ufimtseva error_setg(errp, "fd parameter not specified for %s", 339f811207SElena Ufimtseva DEVICE(device)->id); 349f811207SElena Ufimtseva return; 359f811207SElena Ufimtseva } 369f811207SElena Ufimtseva 379f811207SElena Ufimtseva fd = monitor_fd_param(monitor_cur(), dev->fd, errp); 389f811207SElena Ufimtseva if (fd == -1) { 399f811207SElena Ufimtseva error_prepend(errp, "proxy: unable to parse fd %s: ", dev->fd); 409f811207SElena Ufimtseva return; 419f811207SElena Ufimtseva } 429f811207SElena Ufimtseva 439f811207SElena Ufimtseva if (!fd_is_socket(fd)) { 449f811207SElena Ufimtseva error_setg(errp, "proxy: fd %d is not a socket", fd); 459f811207SElena Ufimtseva close(fd); 469f811207SElena Ufimtseva return; 479f811207SElena Ufimtseva } 489f811207SElena Ufimtseva 499f811207SElena Ufimtseva dev->ioc = qio_channel_new_fd(fd, errp); 509f811207SElena Ufimtseva 519f811207SElena Ufimtseva error_setg(&dev->migration_blocker, "%s does not support migration", 529f811207SElena Ufimtseva TYPE_PCI_PROXY_DEV); 539f811207SElena Ufimtseva migrate_add_blocker(dev->migration_blocker, errp); 549f811207SElena Ufimtseva 559f811207SElena Ufimtseva qemu_mutex_init(&dev->io_mutex); 569f811207SElena Ufimtseva qio_channel_set_blocking(dev->ioc, true, NULL); 57*c746b74aSJagannathan Raman 58*c746b74aSJagannathan Raman proxy_memory_listener_configure(&dev->proxy_listener, dev->ioc); 599f811207SElena Ufimtseva } 609f811207SElena Ufimtseva 619f811207SElena Ufimtseva static void pci_proxy_dev_exit(PCIDevice *pdev) 629f811207SElena Ufimtseva { 639f811207SElena Ufimtseva PCIProxyDev *dev = PCI_PROXY_DEV(pdev); 649f811207SElena Ufimtseva 659f811207SElena Ufimtseva if (dev->ioc) { 669f811207SElena Ufimtseva qio_channel_close(dev->ioc, NULL); 679f811207SElena Ufimtseva } 689f811207SElena Ufimtseva 699f811207SElena Ufimtseva migrate_del_blocker(dev->migration_blocker); 709f811207SElena Ufimtseva 719f811207SElena Ufimtseva error_free(dev->migration_blocker); 72*c746b74aSJagannathan Raman 73*c746b74aSJagannathan Raman proxy_memory_listener_deconfigure(&dev->proxy_listener); 749f811207SElena Ufimtseva } 759f811207SElena Ufimtseva 7611ab8725SElena Ufimtseva static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val, 7711ab8725SElena Ufimtseva int len, unsigned int op) 7811ab8725SElena Ufimtseva { 7911ab8725SElena Ufimtseva MPQemuMsg msg = { 0 }; 8011ab8725SElena Ufimtseva uint64_t ret = -EINVAL; 8111ab8725SElena Ufimtseva Error *local_err = NULL; 8211ab8725SElena Ufimtseva 8311ab8725SElena Ufimtseva msg.cmd = op; 8411ab8725SElena Ufimtseva msg.data.pci_conf_data.addr = addr; 8511ab8725SElena Ufimtseva msg.data.pci_conf_data.val = (op == MPQEMU_CMD_PCI_CFGWRITE) ? *val : 0; 8611ab8725SElena Ufimtseva msg.data.pci_conf_data.len = len; 8711ab8725SElena Ufimtseva msg.size = sizeof(PciConfDataMsg); 8811ab8725SElena Ufimtseva 8911ab8725SElena Ufimtseva ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); 9011ab8725SElena Ufimtseva if (local_err) { 9111ab8725SElena Ufimtseva error_report_err(local_err); 9211ab8725SElena Ufimtseva } 9311ab8725SElena Ufimtseva 9411ab8725SElena Ufimtseva if (ret == UINT64_MAX) { 9511ab8725SElena Ufimtseva error_report("Failed to perform PCI config %s operation", 9611ab8725SElena Ufimtseva (op == MPQEMU_CMD_PCI_CFGREAD) ? "READ" : "WRITE"); 9711ab8725SElena Ufimtseva } 9811ab8725SElena Ufimtseva 9911ab8725SElena Ufimtseva if (op == MPQEMU_CMD_PCI_CFGREAD) { 10011ab8725SElena Ufimtseva *val = (uint32_t)ret; 10111ab8725SElena Ufimtseva } 10211ab8725SElena Ufimtseva } 10311ab8725SElena Ufimtseva 10411ab8725SElena Ufimtseva static uint32_t pci_proxy_read_config(PCIDevice *d, uint32_t addr, int len) 10511ab8725SElena Ufimtseva { 10611ab8725SElena Ufimtseva uint32_t val; 10711ab8725SElena Ufimtseva 10811ab8725SElena Ufimtseva config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGREAD); 10911ab8725SElena Ufimtseva 11011ab8725SElena Ufimtseva return val; 11111ab8725SElena Ufimtseva } 11211ab8725SElena Ufimtseva 11311ab8725SElena Ufimtseva static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t val, 11411ab8725SElena Ufimtseva int len) 11511ab8725SElena Ufimtseva { 11611ab8725SElena Ufimtseva /* 11711ab8725SElena Ufimtseva * Some of the functions access the copy of remote device's PCI config 11811ab8725SElena Ufimtseva * space which is cached in the proxy device. Therefore, maintain 11911ab8725SElena Ufimtseva * it updated. 12011ab8725SElena Ufimtseva */ 12111ab8725SElena Ufimtseva pci_default_write_config(d, addr, val, len); 12211ab8725SElena Ufimtseva 12311ab8725SElena Ufimtseva config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGWRITE); 12411ab8725SElena Ufimtseva } 12511ab8725SElena Ufimtseva 1269f811207SElena Ufimtseva static Property proxy_properties[] = { 1279f811207SElena Ufimtseva DEFINE_PROP_STRING("fd", PCIProxyDev, fd), 1289f811207SElena Ufimtseva DEFINE_PROP_END_OF_LIST(), 1299f811207SElena Ufimtseva }; 1309f811207SElena Ufimtseva 1319f811207SElena Ufimtseva static void pci_proxy_dev_class_init(ObjectClass *klass, void *data) 1329f811207SElena Ufimtseva { 1339f811207SElena Ufimtseva DeviceClass *dc = DEVICE_CLASS(klass); 1349f811207SElena Ufimtseva PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 1359f811207SElena Ufimtseva 1369f811207SElena Ufimtseva k->realize = pci_proxy_dev_realize; 1379f811207SElena Ufimtseva k->exit = pci_proxy_dev_exit; 13811ab8725SElena Ufimtseva k->config_read = pci_proxy_read_config; 13911ab8725SElena Ufimtseva k->config_write = pci_proxy_write_config; 14011ab8725SElena Ufimtseva 1419f811207SElena Ufimtseva device_class_set_props(dc, proxy_properties); 1429f811207SElena Ufimtseva } 1439f811207SElena Ufimtseva 1449f811207SElena Ufimtseva static const TypeInfo pci_proxy_dev_type_info = { 1459f811207SElena Ufimtseva .name = TYPE_PCI_PROXY_DEV, 1469f811207SElena Ufimtseva .parent = TYPE_PCI_DEVICE, 1479f811207SElena Ufimtseva .instance_size = sizeof(PCIProxyDev), 1489f811207SElena Ufimtseva .class_init = pci_proxy_dev_class_init, 1499f811207SElena Ufimtseva .interfaces = (InterfaceInfo[]) { 1509f811207SElena Ufimtseva { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 1519f811207SElena Ufimtseva { }, 1529f811207SElena Ufimtseva }, 1539f811207SElena Ufimtseva }; 1549f811207SElena Ufimtseva 1559f811207SElena Ufimtseva static void pci_proxy_dev_register_types(void) 1569f811207SElena Ufimtseva { 1579f811207SElena Ufimtseva type_register_static(&pci_proxy_dev_type_info); 1589f811207SElena Ufimtseva } 1599f811207SElena Ufimtseva 1609f811207SElena Ufimtseva type_init(pci_proxy_dev_register_types) 1617ee3f823SJagannathan Raman 1627ee3f823SJagannathan Raman static void send_bar_access_msg(PCIProxyDev *pdev, MemoryRegion *mr, 1637ee3f823SJagannathan Raman bool write, hwaddr addr, uint64_t *val, 1647ee3f823SJagannathan Raman unsigned size, bool memory) 1657ee3f823SJagannathan Raman { 1667ee3f823SJagannathan Raman MPQemuMsg msg = { 0 }; 1677ee3f823SJagannathan Raman long ret = -EINVAL; 1687ee3f823SJagannathan Raman Error *local_err = NULL; 1697ee3f823SJagannathan Raman 1707ee3f823SJagannathan Raman msg.size = sizeof(BarAccessMsg); 1717ee3f823SJagannathan Raman msg.data.bar_access.addr = mr->addr + addr; 1727ee3f823SJagannathan Raman msg.data.bar_access.size = size; 1737ee3f823SJagannathan Raman msg.data.bar_access.memory = memory; 1747ee3f823SJagannathan Raman 1757ee3f823SJagannathan Raman if (write) { 1767ee3f823SJagannathan Raman msg.cmd = MPQEMU_CMD_BAR_WRITE; 1777ee3f823SJagannathan Raman msg.data.bar_access.val = *val; 1787ee3f823SJagannathan Raman } else { 1797ee3f823SJagannathan Raman msg.cmd = MPQEMU_CMD_BAR_READ; 1807ee3f823SJagannathan Raman } 1817ee3f823SJagannathan Raman 1827ee3f823SJagannathan Raman ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); 1837ee3f823SJagannathan Raman if (local_err) { 1847ee3f823SJagannathan Raman error_report_err(local_err); 1857ee3f823SJagannathan Raman } 1867ee3f823SJagannathan Raman 1877ee3f823SJagannathan Raman if (!write) { 1887ee3f823SJagannathan Raman *val = ret; 1897ee3f823SJagannathan Raman } 1907ee3f823SJagannathan Raman } 1917ee3f823SJagannathan Raman 1927ee3f823SJagannathan Raman static void proxy_bar_write(void *opaque, hwaddr addr, uint64_t val, 1937ee3f823SJagannathan Raman unsigned size) 1947ee3f823SJagannathan Raman { 1957ee3f823SJagannathan Raman ProxyMemoryRegion *pmr = opaque; 1967ee3f823SJagannathan Raman 1977ee3f823SJagannathan Raman send_bar_access_msg(pmr->dev, &pmr->mr, true, addr, &val, size, 1987ee3f823SJagannathan Raman pmr->memory); 1997ee3f823SJagannathan Raman } 2007ee3f823SJagannathan Raman 2017ee3f823SJagannathan Raman static uint64_t proxy_bar_read(void *opaque, hwaddr addr, unsigned size) 2027ee3f823SJagannathan Raman { 2037ee3f823SJagannathan Raman ProxyMemoryRegion *pmr = opaque; 2047ee3f823SJagannathan Raman uint64_t val; 2057ee3f823SJagannathan Raman 2067ee3f823SJagannathan Raman send_bar_access_msg(pmr->dev, &pmr->mr, false, addr, &val, size, 2077ee3f823SJagannathan Raman pmr->memory); 2087ee3f823SJagannathan Raman 2097ee3f823SJagannathan Raman return val; 2107ee3f823SJagannathan Raman } 2117ee3f823SJagannathan Raman 2127ee3f823SJagannathan Raman const MemoryRegionOps proxy_mr_ops = { 2137ee3f823SJagannathan Raman .read = proxy_bar_read, 2147ee3f823SJagannathan Raman .write = proxy_bar_write, 2157ee3f823SJagannathan Raman .endianness = DEVICE_NATIVE_ENDIAN, 2167ee3f823SJagannathan Raman .impl = { 2177ee3f823SJagannathan Raman .min_access_size = 1, 2187ee3f823SJagannathan Raman .max_access_size = 8, 2197ee3f823SJagannathan Raman }, 2207ee3f823SJagannathan Raman }; 221