drm/nouveau/core: rework event interface

This is a lot of prep-work for being able to send event notifications
back to userspace.  Events now contain data, rather than a "something
just happened" signal.

Handler data is now embedded into a containing structure, rather than
being kmalloc()'d, and can optionally have the notify routine handled
in a workqueue.

Various races between suspend/unload with display HPD/DP IRQ handlers
automagically solved as a result.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c
index 6c16dab..ac31a6d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/base.c
@@ -364,6 +364,7 @@
 /******************************************************************************
  * nouveau_device: engine functions
  *****************************************************************************/
+
 static struct nouveau_oclass
 nouveau_device_sclass[] = {
 	{ 0x0080, &nouveau_devobj_ofuncs },
@@ -371,6 +372,23 @@
 };
 
 static int
+nouveau_device_event_ctor(void *data, u32 size, struct nvkm_notify *notify)
+{
+	if (!WARN_ON(size != 0)) {
+		notify->size  = 0;
+		notify->types = 1;
+		notify->index = 0;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static const struct nvkm_event_func
+nouveau_device_event_func = {
+	.ctor = nouveau_device_event_ctor,
+};
+
+static int
 nouveau_device_fini(struct nouveau_object *object, bool suspend)
 {
 	struct nouveau_device *device = (void *)object;
@@ -445,7 +463,7 @@
 {
 	struct nouveau_device *device = (void *)object;
 
-	nouveau_event_destroy(&device->ntfy);
+	nvkm_event_fini(&device->event);
 
 	mutex_lock(&nv_devices_mutex);
 	list_del(&device->head);
@@ -545,7 +563,8 @@
 	nv_engine(device)->sclass = nouveau_device_sclass;
 	list_add(&device->head, &nv_devices);
 
-	ret = nouveau_event_create(1, NVKM_DEVICE_NTFY, &device->ntfy);
+	ret = nvkm_event_init(&nouveau_device_event_func, 1, 1,
+			      &device->event);
 done:
 	mutex_unlock(&nv_devices_mutex);
 	return ret;