Commit 79ca2770 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/core: rework event interface

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

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

Various races between suspend/unload with display HPD/DP IRQ handlers
automagically solved as a result.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 4d681b66
...@@ -16,6 +16,7 @@ nouveau-y += core/core/gpuobj.o ...@@ -16,6 +16,7 @@ nouveau-y += core/core/gpuobj.o
nouveau-y += core/core/handle.o nouveau-y += core/core/handle.o
nouveau-y += core/core/mm.o nouveau-y += core/core/mm.o
nouveau-y += core/core/namedb.o nouveau-y += core/core/namedb.o
nouveau-y += core/core/notify.o
nouveau-y += core/core/object.o nouveau-y += core/core/object.o
nouveau-y += core/core/option.o nouveau-y += core/core/option.o
nouveau-y += core/core/parent.o nouveau-y += core/core/parent.o
......
/* /*
* Copyright 2013 Red Hat Inc. * Copyright 2013-2014 Red Hat Inc.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
...@@ -24,173 +24,77 @@ ...@@ -24,173 +24,77 @@
#include <core/event.h> #include <core/event.h>
void 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; BUG_ON(!spin_is_locked(&event->refs_lock));
unsigned long flags; while (types) {
u32 m, t; int type = __ffs(types); types &= ~(1 << type);
if (--event->refs[index * event->types_nr + type] == 0) {
if (!__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags)) if (event->func->fini)
return; event->func->fini(event, 1 << type, index);
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);
} }
} }
spin_unlock_irqrestore(&event->refs_lock, flags);
} }
void 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; BUG_ON(!spin_is_locked(&event->refs_lock));
unsigned long flags; while (types) {
u32 m, t; int type = __ffs(types); types &= ~(1 << type);
if (++event->refs[index * event->types_nr + type] == 1) {
if (__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) if (event->func->init)
return; event->func->init(event, 1 << type, index);
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);
} }
} }
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 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; unsigned long flags;
if (WARN_ON(index >= event->index_nr)) if (!event->refs || WARN_ON(index >= event->index_nr))
return; return;
spin_lock_irqsave(&event->list_lock, flags); spin_lock_irqsave(&event->list_lock, flags);
list_for_each_entry(handler, &event->list[index], head) { list_for_each_entry(notify, &event->list, head) {
if (!test_bit(NVKM_EVENT_ENABLE, &handler->flags)) if (notify->index == index && (notify->types & types)) {
continue; if (event->func->send) {
if (!(handler->types & types)) event->func->send(data, size, notify);
continue; continue;
if (handler->func(handler->priv, handler->types & types, index) }
!= NVKM_EVENT_DROP) nvkm_notify_send(notify, data, size);
continue; }
nouveau_event_put(handler);
} }
spin_unlock_irqrestore(&event->list_lock, flags); spin_unlock_irqrestore(&event->list_lock, flags);
} }
void void
nouveau_event_destroy(struct nouveau_event **pevent) nvkm_event_fini(struct nvkm_event *event)
{ {
struct nouveau_event *event = *pevent; if (event->refs) {
if (event) { kfree(event->refs);
kfree(event); event->refs = NULL;
*pevent = NULL;
} }
} }
int 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; event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr,
int i; GFP_KERNEL);
if (!event->refs)
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);
return -ENOMEM; return -ENOMEM;
}
spin_lock_init(&event->list_lock); event->func = func;
spin_lock_init(&event->refs_lock);
for (i = 0; i < index_nr; i++)
INIT_LIST_HEAD(&event->list[i]);
event->types_nr = types_nr; event->types_nr = types_nr;
event->index_nr = index_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; return 0;
} }
/*
* 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;
}
...@@ -33,7 +33,7 @@ nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data) ...@@ -33,7 +33,7 @@ nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data)
struct acpi_bus_event *info = data; struct acpi_bus_event *info = data;
if (!strcmp(info->device_class, "ac_adapter")) 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; return NOTIFY_DONE;
} }
......
...@@ -364,12 +364,30 @@ nouveau_devobj_ofuncs = { ...@@ -364,12 +364,30 @@ nouveau_devobj_ofuncs = {
/****************************************************************************** /******************************************************************************
* nouveau_device: engine functions * nouveau_device: engine functions
*****************************************************************************/ *****************************************************************************/
static struct nouveau_oclass static struct nouveau_oclass
nouveau_device_sclass[] = { nouveau_device_sclass[] = {
{ 0x0080, &nouveau_devobj_ofuncs }, { 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 static int
nouveau_device_fini(struct nouveau_object *object, bool suspend) nouveau_device_fini(struct nouveau_object *object, bool suspend)
{ {
...@@ -445,7 +463,7 @@ nouveau_device_dtor(struct nouveau_object *object) ...@@ -445,7 +463,7 @@ nouveau_device_dtor(struct nouveau_object *object)
{ {
struct nouveau_device *device = (void *)object; struct nouveau_device *device = (void *)object;
nouveau_event_destroy(&device->ntfy); nvkm_event_fini(&device->event);
mutex_lock(&nv_devices_mutex); mutex_lock(&nv_devices_mutex);
list_del(&device->head); list_del(&device->head);
...@@ -545,7 +563,8 @@ nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name, ...@@ -545,7 +563,8 @@ nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name,
nv_engine(device)->sclass = nouveau_device_sclass; nv_engine(device)->sclass = nouveau_device_sclass;
list_add(&device->head, &nv_devices); 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: done:
mutex_unlock(&nv_devices_mutex); mutex_unlock(&nv_devices_mutex);
return ret; return ret;
......
...@@ -22,25 +22,76 @@ ...@@ -22,25 +22,76 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include <core/os.h>
#include <nvif/unpack.h>
#include <nvif/event.h>
#include "priv.h" #include "priv.h"
#include "outp.h" #include "outp.h"
#include "conn.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 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; struct nvkm_output *outp;
list_for_each_entry(outp, &disp->outp, head) { int ret;
if (outp->conn->index == index) {
if (outp->conn->hpd.event) if (nvif_unpack(req->v0, 0, 0, false)) {
return 0; notify->size = sizeof(struct nvif_notify_conn_rep_v0);
break; 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 int
_nouveau_disp_fini(struct nouveau_object *object, bool suspend) _nouveau_disp_fini(struct nouveau_object *object, bool suspend)
{ {
...@@ -97,7 +148,8 @@ _nouveau_disp_dtor(struct nouveau_object *object) ...@@ -97,7 +148,8 @@ _nouveau_disp_dtor(struct nouveau_object *object)
struct nouveau_disp *disp = (void *)object; struct nouveau_disp *disp = (void *)object;
struct nvkm_output *outp, *outt; struct nvkm_output *outp, *outt;
nouveau_event_destroy(&disp->vblank); nvkm_event_fini(&disp->vblank);
nvkm_event_fini(&disp->hpd);
if (disp->outp.next) { if (disp->outp.next) {
list_for_each_entry_safe(outp, outt, &disp->outp, head) { list_for_each_entry_safe(outp, outt, &disp->outp, head) {
...@@ -157,14 +209,11 @@ nouveau_disp_create_(struct nouveau_object *parent, ...@@ -157,14 +209,11 @@ nouveau_disp_create_(struct nouveau_object *parent,
hpd = max(hpd, (u8)(dcbE.connector + 1)); 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) if (ret)
return ret; return ret;
disp->hpd->priv = disp; ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank);
disp->hpd->check = nouveau_disp_hpd_check;
ret = nouveau_event_create(1, heads, &disp->vblank);
if (ret) if (ret)
return ret; return ret;
......
...@@ -22,39 +22,41 @@ ...@@ -22,39 +22,41 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include <core/os.h>
#include <nvif/event.h>
#include <subdev/gpio.h> #include <subdev/gpio.h>
#include "conn.h" #include "conn.h"
#include "outp.h" #include "outp.h"
static void static int
nvkm_connector_hpd_work(struct work_struct *w) 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_disp *disp = nouveau_disp(conn);
struct nouveau_gpio *gpio = nouveau_gpio(conn); struct nouveau_gpio *gpio = nouveau_gpio(conn);
u32 send = NVKM_HPD_UNPLUG; const struct nvkm_gpio_ntfy_rep *line = notify->data;
if (gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.event->index)) struct nvif_notify_conn_rep_v0 rep;
send = NVKM_HPD_PLUG; int index = conn->index;
nouveau_event_trigger(disp->hpd, send, conn->index);
nouveau_event_get(conn->hpd.event);
}
static int DBG("HPD: %d\n", line->mask);
nvkm_connector_hpd(void *data, u32 type, int index)
{ if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
struct nvkm_connector *conn = data; rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
DBG("HPD: %d\n", type); else
schedule_work(&conn->hpd.work); rep.mask = NVIF_NOTIFY_CONN_V0_PLUG;
return NVKM_EVENT_DROP; rep.version = 0;
nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
return NVKM_NOTIFY_KEEP;
} }
int int
_nvkm_connector_fini(struct nouveau_object *object, bool suspend) _nvkm_connector_fini(struct nouveau_object *object, bool suspend)
{ {
struct nvkm_connector *conn = (void *)object; struct nvkm_connector *conn = (void *)object;
if (conn->hpd.event) nvkm_notify_put(&conn->hpd);
nouveau_event_put(conn->hpd.event);
return nouveau_object_fini(&conn->base, suspend); return nouveau_object_fini(&conn->base, suspend);
} }
...@@ -63,10 +65,8 @@ _nvkm_connector_init(struct nouveau_object *object) ...@@ -63,10 +65,8 @@ _nvkm_connector_init(struct nouveau_object *object)
{ {
struct nvkm_connector *conn = (void *)object; struct nvkm_connector *conn = (void *)object;
int ret = nouveau_object_init(&conn->base); int ret = nouveau_object_init(&conn->base);
if (ret == 0) { if (ret == 0)
if (conn->hpd.event) nvkm_notify_get(&conn->hpd);
nouveau_event_get(conn->hpd.event);
}
return ret; return ret;
} }
...@@ -74,7 +74,7 @@ void ...@@ -74,7 +74,7 @@ void
_nvkm_connector_dtor(struct nouveau_object *object) _nvkm_connector_dtor(struct nouveau_object *object)
{ {
struct nvkm_connector *conn = (void *)object; struct nvkm_connector *conn = (void *)object;
nouveau_event_ref(NULL, &conn->hpd.event); nvkm_notify_fini(&conn->hpd);
nouveau_object_destroy(&conn->base); nouveau_object_destroy(&conn->base);
} }
...@@ -116,19 +116,24 @@ nvkm_connector_create_(struct nouveau_object *parent, ...@@ -116,19 +116,24 @@ nvkm_connector_create_(struct nouveau_object *parent,
if ((info->hpd = ffs(info->hpd))) { if ((info->hpd = ffs(info->hpd))) {
if (--info->hpd >= ARRAY_SIZE(hpd)) { if (--info->hpd >= ARRAY_SIZE(hpd)) {
ERR("hpd %02x unknown\n", info->hpd); ERR("hpd %02x unknown\n", info->hpd);
goto done; return 0;
} }
info->hpd = hpd[info->hpd]; info->hpd = hpd[info->hpd];
ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
if (ret) { if (ret) {
ERR("func %02x lookup failed, %d\n", info->hpd, ret); ERR("func %02x lookup failed, %d\n", info->hpd, ret);
goto done; return 0;
} }
ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED, ret = nvkm_notify_init(&gpio->event, nvkm_connector_hpd, true,
func.line, nvkm_connector_hpd, &(struct nvkm_gpio_ntfy_req) {
conn, &conn->hpd.event); .mask = NVKM_GPIO_TOGGLED,
.line = func.line,
},
sizeof(struct nvkm_gpio_ntfy_req),
sizeof(struct nvkm_gpio_ntfy_rep),
&conn->hpd);
if (ret) { if (ret) {
ERR("func %02x failed, %d\n", info->hpd, ret); ERR("func %02x failed, %d\n", info->hpd, ret);
} else { } else {
...@@ -136,8 +141,6 @@ nvkm_connector_create_(struct nouveau_object *parent, ...@@ -136,8 +141,6 @@ nvkm_connector_create_(struct nouveau_object *parent,
} }
} }
done:
INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work);
return 0; return 0;
} }
......
...@@ -10,10 +10,7 @@ struct nvkm_connector { ...@@ -10,10 +10,7 @@ struct nvkm_connector {
struct nvbios_connE info; struct nvbios_connE info;
int index; int index;
struct { struct nvkm_notify hpd;
struct nouveau_eventh *event;
struct work_struct work;
} hpd;
}; };
#define nvkm_connector_create(p,e,c,b,i,d) \ #define nvkm_connector_create(p,e,c,b,i,d) \
......
...@@ -354,7 +354,7 @@ nouveau_dp_train(struct work_struct *w) ...@@ -354,7 +354,7 @@ nouveau_dp_train(struct work_struct *w)
cfg--; cfg--;
/* disable link interrupt handling during link training */ /* 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 */ /* enable down-spreading and execute pre-train script from vbios */
dp_link_train_init(dp, outp->dpcd[3] & 0x01); dp_link_train_init(dp, outp->dpcd[3] & 0x01);
...@@ -395,5 +395,5 @@ nouveau_dp_train(struct work_struct *w) ...@@ -395,5 +395,5 @@ nouveau_dp_train(struct work_struct *w)
DBG("training complete\n"); DBG("training complete\n");
atomic_set(&outp->lt.done, 1); atomic_set(&outp->lt.done, 1);
wake_up(&outp->lt.wait); wake_up(&outp->lt.wait);
nouveau_event_get(outp->irq); nvkm_notify_get(&outp->irq);
} }
...@@ -93,6 +93,7 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { ...@@ -93,6 +93,7 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass, .base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan, .mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
......
...@@ -86,17 +86,26 @@ nv04_disp_sclass[] = { ...@@ -86,17 +86,26 @@ nv04_disp_sclass[] = {
******************************************************************************/ ******************************************************************************/
static void 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 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 static void
nv04_disp_intr(struct nouveau_subdev *subdev) nv04_disp_intr(struct nouveau_subdev *subdev)
{ {
...@@ -106,12 +115,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev) ...@@ -106,12 +115,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
u32 pvideo; u32 pvideo;
if (crtc0 & 0x00000001) { if (crtc0 & 0x00000001) {
nouveau_event_trigger(priv->base.vblank, 1, 0); nouveau_disp_vblank(&priv->base, 0);
nv_wr32(priv, 0x600100, 0x00000001); nv_wr32(priv, 0x600100, 0x00000001);
} }
if (crtc1 & 0x00000001) { if (crtc1 & 0x00000001) {
nouveau_event_trigger(priv->base.vblank, 1, 1); nouveau_disp_vblank(&priv->base, 1);
nv_wr32(priv, 0x602100, 0x00000001); nv_wr32(priv, 0x602100, 0x00000001);
} }
...@@ -140,9 +149,6 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -140,9 +149,6 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_engine(priv)->sclass = nv04_disp_sclass; nv_engine(priv)->sclass = nv04_disp_sclass;
nv_subdev(priv)->intr = nv04_disp_intr; 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; return 0;
} }
...@@ -155,4 +161,5 @@ nv04_disp_oclass = &(struct nouveau_disp_impl) { ...@@ -155,4 +161,5 @@ nv04_disp_oclass = &(struct nouveau_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.vblank = &nv04_disp_vblank_func,
}.base; }.base;
...@@ -828,19 +828,7 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, ...@@ -828,19 +828,7 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
return 0; return 0;
} }
static void int
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
nv50_disp_base_ctor(struct nouveau_object *parent, nv50_disp_base_ctor(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
...@@ -856,14 +844,11 @@ nv50_disp_base_ctor(struct nouveau_object *parent, ...@@ -856,14 +844,11 @@ nv50_disp_base_ctor(struct nouveau_object *parent,
if (ret) if (ret)
return 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, return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
&base->ramht); &base->ramht);
} }
static void void
nv50_disp_base_dtor(struct nouveau_object *object) nv50_disp_base_dtor(struct nouveau_object *object)
{ {
struct nv50_disp_base *base = (void *)object; struct nv50_disp_base *base = (void *)object;
...@@ -1040,6 +1025,27 @@ nv50_disp_cclass = { ...@@ -1040,6 +1025,27 @@ nv50_disp_cclass = {
* Display engine implementation * 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 static const struct nouveau_enum
nv50_disp_intr_error_type[] = { nv50_disp_intr_error_type[] = {
{ 3, "ILLEGAL_MTHD" }, { 3, "ILLEGAL_MTHD" },
...@@ -1654,13 +1660,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev) ...@@ -1654,13 +1660,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
} }
if (intr1 & 0x00000004) { if (intr1 & 0x00000004) {
nouveau_event_trigger(priv->base.vblank, 1, 0); nouveau_disp_vblank(&priv->base, 0);
nv_wr32(priv, 0x610024, 0x00000004); nv_wr32(priv, 0x610024, 0x00000004);
intr1 &= ~0x00000004; intr1 &= ~0x00000004;
} }
if (intr1 & 0x00000008) { if (intr1 & 0x00000008) {
nouveau_event_trigger(priv->base.vblank, 1, 1); nouveau_disp_vblank(&priv->base, 1);
nv_wr32(priv, 0x610024, 0x00000008); nv_wr32(priv, 0x610024, 0x00000008);
intr1 &= ~0x00000008; intr1 &= ~0x00000008;
} }
...@@ -1718,6 +1724,7 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { ...@@ -1718,6 +1724,7 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass, .base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv50_disp_mast_mthd_chan, .mthd.core = &nv50_disp_mast_mthd_chan,
.mthd.base = &nv50_disp_sync_mthd_chan, .mthd.base = &nv50_disp_sync_mthd_chan,
......
...@@ -165,11 +165,16 @@ extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base; ...@@ -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_oimm_ofuncs;
extern struct nouveau_ofuncs nv50_disp_curs_ofuncs; extern struct nouveau_ofuncs nv50_disp_curs_ofuncs;
extern struct nouveau_ofuncs nv50_disp_base_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; extern struct nouveau_oclass nv50_disp_cclass;
void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head, void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
const struct nv50_disp_mthd_chan *); const struct nv50_disp_mthd_chan *);
void nv50_disp_intr_supervisor(struct work_struct *); void nv50_disp_intr_supervisor(struct work_struct *);
void nv50_disp_intr(struct nouveau_subdev *); 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_chan nv84_disp_mast_mthd_chan;
extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac; extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac;
...@@ -195,6 +200,7 @@ extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; ...@@ -195,6 +200,7 @@ extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
extern struct nouveau_oclass nvd0_disp_cclass; extern struct nouveau_oclass nvd0_disp_cclass;
void nvd0_disp_intr_supervisor(struct work_struct *); void nvd0_disp_intr_supervisor(struct work_struct *);
void nvd0_disp_intr(struct nouveau_subdev *); 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_mast_mthd_chan;
extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan; extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;
......
...@@ -276,6 +276,7 @@ nv84_disp_oclass = &(struct nv50_disp_impl) { ...@@ -276,6 +276,7 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass, .base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan, .mthd.core = &nv84_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
......
...@@ -143,6 +143,7 @@ nv94_disp_oclass = &(struct nv50_disp_impl) { ...@@ -143,6 +143,7 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv94_disp_outp_sclass, .base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan, .mthd.core = &nv94_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
......
...@@ -138,6 +138,7 @@ nva0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -138,6 +138,7 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass, .base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan, .mthd.core = &nv84_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
......
...@@ -110,6 +110,7 @@ nva3_disp_oclass = &(struct nv50_disp_impl) { ...@@ -110,6 +110,7 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv94_disp_outp_sclass, .base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan, .mthd.core = &nv94_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
......
...@@ -747,50 +747,6 @@ nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, ...@@ -747,50 +747,6 @@ nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
return 0; 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 static int
nvd0_disp_base_init(struct nouveau_object *object) nvd0_disp_base_init(struct nouveau_object *object)
{ {
...@@ -874,8 +830,8 @@ nvd0_disp_base_fini(struct nouveau_object *object, bool suspend) ...@@ -874,8 +830,8 @@ nvd0_disp_base_fini(struct nouveau_object *object, bool suspend)
struct nouveau_ofuncs struct nouveau_ofuncs
nvd0_disp_base_ofuncs = { nvd0_disp_base_ofuncs = {
.ctor = nvd0_disp_base_ctor, .ctor = nv50_disp_base_ctor,
.dtor = nvd0_disp_base_dtor, .dtor = nv50_disp_base_dtor,
.init = nvd0_disp_base_init, .init = nvd0_disp_base_init,
.fini = nvd0_disp_base_fini, .fini = nvd0_disp_base_fini,
}; };
...@@ -916,6 +872,27 @@ nvd0_disp_sclass[] = { ...@@ -916,6 +872,27 @@ nvd0_disp_sclass[] = {
* Display engine implementation * 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 * static struct nvkm_output *
exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
...@@ -1343,7 +1320,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) ...@@ -1343,7 +1320,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
if (mask & intr) { if (mask & intr) {
u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
if (stat & 0x00000001) 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_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
nv_rd32(priv, 0x6100c0 + (i * 0x800)); nv_rd32(priv, 0x6100c0 + (i * 0x800));
} }
...@@ -1396,6 +1373,7 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -1396,6 +1373,7 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass, .base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nvd0_disp_mast_mthd_chan, .mthd.core = &nvd0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
......
...@@ -258,6 +258,7 @@ nve0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -258,6 +258,7 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass, .base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan, .mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
......
...@@ -93,6 +93,7 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -93,6 +93,7 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass, .base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan, .mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include <core/os.h>
#include <nvif/event.h>
#include <subdev/i2c.h> #include <subdev/i2c.h>
#include "outpdp.h" #include "outpdp.h"
...@@ -86,7 +89,7 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) ...@@ -86,7 +89,7 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
atomic_set(&outp->lt.done, 0); atomic_set(&outp->lt.done, 0);
schedule_work(&outp->lt.work); schedule_work(&outp->lt.work);
} else { } else {
nouveau_event_get(outp->irq); nvkm_notify_get(&outp->irq);
} }
if (wait) { if (wait) {
...@@ -133,46 +136,59 @@ nvkm_output_dp_detect(struct nvkm_output_dp *outp) ...@@ -133,46 +136,59 @@ nvkm_output_dp_detect(struct nvkm_output_dp *outp)
} }
} }
static void static int
nvkm_output_dp_service_work(struct work_struct *work) nvkm_output_dp_hpd(struct nvkm_notify *notify)
{ {
struct nvkm_output_dp *outp = container_of(work, typeof(*outp), work); struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
struct nouveau_disp *disp = nouveau_disp(outp); struct nvkm_output_dp *outp;
int type = atomic_xchg(&outp->pending, 0); struct nouveau_disp *disp = nouveau_disp(conn);
u32 send = 0; const struct nvkm_i2c_ntfy_rep *line = notify->data;
struct nvif_notify_conn_rep_v0 rep = {};
if (type & (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG)) {
nvkm_output_dp_detect(outp); list_for_each_entry(outp, &disp->outp, base.head) {
if (type & NVKM_I2C_UNPLUG) if (outp->base.conn == conn &&
send |= NVKM_HPD_UNPLUG; outp->info.type == DCB_OUTPUT_DP) {
if (type & NVKM_I2C_PLUG) DBG("HPD: %d\n", line->mask);
send |= NVKM_HPD_PLUG; nvkm_output_dp_detect(outp);
nouveau_event_get(outp->base.conn->hpd.event);
} if (line->mask & NVKM_I2C_UNPLUG)
rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
if (type & NVKM_I2C_IRQ) { if (line->mask & NVKM_I2C_PLUG)
nvkm_output_dp_train(&outp->base, 0, true); rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
send |= NVKM_HPD_IRQ;
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 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; struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
DBG("HPD: %d\n", type); struct nouveau_disp *disp = nouveau_disp(outp);
atomic_or(type, &outp->pending); const struct nvkm_i2c_ntfy_rep *line = notify->data;
schedule_work(&outp->work); struct nvif_notify_conn_rep_v0 rep = {
return NVKM_EVENT_DROP; .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 int
_nvkm_output_dp_fini(struct nouveau_object *object, bool suspend) _nvkm_output_dp_fini(struct nouveau_object *object, bool suspend)
{ {
struct nvkm_output_dp *outp = (void *)object; struct nvkm_output_dp *outp = (void *)object;
nouveau_event_put(outp->irq); nvkm_notify_put(&outp->irq);
nvkm_output_dp_enable(outp, false); nvkm_output_dp_enable(outp, false);
return nvkm_output_fini(&outp->base, suspend); return nvkm_output_fini(&outp->base, suspend);
} }
...@@ -189,7 +205,7 @@ void ...@@ -189,7 +205,7 @@ void
_nvkm_output_dp_dtor(struct nouveau_object *object) _nvkm_output_dp_dtor(struct nouveau_object *object)
{ {
struct nvkm_output_dp *outp = (void *)object; struct nvkm_output_dp *outp = (void *)object;
nouveau_event_ref(NULL, &outp->irq); nvkm_notify_fini(&outp->irq);
nvkm_output_destroy(&outp->base); nvkm_output_destroy(&outp->base);
} }
...@@ -213,7 +229,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent, ...@@ -213,7 +229,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
if (ret) if (ret)
return 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... */ /* access to the aux channel is not optional... */
if (!outp->base.edid) { if (!outp->base.edid) {
...@@ -238,20 +254,28 @@ nvkm_output_dp_create_(struct nouveau_object *parent, ...@@ -238,20 +254,28 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
atomic_set(&outp->lt.done, 0); atomic_set(&outp->lt.done, 0);
/* link maintenance */ /* link maintenance */
ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_IRQ, outp->base.edid->index, ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_irq, true,
nvkm_output_dp_service, outp, &outp->irq); &(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) { if (ret) {
ERR("error monitoring aux irq event: %d\n", ret); ERR("error monitoring aux irq event: %d\n", ret);
return ret; return ret;
} }
INIT_WORK(&outp->work, nvkm_output_dp_service_work);
/* hotplug detect, replaces gpio-based mechanism with aux events */ /* hotplug detect, replaces gpio-based mechanism with aux events */
ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_hpd, true,
outp->base.edid->index, &(struct nvkm_i2c_ntfy_req) {
nvkm_output_dp_service, outp, .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
&outp->base.conn->hpd.event); .port = outp->base.edid->index,
},
sizeof(struct nvkm_i2c_ntfy_req),
sizeof(struct nvkm_i2c_ntfy_rep),
&outp->base.conn->hpd);
if (ret) { if (ret) {
ERR("error monitoring aux hpd events: %d\n", ret); ERR("error monitoring aux hpd events: %d\n", ret);
return ret; return ret;
......
...@@ -12,10 +12,7 @@ struct nvkm_output_dp { ...@@ -12,10 +12,7 @@ struct nvkm_output_dp {
struct nvbios_dpout info; struct nvbios_dpout info;
u8 version; u8 version;
struct nouveau_eventh *irq; struct nvkm_notify irq;
struct nouveau_eventh *hpd;
struct work_struct work;
atomic_t pending;
bool present; bool present;
u8 dpcd[16]; u8 dpcd[16];
......
...@@ -11,6 +11,7 @@ struct nouveau_disp_impl { ...@@ -11,6 +11,7 @@ struct nouveau_disp_impl {
struct nouveau_oclass base; struct nouveau_oclass base;
struct nouveau_oclass **outp; struct nouveau_oclass **outp;
struct nouveau_oclass **conn; struct nouveau_oclass **conn;
const struct nvkm_event_func *vblank;
}; };
#define nouveau_disp_create(p,e,c,h,i,x,d) \ #define nouveau_disp_create(p,e,c,h,i,x,d) \
...@@ -39,4 +40,7 @@ int _nouveau_disp_fini(struct nouveau_object *, bool); ...@@ -39,4 +40,7 @@ int _nouveau_disp_fini(struct nouveau_object *, bool);
extern struct nouveau_oclass *nvkm_output_oclass; extern struct nouveau_oclass *nvkm_output_oclass;
extern struct nouveau_oclass *nvkm_connector_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 #endif
...@@ -87,7 +87,7 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) ...@@ -87,7 +87,7 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
struct nvkm_output_dp *outpdp = (void *)outp; struct nvkm_output_dp *outpdp = (void *)outp;
switch (data) { switch (data) {
case NV94_DISP_SOR_DP_PWR_STATE_OFF: 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)) ((struct nvkm_output_dp_impl *)nv_oclass(outp))
->lnk_pwr(outpdp, 0); ->lnk_pwr(outpdp, 0);
atomic_set(&outpdp->lt.done, 0); atomic_set(&outpdp->lt.done, 0);
......
...@@ -31,6 +31,23 @@ ...@@ -31,6 +31,23 @@
#include <engine/dmaobj.h> #include <engine/dmaobj.h>
#include <engine/fifo.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 int
nouveau_fifo_channel_create_(struct nouveau_object *parent, nouveau_fifo_channel_create_(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
...@@ -91,7 +108,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent, ...@@ -91,7 +108,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
if (!chan->user) if (!chan->user)
return -EFAULT; return -EFAULT;
nouveau_event_trigger(priv->cevent, 1, 0); nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
chan->size = size; chan->size = size;
return 0; return 0;
...@@ -168,8 +185,8 @@ void ...@@ -168,8 +185,8 @@ void
nouveau_fifo_destroy(struct nouveau_fifo *priv) nouveau_fifo_destroy(struct nouveau_fifo *priv)
{ {
kfree(priv->channel); kfree(priv->channel);
nouveau_event_destroy(&priv->uevent); nvkm_event_fini(&priv->uevent);
nouveau_event_destroy(&priv->cevent); nvkm_event_fini(&priv->cevent);
nouveau_engine_destroy(&priv->base); nouveau_engine_destroy(&priv->base);
} }
...@@ -194,11 +211,7 @@ nouveau_fifo_create_(struct nouveau_object *parent, ...@@ -194,11 +211,7 @@ nouveau_fifo_create_(struct nouveau_object *parent,
if (!priv->channel) if (!priv->channel)
return -ENOMEM; return -ENOMEM;
ret = nouveau_event_create(1, 1, &priv->cevent); ret = nvkm_event_init(&nouveau_fifo_event_func, 1, 1, &priv->cevent);
if (ret)
return ret;
ret = nouveau_event_create(1, 1, &priv->uevent);
if (ret) if (ret)
return ret; return ret;
......
...@@ -539,7 +539,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev) ...@@ -539,7 +539,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
} }
if (status & 0x40000000) { 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); nv_wr32(priv, 0x002100, 0x40000000);
status &= ~0x40000000; status &= ~0x40000000;
} }
......
...@@ -389,19 +389,38 @@ nv84_fifo_cclass = { ...@@ -389,19 +389,38 @@ nv84_fifo_cclass = {
******************************************************************************/ ******************************************************************************/
static void 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; struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(priv, 0x002140, 0x40000000, 0x40000000); nv_mask(fifo, 0x002140, 0x40000000, 0x40000000);
} }
static void 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; struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(priv, 0x002140, 0x40000000, 0x00000000); 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 static int
nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
...@@ -425,9 +444,9 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -425,9 +444,9 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
priv->base.uevent->enable = nv84_fifo_uevent_enable; ret = nvkm_event_init(&nv84_fifo_uevent_func, 1, 1, &priv->base.uevent);
priv->base.uevent->disable = nv84_fifo_uevent_disable; if (ret)
priv->base.uevent->priv = priv; return ret;
nv_subdev(priv)->unit = 0x00000100; nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr; nv_subdev(priv)->intr = nv04_fifo_intr;
......
...@@ -730,7 +730,7 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) ...@@ -730,7 +730,7 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
for (unkn = 0; unkn < 8; unkn++) { for (unkn = 0; unkn < 8; unkn++) {
u32 ints = (intr >> (unkn * 0x04)) & inte; u32 ints = (intr >> (unkn * 0x04)) & inte;
if (ints & 0x1) { if (ints & 0x1) {
nouveau_event_trigger(priv->base.uevent, 1, 0); nvkm_event_send(&priv->base.uevent, 1, 0, NULL, 0);
ints &= ~1; ints &= ~1;
} }
if (ints) { if (ints) {
...@@ -827,19 +827,38 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) ...@@ -827,19 +827,38 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
} }
static void 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; struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(priv, 0x002140, 0x80000000, 0x80000000); nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
} }
static void 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; struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(priv, 0x002140, 0x80000000, 0x00000000); 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 static int
nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
...@@ -877,9 +896,9 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -877,9 +896,9 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
priv->base.uevent->enable = nvc0_fifo_uevent_enable; ret = nvkm_event_init(&nvc0_fifo_uevent_func, 1, 1, &priv->base.uevent);
priv->base.uevent->disable = nvc0_fifo_uevent_disable; if (ret)
priv->base.uevent->priv = priv; return ret;
nv_subdev(priv)->unit = 0x00000100; nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nvc0_fifo_intr; nv_subdev(priv)->intr = nvc0_fifo_intr;
......
...@@ -859,7 +859,7 @@ nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv) ...@@ -859,7 +859,7 @@ nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
static void static void
nve0_fifo_intr_engine(struct nve0_fifo_priv *priv) 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 static void
...@@ -952,19 +952,38 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) ...@@ -952,19 +952,38 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
} }
static void 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; struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(priv, 0x002140, 0x80000000, 0x80000000); nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
} }
static void 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; struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(priv, 0x002140, 0x80000000, 0x00000000); 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 int
nve0_fifo_fini(struct nouveau_object *object, bool suspend) nve0_fifo_fini(struct nouveau_object *object, bool suspend)
{ {
...@@ -1067,9 +1086,9 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1067,9 +1086,9 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
priv->base.uevent->enable = nve0_fifo_uevent_enable; ret = nvkm_event_init(&nve0_fifo_uevent_func, 1, 1, &priv->base.uevent);
priv->base.uevent->disable = nve0_fifo_uevent_disable; if (ret)
priv->base.uevent->priv = priv; return ret;
nv_subdev(priv)->unit = 0x00000100; nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nve0_fifo_intr; nv_subdev(priv)->intr = nve0_fifo_intr;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <core/handle.h> #include <core/handle.h>
#include <core/gpuobj.h> #include <core/gpuobj.h>
#include <core/event.h> #include <core/event.h>
#include <nvif/event.h>
#include <subdev/bar.h> #include <subdev/bar.h>
...@@ -86,10 +87,10 @@ nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd, ...@@ -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); struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
u32 head = *(u32 *)args; u32 head = *(u32 *)args;
if (head >= chan->vblank.nr_event) if (head >= nouveau_disp(chan)->vblank.index_nr)
return -EINVAL; return -EINVAL;
nouveau_event_get(chan->vblank.event[head]); nvkm_notify_get(&chan->vblank.notify[head]);
return 0; return 0;
} }
...@@ -124,9 +125,10 @@ nv50_software_sclass[] = { ...@@ -124,9 +125,10 @@ nv50_software_sclass[] = {
******************************************************************************/ ******************************************************************************/
static int 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 nv50_software_priv *priv = (void *)nv_object(chan)->engine;
struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_bar *bar = nouveau_bar(priv);
...@@ -142,7 +144,7 @@ nv50_software_vblsem_release(void *data, u32 type, int head) ...@@ -142,7 +144,7 @@ nv50_software_vblsem_release(void *data, u32 type, int head)
nv_wr32(priv, 0x060014, chan->vblank.value); nv_wr32(priv, 0x060014, chan->vblank.value);
} }
return NVKM_EVENT_DROP; return NVKM_NOTIFY_DROP;
} }
void void
...@@ -151,11 +153,8 @@ nv50_software_context_dtor(struct nouveau_object *object) ...@@ -151,11 +153,8 @@ nv50_software_context_dtor(struct nouveau_object *object)
struct nv50_software_chan *chan = (void *)object; struct nv50_software_chan *chan = (void *)object;
int i; int i;
if (chan->vblank.event) { for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++)
for (i = 0; i < chan->vblank.nr_event; i++) nvkm_notify_fini(&chan->vblank.notify[i]);
nouveau_event_ref(NULL, &chan->vblank.event[i]);
kfree(chan->vblank.event);
}
nouveau_software_context_destroy(&chan->base); nouveau_software_context_destroy(&chan->base);
} }
...@@ -176,15 +175,14 @@ nv50_software_context_ctor(struct nouveau_object *parent, ...@@ -176,15 +175,14 @@ nv50_software_context_ctor(struct nouveau_object *parent,
if (ret) if (ret)
return ret; return ret;
chan->vblank.nr_event = pdisp ? pdisp->vblank->index_nr : 0; for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) {
chan->vblank.event = kzalloc(chan->vblank.nr_event * ret = nvkm_notify_init(&pdisp->vblank, pclass->vblank, false,
sizeof(*chan->vblank.event), GFP_KERNEL); &(struct nvif_notify_head_req_v0) {
if (!chan->vblank.event) .head = i,
return -ENOMEM; },
sizeof(struct nvif_notify_head_req_v0),
for (i = 0; i < chan->vblank.nr_event; i++) { sizeof(struct nvif_notify_head_rep_v0),
ret = nouveau_event_new(pdisp->vblank, 1, i, pclass->vblank, &chan->vblank.notify[i]);
chan, &chan->vblank.event[i]);
if (ret) if (ret)
return ret; return ret;
} }
......
...@@ -19,14 +19,13 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *, ...@@ -19,14 +19,13 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
struct nv50_software_cclass { struct nv50_software_cclass {
struct nouveau_oclass base; struct nouveau_oclass base;
int (*vblank)(void *, u32, int); int (*vblank)(struct nvkm_notify *);
}; };
struct nv50_software_chan { struct nv50_software_chan {
struct nouveau_software_chan base; struct nouveau_software_chan base;
struct { struct {
struct nouveau_eventh **event; struct nvkm_notify notify[4];
int nr_event;
u32 channel; u32 channel;
u32 ctxdma; u32 ctxdma;
u64 offset; u64 offset;
......
...@@ -104,9 +104,10 @@ nvc0_software_sclass[] = { ...@@ -104,9 +104,10 @@ nvc0_software_sclass[] = {
******************************************************************************/ ******************************************************************************/
static int 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 nv50_software_priv *priv = (void *)nv_object(chan)->engine;
struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_bar *bar = nouveau_bar(priv);
...@@ -116,7 +117,7 @@ nvc0_software_vblsem_release(void *data, u32 type, int head) ...@@ -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, 0x060010, lower_32_bits(chan->vblank.offset));
nv_wr32(priv, 0x060014, chan->vblank.value); nv_wr32(priv, 0x060014, chan->vblank.value);
return NVKM_EVENT_DROP; return NVKM_NOTIFY_DROP;
} }
static struct nv50_software_cclass static struct nv50_software_cclass
......
...@@ -62,11 +62,6 @@ enum nv_subdev_type { ...@@ -62,11 +62,6 @@ enum nv_subdev_type {
NVDEV_SUBDEV_NR, NVDEV_SUBDEV_NR,
}; };
enum nvkm_device_ntfy {
NVKM_DEVICE_NTFY_POWER = 0,
NVKM_DEVICE_NTFY
};
struct nouveau_device { struct nouveau_device {
struct nouveau_engine base; struct nouveau_engine base;
struct list_head head; struct list_head head;
...@@ -75,7 +70,7 @@ struct nouveau_device { ...@@ -75,7 +70,7 @@ struct nouveau_device {
struct platform_device *platformdev; struct platform_device *platformdev;
u64 handle; u64 handle;
struct nouveau_event *ntfy; struct nvkm_event event;
const char *cfgopt; const char *cfgopt;
const char *dbgopt; const char *dbgopt;
......
#ifndef __NVKM_EVENT_H__ #ifndef __NVKM_EVENT_H__
#define __NVKM_EVENT_H__ #define __NVKM_EVENT_H__
/* return codes from event handlers */ #include <core/notify.h>
#define NVKM_EVENT_DROP 0
#define NVKM_EVENT_KEEP 1
/* nouveau_eventh.flags bit #s */ struct nvkm_event_func {
#define NVKM_EVENT_ENABLE 0 int (*ctor)(void *data, u32 size, struct nvkm_notify *);
void (*send)(void *data, u32 size, struct nvkm_notify *);
struct nouveau_eventh { void (*init)(struct nvkm_event *, int type, int index);
struct nouveau_event *event; void (*fini)(struct nvkm_event *, int type, int index);
struct list_head head;
unsigned long flags;
u32 types;
int index;
int (*func)(void *, u32, int);
void *priv;
}; };
struct nouveau_event { struct nvkm_event {
void *priv; const struct nvkm_event_func *func;
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);
int types_nr; int types_nr;
int index_nr; int index_nr;
spinlock_t list_lock;
struct list_head *list;
spinlock_t refs_lock; 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 **); int nvkm_event_init(const struct nvkm_event_func *func,
void nouveau_event_destroy(struct nouveau_event **); int types_nr, int index_nr,
void nouveau_event_trigger(struct nouveau_event *, u32 types, int index); struct nvkm_event *);
void nvkm_event_fini(struct nvkm_event *);
int nouveau_event_new(struct nouveau_event *, u32 types, int index, void nvkm_event_get(struct nvkm_event *, u32 types, int index);
int (*func)(void *, u32, int), void *, void nvkm_event_put(struct nvkm_event *, u32 types, int index);
struct nouveau_eventh **); void nvkm_event_send(struct nvkm_event *, u32 types, int index,
void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **); void *data, u32 size);
void nouveau_event_get(struct nouveau_eventh *);
void nouveau_event_put(struct nouveau_eventh *);
#endif #endif
#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
...@@ -6,20 +6,13 @@ ...@@ -6,20 +6,13 @@
#include <core/device.h> #include <core/device.h>
#include <core/event.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_disp {
struct nouveau_engine base; struct nouveau_engine base;
struct list_head outp; 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 * static inline struct nouveau_disp *
......
...@@ -65,8 +65,8 @@ struct nouveau_fifo_base { ...@@ -65,8 +65,8 @@ struct nouveau_fifo_base {
struct nouveau_fifo { struct nouveau_fifo {
struct nouveau_engine base; struct nouveau_engine base;
struct nouveau_event *cevent; /* channel creation event */ struct nvkm_event cevent; /* channel creation event */
struct nouveau_event *uevent; /* async user trigger */ struct nvkm_event uevent; /* async user trigger */
struct nouveau_object **channel; struct nouveau_object **channel;
spinlock_t lock; spinlock_t lock;
......
../../../nvif/event.h
\ No newline at end of file
../../../nvif/unpack.h
\ No newline at end of file
...@@ -75,7 +75,7 @@ struct nouveau_clock { ...@@ -75,7 +75,7 @@ struct nouveau_clock {
wait_queue_head_t wait; wait_queue_head_t wait;
atomic_t waiting; atomic_t waiting;
struct nouveau_eventh *pwrsrc_ntfy; struct nvkm_notify pwrsrc_ntfy;
int pwrsrc; int pwrsrc;
int pstate; /* current */ int pstate; /* current */
int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */ int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
......
...@@ -8,16 +8,22 @@ ...@@ -8,16 +8,22 @@
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/gpio.h> #include <subdev/bios/gpio.h>
enum nvkm_gpio_event { struct nvkm_gpio_ntfy_req {
NVKM_GPIO_HI = 1, #define NVKM_GPIO_HI 0x01
NVKM_GPIO_LO = 2, #define NVKM_GPIO_LO 0x02
NVKM_GPIO_TOGGLED = (NVKM_GPIO_HI | NVKM_GPIO_LO), #define NVKM_GPIO_TOGGLED 0x03
u8 mask;
u8 line;
};
struct nvkm_gpio_ntfy_rep {
u8 mask;
}; };
struct nouveau_gpio { struct nouveau_gpio {
struct nouveau_subdev base; struct nouveau_subdev base;
struct nouveau_event *events; struct nvkm_event event;
void (*reset)(struct nouveau_gpio *, u8 func); void (*reset)(struct nouveau_gpio *, u8 func);
int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
......
...@@ -14,15 +14,18 @@ ...@@ -14,15 +14,18 @@
#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) #define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) #define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
enum nvkm_i2c_event { struct nvkm_i2c_ntfy_req {
NVKM_I2C_PLUG = 1, #define NVKM_I2C_PLUG 0x01
NVKM_I2C_UNPLUG = 2, #define NVKM_I2C_UNPLUG 0x02
NVKM_I2C_IRQ = 4, #define NVKM_I2C_IRQ 0x04
NVKM_I2C_DONE = 8, #define NVKM_I2C_DONE 0x08
NVKM_I2C_ANY = (NVKM_I2C_PLUG | #define NVKM_I2C_ANY 0x0f
NVKM_I2C_UNPLUG | u8 mask;
NVKM_I2C_IRQ | u8 port;
NVKM_I2C_DONE), };
struct nvkm_i2c_ntfy_rep {
u8 mask;
}; };
struct nouveau_i2c_port { struct nouveau_i2c_port {
...@@ -56,7 +59,7 @@ struct nouveau_i2c_board_info { ...@@ -56,7 +59,7 @@ struct nouveau_i2c_board_info {
struct nouveau_i2c { struct nouveau_i2c {
struct nouveau_subdev base; 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)(struct nouveau_i2c *, u8 index);
struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
......
...@@ -235,7 +235,7 @@ nouveau_pstate_work(struct work_struct *work) ...@@ -235,7 +235,7 @@ nouveau_pstate_work(struct work_struct *work)
} }
wake_up_all(&clk->wait); wake_up_all(&clk->wait);
nouveau_event_get(clk->pwrsrc_ntfy); nvkm_notify_get(&clk->pwrsrc_ntfy);
} }
static int static int
...@@ -460,11 +460,12 @@ nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel) ...@@ -460,11 +460,12 @@ nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel)
} }
static int 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); nouveau_pstate_calc(clk, false);
return NVKM_EVENT_DROP; return NVKM_NOTIFY_DROP;
} }
/****************************************************************************** /******************************************************************************
...@@ -475,7 +476,7 @@ int ...@@ -475,7 +476,7 @@ int
_nouveau_clock_fini(struct nouveau_object *object, bool suspend) _nouveau_clock_fini(struct nouveau_object *object, bool suspend)
{ {
struct nouveau_clock *clk = (void *)object; 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); return nouveau_subdev_fini(&clk->base, suspend);
} }
...@@ -520,7 +521,7 @@ _nouveau_clock_dtor(struct nouveau_object *object) ...@@ -520,7 +521,7 @@ _nouveau_clock_dtor(struct nouveau_object *object)
struct nouveau_clock *clk = (void *)object; struct nouveau_clock *clk = (void *)object;
struct nouveau_pstate *pstate, *temp; 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) { list_for_each_entry_safe(pstate, temp, &clk->states, head) {
nouveau_pstate_del(pstate); nouveau_pstate_del(pstate);
...@@ -572,9 +573,8 @@ nouveau_clock_create_(struct nouveau_object *parent, ...@@ -572,9 +573,8 @@ nouveau_clock_create_(struct nouveau_object *parent,
clk->allow_reclock = allow_reclock; clk->allow_reclock = allow_reclock;
ret = nouveau_event_new(device->ntfy, 1, NVKM_DEVICE_NTFY_POWER, ret = nvkm_notify_init(&device->event, nouveau_clock_pwrsrc, true,
nouveau_clock_pwrsrc, clk, NULL, 0, 0, &clk->pwrsrc_ntfy);
&clk->pwrsrc_ntfy);
if (ret) if (ret)
return ret; return ret;
......
...@@ -106,39 +106,59 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line) ...@@ -106,39 +106,59 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
} }
static void 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; const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
impl->intr_mask(gpio, type, 1 << index, 0); impl->intr_mask(gpio, type, 1 << index, 0);
} }
static void 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; const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
impl->intr_mask(gpio, type, 1 << index, 1 << index); 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 static void
nouveau_gpio_intr(struct nouveau_subdev *subdev) nouveau_gpio_intr(struct nouveau_subdev *subdev)
{ {
struct nouveau_gpio *gpio = nouveau_gpio(subdev); struct nouveau_gpio *gpio = nouveau_gpio(subdev);
const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass; 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); impl->intr_stat(gpio, &hi, &lo);
for (i = 0; e = 0, (hi | lo) && i < impl->lines; i++) { for (i = 0; (hi | lo) && i < impl->lines; i++) {
if (hi & (1 << i)) struct nvkm_gpio_ntfy_rep rep = {
e |= NVKM_GPIO_HI; .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
if (lo & (1 << i)) (NVKM_GPIO_LO * !!(lo & (1 << i))),
e |= NVKM_GPIO_LO; };
nouveau_event_trigger(gpio->events, e, 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 int
_nouveau_gpio_fini(struct nouveau_object *object, bool suspend) _nouveau_gpio_fini(struct nouveau_object *object, bool suspend)
{ {
...@@ -183,7 +203,7 @@ void ...@@ -183,7 +203,7 @@ void
_nouveau_gpio_dtor(struct nouveau_object *object) _nouveau_gpio_dtor(struct nouveau_object *object)
{ {
struct nouveau_gpio *gpio = (void *)object; struct nouveau_gpio *gpio = (void *)object;
nouveau_event_destroy(&gpio->events); nvkm_event_fini(&gpio->event);
nouveau_subdev_destroy(&gpio->base); nouveau_subdev_destroy(&gpio->base);
} }
...@@ -208,13 +228,11 @@ nouveau_gpio_create_(struct nouveau_object *parent, ...@@ -208,13 +228,11 @@ nouveau_gpio_create_(struct nouveau_object *parent,
gpio->get = nouveau_gpio_get; gpio->get = nouveau_gpio_get;
gpio->reset = impl->reset; 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) if (ret)
return 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; nv_subdev(gpio)->intr = nouveau_gpio_intr;
return 0; return 0;
} }
......
...@@ -326,9 +326,9 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, ...@@ -326,9 +326,9 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
} }
static void 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); struct nouveau_i2c_port *port = i2c->find(i2c, index);
const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
if (port && port->aux >= 0) if (port && port->aux >= 0)
...@@ -336,15 +336,28 @@ nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index) ...@@ -336,15 +336,28 @@ nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index)
} }
static void 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); struct nouveau_i2c_port *port = i2c->find(i2c, index);
const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass; const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
if (port && port->aux >= 0) if (port && port->aux >= 0)
impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux); 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 static void
nouveau_i2c_intr(struct nouveau_subdev *subdev) nouveau_i2c_intr(struct nouveau_subdev *subdev)
{ {
...@@ -364,13 +377,26 @@ 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 (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG;
if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ; if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ;
if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE; if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE;
if (e) {
nouveau_event_trigger(i2c->ntfy, e, port->index); 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 int
_nouveau_i2c_fini(struct nouveau_object *object, bool suspend) _nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
{ {
...@@ -431,7 +457,7 @@ _nouveau_i2c_dtor(struct nouveau_object *object) ...@@ -431,7 +457,7 @@ _nouveau_i2c_dtor(struct nouveau_object *object)
struct nouveau_i2c *i2c = (void *)object; struct nouveau_i2c *i2c = (void *)object;
struct nouveau_i2c_port *port, *temp; 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) { list_for_each_entry_safe(port, temp, &i2c->ports, head) {
nouveau_object_ref(NULL, (struct nouveau_object **)&port); nouveau_object_ref(NULL, (struct nouveau_object **)&port);
...@@ -547,13 +573,10 @@ nouveau_i2c_create_(struct nouveau_object *parent, ...@@ -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) if (ret)
return ret; return ret;
i2c->ntfy->priv = i2c;
i2c->ntfy->enable = nouveau_i2c_intr_enable;
i2c->ntfy->disable = nouveau_i2c_intr_disable;
return 0; return 0;
} }
......
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
#include <subdev/gpio.h> #include <subdev/gpio.h>
#include <engine/disp.h> #include <engine/disp.h>
#include <nvif/event.h>
MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
static int nouveau_tv_disable = 0; static int nouveau_tv_disable = 0;
module_param_named(tv_disable, nouveau_tv_disable, int, 0400); module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
...@@ -102,7 +104,7 @@ static void ...@@ -102,7 +104,7 @@ static void
nouveau_connector_destroy(struct drm_connector *connector) nouveau_connector_destroy(struct drm_connector *connector)
{ {
struct nouveau_connector *nv_connector = nouveau_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); kfree(nv_connector->edid);
drm_connector_unregister(connector); drm_connector_unregister(connector);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
...@@ -939,18 +941,19 @@ nouveau_connector_funcs_dp = { ...@@ -939,18 +941,19 @@ nouveau_connector_funcs_dp = {
.force = nouveau_connector_force .force = nouveau_connector_force
}; };
static void static int
nouveau_connector_hotplug_work(struct work_struct *work) nouveau_connector_hotplug(struct nvkm_notify *notify)
{ {
struct nouveau_connector *nv_connector = 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 drm_connector *connector = &nv_connector->base;
struct nouveau_drm *drm = nouveau_drm(connector->dev); struct nouveau_drm *drm = nouveau_drm(connector->dev);
const struct nvif_notify_conn_rep_v0 *rep = notify->data;
const char *name = connector->name; const char *name = connector->name;
if (nv_connector->status & NVKM_HPD_IRQ) { if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
} else { } 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); NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
...@@ -961,16 +964,7 @@ nouveau_connector_hotplug_work(struct work_struct *work) ...@@ -961,16 +964,7 @@ nouveau_connector_hotplug_work(struct work_struct *work)
drm_helper_hpd_irq_event(connector->dev); drm_helper_hpd_irq_event(connector->dev);
} }
nouveau_event_get(nv_connector->hpd); return NVKM_NOTIFY_KEEP;
}
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;
} }
static ssize_t static ssize_t
...@@ -1226,16 +1220,19 @@ nouveau_connector_create(struct drm_device *dev, int index) ...@@ -1226,16 +1220,19 @@ nouveau_connector_create(struct drm_device *dev, int index)
break; break;
} }
ret = nouveau_event_new(pdisp->hpd, NVKM_HPD, index, ret = nvkm_notify_init(&pdisp->hpd, nouveau_connector_hotplug, true,
nouveau_connector_hotplug, &(struct nvif_notify_conn_req_v0) {
nv_connector, &nv_connector->hpd); .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) if (ret)
connector->polled = DRM_CONNECTOR_POLL_CONNECT; connector->polled = DRM_CONNECTOR_POLL_CONNECT;
else else
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_HPD;
INIT_WORK(&nv_connector->work, nouveau_connector_hotplug_work);
drm_connector_register(connector); drm_connector_register(connector);
return connector; return connector;
} }
...@@ -67,9 +67,7 @@ struct nouveau_connector { ...@@ -67,9 +67,7 @@ struct nouveau_connector {
u8 index; u8 index;
u8 *dcb; u8 *dcb;
struct nouveau_eventh *hpd; struct nvkm_notify hpd;
u32 status;
struct work_struct work;
struct drm_dp_aux aux; struct drm_dp_aux aux;
......
...@@ -31,7 +31,7 @@ struct nouveau_crtc { ...@@ -31,7 +31,7 @@ struct nouveau_crtc {
struct drm_crtc base; struct drm_crtc base;
int index; int index;
struct nouveau_eventh *vblank; struct nvkm_notify vblank;
uint32_t dpms_saved_fp_control; uint32_t dpms_saved_fp_control;
uint32_t fp_users; uint32_t fp_users;
......
...@@ -40,13 +40,15 @@ ...@@ -40,13 +40,15 @@
#include <engine/disp.h> #include <engine/disp.h>
#include <core/class.h> #include <core/class.h>
#include <nvif/event.h>
static int 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); drm_handle_vblank(nv_crtc->base.dev, nv_crtc->index);
return NVKM_EVENT_KEEP; return NVKM_NOTIFY_KEEP;
} }
int int
...@@ -56,7 +58,7 @@ nouveau_display_vblank_enable(struct drm_device *dev, int head) ...@@ -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) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
if (nv_crtc->index == head) { if (nv_crtc->index == head) {
nouveau_event_get(nv_crtc->vblank); nvkm_notify_get(&nv_crtc->vblank);
return 0; return 0;
} }
} }
...@@ -70,7 +72,7 @@ nouveau_display_vblank_disable(struct drm_device *dev, int head) ...@@ -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) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
if (nv_crtc->index == head) { if (nv_crtc->index == head) {
nouveau_event_put(nv_crtc->vblank); nvkm_notify_put(&nv_crtc->vblank);
return; return;
} }
} }
...@@ -165,7 +167,7 @@ nouveau_display_vblank_fini(struct drm_device *dev) ...@@ -165,7 +167,7 @@ nouveau_display_vblank_fini(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 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) ...@@ -179,9 +181,14 @@ nouveau_display_vblank_init(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
ret = nouveau_event_new(pdisp->vblank, 1, nv_crtc->index, ret = nvkm_notify_init(&pdisp->vblank,
nouveau_display_vblank_handler, nouveau_display_vblank_handler, false,
nv_crtc, &nv_crtc->vblank); &(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) { if (ret) {
nouveau_display_vblank_fini(dev); nouveau_display_vblank_fini(dev);
return ret; return ret;
...@@ -359,7 +366,7 @@ nouveau_display_init(struct drm_device *dev) ...@@ -359,7 +366,7 @@ nouveau_display_init(struct drm_device *dev)
/* enable hotplug interrupts */ /* enable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_connector *conn = nouveau_connector(connector);
if (conn->hpd) nouveau_event_get(conn->hpd); nvkm_notify_get(&conn->hpd);
} }
return ret; return ret;
...@@ -379,7 +386,7 @@ nouveau_display_fini(struct drm_device *dev) ...@@ -379,7 +386,7 @@ nouveau_display_fini(struct drm_device *dev)
/* disable hotplug interrupts */ /* disable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct nouveau_connector *conn = nouveau_connector(connector); 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); drm_kms_helper_poll_disable(dev);
......
...@@ -165,12 +165,18 @@ nouveau_fence_done(struct nouveau_fence *fence) ...@@ -165,12 +165,18 @@ nouveau_fence_done(struct nouveau_fence *fence)
return !fence->channel; return !fence->channel;
} }
struct nouveau_fence_wait {
struct nouveau_fence_priv *priv;
struct nvkm_notify notify;
};
static int 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; struct nouveau_fence_wait *wait =
wake_up_all(&priv->waiting); container_of(notify, typeof(*wait), notify);
return NVKM_EVENT_KEEP; wake_up_all(&wait->priv->waiting);
return NVKM_NOTIFY_KEEP;
} }
static int static int
...@@ -180,16 +186,16 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) ...@@ -180,16 +186,16 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
struct nouveau_channel *chan = fence->channel; struct nouveau_channel *chan = fence->channel;
struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device); struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device);
struct nouveau_fence_priv *priv = chan->drm->fence; struct nouveau_fence_priv *priv = chan->drm->fence;
struct nouveau_eventh *handler; struct nouveau_fence_wait wait = { .priv = priv };
int ret = 0; int ret = 0;
ret = nouveau_event_new(pfifo->uevent, 1, 0, ret = nvkm_notify_init(&pfifo->uevent,
nouveau_fence_wait_uevent_handler, nouveau_fence_wait_uevent_handler, false,
priv, &handler); NULL, 0, 0, &wait.notify);
if (ret) if (ret)
return ret; return ret;
nouveau_event_get(handler); nvkm_notify_get(&wait.notify);
if (fence->timeout) { if (fence->timeout) {
unsigned long timeout = fence->timeout - jiffies; unsigned long timeout = fence->timeout - jiffies;
...@@ -221,7 +227,7 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) ...@@ -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)) if (unlikely(ret < 0))
return ret; return ret;
......
#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
#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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment