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/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index a1247f2..ff43b41 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -40,13 +40,15 @@
 #include <engine/disp.h>
 
 #include <core/class.h>
+#include <nvif/event.h>
 
 static int
-nouveau_display_vblank_handler(void *data, u32 type, int head)
+nouveau_display_vblank_handler(struct nvkm_notify *notify)
 {
-	struct nouveau_crtc *nv_crtc = data;
+	struct nouveau_crtc *nv_crtc =
+		container_of(notify, typeof(*nv_crtc), vblank);
 	drm_handle_vblank(nv_crtc->base.dev, nv_crtc->index);
-	return NVKM_EVENT_KEEP;
+	return NVKM_NOTIFY_KEEP;
 }
 
 int
@@ -56,7 +58,7 @@
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 		if (nv_crtc->index == head) {
-			nouveau_event_get(nv_crtc->vblank);
+			nvkm_notify_get(&nv_crtc->vblank);
 			return 0;
 		}
 	}
@@ -70,7 +72,7 @@
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 		if (nv_crtc->index == head) {
-			nouveau_event_put(nv_crtc->vblank);
+			nvkm_notify_put(&nv_crtc->vblank);
 			return;
 		}
 	}
@@ -165,7 +167,7 @@
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-		nouveau_event_ref(NULL, &nv_crtc->vblank);
+		nvkm_notify_fini(&nv_crtc->vblank);
 	}
 }
 
@@ -179,9 +181,14 @@
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-		ret = nouveau_event_new(pdisp->vblank, 1, nv_crtc->index,
-					nouveau_display_vblank_handler,
-					nv_crtc, &nv_crtc->vblank);
+		ret = nvkm_notify_init(&pdisp->vblank,
+				       nouveau_display_vblank_handler, false,
+				       &(struct nvif_notify_head_req_v0) {
+					.head = nv_crtc->index,
+				       },
+				       sizeof(struct nvif_notify_head_req_v0),
+				       sizeof(struct nvif_notify_head_rep_v0),
+				       &nv_crtc->vblank);
 		if (ret) {
 			nouveau_display_vblank_fini(dev);
 			return ret;
@@ -359,7 +366,7 @@
 	/* enable hotplug interrupts */
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct nouveau_connector *conn = nouveau_connector(connector);
-		if (conn->hpd) nouveau_event_get(conn->hpd);
+		nvkm_notify_get(&conn->hpd);
 	}
 
 	return ret;
@@ -379,7 +386,7 @@
 	/* disable hotplug interrupts */
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct nouveau_connector *conn = nouveau_connector(connector);
-		if (conn->hpd) nouveau_event_put(conn->hpd);
+		nvkm_notify_put(&conn->hpd);
 	}
 
 	drm_kms_helper_poll_disable(dev);