drm/nouveau/core: rework event interface
authorBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 18:10:20 +0000 (04:10 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 19:13:02 +0000 (05:13 +1000)
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>
52 files changed:
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/core/event.c
drivers/gpu/drm/nouveau/core/core/notify.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/device/acpi.c
drivers/gpu/drm/nouveau/core/engine/device/base.c
drivers/gpu/drm/nouveau/core/engine/disp/base.c
drivers/gpu/drm/nouveau/core/engine/disp/conn.c
drivers/gpu/drm/nouveau/core/engine/disp/conn.h
drivers/gpu/drm/nouveau/core/engine/disp/dport.c
drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
drivers/gpu/drm/nouveau/core/engine/disp/priv.h
drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
drivers/gpu/drm/nouveau/core/engine/fifo/base.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
drivers/gpu/drm/nouveau/core/engine/software/nv50.c
drivers/gpu/drm/nouveau/core/engine/software/nv50.h
drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
drivers/gpu/drm/nouveau/core/include/core/device.h
drivers/gpu/drm/nouveau/core/include/core/event.h
drivers/gpu/drm/nouveau/core/include/core/notify.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/engine/disp.h
drivers/gpu/drm/nouveau/core/include/engine/fifo.h
drivers/gpu/drm/nouveau/core/include/nvif/event.h [new symlink]
drivers/gpu/drm/nouveau/core/include/nvif/unpack.h [new symlink]
drivers/gpu/drm/nouveau/core/include/subdev/clock.h
drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
drivers/gpu/drm/nouveau/core/subdev/clock/base.c
drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_crtc.h
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nvif/event.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/unpack.h [new file with mode: 0644]

index fcd915c..749a047 100644 (file)
@@ -16,6 +16,7 @@ nouveau-y += core/core/gpuobj.o
 nouveau-y += core/core/handle.o
 nouveau-y += core/core/mm.o
 nouveau-y += core/core/namedb.o
+nouveau-y += core/core/notify.o
 nouveau-y += core/core/object.o
 nouveau-y += core/core/option.o
 nouveau-y += core/core/parent.o
index ae81d3b..0540a48 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Red Hat Inc.
+ * Copyright 2013-2014 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 #include <core/event.h>
 
 void
-nouveau_event_put(struct nouveau_eventh *handler)
+nvkm_event_put(struct nvkm_event *event, u32 types, int index)
 {
-       struct nouveau_event *event = handler->event;
-       unsigned long flags;
-       u32 m, t;
-
-       if (!__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags))
-               return;
-
-       spin_lock_irqsave(&event->refs_lock, flags);
-       for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) {
-               if (!--event->refs[handler->index * event->types_nr + t]) {
-                       if (event->disable)
-                               event->disable(event, 1 << t, handler->index);
+       BUG_ON(!spin_is_locked(&event->refs_lock));
+       while (types) {
+               int type = __ffs(types); types &= ~(1 << type);
+               if (--event->refs[index * event->types_nr + type] == 0) {
+                       if (event->func->fini)
+                               event->func->fini(event, 1 << type, index);
                }
-
        }
-       spin_unlock_irqrestore(&event->refs_lock, flags);
 }
 
 void
-nouveau_event_get(struct nouveau_eventh *handler)
+nvkm_event_get(struct nvkm_event *event, u32 types, int index)
 {
-       struct nouveau_event *event = handler->event;
-       unsigned long flags;
-       u32 m, t;
-
-       if (__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags))
-               return;
-
-       spin_lock_irqsave(&event->refs_lock, flags);
-       for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) {
-               if (!event->refs[handler->index * event->types_nr + t]++) {
-                       if (event->enable)
-                               event->enable(event, 1 << t, handler->index);
+       BUG_ON(!spin_is_locked(&event->refs_lock));
+       while (types) {
+               int type = __ffs(types); types &= ~(1 << type);
+               if (++event->refs[index * event->types_nr + type] == 1) {
+                       if (event->func->init)
+                               event->func->init(event, 1 << type, index);
                }
-
        }
-       spin_unlock_irqrestore(&event->refs_lock, flags);
-}
-
-static void
-nouveau_event_fini(struct nouveau_eventh *handler)
-{
-       struct nouveau_event *event = handler->event;
-       unsigned long flags;
-       nouveau_event_put(handler);
-       spin_lock_irqsave(&event->list_lock, flags);
-       list_del(&handler->head);
-       spin_unlock_irqrestore(&event->list_lock, flags);
-}
-
-static int
-nouveau_event_init(struct nouveau_event *event, u32 types, int index,
-                  int (*func)(void *, u32, int), void *priv,
-                  struct nouveau_eventh *handler)
-{
-       unsigned long flags;
-
-       if (types & ~((1 << event->types_nr) - 1))
-               return -EINVAL;
-       if (index >= event->index_nr)
-               return -EINVAL;
-
-       handler->event = event;
-       handler->flags = 0;
-       handler->types = types;
-       handler->index = index;
-       handler->func = func;
-       handler->priv = priv;
-
-       spin_lock_irqsave(&event->list_lock, flags);
-       list_add_tail(&handler->head, &event->list[index]);
-       spin_unlock_irqrestore(&event->list_lock, flags);
-       return 0;
-}
-
-int
-nouveau_event_new(struct nouveau_event *event, u32 types, int index,
-                 int (*func)(void *, u32, int), void *priv,
-                 struct nouveau_eventh **phandler)
-{
-       struct nouveau_eventh *handler;
-       int ret = -ENOMEM;
-
-       if (event->check) {
-               ret = event->check(event, types, index);
-               if (ret)
-                       return ret;
-       }
-
-       handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL);
-       if (handler) {
-               ret = nouveau_event_init(event, types, index, func, priv, handler);
-               if (ret)
-                       kfree(handler);
-       }
-
-       return ret;
-}
-
-void
-nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref)
-{
-       BUG_ON(handler != NULL);
-       if (*ref) {
-               nouveau_event_fini(*ref);
-               kfree(*ref);
-       }
-       *ref = handler;
 }
 
 void
-nouveau_event_trigger(struct nouveau_event *event, u32 types, int index)
+nvkm_event_send(struct nvkm_event *event, u32 types, int index,
+               void *data, u32 size)
 {
-       struct nouveau_eventh *handler;
+       struct nvkm_notify *notify;
        unsigned long flags;
 
-       if (WARN_ON(index >= event->index_nr))
+       if (!event->refs || WARN_ON(index >= event->index_nr))
                return;
 
        spin_lock_irqsave(&event->list_lock, flags);
-       list_for_each_entry(handler, &event->list[index], head) {
-               if (!test_bit(NVKM_EVENT_ENABLE, &handler->flags))
-                       continue;
-               if (!(handler->types & types))
-                       continue;
-               if (handler->func(handler->priv, handler->types & types, index)
-                               != NVKM_EVENT_DROP)
-                       continue;
-               nouveau_event_put(handler);
+       list_for_each_entry(notify, &event->list, head) {
+               if (notify->index == index && (notify->types & types)) {
+                       if (event->func->send) {
+                               event->func->send(data, size, notify);
+                               continue;
+                       }
+                       nvkm_notify_send(notify, data, size);
+               }
        }
        spin_unlock_irqrestore(&event->list_lock, flags);
 }
 
 void
-nouveau_event_destroy(struct nouveau_event **pevent)
+nvkm_event_fini(struct nvkm_event *event)
 {
-       struct nouveau_event *event = *pevent;
-       if (event) {
-               kfree(event);
-               *pevent = NULL;
+       if (event->refs) {
+               kfree(event->refs);
+               event->refs = NULL;
        }
 }
 
 int
-nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **pevent)
+nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr,
+               struct nvkm_event *event)
 {
-       struct nouveau_event *event;
-       int i;
-
-       event = *pevent = kzalloc(sizeof(*event) + (index_nr * types_nr) *
-                                 sizeof(event->refs[0]), GFP_KERNEL);
-       if (!event)
-               return -ENOMEM;
-
-       event->list = kmalloc(sizeof(*event->list) * index_nr, GFP_KERNEL);
-       if (!event->list) {
-               kfree(event);
+       event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr,
+                             GFP_KERNEL);
+       if (!event->refs)
                return -ENOMEM;
-       }
 
-       spin_lock_init(&event->list_lock);
-       spin_lock_init(&event->refs_lock);
-       for (i = 0; i < index_nr; i++)
-               INIT_LIST_HEAD(&event->list[i]);
+       event->func = func;
        event->types_nr = types_nr;
        event->index_nr = index_nr;
+       spin_lock_init(&event->refs_lock);
+       spin_lock_init(&event->list_lock);
+       INIT_LIST_HEAD(&event->list);
        return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/core/core/notify.c b/drivers/gpu/drm/nouveau/core/core/notify.c
new file mode 100644 (file)
index 0000000..460f4ec
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <core/os.h>
+#include <core/event.h>
+#include <core/notify.h>
+
+static inline void
+nvkm_notify_put_locked(struct nvkm_notify *notify)
+{
+       if (notify->block++ == 0)
+               nvkm_event_put(notify->event, notify->types, notify->index);
+}
+
+void
+nvkm_notify_put(struct nvkm_notify *notify)
+{
+       struct nvkm_event *event = notify->event;
+       unsigned long flags;
+       if (likely(event) &&
+           test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+               spin_lock_irqsave(&event->refs_lock, flags);
+               nvkm_notify_put_locked(notify);
+               spin_unlock_irqrestore(&event->refs_lock, flags);
+               if (test_bit(NVKM_NOTIFY_WORK, &notify->flags))
+                       flush_work(&notify->work);
+       }
+}
+
+static inline void
+nvkm_notify_get_locked(struct nvkm_notify *notify)
+{
+       if (--notify->block == 0)
+               nvkm_event_get(notify->event, notify->types, notify->index);
+}
+
+void
+nvkm_notify_get(struct nvkm_notify *notify)
+{
+       struct nvkm_event *event = notify->event;
+       unsigned long flags;
+       if (likely(event) &&
+           !test_and_set_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+               spin_lock_irqsave(&event->refs_lock, flags);
+               nvkm_notify_get_locked(notify);
+               spin_unlock_irqrestore(&event->refs_lock, flags);
+       }
+}
+
+static inline void
+nvkm_notify_func(struct nvkm_notify *notify)
+{
+       struct nvkm_event *event = notify->event;
+       int ret = notify->func(notify);
+       unsigned long flags;
+       if ((ret == NVKM_NOTIFY_KEEP) ||
+           !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+               spin_lock_irqsave(&event->refs_lock, flags);
+               nvkm_notify_get_locked(notify);
+               spin_unlock_irqrestore(&event->refs_lock, flags);
+       }
+}
+
+static void
+nvkm_notify_work(struct work_struct *work)
+{
+       struct nvkm_notify *notify = container_of(work, typeof(*notify), work);
+       nvkm_notify_func(notify);
+}
+
+void
+nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size)
+{
+       struct nvkm_event *event = notify->event;
+       unsigned long flags;
+
+       BUG_ON(!spin_is_locked(&event->list_lock));
+       BUG_ON(size != notify->size);
+
+       spin_lock_irqsave(&event->refs_lock, flags);
+       if (notify->block) {
+               spin_unlock_irqrestore(&event->refs_lock, flags);
+               return;
+       }
+       nvkm_notify_put_locked(notify);
+       spin_unlock_irqrestore(&event->refs_lock, flags);
+
+       if (test_bit(NVKM_NOTIFY_WORK, &notify->flags)) {
+               memcpy((void *)notify->data, data, size);
+               schedule_work(&notify->work);
+       } else {
+               notify->data = data;
+               nvkm_notify_func(notify);
+               notify->data = NULL;
+       }
+}
+
+void
+nvkm_notify_fini(struct nvkm_notify *notify)
+{
+       unsigned long flags;
+       if (notify->event) {
+               nvkm_notify_put(notify);
+               spin_lock_irqsave(&notify->event->list_lock, flags);
+               list_del(&notify->head);
+               spin_unlock_irqrestore(&notify->event->list_lock, flags);
+               kfree((void *)notify->data);
+               notify->event = NULL;
+       }
+}
+
+int
+nvkm_notify_init(struct nvkm_event *event, int (*func)(struct nvkm_notify *),
+                bool work, void *data, u32 size, u32 reply,
+                struct nvkm_notify *notify)
+{
+       unsigned long flags;
+       int ret = -ENODEV;
+       if ((notify->event = event), event->refs) {
+               ret = event->func->ctor(data, size, notify);
+               if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
+                       notify->flags = 0;
+                       notify->block = 1;
+                       notify->func = func;
+                       notify->data = NULL;
+                       if (ret = 0, work) {
+                               INIT_WORK(&notify->work, nvkm_notify_work);
+                               set_bit(NVKM_NOTIFY_WORK, &notify->flags);
+                               notify->data = kmalloc(reply, GFP_KERNEL);
+                               if (!notify->data)
+                                       ret = -ENOMEM;
+                       }
+               }
+               if (ret == 0) {
+                       spin_lock_irqsave(&event->list_lock, flags);
+                       list_add_tail(&notify->head, &event->list);
+                       spin_unlock_irqrestore(&event->list_lock, flags);
+               }
+       }
+       if (ret)
+               notify->event = NULL;
+       return ret;
+}
index 79a2e4d..4dbf0ba 100644 (file)
@@ -33,7 +33,7 @@ nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data)
        struct acpi_bus_event *info = data;
 
        if (!strcmp(info->device_class, "ac_adapter"))
-               nouveau_event_trigger(device->ntfy, 1, NVKM_DEVICE_NTFY_POWER);
+               nvkm_event_send(&device->event, 1, 0, NULL, 0);
 
        return NOTIFY_DONE;
 }
index 6c16dab..ac31a6d 100644 (file)
@@ -364,12 +364,30 @@ nouveau_devobj_ofuncs = {
 /******************************************************************************
  * nouveau_device: engine functions
  *****************************************************************************/
+
 static struct nouveau_oclass
 nouveau_device_sclass[] = {
        { 0x0080, &nouveau_devobj_ofuncs },
        {}
 };
 
+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)
 {
@@ -445,7 +463,7 @@ nouveau_device_dtor(struct nouveau_object *object)
 {
        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 @@ nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name,
        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;
index 9c38c5e..d1df0ce 100644 (file)
  * Authors: Ben Skeggs
  */
 
+#include <core/os.h>
+#include <nvif/unpack.h>
+#include <nvif/event.h>
+
 #include "priv.h"
 #include "outp.h"
 #include "conn.h"
 
+int
+nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *notify)
+{
+       struct nouveau_disp *disp =
+               container_of(notify->event, typeof(*disp), vblank);
+       union {
+               struct nvif_notify_head_req_v0 v0;
+       } *req = data;
+       int ret;
+
+       if (nvif_unpack(req->v0, 0, 0, false)) {
+               notify->size = sizeof(struct nvif_notify_head_rep_v0);
+               if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) {
+                       notify->types = 1;
+                       notify->index = req->v0.head;
+                       return 0;
+               }
+       }
+
+       return ret;
+}
+
+void
+nouveau_disp_vblank(struct nouveau_disp *disp, int head)
+{
+       struct nvif_notify_head_rep_v0 rep = {};
+       nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep));
+}
+
 static int
-nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index)
+nouveau_disp_hpd_ctor(void *data, u32 size, struct nvkm_notify *notify)
 {
-       struct nouveau_disp *disp = event->priv;
+       struct nouveau_disp *disp =
+               container_of(notify->event, typeof(*disp), hpd);
+       union {
+               struct nvif_notify_conn_req_v0 v0;
+       } *req = data;
        struct nvkm_output *outp;
-       list_for_each_entry(outp, &disp->outp, head) {
-               if (outp->conn->index == index) {
-                       if (outp->conn->hpd.event)
-                               return 0;
-                       break;
+       int ret;
+
+       if (nvif_unpack(req->v0, 0, 0, false)) {
+               notify->size = sizeof(struct nvif_notify_conn_rep_v0);
+               list_for_each_entry(outp, &disp->outp, head) {
+                       if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
+                               if (ret = -ENODEV, outp->conn->hpd.event) {
+                                       notify->types = req->v0.mask;
+                                       notify->index = req->v0.conn;
+                                       ret = 0;
+                               }
+                               break;
+                       }
                }
        }
-       return -ENOSYS;
+
+       return ret;
 }
 
+static const struct nvkm_event_func
+nouveau_disp_hpd_func = {
+       .ctor = nouveau_disp_hpd_ctor
+};
+
 int
 _nouveau_disp_fini(struct nouveau_object *object, bool suspend)
 {
@@ -97,7 +148,8 @@ _nouveau_disp_dtor(struct nouveau_object *object)
        struct nouveau_disp *disp = (void *)object;
        struct nvkm_output *outp, *outt;
 
-       nouveau_event_destroy(&disp->vblank);
+       nvkm_event_fini(&disp->vblank);
+       nvkm_event_fini(&disp->hpd);
 
        if (disp->outp.next) {
                list_for_each_entry_safe(outp, outt, &disp->outp, head) {
@@ -157,14 +209,11 @@ nouveau_disp_create_(struct nouveau_object *parent,
                hpd = max(hpd, (u8)(dcbE.connector + 1));
        }
 
-       ret = nouveau_event_create(3, hpd, &disp->hpd);
+       ret = nvkm_event_init(&nouveau_disp_hpd_func, 3, hpd, &disp->hpd);
        if (ret)
                return ret;
 
-       disp->hpd->priv = disp;
-       disp->hpd->check = nouveau_disp_hpd_check;
-
-       ret = nouveau_event_create(1, heads, &disp->vblank);
+       ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank);
        if (ret)
                return ret;
 
index 4ffbc70..3d10702 100644 (file)
  * Authors: Ben Skeggs
  */
 
+#include <core/os.h>
+#include <nvif/event.h>
+
 #include <subdev/gpio.h>
 
 #include "conn.h"
 #include "outp.h"
 
-static void
-nvkm_connector_hpd_work(struct work_struct *w)
+static int
+nvkm_connector_hpd(struct nvkm_notify *notify)
 {
-       struct nvkm_connector *conn = container_of(w, typeof(*conn), hpd.work);
+       struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
        struct nouveau_disp *disp = nouveau_disp(conn);
        struct nouveau_gpio *gpio = nouveau_gpio(conn);
-       u32 send = NVKM_HPD_UNPLUG;
-       if (gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.event->index))
-               send = NVKM_HPD_PLUG;
-       nouveau_event_trigger(disp->hpd, send, conn->index);
-       nouveau_event_get(conn->hpd.event);
-}
+       const struct nvkm_gpio_ntfy_rep *line = notify->data;
+       struct nvif_notify_conn_rep_v0 rep;
+       int index = conn->index;
 
-static int
-nvkm_connector_hpd(void *data, u32 type, int index)
-{
-       struct nvkm_connector *conn = data;
-       DBG("HPD: %d\n", type);
-       schedule_work(&conn->hpd.work);
-       return NVKM_EVENT_DROP;
+       DBG("HPD: %d\n", line->mask);
+
+       if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
+               rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
+       else
+               rep.mask = NVIF_NOTIFY_CONN_V0_PLUG;
+       rep.version = 0;
+
+       nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
+       return NVKM_NOTIFY_KEEP;
 }
 
 int
 _nvkm_connector_fini(struct nouveau_object *object, bool suspend)
 {
        struct nvkm_connector *conn = (void *)object;
-       if (conn->hpd.event)
-               nouveau_event_put(conn->hpd.event);
+       nvkm_notify_put(&conn->hpd);
        return nouveau_object_fini(&conn->base, suspend);
 }
 
@@ -63,10 +65,8 @@ _nvkm_connector_init(struct nouveau_object *object)
 {
        struct nvkm_connector *conn = (void *)object;
        int ret = nouveau_object_init(&conn->base);
-       if (ret == 0) {
-               if (conn->hpd.event)
-                       nouveau_event_get(conn->hpd.event);
-       }
+       if (ret == 0)
+               nvkm_notify_get(&conn->hpd);
        return ret;
 }
 
@@ -74,7 +74,7 @@ void
 _nvkm_connector_dtor(struct nouveau_object *object)
 {
        struct nvkm_connector *conn = (void *)object;
-       nouveau_event_ref(NULL, &conn->hpd.event);
+       nvkm_notify_fini(&conn->hpd);
        nouveau_object_destroy(&conn->base);
 }
 
@@ -116,19 +116,24 @@ nvkm_connector_create_(struct nouveau_object *parent,
        if ((info->hpd = ffs(info->hpd))) {
                if (--info->hpd >= ARRAY_SIZE(hpd)) {
                        ERR("hpd %02x unknown\n", info->hpd);
-                       goto done;
+                       return 0;
                }
                info->hpd = hpd[info->hpd];
 
                ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
                if (ret) {
                        ERR("func %02x lookup failed, %d\n", info->hpd, ret);
-                       goto done;
+                       return 0;
                }
 
-               ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED,
-                                       func.line, nvkm_connector_hpd,
-                                       conn, &conn->hpd.event);
+               ret = nvkm_notify_init(&gpio->event, nvkm_connector_hpd, true,
+                                      &(struct nvkm_gpio_ntfy_req) {
+                                       .mask = NVKM_GPIO_TOGGLED,
+                                       .line = func.line,
+                                      },
+                                      sizeof(struct nvkm_gpio_ntfy_req),
+                                      sizeof(struct nvkm_gpio_ntfy_rep),
+                                      &conn->hpd);
                if (ret) {
                        ERR("func %02x failed, %d\n", info->hpd, ret);
                } else {
@@ -136,8 +141,6 @@ nvkm_connector_create_(struct nouveau_object *parent,
                }
        }
 
-done:
-       INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work);
        return 0;
 }
 
index 035ebea..55e5f5c 100644 (file)
@@ -10,10 +10,7 @@ struct nvkm_connector {
        struct nvbios_connE info;
        int index;
 
-       struct {
-               struct nouveau_eventh *event;
-               struct work_struct work;
-       } hpd;
+       struct nvkm_notify hpd;
 };
 
 #define nvkm_connector_create(p,e,c,b,i,d)                                     \
index 5a5b59b..157bda9 100644 (file)
@@ -354,7 +354,7 @@ nouveau_dp_train(struct work_struct *w)
        cfg--;
 
        /* disable link interrupt handling during link training */
-       nouveau_event_put(outp->irq);
+       nvkm_notify_put(&outp->irq);
 
        /* enable down-spreading and execute pre-train script from vbios */
        dp_link_train_init(dp, outp->dpcd[3] & 0x01);
@@ -395,5 +395,5 @@ nouveau_dp_train(struct work_struct *w)
        DBG("training complete\n");
        atomic_set(&outp->lt.done, 1);
        wake_up(&outp->lt.wait);
-       nouveau_event_get(outp->irq);
+       nvkm_notify_get(&outp->irq);
 }
index 9fc7447..a9681df 100644 (file)
@@ -93,6 +93,7 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .base.vblank = &nvd0_disp_vblank_func,
        .base.outp =  nvd0_disp_outp_sclass,
        .mthd.core = &nve0_disp_mast_mthd_chan,
        .mthd.base = &nvd0_disp_sync_mthd_chan,
index a32666e..f1f3bd1 100644 (file)
@@ -86,17 +86,26 @@ nv04_disp_sclass[] = {
  ******************************************************************************/
 
 static void
-nv04_disp_vblank_enable(struct nouveau_event *event, int type, int head)
+nv04_disp_vblank_init(struct nvkm_event *event, int type, int head)
 {
-       nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001);
+       struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
+       nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001);
 }
 
 static void
-nv04_disp_vblank_disable(struct nouveau_event *event, int type, int head)
+nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head)
 {
-       nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000);
+       struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
+       nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000);
 }
 
+static const struct nvkm_event_func
+nv04_disp_vblank_func = {
+       .ctor = nouveau_disp_vblank_ctor,
+       .init = nv04_disp_vblank_init,
+       .fini = nv04_disp_vblank_fini,
+};
+
 static void
 nv04_disp_intr(struct nouveau_subdev *subdev)
 {
@@ -106,12 +115,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
        u32 pvideo;
 
        if (crtc0 & 0x00000001) {
-               nouveau_event_trigger(priv->base.vblank, 1, 0);
+               nouveau_disp_vblank(&priv->base, 0);
                nv_wr32(priv, 0x600100, 0x00000001);
        }
 
        if (crtc1 & 0x00000001) {
-               nouveau_event_trigger(priv->base.vblank, 1, 1);
+               nouveau_disp_vblank(&priv->base, 1);
                nv_wr32(priv, 0x602100, 0x00000001);
        }
 
@@ -140,9 +149,6 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        nv_engine(priv)->sclass = nv04_disp_sclass;
        nv_subdev(priv)->intr = nv04_disp_intr;
-       priv->base.vblank->priv = priv;
-       priv->base.vblank->enable = nv04_disp_vblank_enable;
-       priv->base.vblank->disable = nv04_disp_vblank_disable;
        return 0;
 }
 
@@ -155,4 +161,5 @@ nv04_disp_oclass = &(struct nouveau_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .vblank = &nv04_disp_vblank_func,
 }.base;
index 2283c44..5311f0f 100644 (file)
@@ -828,19 +828,7 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
        return 0;
 }
 
-static void
-nv50_disp_base_vblank_enable(struct nouveau_event *event, int type, int head)
-{
-       nv_mask(event->priv, 0x61002c, (4 << head), (4 << head));
-}
-
-static void
-nv50_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
-{
-       nv_mask(event->priv, 0x61002c, (4 << head), 0);
-}
-
-static int
+int
 nv50_disp_base_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
                    struct nouveau_oclass *oclass, void *data, u32 size,
@@ -856,14 +844,11 @@ nv50_disp_base_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       priv->base.vblank->priv = priv;
-       priv->base.vblank->enable = nv50_disp_base_vblank_enable;
-       priv->base.vblank->disable = nv50_disp_base_vblank_disable;
        return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
                                &base->ramht);
 }
 
-static void
+void
 nv50_disp_base_dtor(struct nouveau_object *object)
 {
        struct nv50_disp_base *base = (void *)object;
@@ -1040,6 +1025,27 @@ nv50_disp_cclass = {
  * Display engine implementation
  ******************************************************************************/
 
+static void
+nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head)
+{
+       struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
+       nv_mask(disp, 0x61002c, (4 << head), 0);
+}
+
+static void
+nv50_disp_vblank_init(struct nvkm_event *event, int type, int head)
+{
+       struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
+       nv_mask(disp, 0x61002c, (4 << head), (4 << head));
+}
+
+const struct nvkm_event_func
+nv50_disp_vblank_func = {
+       .ctor = nouveau_disp_vblank_ctor,
+       .init = nv50_disp_vblank_init,
+       .fini = nv50_disp_vblank_fini,
+};
+
 static const struct nouveau_enum
 nv50_disp_intr_error_type[] = {
        { 3, "ILLEGAL_MTHD" },
@@ -1654,13 +1660,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
        }
 
        if (intr1 & 0x00000004) {
-               nouveau_event_trigger(priv->base.vblank, 1, 0);
+               nouveau_disp_vblank(&priv->base, 0);
                nv_wr32(priv, 0x610024, 0x00000004);
                intr1 &= ~0x00000004;
        }
 
        if (intr1 & 0x00000008) {
-               nouveau_event_trigger(priv->base.vblank, 1, 1);
+               nouveau_disp_vblank(&priv->base, 1);
                nv_wr32(priv, 0x610024, 0x00000008);
                intr1 &= ~0x00000008;
        }
@@ -1718,6 +1724,7 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv50_disp_outp_sclass,
        .mthd.core = &nv50_disp_mast_mthd_chan,
        .mthd.base = &nv50_disp_sync_mthd_chan,
index 1a88647..c0e8b79 100644 (file)
@@ -165,11 +165,16 @@ extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base;
 extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs;
 extern struct nouveau_ofuncs nv50_disp_curs_ofuncs;
 extern struct nouveau_ofuncs nv50_disp_base_ofuncs;
+int  nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *,
+                        struct nouveau_oclass *, void *, u32,
+                        struct nouveau_object **);
+void nv50_disp_base_dtor(struct nouveau_object *);
 extern struct nouveau_oclass nv50_disp_cclass;
 void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
                         const struct nv50_disp_mthd_chan *);
 void nv50_disp_intr_supervisor(struct work_struct *);
 void nv50_disp_intr(struct nouveau_subdev *);
+extern const struct nvkm_event_func nv50_disp_vblank_func;
 
 extern const struct nv50_disp_mthd_chan nv84_disp_mast_mthd_chan;
 extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac;
@@ -195,6 +200,7 @@ extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
 extern struct nouveau_oclass nvd0_disp_cclass;
 void nvd0_disp_intr_supervisor(struct work_struct *);
 void nvd0_disp_intr(struct nouveau_subdev *);
+extern const struct nvkm_event_func nvd0_disp_vblank_func;
 
 extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan;
 extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;
index 1cc62e4..dd59774 100644 (file)
@@ -276,6 +276,7 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv50_disp_outp_sclass,
        .mthd.core = &nv84_disp_mast_mthd_chan,
        .mthd.base = &nv84_disp_sync_mthd_chan,
index 4f718a9..03a6b25 100644 (file)
@@ -143,6 +143,7 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv94_disp_outp_sclass,
        .mthd.core = &nv94_disp_mast_mthd_chan,
        .mthd.base = &nv84_disp_sync_mthd_chan,
index 6237a9a..ea1b5a7 100644 (file)
@@ -138,6 +138,7 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv50_disp_outp_sclass,
        .mthd.core = &nv84_disp_mast_mthd_chan,
        .mthd.base = &nv84_disp_sync_mthd_chan,
index 019124d..00f38a3 100644 (file)
@@ -110,6 +110,7 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv94_disp_outp_sclass,
        .mthd.core = &nv94_disp_mast_mthd_chan,
        .mthd.base = &nv84_disp_sync_mthd_chan,
index fa30d81..1ab2169 100644 (file)
@@ -747,50 +747,6 @@ nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
        return 0;
 }
 
-static void
-nvd0_disp_base_vblank_enable(struct nouveau_event *event, int type, int head)
-{
-       nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
-}
-
-static void
-nvd0_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
-{
-       nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
-}
-
-static int
-nvd0_disp_base_ctor(struct nouveau_object *parent,
-                   struct nouveau_object *engine,
-                   struct nouveau_oclass *oclass, void *data, u32 size,
-                   struct nouveau_object **pobject)
-{
-       struct nv50_disp_priv *priv = (void *)engine;
-       struct nv50_disp_base *base;
-       int ret;
-
-       ret = nouveau_parent_create(parent, engine, oclass, 0,
-                                   priv->sclass, 0, &base);
-       *pobject = nv_object(base);
-       if (ret)
-               return ret;
-
-       priv->base.vblank->priv = priv;
-       priv->base.vblank->enable = nvd0_disp_base_vblank_enable;
-       priv->base.vblank->disable = nvd0_disp_base_vblank_disable;
-
-       return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
-                               &base->ramht);
-}
-
-static void
-nvd0_disp_base_dtor(struct nouveau_object *object)
-{
-       struct nv50_disp_base *base = (void *)object;
-       nouveau_ramht_ref(NULL, &base->ramht);
-       nouveau_parent_destroy(&base->base);
-}
-
 static int
 nvd0_disp_base_init(struct nouveau_object *object)
 {
@@ -874,8 +830,8 @@ nvd0_disp_base_fini(struct nouveau_object *object, bool suspend)
 
 struct nouveau_ofuncs
 nvd0_disp_base_ofuncs = {
-       .ctor = nvd0_disp_base_ctor,
-       .dtor = nvd0_disp_base_dtor,
+       .ctor = nv50_disp_base_ctor,
+       .dtor = nv50_disp_base_dtor,
        .init = nvd0_disp_base_init,
        .fini = nvd0_disp_base_fini,
 };
@@ -916,6 +872,27 @@ nvd0_disp_sclass[] = {
  * Display engine implementation
  ******************************************************************************/
 
+static void
+nvd0_disp_vblank_init(struct nvkm_event *event, int type, int head)
+{
+       struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
+       nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
+}
+
+static void
+nvd0_disp_vblank_fini(struct nvkm_event *event, int type, int head)
+{
+       struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
+       nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
+}
+
+const struct nvkm_event_func
+nvd0_disp_vblank_func = {
+       .ctor = nouveau_disp_vblank_ctor,
+       .init = nvd0_disp_vblank_init,
+       .fini = nvd0_disp_vblank_fini,
+};
+
 static struct nvkm_output *
 exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
            u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
@@ -1343,7 +1320,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
                if (mask & intr) {
                        u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
                        if (stat & 0x00000001)
-                               nouveau_event_trigger(priv->base.vblank, 1, i);
+                               nouveau_disp_vblank(&priv->base, i);
                        nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
                        nv_rd32(priv, 0x6100c0 + (i * 0x800));
                }
@@ -1396,6 +1373,7 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .base.vblank = &nvd0_disp_vblank_func,
        .base.outp =  nvd0_disp_outp_sclass,
        .mthd.core = &nvd0_disp_mast_mthd_chan,
        .mthd.base = &nvd0_disp_sync_mthd_chan,
index 11328e3..1e5a79a 100644 (file)
@@ -258,6 +258,7 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .base.vblank = &nvd0_disp_vblank_func,
        .base.outp =  nvd0_disp_outp_sclass,
        .mthd.core = &nve0_disp_mast_mthd_chan,
        .mthd.base = &nvd0_disp_sync_mthd_chan,
index 1043880..198bc4b 100644 (file)
@@ -93,6 +93,7 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
+       .base.vblank = &nvd0_disp_vblank_func,
        .base.outp =  nvd0_disp_outp_sclass,
        .mthd.core = &nve0_disp_mast_mthd_chan,
        .mthd.base = &nvd0_disp_sync_mthd_chan,
index eb2d778..6f6e2a8 100644 (file)
@@ -22,6 +22,9 @@
  * Authors: Ben Skeggs
  */
 
+#include <core/os.h>
+#include <nvif/event.h>
+
 #include <subdev/i2c.h>
 
 #include "outpdp.h"
@@ -86,7 +89,7 @@ done:
                atomic_set(&outp->lt.done, 0);
                schedule_work(&outp->lt.work);
        } else {
-               nouveau_event_get(outp->irq);
+               nvkm_notify_get(&outp->irq);
        }
 
        if (wait) {
@@ -133,46 +136,59 @@ nvkm_output_dp_detect(struct nvkm_output_dp *outp)
        }
 }
 
-static void
-nvkm_output_dp_service_work(struct work_struct *work)
+static int
+nvkm_output_dp_hpd(struct nvkm_notify *notify)
 {
-       struct nvkm_output_dp *outp = container_of(work, typeof(*outp), work);
-       struct nouveau_disp *disp = nouveau_disp(outp);
-       int type = atomic_xchg(&outp->pending, 0);
-       u32 send = 0;
-
-       if (type & (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG)) {
-               nvkm_output_dp_detect(outp);
-               if (type & NVKM_I2C_UNPLUG)
-                       send |= NVKM_HPD_UNPLUG;
-               if (type & NVKM_I2C_PLUG)
-                       send |= NVKM_HPD_PLUG;
-               nouveau_event_get(outp->base.conn->hpd.event);
-       }
-
-       if (type & NVKM_I2C_IRQ) {
-               nvkm_output_dp_train(&outp->base, 0, true);
-               send |= NVKM_HPD_IRQ;
+       struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
+       struct nvkm_output_dp *outp;
+       struct nouveau_disp *disp = nouveau_disp(conn);
+       const struct nvkm_i2c_ntfy_rep *line = notify->data;
+       struct nvif_notify_conn_rep_v0 rep = {};
+
+       list_for_each_entry(outp, &disp->outp, base.head) {
+               if (outp->base.conn == conn &&
+                   outp->info.type == DCB_OUTPUT_DP) {
+                       DBG("HPD: %d\n", line->mask);
+                       nvkm_output_dp_detect(outp);
+
+                       if (line->mask & NVKM_I2C_UNPLUG)
+                               rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
+                       if (line->mask & NVKM_I2C_PLUG)
+                               rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
+
+                       nvkm_event_send(&disp->hpd, rep.mask, conn->index,
+                                       &rep, sizeof(rep));
+                       return NVKM_NOTIFY_KEEP;
+               }
        }
 
-       nouveau_event_trigger(disp->hpd, send, outp->base.info.connector);
+       WARN_ON(1);
+       return NVKM_NOTIFY_DROP;
 }
 
 static int
-nvkm_output_dp_service(void *data, u32 type, int index)
+nvkm_output_dp_irq(struct nvkm_notify *notify)
 {
-       struct nvkm_output_dp *outp = data;
-       DBG("HPD: %d\n", type);
-       atomic_or(type, &outp->pending);
-       schedule_work(&outp->work);
-       return NVKM_EVENT_DROP;
+       struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
+       struct nouveau_disp *disp = nouveau_disp(outp);
+       const struct nvkm_i2c_ntfy_rep *line = notify->data;
+       struct nvif_notify_conn_rep_v0 rep = {
+               .mask = NVIF_NOTIFY_CONN_V0_IRQ,
+       };
+       int index = outp->base.info.connector;
+
+       DBG("IRQ: %d\n", line->mask);
+       nvkm_output_dp_train(&outp->base, 0, true);
+
+       nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
+       return NVKM_NOTIFY_DROP;
 }
 
 int
 _nvkm_output_dp_fini(struct nouveau_object *object, bool suspend)
 {
        struct nvkm_output_dp *outp = (void *)object;
-       nouveau_event_put(outp->irq);
+       nvkm_notify_put(&outp->irq);
        nvkm_output_dp_enable(outp, false);
        return nvkm_output_fini(&outp->base, suspend);
 }
@@ -189,7 +205,7 @@ void
 _nvkm_output_dp_dtor(struct nouveau_object *object)
 {
        struct nvkm_output_dp *outp = (void *)object;
-       nouveau_event_ref(NULL, &outp->irq);
+       nvkm_notify_fini(&outp->irq);
        nvkm_output_destroy(&outp->base);
 }
 
@@ -213,7 +229,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       nouveau_event_ref(NULL, &outp->base.conn->hpd.event);
+       nvkm_notify_fini(&outp->base.conn->hpd);
 
        /* access to the aux channel is not optional... */
        if (!outp->base.edid) {
@@ -238,20 +254,28 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
        atomic_set(&outp->lt.done, 0);
 
        /* link maintenance */
-       ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_IRQ, outp->base.edid->index,
-                               nvkm_output_dp_service, outp, &outp->irq);
+       ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_irq, true,
+                              &(struct nvkm_i2c_ntfy_req) {
+                               .mask = NVKM_I2C_IRQ,
+                               .port = outp->base.edid->index,
+                              },
+                              sizeof(struct nvkm_i2c_ntfy_req),
+                              sizeof(struct nvkm_i2c_ntfy_rep),
+                              &outp->irq);
        if (ret) {
                ERR("error monitoring aux irq event: %d\n", ret);
                return ret;
        }
 
-       INIT_WORK(&outp->work, nvkm_output_dp_service_work);
-
        /* hotplug detect, replaces gpio-based mechanism with aux events */
-       ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
-                               outp->base.edid->index,
-                               nvkm_output_dp_service, outp,
-                              &outp->base.conn->hpd.event);
+       ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_hpd, true,
+                              &(struct nvkm_i2c_ntfy_req) {
+                               .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
+                               .port = outp->base.edid->index,
+                              },
+                              sizeof(struct nvkm_i2c_ntfy_req),
+                              sizeof(struct nvkm_i2c_ntfy_rep),
+                              &outp->base.conn->hpd);
        if (ret) {
                ERR("error monitoring aux hpd events: %d\n", ret);
                return ret;
index ff33ba1..1fac367 100644 (file)
@@ -12,10 +12,7 @@ struct nvkm_output_dp {
        struct nvbios_dpout info;
        u8 version;
 
-       struct nouveau_eventh *irq;
-       struct nouveau_eventh *hpd;
-       struct work_struct work;
-       atomic_t pending;
+       struct nvkm_notify irq;
        bool present;
        u8 dpcd[16];
 
index 26e9a42..5506d11 100644 (file)
@@ -11,6 +11,7 @@ struct nouveau_disp_impl {
        struct nouveau_oclass base;
        struct nouveau_oclass **outp;
        struct nouveau_oclass **conn;
+       const struct nvkm_event_func *vblank;
 };
 
 #define nouveau_disp_create(p,e,c,h,i,x,d)                                     \
@@ -39,4 +40,7 @@ int  _nouveau_disp_fini(struct nouveau_object *, bool);
 extern struct nouveau_oclass *nvkm_output_oclass;
 extern struct nouveau_oclass *nvkm_connector_oclass;
 
+int  nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *);
+void nouveau_disp_vblank(struct nouveau_disp *, int head);
+
 #endif
index 7a1ebdf..3101248 100644 (file)
@@ -87,7 +87,7 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
                        struct nvkm_output_dp *outpdp = (void *)outp;
                        switch (data) {
                        case NV94_DISP_SOR_DP_PWR_STATE_OFF:
-                               nouveau_event_put(outpdp->irq);
+                               nvkm_notify_put(&outpdp->irq);
                                ((struct nvkm_output_dp_impl *)nv_oclass(outp))
                                        ->lnk_pwr(outpdp, 0);
                                atomic_set(&outpdp->lt.done, 0);
index 56ed3d7..812d85d 100644 (file)
 #include <engine/dmaobj.h>
 #include <engine/fifo.h>
 
+static int
+nouveau_fifo_event_ctor(void *data, u32 size, struct nvkm_notify *notify)
+{
+       if (size == 0) {
+               notify->size  = 0;
+               notify->types = 1;
+               notify->index = 0;
+               return 0;
+       }
+       return -ENOSYS;
+}
+
+static const struct nvkm_event_func
+nouveau_fifo_event_func = {
+       .ctor = nouveau_fifo_event_ctor,
+};
+
 int
 nouveau_fifo_channel_create_(struct nouveau_object *parent,
                             struct nouveau_object *engine,
@@ -91,7 +108,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
        if (!chan->user)
                return -EFAULT;
 
-       nouveau_event_trigger(priv->cevent, 1, 0);
+       nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
 
        chan->size = size;
        return 0;
@@ -168,8 +185,8 @@ void
 nouveau_fifo_destroy(struct nouveau_fifo *priv)
 {
        kfree(priv->channel);
-       nouveau_event_destroy(&priv->uevent);
-       nouveau_event_destroy(&priv->cevent);
+       nvkm_event_fini(&priv->uevent);
+       nvkm_event_fini(&priv->cevent);
        nouveau_engine_destroy(&priv->base);
 }
 
@@ -194,11 +211,7 @@ nouveau_fifo_create_(struct nouveau_object *parent,
        if (!priv->channel)
                return -ENOMEM;
 
-       ret = nouveau_event_create(1, 1, &priv->cevent);
-       if (ret)
-               return ret;
-
-       ret = nouveau_event_create(1, 1, &priv->uevent);
+       ret = nvkm_event_init(&nouveau_fifo_event_func, 1, 1, &priv->cevent);
        if (ret)
                return ret;
 
index c61b16a..921062c 100644 (file)
@@ -539,7 +539,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
                        }
 
                        if (status & 0x40000000) {
-                               nouveau_event_trigger(priv->base.uevent, 1, 0);
+                               nvkm_event_send(&priv->base.uevent, 1, 0, NULL, 0);
                                nv_wr32(priv, 0x002100, 0x40000000);
                                status &= ~0x40000000;
                        }
index 6e5ac16..0bf844d 100644 (file)
@@ -389,19 +389,38 @@ nv84_fifo_cclass = {
  ******************************************************************************/
 
 static void
-nv84_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
+nv84_fifo_uevent_init(struct nvkm_event *event, int type, int index)
 {
-       struct nv84_fifo_priv *priv = event->priv;
-       nv_mask(priv, 0x002140, 0x40000000, 0x40000000);
+       struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+       nv_mask(fifo, 0x002140, 0x40000000, 0x40000000);
 }
 
 static void
-nv84_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
+nv84_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
 {
-       struct nv84_fifo_priv *priv = event->priv;
-       nv_mask(priv, 0x002140, 0x40000000, 0x00000000);
+       struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+       nv_mask(fifo, 0x002140, 0x40000000, 0x00000000);
 }
 
+static int
+nv84_fifo_uevent_ctor(void *data, u32 size, struct nvkm_notify *notify)
+{
+       if (size == 0) {
+               notify->size  = 0;
+               notify->types = 1;
+               notify->index = 0;
+               return 0;
+       }
+       return -ENOSYS;
+}
+
+static const struct nvkm_event_func
+nv84_fifo_uevent_func = {
+       .ctor = nv84_fifo_uevent_ctor,
+       .init = nv84_fifo_uevent_init,
+       .fini = nv84_fifo_uevent_fini,
+};
+
 static int
 nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -425,9 +444,9 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       priv->base.uevent->enable = nv84_fifo_uevent_enable;
-       priv->base.uevent->disable = nv84_fifo_uevent_disable;
-       priv->base.uevent->priv = priv;
+       ret = nvkm_event_init(&nv84_fifo_uevent_func, 1, 1, &priv->base.uevent);
+       if (ret)
+               return ret;
 
        nv_subdev(priv)->unit = 0x00000100;
        nv_subdev(priv)->intr = nv04_fifo_intr;
index ae4a4dc..bd7bf3c 100644 (file)
@@ -730,7 +730,7 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
        for (unkn = 0; unkn < 8; unkn++) {
                u32 ints = (intr >> (unkn * 0x04)) & inte;
                if (ints & 0x1) {
-                       nouveau_event_trigger(priv->base.uevent, 1, 0);
+                       nvkm_event_send(&priv->base.uevent, 1, 0, NULL, 0);
                        ints &= ~1;
                }
                if (ints) {
@@ -827,19 +827,38 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
 }
 
 static void
-nvc0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
+nvc0_fifo_uevent_init(struct nvkm_event *event, int type, int index)
 {
-       struct nvc0_fifo_priv *priv = event->priv;
-       nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
+       struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+       nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
 }
 
 static void
-nvc0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
+nvc0_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
 {
-       struct nvc0_fifo_priv *priv = event->priv;
-       nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
+       struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+       nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
 }
 
+static int
+nvc0_fifo_uevent_ctor(void *data, u32 size, struct nvkm_notify *notify)
+{
+       if (size == 0) {
+               notify->size  = 0;
+               notify->types = 1;
+               notify->index = 0;
+               return 0;
+       }
+       return -ENOSYS;
+}
+
+static const struct nvkm_event_func
+nvc0_fifo_uevent_func = {
+       .ctor = nvc0_fifo_uevent_ctor,
+       .init = nvc0_fifo_uevent_init,
+       .fini = nvc0_fifo_uevent_fini,
+};
+
 static int
 nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -877,9 +896,9 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       priv->base.uevent->enable = nvc0_fifo_uevent_enable;
-       priv->base.uevent->disable = nvc0_fifo_uevent_disable;
-       priv->base.uevent->priv = priv;
+       ret = nvkm_event_init(&nvc0_fifo_uevent_func, 1, 1, &priv->base.uevent);
+       if (ret)
+               return ret;
 
        nv_subdev(priv)->unit = 0x00000100;
        nv_subdev(priv)->intr = nvc0_fifo_intr;
index 298063e..3e7f03d 100644 (file)
@@ -859,7 +859,7 @@ nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
 static void
 nve0_fifo_intr_engine(struct nve0_fifo_priv *priv)
 {
-       nouveau_event_trigger(priv->base.uevent, 1, 0);
+       nvkm_event_send(&priv->base.uevent, 1, 0, NULL, 0);
 }
 
 static void
@@ -952,19 +952,38 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
 }
 
 static void
-nve0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
+nve0_fifo_uevent_init(struct nvkm_event *event, int type, int index)
 {
-       struct nve0_fifo_priv *priv = event->priv;
-       nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
+       struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+       nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
 }
 
 static void
-nve0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
+nve0_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
 {
-       struct nve0_fifo_priv *priv = event->priv;
-       nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
+       struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+       nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
 }
 
+static int
+nve0_fifo_uevent_ctor(void *data, u32 size, struct nvkm_notify *notify)
+{
+       if (size == 0) {
+               notify->size  = 0;
+               notify->types = 1;
+               notify->index = 0;
+               return 0;
+       }
+       return -ENOSYS;
+}
+
+static const struct nvkm_event_func
+nve0_fifo_uevent_func = {
+       .ctor = nve0_fifo_uevent_ctor,
+       .init = nve0_fifo_uevent_init,
+       .fini = nve0_fifo_uevent_fini,
+};
+
 int
 nve0_fifo_fini(struct nouveau_object *object, bool suspend)
 {
@@ -1067,9 +1086,9 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       priv->base.uevent->enable = nve0_fifo_uevent_enable;
-       priv->base.uevent->disable = nve0_fifo_uevent_disable;
-       priv->base.uevent->priv = priv;
+       ret = nvkm_event_init(&nve0_fifo_uevent_func, 1, 1, &priv->base.uevent);
+       if (ret)
+               return ret;
 
        nv_subdev(priv)->unit = 0x00000100;
        nv_subdev(priv)->intr = nve0_fifo_intr;
index c150fff..48678ed 100644 (file)
@@ -29,6 +29,7 @@
 #include <core/handle.h>
 #include <core/gpuobj.h>
 #include <core/event.h>
+#include <nvif/event.h>
 
 #include <subdev/bar.h>
 
@@ -86,10 +87,10 @@ nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
 {
        struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
        u32 head = *(u32 *)args;
-       if (head >= chan->vblank.nr_event)
+       if (head >= nouveau_disp(chan)->vblank.index_nr)
                return -EINVAL;
 
-       nouveau_event_get(chan->vblank.event[head]);
+       nvkm_notify_get(&chan->vblank.notify[head]);
        return 0;
 }
 
@@ -124,9 +125,10 @@ nv50_software_sclass[] = {
  ******************************************************************************/
 
 static int
-nv50_software_vblsem_release(void *data, u32 type, int head)
+nv50_software_vblsem_release(struct nvkm_notify *notify)
 {
-       struct nv50_software_chan *chan = data;
+       struct nv50_software_chan *chan =
+               container_of(notify, typeof(*chan), vblank.notify[notify->index]);
        struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
        struct nouveau_bar *bar = nouveau_bar(priv);
 
@@ -142,7 +144,7 @@ nv50_software_vblsem_release(void *data, u32 type, int head)
                nv_wr32(priv, 0x060014, chan->vblank.value);
        }
 
-       return NVKM_EVENT_DROP;
+       return NVKM_NOTIFY_DROP;
 }
 
 void
@@ -151,11 +153,8 @@ nv50_software_context_dtor(struct nouveau_object *object)
        struct nv50_software_chan *chan = (void *)object;
        int i;
 
-       if (chan->vblank.event) {
-               for (i = 0; i < chan->vblank.nr_event; i++)
-                       nouveau_event_ref(NULL, &chan->vblank.event[i]);
-               kfree(chan->vblank.event);
-       }
+       for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++)
+               nvkm_notify_fini(&chan->vblank.notify[i]);
 
        nouveau_software_context_destroy(&chan->base);
 }
@@ -176,15 +175,14 @@ nv50_software_context_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       chan->vblank.nr_event = pdisp ? pdisp->vblank->index_nr : 0;
-       chan->vblank.event = kzalloc(chan->vblank.nr_event *
-                                    sizeof(*chan->vblank.event), GFP_KERNEL);
-       if (!chan->vblank.event)
-               return -ENOMEM;
-
-       for (i = 0; i < chan->vblank.nr_event; i++) {
-               ret = nouveau_event_new(pdisp->vblank, 1, i, pclass->vblank,
-                                       chan, &chan->vblank.event[i]);
+       for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) {
+               ret = nvkm_notify_init(&pdisp->vblank, pclass->vblank, false,
+                                      &(struct nvif_notify_head_req_v0) {
+                                       .head = i,
+                                      },
+                                      sizeof(struct nvif_notify_head_req_v0),
+                                      sizeof(struct nvif_notify_head_rep_v0),
+                                      &chan->vblank.notify[i]);
                if (ret)
                        return ret;
        }
index bb49a7a..41542e7 100644 (file)
@@ -19,14 +19,13 @@ int  nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
 
 struct nv50_software_cclass {
        struct nouveau_oclass base;
-       int (*vblank)(void *, u32, int);
+       int (*vblank)(struct nvkm_notify *);
 };
 
 struct nv50_software_chan {
        struct nouveau_software_chan base;
        struct {
-               struct nouveau_eventh **event;
-               int nr_event;
+               struct nvkm_notify notify[4];
                u32 channel;
                u32 ctxdma;
                u64 offset;
index 6be97b0..df299a9 100644 (file)
@@ -104,9 +104,10 @@ nvc0_software_sclass[] = {
  ******************************************************************************/
 
 static int
-nvc0_software_vblsem_release(void *data, u32 type, int head)
+nvc0_software_vblsem_release(struct nvkm_notify *notify)
 {
-       struct nv50_software_chan *chan = data;
+       struct nv50_software_chan *chan =
+               container_of(notify, typeof(*chan), vblank.notify[notify->index]);
        struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
        struct nouveau_bar *bar = nouveau_bar(priv);
 
@@ -116,7 +117,7 @@ nvc0_software_vblsem_release(void *data, u32 type, int head)
        nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
        nv_wr32(priv, 0x060014, chan->vblank.value);
 
-       return NVKM_EVENT_DROP;
+       return NVKM_NOTIFY_DROP;
 }
 
 static struct nv50_software_cclass
index 03c039d..0e41036 100644 (file)
@@ -62,11 +62,6 @@ enum nv_subdev_type {
        NVDEV_SUBDEV_NR,
 };
 
-enum nvkm_device_ntfy {
-       NVKM_DEVICE_NTFY_POWER = 0,
-       NVKM_DEVICE_NTFY
-};
-
 struct nouveau_device {
        struct nouveau_engine base;
        struct list_head head;
@@ -75,7 +70,7 @@ struct nouveau_device {
        struct platform_device *platformdev;
        u64 handle;
 
-       struct nouveau_event *ntfy;
+       struct nvkm_event event;
 
        const char *cfgopt;
        const char *dbgopt;
index ba3f1a7..51e55d0 100644 (file)
@@ -1,47 +1,34 @@
 #ifndef __NVKM_EVENT_H__
 #define __NVKM_EVENT_H__
 
-/* return codes from event handlers */
-#define NVKM_EVENT_DROP 0
-#define NVKM_EVENT_KEEP 1
+#include <core/notify.h>
 
-/* nouveau_eventh.flags bit #s */
-#define NVKM_EVENT_ENABLE 0
-
-struct nouveau_eventh {
-       struct nouveau_event *event;
-       struct list_head head;
-       unsigned long flags;
-       u32 types;
-       int index;
-       int (*func)(void *, u32, int);
-       void *priv;
+struct nvkm_event_func {
+       int  (*ctor)(void *data, u32 size, struct nvkm_notify *);
+       void (*send)(void *data, u32 size, struct nvkm_notify *);
+       void (*init)(struct nvkm_event *, int type, int index);
+       void (*fini)(struct nvkm_event *, int type, int index);
 };
 
-struct nouveau_event {
-       void *priv;
-       int (*check)(struct nouveau_event *, u32 type, int index);
-       void (*enable)(struct nouveau_event *, int type, int index);
-       void (*disable)(struct nouveau_event *, int type, int index);
+struct nvkm_event {
+       const struct nvkm_event_func *func;
 
        int types_nr;
        int index_nr;
 
-       spinlock_t list_lock;
-       struct list_head *list;
        spinlock_t refs_lock;
-       int refs[];
+       spinlock_t list_lock;
+       struct list_head list;
+       int *refs;
 };
 
-int  nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **);
-void nouveau_event_destroy(struct nouveau_event **);
-void nouveau_event_trigger(struct nouveau_event *, u32 types, int index);
-
-int  nouveau_event_new(struct nouveau_event *, u32 types, int index,
-                      int (*func)(void *, u32, int), void *,
-                      struct nouveau_eventh **);
-void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **);
-void nouveau_event_get(struct nouveau_eventh *);
-void nouveau_event_put(struct nouveau_eventh *);
+int  nvkm_event_init(const struct nvkm_event_func *func,
+                    int types_nr, int index_nr,
+                    struct nvkm_event *);
+void nvkm_event_fini(struct nvkm_event *);
+void nvkm_event_get(struct nvkm_event *, u32 types, int index);
+void nvkm_event_put(struct nvkm_event *, u32 types, int index);
+void nvkm_event_send(struct nvkm_event *, u32 types, int index,
+                    void *data, u32 size);
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/notify.h b/drivers/gpu/drm/nouveau/core/include/core/notify.h
new file mode 100644 (file)
index 0000000..5df2cba
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __NVKM_NOTIFY_H__
+#define __NVKM_NOTIFY_H__
+
+struct nvkm_notify {
+       struct nvkm_event *event;
+       struct list_head head;
+#define NVKM_NOTIFY_USER 0
+#define NVKM_NOTIFY_WORK 1
+       unsigned long flags;
+       int block;
+#define NVKM_NOTIFY_DROP 0
+#define NVKM_NOTIFY_KEEP 1
+       int (*func)(struct nvkm_notify *);
+
+       /* set by nvkm_event ctor */
+       u32 types;
+       int index;
+       u8  size;
+
+       struct work_struct work;
+       /* this is const for a *very* good reason - the data might be on the
+        * stack from an irq handler.  if you're not core/notify.c then you
+        * should probably think twice before casting it away...
+        */
+       const void *data;
+};
+
+int  nvkm_notify_init(struct nvkm_event *, int (*func)(struct nvkm_notify *),
+                     bool work, void *data, u32 size, u32 reply,
+                     struct nvkm_notify *);
+void nvkm_notify_fini(struct nvkm_notify *);
+void nvkm_notify_get(struct nvkm_notify *);
+void nvkm_notify_put(struct nvkm_notify *);
+void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size);
+
+#endif
index fde8428..7a64f34 100644 (file)
@@ -6,20 +6,13 @@
 #include <core/device.h>
 #include <core/event.h>
 
-enum nvkm_hpd_event {
-       NVKM_HPD_PLUG = 1,
-       NVKM_HPD_UNPLUG = 2,
-       NVKM_HPD_IRQ = 4,
-       NVKM_HPD = (NVKM_HPD_PLUG | NVKM_HPD_UNPLUG | NVKM_HPD_IRQ)
-};
-
 struct nouveau_disp {
        struct nouveau_engine base;
 
        struct list_head outp;
-       struct nouveau_event *hpd;
 
-       struct nouveau_event *vblank;
+       struct nvkm_event hpd;
+       struct nvkm_event vblank;
 };
 
 static inline struct nouveau_disp *
index b639eb2..8356712 100644 (file)
@@ -65,8 +65,8 @@ struct nouveau_fifo_base {
 struct nouveau_fifo {
        struct nouveau_engine base;
 
-       struct nouveau_event *cevent; /* channel creation event */
-       struct nouveau_event *uevent; /* async user trigger */
+       struct nvkm_event cevent; /* channel creation event */
+       struct nvkm_event uevent; /* async user trigger */
 
        struct nouveau_object **channel;
        spinlock_t lock;
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/event.h b/drivers/gpu/drm/nouveau/core/include/nvif/event.h
new file mode 120000 (symlink)
index 0000000..1b79853
--- /dev/null
@@ -0,0 +1 @@
+../../../nvif/event.h
\ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h b/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h
new file mode 120000 (symlink)
index 0000000..69d9929
--- /dev/null
@@ -0,0 +1 @@
+../../../nvif/unpack.h
\ No newline at end of file
index 0d30fa0..a5ca00d 100644 (file)
@@ -75,7 +75,7 @@ struct nouveau_clock {
        wait_queue_head_t wait;
        atomic_t waiting;
 
-       struct nouveau_eventh *pwrsrc_ntfy;
+       struct nvkm_notify pwrsrc_ntfy;
        int pwrsrc;
        int pstate; /* current */
        int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
index 612d82a..b73733d 100644 (file)
@@ -8,16 +8,22 @@
 #include <subdev/bios.h>
 #include <subdev/bios/gpio.h>
 
-enum nvkm_gpio_event {
-       NVKM_GPIO_HI = 1,
-       NVKM_GPIO_LO = 2,
-       NVKM_GPIO_TOGGLED = (NVKM_GPIO_HI | NVKM_GPIO_LO),
+struct nvkm_gpio_ntfy_req {
+#define NVKM_GPIO_HI                                                       0x01
+#define NVKM_GPIO_LO                                                       0x02
+#define NVKM_GPIO_TOGGLED                                                  0x03
+       u8 mask;
+       u8 line;
+};
+
+struct nvkm_gpio_ntfy_rep {
+       u8 mask;
 };
 
 struct nouveau_gpio {
        struct nouveau_subdev base;
 
-       struct nouveau_event *events;
+       struct nvkm_event event;
 
        void (*reset)(struct nouveau_gpio *, u8 func);
        int  (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
index 825f7bb..1b937c2 100644 (file)
 #define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
 #define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
 
-enum nvkm_i2c_event {
-       NVKM_I2C_PLUG = 1,
-       NVKM_I2C_UNPLUG = 2,
-       NVKM_I2C_IRQ = 4,
-       NVKM_I2C_DONE = 8,
-       NVKM_I2C_ANY = (NVKM_I2C_PLUG |
-                       NVKM_I2C_UNPLUG |
-                       NVKM_I2C_IRQ |
-                       NVKM_I2C_DONE),
+struct nvkm_i2c_ntfy_req {
+#define NVKM_I2C_PLUG                                                      0x01
+#define NVKM_I2C_UNPLUG                                                    0x02
+#define NVKM_I2C_IRQ                                                       0x04
+#define NVKM_I2C_DONE                                                      0x08
+#define NVKM_I2C_ANY                                                       0x0f
+       u8 mask;
+       u8 port;
+};
+
+struct nvkm_i2c_ntfy_rep {
+       u8 mask;
 };
 
 struct nouveau_i2c_port {
@@ -56,7 +59,7 @@ struct nouveau_i2c_board_info {
 
 struct nouveau_i2c {
        struct nouveau_subdev base;
-       struct nouveau_event *ntfy;
+       struct nvkm_event event;
 
        struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
        struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
index d3f70d8..a276a71 100644 (file)
@@ -235,7 +235,7 @@ nouveau_pstate_work(struct work_struct *work)
        }
 
        wake_up_all(&clk->wait);
-       nouveau_event_get(clk->pwrsrc_ntfy);
+       nvkm_notify_get(&clk->pwrsrc_ntfy);
 }
 
 static int
@@ -460,11 +460,12 @@ nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel)
 }
 
 static int
-nouveau_clock_pwrsrc(void *data, u32 mask, int type)
+nouveau_clock_pwrsrc(struct nvkm_notify *notify)
 {
-       struct nouveau_clock *clk = data;
+       struct nouveau_clock *clk =
+               container_of(notify, typeof(*clk), pwrsrc_ntfy);
        nouveau_pstate_calc(clk, false);
-       return NVKM_EVENT_DROP;
+       return NVKM_NOTIFY_DROP;
 }
 
 /******************************************************************************
@@ -475,7 +476,7 @@ int
 _nouveau_clock_fini(struct nouveau_object *object, bool suspend)
 {
        struct nouveau_clock *clk = (void *)object;
-       nouveau_event_put(clk->pwrsrc_ntfy);
+       nvkm_notify_put(&clk->pwrsrc_ntfy);
        return nouveau_subdev_fini(&clk->base, suspend);
 }
 
@@ -520,7 +521,7 @@ _nouveau_clock_dtor(struct nouveau_object *object)
        struct nouveau_clock *clk = (void *)object;
        struct nouveau_pstate *pstate, *temp;
 
-       nouveau_event_ref(NULL, &clk->pwrsrc_ntfy);
+       nvkm_notify_fini(&clk->pwrsrc_ntfy);
 
        list_for_each_entry_safe(pstate, temp, &clk->states, head) {
                nouveau_pstate_del(pstate);
@@ -572,9 +573,8 @@ nouveau_clock_create_(struct nouveau_object *parent,
 
        clk->allow_reclock = allow_reclock;
 
-       ret = nouveau_event_new(device->ntfy, 1, NVKM_DEVICE_NTFY_POWER,
-                               nouveau_clock_pwrsrc, clk,
-                              &clk->pwrsrc_ntfy);
+       ret = nvkm_notify_init(&device->event, nouveau_clock_pwrsrc, true,
+                              NULL, 0, 0, &clk->pwrsrc_ntfy);
        if (ret)
                return ret;
 
index 45e0202..b1e3ed7 100644 (file)
@@ -106,39 +106,59 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
 }
 
 static void
-nouveau_gpio_intr_disable(struct nouveau_event *event, int type, int index)
+nouveau_gpio_intr_fini(struct nvkm_event *event, int type, int index)
 {
-       struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
+       struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event);
        const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
        impl->intr_mask(gpio, type, 1 << index, 0);
 }
 
 static void
-nouveau_gpio_intr_enable(struct nouveau_event *event, int type, int index)
+nouveau_gpio_intr_init(struct nvkm_event *event, int type, int index)
 {
-       struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
+       struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event);
        const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
        impl->intr_mask(gpio, type, 1 << index, 1 << index);
 }
 
+static int
+nouveau_gpio_intr_ctor(void *data, u32 size, struct nvkm_notify *notify)
+{
+       struct nvkm_gpio_ntfy_req *req = data;
+       if (!WARN_ON(size != sizeof(*req))) {
+               notify->size  = sizeof(struct nvkm_gpio_ntfy_rep);
+               notify->types = req->mask;
+               notify->index = req->line;
+               return 0;
+       }
+       return -EINVAL;
+}
+
 static void
 nouveau_gpio_intr(struct nouveau_subdev *subdev)
 {
        struct nouveau_gpio *gpio = nouveau_gpio(subdev);
        const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
-       u32 hi, lo, e, i;
+       u32 hi, lo, i;
 
        impl->intr_stat(gpio, &hi, &lo);
 
-       for (i = 0; e = 0, (hi | lo) && i < impl->lines; i++) {
-               if (hi & (1 << i))
-                       e |= NVKM_GPIO_HI;
-               if (lo & (1 << i))
-                       e |= NVKM_GPIO_LO;
-               nouveau_event_trigger(gpio->events, e, i);
+       for (i = 0; (hi | lo) && i < impl->lines; i++) {
+               struct nvkm_gpio_ntfy_rep rep = {
+                       .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
+                               (NVKM_GPIO_LO * !!(lo & (1 << i))),
+               };
+               nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep));
        }
 }
 
+static const struct nvkm_event_func
+nouveau_gpio_intr_func = {
+       .ctor = nouveau_gpio_intr_ctor,
+       .init = nouveau_gpio_intr_init,
+       .fini = nouveau_gpio_intr_fini,
+};
+
 int
 _nouveau_gpio_fini(struct nouveau_object *object, bool suspend)
 {
@@ -183,7 +203,7 @@ void
 _nouveau_gpio_dtor(struct nouveau_object *object)
 {
        struct nouveau_gpio *gpio = (void *)object;
-       nouveau_event_destroy(&gpio->events);
+       nvkm_event_fini(&gpio->event);
        nouveau_subdev_destroy(&gpio->base);
 }
 
@@ -208,13 +228,11 @@ nouveau_gpio_create_(struct nouveau_object *parent,
        gpio->get  = nouveau_gpio_get;
        gpio->reset = impl->reset;
 
-       ret = nouveau_event_create(2, impl->lines, &gpio->events);
+       ret = nvkm_event_init(&nouveau_gpio_intr_func, 2, impl->lines,
+                             &gpio->event);
        if (ret)
                return ret;
 
-       gpio->events->priv = gpio;
-       gpio->events->enable = nouveau_gpio_intr_enable;
-       gpio->events->disable = nouveau_gpio_intr_disable;
        nv_subdev(gpio)->intr = nouveau_gpio_intr;
        return 0;
 }
index 09ba2cc..a652caf 100644 (file)
@@ -326,9 +326,9 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
 }
 
 static void
-nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index)
+nouveau_i2c_intr_fini(struct nvkm_event *event, int type, int index)
 {
-       struct nouveau_i2c *i2c = nouveau_i2c(event->priv);
+       struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event);
        struct nouveau_i2c_port *port = i2c->find(i2c, index);
        const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
        if (port && port->aux >= 0)
@@ -336,15 +336,28 @@ nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index)
 }
 
 static void
-nouveau_i2c_intr_enable(struct nouveau_event *event, int type, int index)
+nouveau_i2c_intr_init(struct nvkm_event *event, int type, int index)
 {
-       struct nouveau_i2c *i2c = nouveau_i2c(event->priv);
+       struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event);
        struct nouveau_i2c_port *port = i2c->find(i2c, index);
        const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
        if (port && port->aux >= 0)
                impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux);
 }
 
+static int
+nouveau_i2c_intr_ctor(void *data, u32 size, struct nvkm_notify *notify)
+{
+       struct nvkm_i2c_ntfy_req *req = data;
+       if (!WARN_ON(size != sizeof(*req))) {
+               notify->size  = sizeof(struct nvkm_i2c_ntfy_rep);
+               notify->types = req->mask;
+               notify->index = req->port;
+               return 0;
+       }
+       return -EINVAL;
+}
+
 static void
 nouveau_i2c_intr(struct nouveau_subdev *subdev)
 {
@@ -364,13 +377,26 @@ nouveau_i2c_intr(struct nouveau_subdev *subdev)
                                if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG;
                                if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ;
                                if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE;
-
-                               nouveau_event_trigger(i2c->ntfy, e, port->index);
+                               if (e) {
+                                       struct nvkm_i2c_ntfy_rep rep = {
+                                               .mask = e,
+                                       };
+                                       nvkm_event_send(&i2c->event, rep.mask,
+                                                       port->index, &rep,
+                                                       sizeof(rep));
+                               }
                        }
                }
        }
 }
 
+static const struct nvkm_event_func
+nouveau_i2c_intr_func = {
+       .ctor = nouveau_i2c_intr_ctor,
+       .init = nouveau_i2c_intr_init,
+       .fini = nouveau_i2c_intr_fini,
+};
+
 int
 _nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
 {
@@ -431,7 +457,7 @@ _nouveau_i2c_dtor(struct nouveau_object *object)
        struct nouveau_i2c *i2c = (void *)object;
        struct nouveau_i2c_port *port, *temp;
 
-       nouveau_event_destroy(&i2c->ntfy);
+       nvkm_event_fini(&i2c->event);
 
        list_for_each_entry_safe(port, temp, &i2c->ports, head) {
                nouveau_object_ref(NULL, (struct nouveau_object **)&port);
@@ -547,13 +573,10 @@ nouveau_i2c_create_(struct nouveau_object *parent,
                }
        }
 
-       ret = nouveau_event_create(4, index, &i2c->ntfy);
+       ret = nvkm_event_init(&nouveau_i2c_intr_func, 4, index, &i2c->event);
        if (ret)
                return ret;
 
-       i2c->ntfy->priv = i2c;
-       i2c->ntfy->enable = nouveau_i2c_intr_enable;
-       i2c->ntfy->disable = nouveau_i2c_intr_disable;
        return 0;
 }
 
index dbdc9ad..3f1db28 100644 (file)
@@ -46,6 +46,8 @@
 #include <subdev/gpio.h>
 #include <engine/disp.h>
 
+#include <nvif/event.h>
+
 MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
 static int nouveau_tv_disable = 0;
 module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
@@ -102,7 +104,7 @@ static void
 nouveau_connector_destroy(struct drm_connector *connector)
 {
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
-       nouveau_event_ref(NULL, &nv_connector->hpd);
+       nvkm_notify_fini(&nv_connector->hpd);
        kfree(nv_connector->edid);
        drm_connector_unregister(connector);
        drm_connector_cleanup(connector);
@@ -939,18 +941,19 @@ nouveau_connector_funcs_dp = {
        .force = nouveau_connector_force
 };
 
-static void
-nouveau_connector_hotplug_work(struct work_struct *work)
+static int
+nouveau_connector_hotplug(struct nvkm_notify *notify)
 {
        struct nouveau_connector *nv_connector =
-               container_of(work, typeof(*nv_connector), work);
+               container_of(notify, typeof(*nv_connector), hpd);
        struct drm_connector *connector = &nv_connector->base;
        struct nouveau_drm *drm = nouveau_drm(connector->dev);
+       const struct nvif_notify_conn_rep_v0 *rep = notify->data;
        const char *name = connector->name;
 
-       if (nv_connector->status & NVKM_HPD_IRQ) {
+       if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
        } else {
-               bool plugged = (nv_connector->status != NVKM_HPD_UNPLUG);
+               bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
 
                NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
 
@@ -961,16 +964,7 @@ nouveau_connector_hotplug_work(struct work_struct *work)
                drm_helper_hpd_irq_event(connector->dev);
        }
 
-       nouveau_event_get(nv_connector->hpd);
-}
-
-static int
-nouveau_connector_hotplug(void *data, u32 type, int index)
-{
-       struct nouveau_connector *nv_connector = data;
-       nv_connector->status = type;
-       schedule_work(&nv_connector->work);
-       return NVKM_EVENT_DROP;
+       return NVKM_NOTIFY_KEEP;
 }
 
 static ssize_t
@@ -1226,16 +1220,19 @@ nouveau_connector_create(struct drm_device *dev, int index)
                break;
        }
 
-       ret = nouveau_event_new(pdisp->hpd, NVKM_HPD, index,
-                               nouveau_connector_hotplug,
-                               nv_connector, &nv_connector->hpd);
+       ret = nvkm_notify_init(&pdisp->hpd, nouveau_connector_hotplug, true,
+                              &(struct nvif_notify_conn_req_v0) {
+                               .mask = NVIF_NOTIFY_CONN_V0_ANY,
+                               .conn = index,
+                              },
+                              sizeof(struct nvif_notify_conn_req_v0),
+                              sizeof(struct nvif_notify_conn_rep_v0),
+                              &nv_connector->hpd);
        if (ret)
                connector->polled = DRM_CONNECTOR_POLL_CONNECT;
        else
                connector->polled = DRM_CONNECTOR_POLL_HPD;
 
-       INIT_WORK(&nv_connector->work, nouveau_connector_hotplug_work);
-
        drm_connector_register(connector);
        return connector;
 }
index 8861b6c..0dcec02 100644 (file)
@@ -67,9 +67,7 @@ struct nouveau_connector {
        u8 index;
        u8 *dcb;
 
-       struct nouveau_eventh *hpd;
-       u32 status;
-       struct work_struct work;
+       struct nvkm_notify hpd;
 
        struct drm_dp_aux aux;
 
index 6af9b58..6358640 100644 (file)
@@ -31,7 +31,7 @@ struct nouveau_crtc {
        struct drm_crtc base;
 
        int index;
-       struct nouveau_eventh *vblank;
+       struct nvkm_notify vblank;
 
        uint32_t dpms_saved_fp_control;
        uint32_t fp_users;
index a1247f2..ff43b41 100644 (file)
 #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 @@ nouveau_display_vblank_enable(struct drm_device *dev, int head)
        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 @@ nouveau_display_vblank_disable(struct drm_device *dev, int head)
        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 @@ nouveau_display_vblank_fini(struct drm_device *dev)
 
        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 @@ nouveau_display_vblank_init(struct drm_device *dev)
 
        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 @@ nouveau_display_init(struct drm_device *dev)
        /* 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 @@ nouveau_display_fini(struct drm_device *dev)
        /* 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);
index ab5ea3b..c5efe25 100644 (file)
@@ -165,12 +165,18 @@ nouveau_fence_done(struct nouveau_fence *fence)
        return !fence->channel;
 }
 
+struct nouveau_fence_wait {
+       struct nouveau_fence_priv *priv;
+       struct nvkm_notify notify;
+};
+
 static int
-nouveau_fence_wait_uevent_handler(void *data, u32 type, int index)
+nouveau_fence_wait_uevent_handler(struct nvkm_notify *notify)
 {
-       struct nouveau_fence_priv *priv = data;
-       wake_up_all(&priv->waiting);
-       return NVKM_EVENT_KEEP;
+       struct nouveau_fence_wait *wait =
+               container_of(notify, typeof(*wait), notify);
+       wake_up_all(&wait->priv->waiting);
+       return NVKM_NOTIFY_KEEP;
 }
 
 static int
@@ -180,16 +186,16 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
        struct nouveau_channel *chan = fence->channel;
        struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device);
        struct nouveau_fence_priv *priv = chan->drm->fence;
-       struct nouveau_eventh *handler;
+       struct nouveau_fence_wait wait = { .priv = priv };
        int ret = 0;
 
-       ret = nouveau_event_new(pfifo->uevent, 1, 0,
-                               nouveau_fence_wait_uevent_handler,
-                               priv, &handler);
+       ret = nvkm_notify_init(&pfifo->uevent,
+                              nouveau_fence_wait_uevent_handler, false,
+                              NULL, 0, 0, &wait.notify);
        if (ret)
                return ret;
 
-       nouveau_event_get(handler);
+       nvkm_notify_get(&wait.notify);
 
        if (fence->timeout) {
                unsigned long timeout = fence->timeout - jiffies;
@@ -221,7 +227,7 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
                }
        }
 
-       nouveau_event_ref(NULL, &handler);
+       nvkm_notify_fini(&wait.notify);
        if (unlikely(ret < 0))
                return ret;
 
diff --git a/drivers/gpu/drm/nouveau/nvif/event.h b/drivers/gpu/drm/nouveau/nvif/event.h
new file mode 100644 (file)
index 0000000..6daced0
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __NVIF_EVENT_H__
+#define __NVIF_EVENT_H__
+
+struct nvif_notify_head_req_v0 {
+       __u8  version;
+       __u8  head;
+};
+
+struct nvif_notify_head_rep_v0 {
+       __u8  version;
+};
+
+struct nvif_notify_conn_req_v0 {
+       __u8  version;
+#define NVIF_NOTIFY_CONN_V0_PLUG                                           0x01
+#define NVIF_NOTIFY_CONN_V0_UNPLUG                                         0x02
+#define NVIF_NOTIFY_CONN_V0_IRQ                                            0x04
+#define NVIF_NOTIFY_CONN_V0_ANY                                            0x07
+       __u8  mask;
+       __u8  conn;
+};
+
+struct nvif_notify_conn_rep_v0 {
+       __u8  version;
+       __u8  mask;
+};
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/unpack.h b/drivers/gpu/drm/nouveau/nvif/unpack.h
new file mode 100644 (file)
index 0000000..5933188
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __NVIF_UNPACK_H__
+#define __NVIF_UNPACK_H__
+
+#define nvif_unvers(d) ({                                                      \
+       ret = (size == sizeof(d)) ? 0 : -ENOSYS;                               \
+       (ret == 0);                                                            \
+})
+
+#define nvif_unpack(d,vl,vh,m) ({                                              \
+       if ((vl) == 0 || ret == -ENOSYS) {                                     \
+               int _size = sizeof(d);                                         \
+               if (_size <= size && (d).version >= (vl) &&                    \
+                                    (d).version <= (vh)) {                    \
+                       data = (u8 *)data + _size;                             \
+                       size = size - _size;                                   \
+                       ret = ((m) || !size) ? 0 : -E2BIG;                     \
+               } else {                                                       \
+                       ret = -ENOSYS;                                         \
+               }                                                              \
+       }                                                                      \
+       (ret == 0);                                                            \
+})
+
+#endif