@@ -37,4 +37,5 @@ struct IORegionFDObject {
typedef struct IORegionFDObject IORegionFDObject;
+GSList *ioregionfd_get_obj_list(void);
#endif /* IOREGIONFD_H */
@@ -23,6 +23,7 @@ struct RemoteObject {
DeviceState *dev;
DeviceListener listener;
+ GHashTable *ioregionfd_hash;
};
#endif
@@ -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);
@@ -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)
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(+)