diff mbox series

[RFC,5/8] multiprocess: prepare ioregionfds for remote device

Message ID 7b0f00218f64b5b4445837c0edaed2b97a020213.1644302411.git.elena.ufimtseva@oracle.com (mailing list archive)
State New, archived
Headers show
Series ioregionfd introduction | expand

Commit Message

Elena Ufimtseva Feb. 8, 2022, 7:22 a.m. UTC
Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
---
 include/hw/remote/ioregionfd.h |  1 +
 include/hw/remote/remote.h     |  1 +
 hw/remote/ioregionfd.c         | 26 ++++++++++
 hw/remote/remote-obj.c         | 93 ++++++++++++++++++++++++++++++++++
 4 files changed, 121 insertions(+)
diff mbox series

Patch

diff --git a/include/hw/remote/ioregionfd.h b/include/hw/remote/ioregionfd.h
index c8a8b32ee0..85a2ef2c4f 100644
--- a/include/hw/remote/ioregionfd.h
+++ b/include/hw/remote/ioregionfd.h
@@ -37,4 +37,5 @@  struct IORegionFDObject {
 
 typedef struct IORegionFDObject IORegionFDObject;
 
+GSList *ioregionfd_get_obj_list(void);
 #endif /* IOREGIONFD_H */
diff --git a/include/hw/remote/remote.h b/include/hw/remote/remote.h
index a2d23178b9..46390c7934 100644
--- a/include/hw/remote/remote.h
+++ b/include/hw/remote/remote.h
@@ -23,6 +23,7 @@  struct RemoteObject {
 
     DeviceState *dev;
     DeviceListener listener;
+    GHashTable *ioregionfd_hash;
 };
 
 #endif
diff --git a/hw/remote/ioregionfd.c b/hw/remote/ioregionfd.c
index ae95f702a6..85ec0f7d38 100644
--- a/hw/remote/ioregionfd.c
+++ b/hw/remote/ioregionfd.c
@@ -37,6 +37,32 @@  struct IORegionFDObjectClass {
     unsigned int max_ioregfds;
 };
 
+static int ioregionfd_obj_list(Object *obj, void *opaque)
+{
+    GSList **list = opaque;
+
+    if (object_dynamic_cast(obj, TYPE_IOREGIONFD_OBJECT)) {
+        *list = g_slist_append(*list, obj);
+    }
+
+    object_child_foreach(obj, ioregionfd_obj_list, opaque);
+    return 0;
+}
+
+/*
+ * inquire ioregionfd objects and link them into the list which is
+ * returned to the caller.
+ *
+ * Caller must free the list.
+ */
+GSList *ioregionfd_get_obj_list(void)
+{
+    GSList *list = NULL;
+
+    object_child_foreach(object_get_root(), ioregionfd_obj_list, &list);
+    return list;
+}
+
 static void ioregionfd_object_init(Object *obj)
 {
     IORegionFDObjectClass *k = IOREGIONFD_OBJECT_GET_CLASS(obj);
diff --git a/hw/remote/remote-obj.c b/hw/remote/remote-obj.c
index f0da696662..9bb61c3a2d 100644
--- a/hw/remote/remote-obj.c
+++ b/hw/remote/remote-obj.c
@@ -24,6 +24,10 @@ 
 #include "qemu/sockets.h"
 #include "monitor/monitor.h"
 #include "hw/remote/remote.h"
+#include "hw/remote/ioregionfd.h"
+#include "qemu/cutils.h"
+#include "qapi/qapi-visit-qom.h"
+#include "qapi/string-output-visitor.h"
 
 #define TYPE_REMOTE_OBJECT "x-remote-object"
 OBJECT_DECLARE_TYPE(RemoteObject, RemoteObjectClass, REMOTE_OBJECT)
@@ -74,6 +78,80 @@  static void remote_object_unrealize_listener(DeviceListener *listener,
     }
 }
 
+static GSList *ioregions_list;
+
+static unsigned int ioregionfd_bar_hash(const void *key)
+{
+    const IORegionFDObject *o = key;
+
+    return g_int_hash(&o->ioregfd.bar);
+}
+
+/* TODO: allow for multiple ioregionfds per BAR. */
+static gboolean ioregionfd_bar_equal(const void *a, const void *b)
+{
+    const IORegionFDObject *oa = a;
+    const IORegionFDObject *ob = b;
+
+    error_report("BARS comparing %d %d", oa->ioregfd.bar, ob->ioregfd.bar);
+    if (oa->ioregfd.bar == ob->ioregfd.bar) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static void ioregionfd_prepare_for_dev(RemoteObject *o, PCIDevice *dev)
+{
+    IORegionFDObject *ioregfd_obj = NULL;
+    GSList *obj_list, *list;
+
+    list = ioregionfd_get_obj_list();
+
+    o->ioregionfd_hash = g_hash_table_new(ioregionfd_bar_hash,
+                                       ioregionfd_bar_equal);
+
+    for (obj_list = list; obj_list; obj_list = obj_list->next) {
+        ioregfd_obj = obj_list->data;
+        if (strcmp(ioregfd_obj->ioregfd.devid, o->devid) != 0) {
+            list = g_slist_remove(list, ioregfd_obj);
+            error_report("No my dev remove");
+            continue;
+        }
+        if (!g_hash_table_add(o->ioregionfd_hash, ioregfd_obj)) {
+            error_report("Cannot use more than one ioregionfd per bar");
+            list = g_slist_remove(list, ioregfd_obj);
+            object_unparent(OBJECT(ioregfd_obj));
+        } else {
+            error_report("Added to hash");
+        }
+    }
+
+    if (!list) {
+        error_report("Remote device %s will not have ioregionfds.",
+                     o->devid);
+        goto fatal;
+    }
+
+    /*
+     * Take first element in the list of ioregions and use its fd
+     * for all regions for this device.
+     * TODO: make this more flexible and allow different fd for the
+     * device.
+     */
+    ioregfd_obj = list->data;
+
+    /* This is default and will be changed when proxy requests region info. */
+    ioregfd_obj->ioregfd.memory = true;
+
+    ioregions_list = list;
+    return;
+
+ fatal:
+    g_slist_free(list);
+    g_hash_table_destroy(o->ioregionfd_hash);
+    return;
+}
+
 static void remote_object_machine_done(Notifier *notifier, void *data)
 {
     RemoteObject *o = container_of(notifier, RemoteObject, machine_done);
@@ -98,6 +176,10 @@  static void remote_object_machine_done(Notifier *notifier, void *data)
 
     o->dev = dev;
 
+#if CONFIG_IOREGIONFD
+    ioregionfd_prepare_for_dev(o, PCI_DEVICE(dev));
+#endif
+
     o->listener.unrealize = remote_object_unrealize_listener;
     device_listener_register(&o->listener);
 
@@ -132,6 +214,13 @@  static void remote_object_init(Object *obj)
     qemu_add_machine_init_done_notifier(&o->machine_done);
 }
 
+static void ioregionfd_release(gpointer data, gpointer user_data)
+{
+    IORegionFDObject *o = data;
+
+    object_unparent(OBJECT(o));
+}
+
 static void remote_object_finalize(Object *obj)
 {
     RemoteObjectClass *k = REMOTE_OBJECT_GET_CLASS(obj);
@@ -148,6 +237,10 @@  static void remote_object_finalize(Object *obj)
 
     k->nr_devs--;
     g_free(o->devid);
+    /* Free the list of the ioregions. */
+    g_slist_foreach(ioregions_list, ioregionfd_release, NULL);
+    g_slist_free(ioregions_list);
+    g_hash_table_destroy(o->ioregionfd_hash);
 }
 
 static void remote_object_class_init(ObjectClass *klass, void *data)