@@ -23,11 +23,21 @@
#include "exec/memory.h"
#include "qemu/error-report.h"
#include "exec/address-spaces.h"
+#include "qapi/error.h"
+#include "qemu/event_notifier.h"
static void gunyah_region_add(MemoryListener *listener,
MemoryRegionSection *section);
static void gunyah_region_del(MemoryListener *listener,
MemoryRegionSection *section);
+static void gunyah_mem_ioeventfd_add(MemoryListener *listener,
+ MemoryRegionSection *section,
+ bool match_data, uint64_t data,
+ EventNotifier *e);
+static void gunyah_mem_ioeventfd_del(MemoryListener *listener,
+ MemoryRegionSection *section,
+ bool match_data, uint64_t data,
+ EventNotifier *e);
static int gunyah_ioctl(int type, ...)
{
@@ -64,6 +74,8 @@ static MemoryListener gunyah_memory_listener = {
.priority = MEMORY_LISTENER_PRIORITY_ACCEL,
.region_add = gunyah_region_add,
.region_del = gunyah_region_del,
+ .eventfd_add = gunyah_mem_ioeventfd_add,
+ .eventfd_del = gunyah_mem_ioeventfd_del,
};
int gunyah_create_vm(void)
@@ -306,6 +318,88 @@ static void gunyah_region_del(MemoryListener *listener,
gunyah_set_phys_mem(s, section, false);
}
+int gunyah_add_irqfd(int irqfd, int label, Error **errp)
+{
+ int ret;
+ struct gh_fn_desc fdesc;
+ struct gh_fn_irqfd_arg ghirqfd;
+
+ fdesc.type = GH_FN_IRQFD;
+ fdesc.arg_size = sizeof(struct gh_fn_irqfd_arg);
+ fdesc.arg = (__u64)(&ghirqfd);
+
+ ghirqfd.fd = irqfd;
+ ghirqfd.label = label;
+ ghirqfd.flags = GH_IRQFD_FLAGS_LEVEL;
+
+ ret = gunyah_vm_ioctl(GH_VM_ADD_FUNCTION, &fdesc);
+ if (ret) {
+ error_setg_errno(errp, errno, "GH_FN_IRQFD failed");
+ }
+
+ return ret;
+}
+
+static int gunyah_set_ioeventfd_mmio(int fd, hwaddr addr,
+ uint32_t size, uint32_t data, bool datamatch, bool assign)
+{
+ int ret;
+ struct gh_fn_ioeventfd_arg io;
+ struct gh_fn_desc fdesc;
+
+ io.fd = fd;
+ io.datamatch = datamatch ? data : 0;
+ io.len = size;
+ io.addr = addr;
+ io.flags = datamatch ? GH_IOEVENTFD_FLAGS_DATAMATCH : 0;
+
+ fdesc.type = GH_FN_IOEVENTFD;
+ fdesc.arg_size = sizeof(struct gh_fn_ioeventfd_arg);
+ fdesc.arg = (__u64)(&io);
+
+ if (assign) {
+ ret = gunyah_vm_ioctl(GH_VM_ADD_FUNCTION, &fdesc);
+ } else {
+ ret = gunyah_vm_ioctl(GH_VM_REMOVE_FUNCTION, &fdesc);
+ }
+
+ return ret;
+}
+
+static void gunyah_mem_ioeventfd_add(MemoryListener *listener,
+ MemoryRegionSection *section,
+ bool match_data, uint64_t data,
+ EventNotifier *e)
+{
+ int fd = event_notifier_get_fd(e);
+ int r;
+
+ r = gunyah_set_ioeventfd_mmio(fd, section->offset_within_address_space,
+ int128_get64(section->size), data, match_data,
+ true);
+ if (r < 0) {
+ error_report("error adding ioeventfd: %s", strerror(errno));
+ exit(1);
+ }
+}
+
+static void gunyah_mem_ioeventfd_del(MemoryListener *listener,
+ MemoryRegionSection *section,
+ bool match_data, uint64_t data,
+ EventNotifier *e)
+{
+ int fd = event_notifier_get_fd(e);
+ int r;
+
+ r = gunyah_set_ioeventfd_mmio(fd, section->offset_within_address_space,
+ int128_get64(section->size), data, match_data,
+ false);
+ if (r < 0) {
+ error_report("error deleting ioeventfd: %s", strerror(errno));
+ exit(1);
+ }
+}
+
void *gunyah_cpu_thread_fn(void *arg)
{
CPUState *cpu = arg;
@@ -50,5 +50,6 @@ struct GUNYAHState {
int gunyah_create_vm(void);
int gunyah_vm_ioctl(int type, ...);
void *gunyah_cpu_thread_fn(void *arg);
+int gunyah_add_irqfd(int irqfd, int label, Error **errp);
#endif /* GUNYAH_INT_H */
IRQFD function allows registering of an @eventfd and @irq. @irq will be injected inside guest when @eventfd is written into. IOEVENTFD function allows registering an @eventfd and a guest physical address, @addr, along with optional data. A poll() on @eventfd will be woken up when guest attempts to access @addr. Signed-off-by: Srivatsa Vaddagiri <quic_svaddagi@quicinc.com> --- accel/gunyah/gunyah-all.c | 94 +++++++++++++++++++++++++++++++++++++ include/sysemu/gunyah_int.h | 1 + 2 files changed, 95 insertions(+)