diff mbox series

[v7,17/21] multi-process: Retrieve PCI info from remote process

Message ID a6b53187fa9f8ae1bf8470a8a6da36f66a87d53a.1593273671.git.elena.ufimtseva@oracle.com (mailing list archive)
State New, archived
Headers show
Series Initial support for multi-process qemu | expand

Commit Message

Elena Ufimtseva June 27, 2020, 5:09 p.m. UTC
From: Jagannathan Raman <jag.raman@oracle.com>

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.ufimtseva@oracle.com>
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
---
 hw/i386/remote-msg.c     | 23 +++++++++++
 hw/pci/proxy.c           | 89 ++++++++++++++++++++++++++++++++++++++++
 include/io/mpqemu-link.h |  9 ++++
 io/mpqemu-link.c         |  5 +++
 4 files changed, 126 insertions(+)

Comments

Stefan Hajnoczi July 2, 2020, 12:59 p.m. UTC | #1
On Sat, Jun 27, 2020 at 10:09:39AM -0700, elena.ufimtseva@oracle.com wrote:
> @@ -267,3 +275,84 @@ const MemoryRegionOps proxy_mr_ops = {
>          .max_access_size = 1,
>      },
>  };
> +
> +static void probe_pci_info(PCIDevice *dev)
> +{
> +    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
> +    DeviceClass *dc = DEVICE_CLASS(pc);
> +    PCIProxyDev *pdev = PCI_PROXY_DEV(dev);
> +    MPQemuMsg msg = { 0 }, ret =  { 0 };
> +    uint32_t orig_val, new_val, class;
> +    uint8_t type;
> +    int i, size;
> +    char *name;
> +    Error *local_err = NULL;
> +
> +    msg.bytestream = 0;
> +    msg.size = 0;
> +    msg.cmd = GET_PCI_INFO;
> +
> +    ret.data1.u64  = mpqemu_msg_send_reply_co(&msg, pdev->dev, &local_err);
> +    if (local_err) {
> +        error_report("Error while sending GET_PCI_INFO message");
> +    }
> +
> +    pc->vendor_id = ret.data1.ret_pci_info.vendor_id;
> +    pc->device_id = ret.data1.ret_pci_info.device_id;
> +    pc->class_id = ret.data1.ret_pci_info.class_id;
> +    pc->subsystem_id = ret.data1.ret_pci_info.subsystem_id;

Why are the vendor/device/class/subsystem IDs read using a special
GET_PCI_INFO message when they are already accessible from the PCI
Configuration Space? All the other values are being read from the config
space so I wonder why a special message is needed.

> +
> +    config_op_send(pdev, PCI_CLASS_DEVICE, &class, 1, PCI_CONFIG_READ);
> +    switch (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 < 6; i++) {

s/6/G_N_ELEMENTS(pdev->region)/
diff mbox series

Patch

diff --git a/hw/i386/remote-msg.c b/hw/i386/remote-msg.c
index 67fee4bb57..9379ee6442 100644
--- a/hw/i386/remote-msg.c
+++ b/hw/i386/remote-msg.c
@@ -20,6 +20,8 @@  static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
                                 MPQemuMsg *msg);
 static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
 static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
+static void process_get_pci_info_msg(QIOChannel *ioc, MPQemuMsg *msg,
+                                     PCIDevice *pci_dev);
 
 gboolean mpqemu_process_msg(QIOChannel *ioc, GIOCondition cond,
                             gpointer opaque)
@@ -71,6 +73,9 @@  gboolean mpqemu_process_msg(QIOChannel *ioc, GIOCondition cond,
     case SET_IRQFD:
         process_set_irqfd_msg(pci_dev, &msg);
         break;
+    case GET_PCI_INFO:
+        process_get_pci_info_msg(ioc, &msg, pci_dev);
+        break;
     default:
         error_setg(&local_err, "Unknown command (%d) received from proxy \
                    in remote process pid=%d", msg.cmd, getpid());
@@ -246,3 +251,21 @@  fail:
 
     mpqemu_msg_send(&ret, ioc);
 }
+
+static void process_get_pci_info_msg(QIOChannel *ioc, MPQemuMsg *msg,
+                                     PCIDevice *pci_dev)
+{
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
+    MPQemuMsg ret = { 0 };
+
+    ret.cmd = RET_MSG;
+
+    ret.data1.ret_pci_info.vendor_id = pc->vendor_id;
+    ret.data1.ret_pci_info.device_id = pc->device_id;
+    ret.data1.ret_pci_info.class_id = pc->class_id;
+    ret.data1.ret_pci_info.subsystem_id = pc->subsystem_id;
+
+    ret.size = sizeof(ret.data1);
+
+    mpqemu_msg_send(&ret, ioc);
+}
diff --git a/hw/pci/proxy.c b/hw/pci/proxy.c
index 9d8559b6d4..449341e459 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);
+
 static void proxy_set_socket(PCIProxyDev *pdev, int fd, Error **errp)
 {
     DeviceState *dev = DEVICE(pdev);
@@ -110,6 +112,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 proxyfd;
 
     if (dev->fd) {
@@ -121,9 +124,14 @@  static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
         proxy_set_socket(dev, proxyfd, errp);
     }
 
+    pci_conf[PCI_LATENCY_TIMER] = 0xff;
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+
     configure_memory_sync(&dev->sync, dev->com);
 
     setup_irqfd(dev);
+
+    probe_pci_info(PCI_DEVICE(dev));
 }
 
 static int config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val,
@@ -267,3 +275,84 @@  const MemoryRegionOps proxy_mr_ops = {
         .max_access_size = 1,
     },
 };
+
+static void probe_pci_info(PCIDevice *dev)
+{
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+    DeviceClass *dc = DEVICE_CLASS(pc);
+    PCIProxyDev *pdev = PCI_PROXY_DEV(dev);
+    MPQemuMsg msg = { 0 }, ret =  { 0 };
+    uint32_t orig_val, new_val, class;
+    uint8_t type;
+    int i, size;
+    char *name;
+    Error *local_err = NULL;
+
+    msg.bytestream = 0;
+    msg.size = 0;
+    msg.cmd = GET_PCI_INFO;
+
+    ret.data1.u64  = mpqemu_msg_send_reply_co(&msg, pdev->dev, &local_err);
+    if (local_err) {
+        error_report("Error while sending GET_PCI_INFO message");
+    }
+
+    pc->vendor_id = ret.data1.ret_pci_info.vendor_id;
+    pc->device_id = ret.data1.ret_pci_info.device_id;
+    pc->class_id = ret.data1.ret_pci_info.class_id;
+    pc->subsystem_id = ret.data1.ret_pci_info.subsystem_id;
+
+    config_op_send(pdev, PCI_CLASS_DEVICE, &class, 1, PCI_CONFIG_READ);
+    switch (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 < 6; 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 a563b557ce..4b96cb8ccb 100644
--- a/include/io/mpqemu-link.h
+++ b/include/io/mpqemu-link.h
@@ -43,6 +43,7 @@  typedef enum {
     BAR_WRITE,
     BAR_READ,
     SET_IRQFD,
+    GET_PCI_INFO,
     MAX = INT_MAX,
 } MPQemuCmd;
 
@@ -69,6 +70,13 @@  typedef struct {
     int intx;
 } SetIrqFdMsg;
 
+typedef struct {
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint16_t class_id;
+    uint16_t subsystem_id;
+} RetPCIInfoMsg;
+
 /**
  * Maximum size of data2 field in the message to be transmitted.
  */
@@ -98,6 +106,7 @@  typedef struct {
         SyncSysmemMsg sync_sysmem;
         BarAccessMsg bar_access;
         SetIrqFdMsg set_irqfd;
+        RetPCIInfoMsg ret_pci_info;
     } data1;
 
     int fds[REMOTE_MAX_FDS];
diff --git a/io/mpqemu-link.c b/io/mpqemu-link.c
index 561ac0576f..d09b2a2f50 100644
--- a/io/mpqemu-link.c
+++ b/io/mpqemu-link.c
@@ -263,6 +263,11 @@  bool mpqemu_msg_valid(MPQemuMsg *msg)
             return false;
         }
         break;
+    case GET_PCI_INFO:
+        if (msg->size) {
+            return false;
+        }
+        break;
     default:
         break;
     }