Retrieve PCI configuration info about the remote device and configure the Proxy PCI object based on the returned information
Signed-off-by: Elena Ufimtseva <elena.ufimts...@oracle.com> Signed-off-by: John G Johnson <john.g.john...@oracle.com> Signed-off-by: Jagannathan Raman <jag.ra...@oracle.com> --- hw/pci/proxy.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ include/io/mpqemu-link.h | 1 + 2 files changed, 86 insertions(+) diff --git a/hw/pci/proxy.c b/hw/pci/proxy.c index 1c1b682..50a806c 100644 --- a/hw/pci/proxy.c +++ b/hw/pci/proxy.c @@ -23,6 +23,8 @@ #include "sysemu/kvm.h" #include "util/event_notifier-posix.c" +static void probe_pci_info(PCIDevice *dev, Error **errp); + static void proxy_set_socket(PCIProxyDev *pdev, int fd, Error **errp) { pdev->ioc = qio_channel_new_fd(fd, errp); @@ -86,6 +88,7 @@ static void setup_irqfd(PCIProxyDev *dev) static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) { PCIProxyDev *dev = PCI_PROXY_DEV(device); + uint8_t *pci_conf = device->config; int fd; if (dev->fd) { @@ -100,9 +103,14 @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) DEVICE(device)->id); } + pci_conf[PCI_LATENCY_TIMER] = 0xff; + pci_conf[PCI_INTERRUPT_PIN] = 0x01; + configure_memory_sync(&dev->sync, dev->ioc); setup_irqfd(dev); + + probe_pci_info(PCI_DEVICE(dev), errp); } static void pci_proxy_dev_exit(PCIDevice *pdev) @@ -258,3 +266,80 @@ const MemoryRegionOps proxy_mr_ops = { .max_access_size = 1, }, }; + +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; + PCIProxyDev *pdev = PCI_PROXY_DEV(dev); + DeviceClass *dc = DEVICE_CLASS(pc); + uint8_t type; + int i, size; + char *name; + + config_op_send(pdev, PCI_VENDOR_ID, &val, 2, PCI_CONFIG_READ); + pc->vendor_id = (uint16_t)val; + + config_op_send(pdev, PCI_DEVICE_ID, &val, 2, PCI_CONFIG_READ); + pc->device_id = (uint16_t)val; + + config_op_send(pdev, PCI_CLASS_DEVICE, &val, 2, PCI_CONFIG_READ); + pc->class_id = (uint16_t)val; + + config_op_send(pdev, PCI_SUBSYSTEM_ID, &val, 2, PCI_CONFIG_READ); + pc->subsystem_id = (uint16_t)val; + + base_class = pc->class_id >> 4; + switch (base_class) { + case PCI_BASE_CLASS_BRIDGE: + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + break; + case PCI_BASE_CLASS_STORAGE: + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + break; + case PCI_BASE_CLASS_NETWORK: + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + break; + case PCI_BASE_CLASS_INPUT: + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + break; + case PCI_BASE_CLASS_DISPLAY: + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + break; + case PCI_BASE_CLASS_PROCESSOR: + set_bit(DEVICE_CATEGORY_CPU, dc->categories); + break; + default: + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + break; + } + + for (i = 0; i < PCI_NUM_REGIONS; i++) { + config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &orig_val, 4, + PCI_CONFIG_READ); + new_val = 0xffffffff; + config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &new_val, 4, + PCI_CONFIG_WRITE); + config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &new_val, 4, + PCI_CONFIG_READ); + size = (~(new_val & 0xFFFFFFF0)) + 1; + config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &orig_val, 4, + PCI_CONFIG_WRITE); + type = (new_val & 0x1) ? + PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY; + + if (size) { + pdev->region[i].dev = pdev; + pdev->region[i].present = true; + if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) { + pdev->region[i].memory = true; + } + name = g_strdup_printf("bar-region-%d", i); + 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); + g_free(name); + } + } +} diff --git a/include/io/mpqemu-link.h b/include/io/mpqemu-link.h index 6625de6..a3844e1 100644 --- a/include/io/mpqemu-link.h +++ b/include/io/mpqemu-link.h @@ -39,6 +39,7 @@ typedef enum { BAR_WRITE, BAR_READ, SET_IRQFD, + GET_PCI_INFO, MAX = INT_MAX, } MPQemuCmd; -- 1.8.3.1