Signed-off-by: Elena Ufimtseva <elena.ufimts...@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 --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) -- 2.25.1