drm/nouveau/core: rework event interface

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

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

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

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Ben Skeggs 2014-08-10 04:10:20 +10:00
parent 4d681b666d
commit 79ca27706a
52 changed files with 876 additions and 518 deletions

View File

@ -16,6 +16,7 @@ nouveau-y += core/core/gpuobj.o
nouveau-y += core/core/handle.o
nouveau-y += core/core/mm.o
nouveau-y += core/core/namedb.o
nouveau-y += core/core/notify.o
nouveau-y += core/core/object.o
nouveau-y += core/core/option.o
nouveau-y += core/core/parent.o

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013 Red Hat Inc.
* Copyright 2013-2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -24,173 +24,77 @@
#include <core/event.h>
void
nouveau_event_put(struct nouveau_eventh *handler)
nvkm_event_put(struct nvkm_event *event, u32 types, int index)
{
struct nouveau_event *event = handler->event;
unsigned long flags;
u32 m, t;
if (!__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags))
return;
spin_lock_irqsave(&event->refs_lock, flags);
for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) {
if (!--event->refs[handler->index * event->types_nr + t]) {
if (event->disable)
event->disable(event, 1 << t, handler->index);
BUG_ON(!spin_is_locked(&event->refs_lock));
while (types) {
int type = __ffs(types); types &= ~(1 << type);
if (--event->refs[index * event->types_nr + type] == 0) {
if (event->func->fini)
event->func->fini(event, 1 << type, index);
}
}
spin_unlock_irqrestore(&event->refs_lock, flags);
}
void
nouveau_event_get(struct nouveau_eventh *handler)
nvkm_event_get(struct nvkm_event *event, u32 types, int index)
{
struct nouveau_event *event = handler->event;
unsigned long flags;
u32 m, t;
if (__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags))
return;
spin_lock_irqsave(&event->refs_lock, flags);
for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) {
if (!event->refs[handler->index * event->types_nr + t]++) {
if (event->enable)
event->enable(event, 1 << t, handler->index);
BUG_ON(!spin_is_locked(&event->refs_lock));
while (types) {
int type = __ffs(types); types &= ~(1 << type);
if (++event->refs[index * event->types_nr + type] == 1) {
if (event->func->init)
event->func->init(event, 1 << type, index);
}
}
spin_unlock_irqrestore(&event->refs_lock, flags);
}
static void
nouveau_event_fini(struct nouveau_eventh *handler)
{
struct nouveau_event *event = handler->event;
unsigned long flags;
nouveau_event_put(handler);
spin_lock_irqsave(&event->list_lock, flags);
list_del(&handler->head);
spin_unlock_irqrestore(&event->list_lock, flags);
}
static int
nouveau_event_init(struct nouveau_event *event, u32 types, int index,
int (*func)(void *, u32, int), void *priv,
struct nouveau_eventh *handler)
{
unsigned long flags;
if (types & ~((1 << event->types_nr) - 1))
return -EINVAL;
if (index >= event->index_nr)
return -EINVAL;
handler->event = event;
handler->flags = 0;
handler->types = types;
handler->index = index;
handler->func = func;
handler->priv = priv;
spin_lock_irqsave(&event->list_lock, flags);
list_add_tail(&handler->head, &event->list[index]);
spin_unlock_irqrestore(&event->list_lock, flags);
return 0;
}
int
nouveau_event_new(struct nouveau_event *event, u32 types, int index,
int (*func)(void *, u32, int), void *priv,
struct nouveau_eventh **phandler)
{
struct nouveau_eventh *handler;
int ret = -ENOMEM;
if (event->check) {
ret = event->check(event, types, index);
if (ret)
return ret;
}
handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL);
if (handler) {
ret = nouveau_event_init(event, types, index, func, priv, handler);
if (ret)
kfree(handler);
}
return ret;
}
void
nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref)
nvkm_event_send(struct nvkm_event *event, u32 types, int index,
void *data, u32 size)
{
BUG_ON(handler != NULL);
if (*ref) {
nouveau_event_fini(*ref);
kfree(*ref);
}
*ref = handler;
}
void
nouveau_event_trigger(struct nouveau_event *event, u32 types, int index)
{
struct nouveau_eventh *handler;
struct nvkm_notify *notify;
unsigned long flags;
if (WARN_ON(index >= event->index_nr))
if (!event->refs || WARN_ON(index >= event->index_nr))
return;
spin_lock_irqsave(&event->list_lock, flags);
list_for_each_entry(handler, &event->list[index], head) {
if (!test_bit(NVKM_EVENT_ENABLE, &handler->flags))
continue;
if (!(handler->types & types))
continue;
if (handler->func(handler->priv, handler->types & types, index)
!= NVKM_EVENT_DROP)
continue;
nouveau_event_put(handler);
list_for_each_entry(notify, &event->list, head) {
if (notify->index == index && (notify->types & types)) {
if (event->func->send) {
event->func->send(data, size, notify);
continue;
}
nvkm_notify_send(notify, data, size);
}
}
spin_unlock_irqrestore(&event->list_lock, flags);
}
void
nouveau_event_destroy(struct nouveau_event **pevent)
nvkm_event_fini(struct nvkm_event *event)
{
struct nouveau_event *event = *pevent;
if (event) {
kfree(event);
*pevent = NULL;
if (event->refs) {
kfree(event->refs);
event->refs = NULL;
}
}
int
nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **pevent)
nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr,
struct nvkm_event *event)
{
struct nouveau_event *event;
int i;
event = *pevent = kzalloc(sizeof(*event) + (index_nr * types_nr) *
sizeof(event->refs[0]), GFP_KERNEL);
if (!event)
event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr,
GFP_KERNEL);
if (!event->refs)
return -ENOMEM;
event->list = kmalloc(sizeof(*event->list) * index_nr, GFP_KERNEL);
if (!event->list) {
kfree(event);
return -ENOMEM;
}
spin_lock_init(&event->list_lock);
spin_lock_init(&event->refs_lock);
for (i = 0; i < index_nr; i++)
INIT_LIST_HEAD(&event->list[i]);
event->func = func;
event->types_nr = types_nr;
event->index_nr = index_nr;
spin_lock_init(&event->refs_lock);
spin_lock_init(&event->list_lock);
INIT_LIST_HEAD(&event->list);
return 0;
}

View File

@ -0,0 +1,164 @@
/*
* Copyright 2014 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include <core/os.h>
#include <core/event.h>
#include <core/notify.h>
static inline void
nvkm_notify_put_locked(struct nvkm_notify *notify)
{
if (notify->block++ == 0)
nvkm_event_put(notify->event, notify->types, notify->index);
}
void
nvkm_notify_put(struct nvkm_notify *notify)
{
struct nvkm_event *event = notify->event;
unsigned long flags;
if (likely(event) &&
test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
spin_lock_irqsave(&event->refs_lock, flags);
nvkm_notify_put_locked(notify);
spin_unlock_irqrestore(&event->refs_lock, flags);
if (test_bit(NVKM_NOTIFY_WORK, &notify->flags))
flush_work(&notify->work);
}
}
static inline void
nvkm_notify_get_locked(struct nvkm_notify *notify)
{
if (--notify->block == 0)
nvkm_event_get(notify->event, notify->types, notify->index);
}
void
nvkm_notify_get(struct nvkm_notify *notify)
{
struct nvkm_event *event = notify->event;
unsigned long flags;
if (likely(event) &&
!test_and_set_bit(NVKM_NOTIFY_USER, &notify->flags)) {
spin_lock_irqsave(&event->refs_lock, flags);
nvkm_notify_get_locked(notify);
spin_unlock_irqrestore(&event->refs_lock, flags);
}
}
static inline void
nvkm_notify_func(struct nvkm_notify *notify)
{
struct nvkm_event *event = notify->event;
int ret = notify->func(notify);
unsigned long flags;
if ((ret == NVKM_NOTIFY_KEEP) ||
!test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
spin_lock_irqsave(&event->refs_lock, flags);
nvkm_notify_get_locked(notify);
spin_unlock_irqrestore(&event->refs_lock, flags);
}
}
static void
nvkm_notify_work(struct work_struct *work)
{
struct nvkm_notify *notify = container_of(work, typeof(*notify), work);
nvkm_notify_func(notify);
}
void
nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size)
{
struct nvkm_event *event = notify->event;
unsigned long flags;
BUG_ON(!spin_is_locked(&event->list_lock));
BUG_ON(size != notify->size);
spin_lock_irqsave(&event->refs_lock, flags);
if (notify->block) {
spin_unlock_irqrestore(&event->refs_lock, flags);
return;
}
nvkm_notify_put_locked(notify);
spin_unlock_irqrestore(&event->refs_lock, flags);
if (test_bit(NVKM_NOTIFY_WORK, &notify->flags)) {
memcpy((void *)notify->data, data, size);
schedule_work(&notify->work);
} else {
notify->data = data;
nvkm_notify_func(notify);
notify->data = NULL;
}
}
void
nvkm_notify_fini(struct nvkm_notify *notify)
{
unsigned long flags;
if (notify->event) {
nvkm_notify_put(notify);
spin_lock_irqsave(&notify->event->list_lock, flags);
list_del(&notify->head);
spin_unlock_irqrestore(&notify->event->list_lock, flags);
kfree((void *)notify->data);
notify->event = NULL;
}
}
int
nvkm_notify_init(struct nvkm_event *event, int (*func)(struct nvkm_notify *),
bool work, void *data, u32 size, u32 reply,
struct nvkm_notify *notify)
{
unsigned long flags;
int ret = -ENODEV;
if ((notify->event = event), event->refs) {
ret = event->func->ctor(data, size, notify);
if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
notify->flags = 0;
notify->block = 1;
notify->func = func;
notify->data = NULL;
if (ret = 0, work) {
INIT_WORK(&notify->work, nvkm_notify_work);
set_bit(NVKM_NOTIFY_WORK, &notify->flags);
notify->data = kmalloc(reply, GFP_KERNEL);
if (!notify->data)
ret = -ENOMEM;
}
}
if (ret == 0) {
spin_lock_irqsave(&event->list_lock, flags);
list_add_tail(&notify->head, &event->list);
spin_unlock_irqrestore(&event->list_lock, flags);
}
}
if (ret)
notify->event = NULL;
return ret;
}

View File

@ -33,7 +33,7 @@ nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data)
struct acpi_bus_event *info = data;
if (!strcmp(info->device_class, "ac_adapter"))
nouveau_event_trigger(device->ntfy, 1, NVKM_DEVICE_NTFY_POWER);
nvkm_event_send(&device->event, 1, 0, NULL, 0);
return NOTIFY_DONE;
}

View File

@ -364,12 +364,30 @@ nouveau_devobj_ofuncs = {
/******************************************************************************
* nouveau_device: engine functions
*****************************************************************************/
static struct nouveau_oclass
nouveau_device_sclass[] = {
{ 0x0080, &nouveau_devobj_ofuncs },
{}
};
static int
nouveau_device_event_ctor(void *data, u32 size, struct nvkm_notify *notify)
{
if (!WARN_ON(size != 0)) {
notify->size = 0;
notify->types = 1;
notify->index = 0;
return 0;
}
return -EINVAL;
}
static const struct nvkm_event_func
nouveau_device_event_func = {
.ctor = nouveau_device_event_ctor,
};
static int
nouveau_device_fini(struct nouveau_object *object, bool suspend)
{
@ -445,7 +463,7 @@ nouveau_device_dtor(struct nouveau_object *object)
{
struct nouveau_device *device = (void *)object;
nouveau_event_destroy(&device->ntfy);
nvkm_event_fini(&device->event);
mutex_lock(&nv_devices_mutex);
list_del(&device->head);
@ -545,7 +563,8 @@ nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name,
nv_engine(device)->sclass = nouveau_device_sclass;
list_add(&device->head, &nv_devices);
ret = nouveau_event_create(1, NVKM_DEVICE_NTFY, &device->ntfy);
ret = nvkm_event_init(&nouveau_device_event_func, 1, 1,
&device->event);
done:
mutex_unlock(&nv_devices_mutex);
return ret;

View File

@ -22,25 +22,76 @@
* Authors: Ben Skeggs
*/
#include <core/os.h>
#include <nvif/unpack.h>
#include <nvif/event.h>
#include "priv.h"
#include "outp.h"
#include "conn.h"
static int
nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index)
int
nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *notify)
{
struct nouveau_disp *disp = event->priv;
struct nvkm_output *outp;
list_for_each_entry(outp, &disp->outp, head) {
if (outp->conn->index == index) {
if (outp->conn->hpd.event)
return 0;
break;
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 -ENOSYS;
return ret;
}
void
nouveau_disp_vblank(struct nouveau_disp *disp, int head)
{
struct nvif_notify_head_rep_v0 rep = {};
nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep));
}
static int
nouveau_disp_hpd_ctor(void *data, u32 size, struct nvkm_notify *notify)
{
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;
int ret;
if (nvif_unpack(req->v0, 0, 0, false)) {
notify->size = sizeof(struct nvif_notify_conn_rep_v0);
list_for_each_entry(outp, &disp->outp, head) {
if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
if (ret = -ENODEV, outp->conn->hpd.event) {
notify->types = req->v0.mask;
notify->index = req->v0.conn;
ret = 0;
}
break;
}
}
}
return ret;
}
static const struct nvkm_event_func
nouveau_disp_hpd_func = {
.ctor = nouveau_disp_hpd_ctor
};
int
_nouveau_disp_fini(struct nouveau_object *object, bool suspend)
{
@ -97,7 +148,8 @@ _nouveau_disp_dtor(struct nouveau_object *object)
struct nouveau_disp *disp = (void *)object;
struct nvkm_output *outp, *outt;
nouveau_event_destroy(&disp->vblank);
nvkm_event_fini(&disp->vblank);
nvkm_event_fini(&disp->hpd);
if (disp->outp.next) {
list_for_each_entry_safe(outp, outt, &disp->outp, head) {
@ -157,14 +209,11 @@ nouveau_disp_create_(struct nouveau_object *parent,
hpd = max(hpd, (u8)(dcbE.connector + 1));
}
ret = nouveau_event_create(3, hpd, &disp->hpd);
ret = nvkm_event_init(&nouveau_disp_hpd_func, 3, hpd, &disp->hpd);
if (ret)
return ret;
disp->hpd->priv = disp;
disp->hpd->check = nouveau_disp_hpd_check;
ret = nouveau_event_create(1, heads, &disp->vblank);
ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank);
if (ret)
return ret;

View File

@ -22,39 +22,41 @@
* Authors: Ben Skeggs
*/
#include <core/os.h>
#include <nvif/event.h>
#include <subdev/gpio.h>
#include "conn.h"
#include "outp.h"
static void
nvkm_connector_hpd_work(struct work_struct *w)
static int
nvkm_connector_hpd(struct nvkm_notify *notify)
{
struct nvkm_connector *conn = container_of(w, typeof(*conn), hpd.work);
struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
struct nouveau_disp *disp = nouveau_disp(conn);
struct nouveau_gpio *gpio = nouveau_gpio(conn);
u32 send = NVKM_HPD_UNPLUG;
if (gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.event->index))
send = NVKM_HPD_PLUG;
nouveau_event_trigger(disp->hpd, send, conn->index);
nouveau_event_get(conn->hpd.event);
}
const struct nvkm_gpio_ntfy_rep *line = notify->data;
struct nvif_notify_conn_rep_v0 rep;
int index = conn->index;
static int
nvkm_connector_hpd(void *data, u32 type, int index)
{
struct nvkm_connector *conn = data;
DBG("HPD: %d\n", type);
schedule_work(&conn->hpd.work);
return NVKM_EVENT_DROP;
DBG("HPD: %d\n", line->mask);
if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
else
rep.mask = NVIF_NOTIFY_CONN_V0_PLUG;
rep.version = 0;
nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
return NVKM_NOTIFY_KEEP;
}
int
_nvkm_connector_fini(struct nouveau_object *object, bool suspend)
{
struct nvkm_connector *conn = (void *)object;
if (conn->hpd.event)
nouveau_event_put(conn->hpd.event);
nvkm_notify_put(&conn->hpd);
return nouveau_object_fini(&conn->base, suspend);
}
@ -63,10 +65,8 @@ _nvkm_connector_init(struct nouveau_object *object)
{
struct nvkm_connector *conn = (void *)object;
int ret = nouveau_object_init(&conn->base);
if (ret == 0) {
if (conn->hpd.event)
nouveau_event_get(conn->hpd.event);
}
if (ret == 0)
nvkm_notify_get(&conn->hpd);
return ret;
}
@ -74,7 +74,7 @@ void
_nvkm_connector_dtor(struct nouveau_object *object)
{
struct nvkm_connector *conn = (void *)object;
nouveau_event_ref(NULL, &conn->hpd.event);
nvkm_notify_fini(&conn->hpd);
nouveau_object_destroy(&conn->base);
}
@ -116,19 +116,24 @@ nvkm_connector_create_(struct nouveau_object *parent,
if ((info->hpd = ffs(info->hpd))) {
if (--info->hpd >= ARRAY_SIZE(hpd)) {
ERR("hpd %02x unknown\n", info->hpd);
goto done;
return 0;
}
info->hpd = hpd[info->hpd];
ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
if (ret) {
ERR("func %02x lookup failed, %d\n", info->hpd, ret);
goto done;
return 0;
}
ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED,
func.line, nvkm_connector_hpd,
conn, &conn->hpd.event);
ret = nvkm_notify_init(&gpio->event, nvkm_connector_hpd, true,
&(struct nvkm_gpio_ntfy_req) {
.mask = NVKM_GPIO_TOGGLED,
.line = func.line,
},
sizeof(struct nvkm_gpio_ntfy_req),
sizeof(struct nvkm_gpio_ntfy_rep),
&conn->hpd);
if (ret) {
ERR("func %02x failed, %d\n", info->hpd, ret);
} else {
@ -136,8 +141,6 @@ nvkm_connector_create_(struct nouveau_object *parent,
}
}
done:
INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work);
return 0;
}

View File

@ -10,10 +10,7 @@ struct nvkm_connector {
struct nvbios_connE info;
int index;
struct {
struct nouveau_eventh *event;
struct work_struct work;
} hpd;
struct nvkm_notify hpd;
};
#define nvkm_connector_create(p,e,c,b,i,d) \

View File

@ -354,7 +354,7 @@ nouveau_dp_train(struct work_struct *w)
cfg--;
/* disable link interrupt handling during link training */
nouveau_event_put(outp->irq);
nvkm_notify_put(&outp->irq);
/* enable down-spreading and execute pre-train script from vbios */
dp_link_train_init(dp, outp->dpcd[3] & 0x01);
@ -395,5 +395,5 @@ nouveau_dp_train(struct work_struct *w)
DBG("training complete\n");
atomic_set(&outp->lt.done, 1);
wake_up(&outp->lt.wait);
nouveau_event_get(outp->irq);
nvkm_notify_get(&outp->irq);
}

View File

@ -93,6 +93,7 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan,

View File

@ -86,17 +86,26 @@ nv04_disp_sclass[] = {
******************************************************************************/
static void
nv04_disp_vblank_enable(struct nouveau_event *event, int type, int head)
nv04_disp_vblank_init(struct nvkm_event *event, int type, int head)
{
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001);
struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001);
}
static void
nv04_disp_vblank_disable(struct nouveau_event *event, int type, int head)
nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head)
{
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000);
struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000);
}
static const struct nvkm_event_func
nv04_disp_vblank_func = {
.ctor = nouveau_disp_vblank_ctor,
.init = nv04_disp_vblank_init,
.fini = nv04_disp_vblank_fini,
};
static void
nv04_disp_intr(struct nouveau_subdev *subdev)
{
@ -106,12 +115,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
u32 pvideo;
if (crtc0 & 0x00000001) {
nouveau_event_trigger(priv->base.vblank, 1, 0);
nouveau_disp_vblank(&priv->base, 0);
nv_wr32(priv, 0x600100, 0x00000001);
}
if (crtc1 & 0x00000001) {
nouveau_event_trigger(priv->base.vblank, 1, 1);
nouveau_disp_vblank(&priv->base, 1);
nv_wr32(priv, 0x602100, 0x00000001);
}
@ -140,9 +149,6 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_engine(priv)->sclass = nv04_disp_sclass;
nv_subdev(priv)->intr = nv04_disp_intr;
priv->base.vblank->priv = priv;
priv->base.vblank->enable = nv04_disp_vblank_enable;
priv->base.vblank->disable = nv04_disp_vblank_disable;
return 0;
}
@ -155,4 +161,5 @@ nv04_disp_oclass = &(struct nouveau_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.vblank = &nv04_disp_vblank_func,
}.base;

View File

@ -828,19 +828,7 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
return 0;
}
static void
nv50_disp_base_vblank_enable(struct nouveau_event *event, int type, int head)
{
nv_mask(event->priv, 0x61002c, (4 << head), (4 << head));
}
static void
nv50_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
{
nv_mask(event->priv, 0x61002c, (4 << head), 0);
}
static int
int
nv50_disp_base_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@ -856,14 +844,11 @@ nv50_disp_base_ctor(struct nouveau_object *parent,
if (ret)
return ret;
priv->base.vblank->priv = priv;
priv->base.vblank->enable = nv50_disp_base_vblank_enable;
priv->base.vblank->disable = nv50_disp_base_vblank_disable;
return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
&base->ramht);
}
static void
void
nv50_disp_base_dtor(struct nouveau_object *object)
{
struct nv50_disp_base *base = (void *)object;
@ -1040,6 +1025,27 @@ nv50_disp_cclass = {
* Display engine implementation
******************************************************************************/
static void
nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head)
{
struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
nv_mask(disp, 0x61002c, (4 << head), 0);
}
static void
nv50_disp_vblank_init(struct nvkm_event *event, int type, int head)
{
struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
nv_mask(disp, 0x61002c, (4 << head), (4 << head));
}
const struct nvkm_event_func
nv50_disp_vblank_func = {
.ctor = nouveau_disp_vblank_ctor,
.init = nv50_disp_vblank_init,
.fini = nv50_disp_vblank_fini,
};
static const struct nouveau_enum
nv50_disp_intr_error_type[] = {
{ 3, "ILLEGAL_MTHD" },
@ -1654,13 +1660,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
}
if (intr1 & 0x00000004) {
nouveau_event_trigger(priv->base.vblank, 1, 0);
nouveau_disp_vblank(&priv->base, 0);
nv_wr32(priv, 0x610024, 0x00000004);
intr1 &= ~0x00000004;
}
if (intr1 & 0x00000008) {
nouveau_event_trigger(priv->base.vblank, 1, 1);
nouveau_disp_vblank(&priv->base, 1);
nv_wr32(priv, 0x610024, 0x00000008);
intr1 &= ~0x00000008;
}
@ -1718,6 +1724,7 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv50_disp_mast_mthd_chan,
.mthd.base = &nv50_disp_sync_mthd_chan,

View File

@ -165,11 +165,16 @@ extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base;
extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs;
extern struct nouveau_ofuncs nv50_disp_curs_ofuncs;
extern struct nouveau_ofuncs nv50_disp_base_ofuncs;
int nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
void nv50_disp_base_dtor(struct nouveau_object *);
extern struct nouveau_oclass nv50_disp_cclass;
void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
const struct nv50_disp_mthd_chan *);
void nv50_disp_intr_supervisor(struct work_struct *);
void nv50_disp_intr(struct nouveau_subdev *);
extern const struct nvkm_event_func nv50_disp_vblank_func;
extern const struct nv50_disp_mthd_chan nv84_disp_mast_mthd_chan;
extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac;
@ -195,6 +200,7 @@ extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
extern struct nouveau_oclass nvd0_disp_cclass;
void nvd0_disp_intr_supervisor(struct work_struct *);
void nvd0_disp_intr(struct nouveau_subdev *);
extern const struct nvkm_event_func nvd0_disp_vblank_func;
extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan;
extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;

View File

@ -276,6 +276,7 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan,

View File

@ -143,6 +143,7 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan,

View File

@ -138,6 +138,7 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan,

View File

@ -110,6 +110,7 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nv50_disp_vblank_func,
.base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan,

View File

@ -747,50 +747,6 @@ nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
return 0;
}
static void
nvd0_disp_base_vblank_enable(struct nouveau_event *event, int type, int head)
{
nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
}
static void
nvd0_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
{
nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
}
static int
nvd0_disp_base_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_disp_priv *priv = (void *)engine;
struct nv50_disp_base *base;
int ret;
ret = nouveau_parent_create(parent, engine, oclass, 0,
priv->sclass, 0, &base);
*pobject = nv_object(base);
if (ret)
return ret;
priv->base.vblank->priv = priv;
priv->base.vblank->enable = nvd0_disp_base_vblank_enable;
priv->base.vblank->disable = nvd0_disp_base_vblank_disable;
return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
&base->ramht);
}
static void
nvd0_disp_base_dtor(struct nouveau_object *object)
{
struct nv50_disp_base *base = (void *)object;
nouveau_ramht_ref(NULL, &base->ramht);
nouveau_parent_destroy(&base->base);
}
static int
nvd0_disp_base_init(struct nouveau_object *object)
{
@ -874,8 +830,8 @@ nvd0_disp_base_fini(struct nouveau_object *object, bool suspend)
struct nouveau_ofuncs
nvd0_disp_base_ofuncs = {
.ctor = nvd0_disp_base_ctor,
.dtor = nvd0_disp_base_dtor,
.ctor = nv50_disp_base_ctor,
.dtor = nv50_disp_base_dtor,
.init = nvd0_disp_base_init,
.fini = nvd0_disp_base_fini,
};
@ -916,6 +872,27 @@ nvd0_disp_sclass[] = {
* Display engine implementation
******************************************************************************/
static void
nvd0_disp_vblank_init(struct nvkm_event *event, int type, int head)
{
struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
}
static void
nvd0_disp_vblank_fini(struct nvkm_event *event, int type, int head)
{
struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
}
const struct nvkm_event_func
nvd0_disp_vblank_func = {
.ctor = nouveau_disp_vblank_ctor,
.init = nvd0_disp_vblank_init,
.fini = nvd0_disp_vblank_fini,
};
static struct nvkm_output *
exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
@ -1343,7 +1320,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
if (mask & intr) {
u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
if (stat & 0x00000001)
nouveau_event_trigger(priv->base.vblank, 1, i);
nouveau_disp_vblank(&priv->base, i);
nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
nv_rd32(priv, 0x6100c0 + (i * 0x800));
}
@ -1396,6 +1373,7 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nvd0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan,

View File

@ -258,6 +258,7 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan,

View File

@ -93,6 +93,7 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan,

View File

@ -22,6 +22,9 @@
* Authors: Ben Skeggs
*/
#include <core/os.h>
#include <nvif/event.h>
#include <subdev/i2c.h>
#include "outpdp.h"
@ -86,7 +89,7 @@ done:
atomic_set(&outp->lt.done, 0);
schedule_work(&outp->lt.work);
} else {
nouveau_event_get(outp->irq);
nvkm_notify_get(&outp->irq);
}
if (wait) {
@ -133,46 +136,59 @@ nvkm_output_dp_detect(struct nvkm_output_dp *outp)
}
}
static void
nvkm_output_dp_service_work(struct work_struct *work)
static int
nvkm_output_dp_hpd(struct nvkm_notify *notify)
{
struct nvkm_output_dp *outp = container_of(work, typeof(*outp), work);
struct nouveau_disp *disp = nouveau_disp(outp);
int type = atomic_xchg(&outp->pending, 0);
u32 send = 0;
struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
struct nvkm_output_dp *outp;
struct nouveau_disp *disp = nouveau_disp(conn);
const struct nvkm_i2c_ntfy_rep *line = notify->data;
struct nvif_notify_conn_rep_v0 rep = {};
if (type & (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG)) {
nvkm_output_dp_detect(outp);
if (type & NVKM_I2C_UNPLUG)
send |= NVKM_HPD_UNPLUG;
if (type & NVKM_I2C_PLUG)
send |= NVKM_HPD_PLUG;
nouveau_event_get(outp->base.conn->hpd.event);
list_for_each_entry(outp, &disp->outp, base.head) {
if (outp->base.conn == conn &&
outp->info.type == DCB_OUTPUT_DP) {
DBG("HPD: %d\n", line->mask);
nvkm_output_dp_detect(outp);
if (line->mask & NVKM_I2C_UNPLUG)
rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
if (line->mask & NVKM_I2C_PLUG)
rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
nvkm_event_send(&disp->hpd, rep.mask, conn->index,
&rep, sizeof(rep));
return NVKM_NOTIFY_KEEP;
}
}
if (type & NVKM_I2C_IRQ) {
nvkm_output_dp_train(&outp->base, 0, true);
send |= NVKM_HPD_IRQ;
}
nouveau_event_trigger(disp->hpd, send, outp->base.info.connector);
WARN_ON(1);
return NVKM_NOTIFY_DROP;
}
static int
nvkm_output_dp_service(void *data, u32 type, int index)
nvkm_output_dp_irq(struct nvkm_notify *notify)
{
struct nvkm_output_dp *outp = data;
DBG("HPD: %d\n", type);
atomic_or(type, &outp->pending);
schedule_work(&outp->work);
return NVKM_EVENT_DROP;
struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
struct nouveau_disp *disp = nouveau_disp(outp);
const struct nvkm_i2c_ntfy_rep *line = notify->data;
struct nvif_notify_conn_rep_v0 rep = {
.mask = NVIF_NOTIFY_CONN_V0_IRQ,
};
int index = outp->base.info.connector;
DBG("IRQ: %d\n", line->mask);
nvkm_output_dp_train(&outp->base, 0, true);
nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
return NVKM_NOTIFY_DROP;
}
int
_nvkm_output_dp_fini(struct nouveau_object *object, bool suspend)
{
struct nvkm_output_dp *outp = (void *)object;
nouveau_event_put(outp->irq);
nvkm_notify_put(&outp->irq);
nvkm_output_dp_enable(outp, false);
return nvkm_output_fini(&outp->base, suspend);
}
@ -189,7 +205,7 @@ void
_nvkm_output_dp_dtor(struct nouveau_object *object)
{
struct nvkm_output_dp *outp = (void *)object;
nouveau_event_ref(NULL, &outp->irq);
nvkm_notify_fini(&outp->irq);
nvkm_output_destroy(&outp->base);
}
@ -213,7 +229,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
if (ret)
return ret;
nouveau_event_ref(NULL, &outp->base.conn->hpd.event);
nvkm_notify_fini(&outp->base.conn->hpd);
/* access to the aux channel is not optional... */
if (!outp->base.edid) {
@ -238,20 +254,28 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
atomic_set(&outp->lt.done, 0);
/* link maintenance */
ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_IRQ, outp->base.edid->index,
nvkm_output_dp_service, outp, &outp->irq);
ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_irq, true,
&(struct nvkm_i2c_ntfy_req) {
.mask = NVKM_I2C_IRQ,
.port = outp->base.edid->index,
},
sizeof(struct nvkm_i2c_ntfy_req),
sizeof(struct nvkm_i2c_ntfy_rep),
&outp->irq);
if (ret) {
ERR("error monitoring aux irq event: %d\n", ret);
return ret;
}
INIT_WORK(&outp->work, nvkm_output_dp_service_work);
/* hotplug detect, replaces gpio-based mechanism with aux events */
ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
outp->base.edid->index,
nvkm_output_dp_service, outp,
&outp->base.conn->hpd.event);
ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_hpd, true,
&(struct nvkm_i2c_ntfy_req) {
.mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
.port = outp->base.edid->index,
},
sizeof(struct nvkm_i2c_ntfy_req),
sizeof(struct nvkm_i2c_ntfy_rep),
&outp->base.conn->hpd);
if (ret) {
ERR("error monitoring aux hpd events: %d\n", ret);
return ret;

View File

@ -12,10 +12,7 @@ struct nvkm_output_dp {
struct nvbios_dpout info;
u8 version;
struct nouveau_eventh *irq;
struct nouveau_eventh *hpd;
struct work_struct work;
atomic_t pending;
struct nvkm_notify irq;
bool present;
u8 dpcd[16];

View File

@ -11,6 +11,7 @@ struct nouveau_disp_impl {
struct nouveau_oclass base;
struct nouveau_oclass **outp;
struct nouveau_oclass **conn;
const struct nvkm_event_func *vblank;
};
#define nouveau_disp_create(p,e,c,h,i,x,d) \
@ -39,4 +40,7 @@ int _nouveau_disp_fini(struct nouveau_object *, bool);
extern struct nouveau_oclass *nvkm_output_oclass;
extern struct nouveau_oclass *nvkm_connector_oclass;
int nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *);
void nouveau_disp_vblank(struct nouveau_disp *, int head);
#endif

View File

@ -87,7 +87,7 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
struct nvkm_output_dp *outpdp = (void *)outp;
switch (data) {
case NV94_DISP_SOR_DP_PWR_STATE_OFF:
nouveau_event_put(outpdp->irq);
nvkm_notify_put(&outpdp->irq);
((struct nvkm_output_dp_impl *)nv_oclass(outp))
->lnk_pwr(outpdp, 0);
atomic_set(&outpdp->lt.done, 0);

View File

@ -31,6 +31,23 @@
#include <engine/dmaobj.h>
#include <engine/fifo.h>
static int
nouveau_fifo_event_ctor(void *data, u32 size, struct nvkm_notify *notify)
{
if (size == 0) {
notify->size = 0;
notify->types = 1;
notify->index = 0;
return 0;
}
return -ENOSYS;
}
static const struct nvkm_event_func
nouveau_fifo_event_func = {
.ctor = nouveau_fifo_event_ctor,
};
int
nouveau_fifo_channel_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
@ -91,7 +108,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
if (!chan->user)
return -EFAULT;
nouveau_event_trigger(priv->cevent, 1, 0);
nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
chan->size = size;
return 0;
@ -168,8 +185,8 @@ void
nouveau_fifo_destroy(struct nouveau_fifo *priv)
{
kfree(priv->channel);
nouveau_event_destroy(&priv->uevent);
nouveau_event_destroy(&priv->cevent);
nvkm_event_fini(&priv->uevent);
nvkm_event_fini(&priv->cevent);
nouveau_engine_destroy(&priv->base);
}
@ -194,11 +211,7 @@ nouveau_fifo_create_(struct nouveau_object *parent,
if (!priv->channel)
return -ENOMEM;
ret = nouveau_event_create(1, 1, &priv->cevent);
if (ret)
return ret;
ret = nouveau_event_create(1, 1, &priv->uevent);
ret = nvkm_event_init(&nouveau_fifo_event_func, 1, 1, &priv->cevent);
if (ret)
return ret;

View File

@ -539,7 +539,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
}
if (status & 0x40000000) {
nouveau_event_trigger(priv->base.uevent, 1, 0);
nvkm_event_send(&priv->base.uevent, 1, 0, NULL, 0);
nv_wr32(priv, 0x002100, 0x40000000);
status &= ~0x40000000;
}

View File

@ -389,19 +389,38 @@ nv84_fifo_cclass = {
******************************************************************************/
static void
nv84_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
nv84_fifo_uevent_init(struct nvkm_event *event, int type, int index)
{
struct nv84_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x40000000, 0x40000000);
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x40000000, 0x40000000);
}
static void
nv84_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
nv84_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nv84_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x40000000, 0x00000000);
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x40000000, 0x00000000);
}
static int
nv84_fifo_uevent_ctor(void *data, u32 size, struct nvkm_notify *notify)
{
if (size == 0) {
notify->size = 0;
notify->types = 1;
notify->index = 0;
return 0;
}
return -ENOSYS;
}
static const struct nvkm_event_func
nv84_fifo_uevent_func = {
.ctor = nv84_fifo_uevent_ctor,
.init = nv84_fifo_uevent_init,
.fini = nv84_fifo_uevent_fini,
};
static int
nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@ -425,9 +444,9 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.uevent->enable = nv84_fifo_uevent_enable;
priv->base.uevent->disable = nv84_fifo_uevent_disable;
priv->base.uevent->priv = priv;
ret = nvkm_event_init(&nv84_fifo_uevent_func, 1, 1, &priv->base.uevent);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;

View File

@ -730,7 +730,7 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
for (unkn = 0; unkn < 8; unkn++) {
u32 ints = (intr >> (unkn * 0x04)) & inte;
if (ints & 0x1) {
nouveau_event_trigger(priv->base.uevent, 1, 0);
nvkm_event_send(&priv->base.uevent, 1, 0, NULL, 0);
ints &= ~1;
}
if (ints) {
@ -827,19 +827,38 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
}
static void
nvc0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
nvc0_fifo_uevent_init(struct nvkm_event *event, int type, int index)
{
struct nvc0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
}
static void
nvc0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
nvc0_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nvc0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
}
static int
nvc0_fifo_uevent_ctor(void *data, u32 size, struct nvkm_notify *notify)
{
if (size == 0) {
notify->size = 0;
notify->types = 1;
notify->index = 0;
return 0;
}
return -ENOSYS;
}
static const struct nvkm_event_func
nvc0_fifo_uevent_func = {
.ctor = nvc0_fifo_uevent_ctor,
.init = nvc0_fifo_uevent_init,
.fini = nvc0_fifo_uevent_fini,
};
static int
nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@ -877,9 +896,9 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.uevent->enable = nvc0_fifo_uevent_enable;
priv->base.uevent->disable = nvc0_fifo_uevent_disable;
priv->base.uevent->priv = priv;
ret = nvkm_event_init(&nvc0_fifo_uevent_func, 1, 1, &priv->base.uevent);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nvc0_fifo_intr;

View File

@ -859,7 +859,7 @@ nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
static void
nve0_fifo_intr_engine(struct nve0_fifo_priv *priv)
{
nouveau_event_trigger(priv->base.uevent, 1, 0);
nvkm_event_send(&priv->base.uevent, 1, 0, NULL, 0);
}
static void
@ -952,19 +952,38 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
}
static void
nve0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
nve0_fifo_uevent_init(struct nvkm_event *event, int type, int index)
{
struct nve0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
}
static void
nve0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
nve0_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nve0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
}
static int
nve0_fifo_uevent_ctor(void *data, u32 size, struct nvkm_notify *notify)
{
if (size == 0) {
notify->size = 0;
notify->types = 1;
notify->index = 0;
return 0;
}
return -ENOSYS;
}
static const struct nvkm_event_func
nve0_fifo_uevent_func = {
.ctor = nve0_fifo_uevent_ctor,
.init = nve0_fifo_uevent_init,
.fini = nve0_fifo_uevent_fini,
};
int
nve0_fifo_fini(struct nouveau_object *object, bool suspend)
{
@ -1067,9 +1086,9 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.uevent->enable = nve0_fifo_uevent_enable;
priv->base.uevent->disable = nve0_fifo_uevent_disable;
priv->base.uevent->priv = priv;
ret = nvkm_event_init(&nve0_fifo_uevent_func, 1, 1, &priv->base.uevent);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nve0_fifo_intr;

View File

@ -29,6 +29,7 @@
#include <core/handle.h>
#include <core/gpuobj.h>
#include <core/event.h>
#include <nvif/event.h>
#include <subdev/bar.h>
@ -86,10 +87,10 @@ nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
{
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
u32 head = *(u32 *)args;
if (head >= chan->vblank.nr_event)
if (head >= nouveau_disp(chan)->vblank.index_nr)
return -EINVAL;
nouveau_event_get(chan->vblank.event[head]);
nvkm_notify_get(&chan->vblank.notify[head]);
return 0;
}
@ -124,9 +125,10 @@ nv50_software_sclass[] = {
******************************************************************************/
static int
nv50_software_vblsem_release(void *data, u32 type, int head)
nv50_software_vblsem_release(struct nvkm_notify *notify)
{
struct nv50_software_chan *chan = data;
struct nv50_software_chan *chan =
container_of(notify, typeof(*chan), vblank.notify[notify->index]);
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
struct nouveau_bar *bar = nouveau_bar(priv);
@ -142,7 +144,7 @@ nv50_software_vblsem_release(void *data, u32 type, int head)
nv_wr32(priv, 0x060014, chan->vblank.value);
}
return NVKM_EVENT_DROP;
return NVKM_NOTIFY_DROP;
}
void
@ -151,11 +153,8 @@ nv50_software_context_dtor(struct nouveau_object *object)
struct nv50_software_chan *chan = (void *)object;
int i;
if (chan->vblank.event) {
for (i = 0; i < chan->vblank.nr_event; i++)
nouveau_event_ref(NULL, &chan->vblank.event[i]);
kfree(chan->vblank.event);
}
for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++)
nvkm_notify_fini(&chan->vblank.notify[i]);
nouveau_software_context_destroy(&chan->base);
}
@ -176,15 +175,14 @@ nv50_software_context_ctor(struct nouveau_object *parent,
if (ret)
return ret;
chan->vblank.nr_event = pdisp ? pdisp->vblank->index_nr : 0;
chan->vblank.event = kzalloc(chan->vblank.nr_event *
sizeof(*chan->vblank.event), GFP_KERNEL);
if (!chan->vblank.event)
return -ENOMEM;
for (i = 0; i < chan->vblank.nr_event; i++) {
ret = nouveau_event_new(pdisp->vblank, 1, i, pclass->vblank,
chan, &chan->vblank.event[i]);
for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) {
ret = nvkm_notify_init(&pdisp->vblank, pclass->vblank, false,
&(struct nvif_notify_head_req_v0) {
.head = i,
},
sizeof(struct nvif_notify_head_req_v0),
sizeof(struct nvif_notify_head_rep_v0),
&chan->vblank.notify[i]);
if (ret)
return ret;
}

View File

@ -19,14 +19,13 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
struct nv50_software_cclass {
struct nouveau_oclass base;
int (*vblank)(void *, u32, int);
int (*vblank)(struct nvkm_notify *);
};
struct nv50_software_chan {
struct nouveau_software_chan base;
struct {
struct nouveau_eventh **event;
int nr_event;
struct nvkm_notify notify[4];
u32 channel;
u32 ctxdma;
u64 offset;

View File

@ -104,9 +104,10 @@ nvc0_software_sclass[] = {
******************************************************************************/
static int
nvc0_software_vblsem_release(void *data, u32 type, int head)
nvc0_software_vblsem_release(struct nvkm_notify *notify)
{
struct nv50_software_chan *chan = data;
struct nv50_software_chan *chan =
container_of(notify, typeof(*chan), vblank.notify[notify->index]);
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
struct nouveau_bar *bar = nouveau_bar(priv);
@ -116,7 +117,7 @@ nvc0_software_vblsem_release(void *data, u32 type, int head)
nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
nv_wr32(priv, 0x060014, chan->vblank.value);
return NVKM_EVENT_DROP;
return NVKM_NOTIFY_DROP;
}
static struct nv50_software_cclass

View File

@ -62,11 +62,6 @@ enum nv_subdev_type {
NVDEV_SUBDEV_NR,
};
enum nvkm_device_ntfy {
NVKM_DEVICE_NTFY_POWER = 0,
NVKM_DEVICE_NTFY
};
struct nouveau_device {
struct nouveau_engine base;
struct list_head head;
@ -75,7 +70,7 @@ struct nouveau_device {
struct platform_device *platformdev;
u64 handle;
struct nouveau_event *ntfy;
struct nvkm_event event;
const char *cfgopt;
const char *dbgopt;

View File

@ -1,47 +1,34 @@
#ifndef __NVKM_EVENT_H__
#define __NVKM_EVENT_H__
/* return codes from event handlers */
#define NVKM_EVENT_DROP 0
#define NVKM_EVENT_KEEP 1
#include <core/notify.h>
/* nouveau_eventh.flags bit #s */
#define NVKM_EVENT_ENABLE 0
struct nouveau_eventh {
struct nouveau_event *event;
struct list_head head;
unsigned long flags;
u32 types;
int index;
int (*func)(void *, u32, int);
void *priv;
struct nvkm_event_func {
int (*ctor)(void *data, u32 size, struct nvkm_notify *);
void (*send)(void *data, u32 size, struct nvkm_notify *);
void (*init)(struct nvkm_event *, int type, int index);
void (*fini)(struct nvkm_event *, int type, int index);
};
struct nouveau_event {
void *priv;
int (*check)(struct nouveau_event *, u32 type, int index);
void (*enable)(struct nouveau_event *, int type, int index);
void (*disable)(struct nouveau_event *, int type, int index);
struct nvkm_event {
const struct nvkm_event_func *func;
int types_nr;
int index_nr;
spinlock_t list_lock;
struct list_head *list;
spinlock_t refs_lock;
int refs[];
spinlock_t list_lock;
struct list_head list;
int *refs;
};
int nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **);
void nouveau_event_destroy(struct nouveau_event **);
void nouveau_event_trigger(struct nouveau_event *, u32 types, int index);
int nouveau_event_new(struct nouveau_event *, u32 types, int index,
int (*func)(void *, u32, int), void *,
struct nouveau_eventh **);
void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **);
void nouveau_event_get(struct nouveau_eventh *);
void nouveau_event_put(struct nouveau_eventh *);
int nvkm_event_init(const struct nvkm_event_func *func,
int types_nr, int index_nr,
struct nvkm_event *);
void nvkm_event_fini(struct nvkm_event *);
void nvkm_event_get(struct nvkm_event *, u32 types, int index);
void nvkm_event_put(struct nvkm_event *, u32 types, int index);
void nvkm_event_send(struct nvkm_event *, u32 types, int index,
void *data, u32 size);
#endif

View File

@ -0,0 +1,36 @@
#ifndef __NVKM_NOTIFY_H__
#define __NVKM_NOTIFY_H__
struct nvkm_notify {
struct nvkm_event *event;
struct list_head head;
#define NVKM_NOTIFY_USER 0
#define NVKM_NOTIFY_WORK 1
unsigned long flags;
int block;
#define NVKM_NOTIFY_DROP 0
#define NVKM_NOTIFY_KEEP 1
int (*func)(struct nvkm_notify *);
/* set by nvkm_event ctor */
u32 types;
int index;
u8 size;
struct work_struct work;
/* this is const for a *very* good reason - the data might be on the
* stack from an irq handler. if you're not core/notify.c then you
* should probably think twice before casting it away...
*/
const void *data;
};
int nvkm_notify_init(struct nvkm_event *, int (*func)(struct nvkm_notify *),
bool work, void *data, u32 size, u32 reply,
struct nvkm_notify *);
void nvkm_notify_fini(struct nvkm_notify *);
void nvkm_notify_get(struct nvkm_notify *);
void nvkm_notify_put(struct nvkm_notify *);
void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size);
#endif

View File

@ -6,20 +6,13 @@
#include <core/device.h>
#include <core/event.h>
enum nvkm_hpd_event {
NVKM_HPD_PLUG = 1,
NVKM_HPD_UNPLUG = 2,
NVKM_HPD_IRQ = 4,
NVKM_HPD = (NVKM_HPD_PLUG | NVKM_HPD_UNPLUG | NVKM_HPD_IRQ)
};
struct nouveau_disp {
struct nouveau_engine base;
struct list_head outp;
struct nouveau_event *hpd;
struct nouveau_event *vblank;
struct nvkm_event hpd;
struct nvkm_event vblank;
};
static inline struct nouveau_disp *

View File

@ -65,8 +65,8 @@ struct nouveau_fifo_base {
struct nouveau_fifo {
struct nouveau_engine base;
struct nouveau_event *cevent; /* channel creation event */
struct nouveau_event *uevent; /* async user trigger */
struct nvkm_event cevent; /* channel creation event */
struct nvkm_event uevent; /* async user trigger */
struct nouveau_object **channel;
spinlock_t lock;

View File

@ -0,0 +1 @@
../../../nvif/event.h

View File

@ -0,0 +1 @@
../../../nvif/unpack.h

View File

@ -75,7 +75,7 @@ struct nouveau_clock {
wait_queue_head_t wait;
atomic_t waiting;
struct nouveau_eventh *pwrsrc_ntfy;
struct nvkm_notify pwrsrc_ntfy;
int pwrsrc;
int pstate; /* current */
int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */

View File

@ -8,16 +8,22 @@
#include <subdev/bios.h>
#include <subdev/bios/gpio.h>
enum nvkm_gpio_event {
NVKM_GPIO_HI = 1,
NVKM_GPIO_LO = 2,
NVKM_GPIO_TOGGLED = (NVKM_GPIO_HI | NVKM_GPIO_LO),
struct nvkm_gpio_ntfy_req {
#define NVKM_GPIO_HI 0x01
#define NVKM_GPIO_LO 0x02
#define NVKM_GPIO_TOGGLED 0x03
u8 mask;
u8 line;
};
struct nvkm_gpio_ntfy_rep {
u8 mask;
};
struct nouveau_gpio {
struct nouveau_subdev base;
struct nouveau_event *events;
struct nvkm_event event;
void (*reset)(struct nouveau_gpio *, u8 func);
int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,

View File

@ -14,15 +14,18 @@
#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
enum nvkm_i2c_event {
NVKM_I2C_PLUG = 1,
NVKM_I2C_UNPLUG = 2,
NVKM_I2C_IRQ = 4,
NVKM_I2C_DONE = 8,
NVKM_I2C_ANY = (NVKM_I2C_PLUG |
NVKM_I2C_UNPLUG |
NVKM_I2C_IRQ |
NVKM_I2C_DONE),
struct nvkm_i2c_ntfy_req {
#define NVKM_I2C_PLUG 0x01
#define NVKM_I2C_UNPLUG 0x02
#define NVKM_I2C_IRQ 0x04
#define NVKM_I2C_DONE 0x08
#define NVKM_I2C_ANY 0x0f
u8 mask;
u8 port;
};
struct nvkm_i2c_ntfy_rep {
u8 mask;
};
struct nouveau_i2c_port {
@ -56,7 +59,7 @@ struct nouveau_i2c_board_info {
struct nouveau_i2c {
struct nouveau_subdev base;
struct nouveau_event *ntfy;
struct nvkm_event event;
struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);

View File

@ -235,7 +235,7 @@ nouveau_pstate_work(struct work_struct *work)
}
wake_up_all(&clk->wait);
nouveau_event_get(clk->pwrsrc_ntfy);
nvkm_notify_get(&clk->pwrsrc_ntfy);
}
static int
@ -460,11 +460,12 @@ nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel)
}
static int
nouveau_clock_pwrsrc(void *data, u32 mask, int type)
nouveau_clock_pwrsrc(struct nvkm_notify *notify)
{
struct nouveau_clock *clk = data;
struct nouveau_clock *clk =
container_of(notify, typeof(*clk), pwrsrc_ntfy);
nouveau_pstate_calc(clk, false);
return NVKM_EVENT_DROP;
return NVKM_NOTIFY_DROP;
}
/******************************************************************************
@ -475,7 +476,7 @@ int
_nouveau_clock_fini(struct nouveau_object *object, bool suspend)
{
struct nouveau_clock *clk = (void *)object;
nouveau_event_put(clk->pwrsrc_ntfy);
nvkm_notify_put(&clk->pwrsrc_ntfy);
return nouveau_subdev_fini(&clk->base, suspend);
}
@ -520,7 +521,7 @@ _nouveau_clock_dtor(struct nouveau_object *object)
struct nouveau_clock *clk = (void *)object;
struct nouveau_pstate *pstate, *temp;
nouveau_event_ref(NULL, &clk->pwrsrc_ntfy);
nvkm_notify_fini(&clk->pwrsrc_ntfy);
list_for_each_entry_safe(pstate, temp, &clk->states, head) {
nouveau_pstate_del(pstate);
@ -572,9 +573,8 @@ nouveau_clock_create_(struct nouveau_object *parent,
clk->allow_reclock = allow_reclock;
ret = nouveau_event_new(device->ntfy, 1, NVKM_DEVICE_NTFY_POWER,
nouveau_clock_pwrsrc, clk,
&clk->pwrsrc_ntfy);
ret = nvkm_notify_init(&device->event, nouveau_clock_pwrsrc, true,
NULL, 0, 0, &clk->pwrsrc_ntfy);
if (ret)
return ret;

View File

@ -106,39 +106,59 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
}
static void
nouveau_gpio_intr_disable(struct nouveau_event *event, int type, int index)
nouveau_gpio_intr_fini(struct nvkm_event *event, int type, int index)
{
struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event);
const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
impl->intr_mask(gpio, type, 1 << index, 0);
}
static void
nouveau_gpio_intr_enable(struct nouveau_event *event, int type, int index)
nouveau_gpio_intr_init(struct nvkm_event *event, int type, int index)
{
struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event);
const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
impl->intr_mask(gpio, type, 1 << index, 1 << index);
}
static int
nouveau_gpio_intr_ctor(void *data, u32 size, struct nvkm_notify *notify)
{
struct nvkm_gpio_ntfy_req *req = data;
if (!WARN_ON(size != sizeof(*req))) {
notify->size = sizeof(struct nvkm_gpio_ntfy_rep);
notify->types = req->mask;
notify->index = req->line;
return 0;
}
return -EINVAL;
}
static void
nouveau_gpio_intr(struct nouveau_subdev *subdev)
{
struct nouveau_gpio *gpio = nouveau_gpio(subdev);
const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
u32 hi, lo, e, i;
u32 hi, lo, i;
impl->intr_stat(gpio, &hi, &lo);
for (i = 0; e = 0, (hi | lo) && i < impl->lines; i++) {
if (hi & (1 << i))
e |= NVKM_GPIO_HI;
if (lo & (1 << i))
e |= NVKM_GPIO_LO;
nouveau_event_trigger(gpio->events, e, i);
for (i = 0; (hi | lo) && i < impl->lines; i++) {
struct nvkm_gpio_ntfy_rep rep = {
.mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
(NVKM_GPIO_LO * !!(lo & (1 << i))),
};
nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep));
}
}
static const struct nvkm_event_func
nouveau_gpio_intr_func = {
.ctor = nouveau_gpio_intr_ctor,
.init = nouveau_gpio_intr_init,
.fini = nouveau_gpio_intr_fini,
};
int
_nouveau_gpio_fini(struct nouveau_object *object, bool suspend)
{
@ -183,7 +203,7 @@ void
_nouveau_gpio_dtor(struct nouveau_object *object)
{
struct nouveau_gpio *gpio = (void *)object;
nouveau_event_destroy(&gpio->events);
nvkm_event_fini(&gpio->event);
nouveau_subdev_destroy(&gpio->base);
}
@ -208,13 +228,11 @@ nouveau_gpio_create_(struct nouveau_object *parent,
gpio->get = nouveau_gpio_get;
gpio->reset = impl->reset;
ret = nouveau_event_create(2, impl->lines, &gpio->events);
ret = nvkm_event_init(&nouveau_gpio_intr_func, 2, impl->lines,
&gpio->event);
if (ret)
return ret;
gpio->events->priv = gpio;
gpio->events->enable = nouveau_gpio_intr_enable;
gpio->events->disable = nouveau_gpio_intr_disable;
nv_subdev(gpio)->intr = nouveau_gpio_intr;
return 0;
}

View File

@ -326,9 +326,9 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
}
static void
nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index)
nouveau_i2c_intr_fini(struct nvkm_event *event, int type, int index)
{
struct nouveau_i2c *i2c = nouveau_i2c(event->priv);
struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event);
struct nouveau_i2c_port *port = i2c->find(i2c, index);
const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
if (port && port->aux >= 0)
@ -336,15 +336,28 @@ nouveau_i2c_intr_disable(struct nouveau_event *event, int type, int index)
}
static void
nouveau_i2c_intr_enable(struct nouveau_event *event, int type, int index)
nouveau_i2c_intr_init(struct nvkm_event *event, int type, int index)
{
struct nouveau_i2c *i2c = nouveau_i2c(event->priv);
struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event);
struct nouveau_i2c_port *port = i2c->find(i2c, index);
const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
if (port && port->aux >= 0)
impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux);
}
static int
nouveau_i2c_intr_ctor(void *data, u32 size, struct nvkm_notify *notify)
{
struct nvkm_i2c_ntfy_req *req = data;
if (!WARN_ON(size != sizeof(*req))) {
notify->size = sizeof(struct nvkm_i2c_ntfy_rep);
notify->types = req->mask;
notify->index = req->port;
return 0;
}
return -EINVAL;
}
static void
nouveau_i2c_intr(struct nouveau_subdev *subdev)
{
@ -364,13 +377,26 @@ nouveau_i2c_intr(struct nouveau_subdev *subdev)
if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG;
if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ;
if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE;
nouveau_event_trigger(i2c->ntfy, e, port->index);
if (e) {
struct nvkm_i2c_ntfy_rep rep = {
.mask = e,
};
nvkm_event_send(&i2c->event, rep.mask,
port->index, &rep,
sizeof(rep));
}
}
}
}
}
static const struct nvkm_event_func
nouveau_i2c_intr_func = {
.ctor = nouveau_i2c_intr_ctor,
.init = nouveau_i2c_intr_init,
.fini = nouveau_i2c_intr_fini,
};
int
_nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
{
@ -431,7 +457,7 @@ _nouveau_i2c_dtor(struct nouveau_object *object)
struct nouveau_i2c *i2c = (void *)object;
struct nouveau_i2c_port *port, *temp;
nouveau_event_destroy(&i2c->ntfy);
nvkm_event_fini(&i2c->event);
list_for_each_entry_safe(port, temp, &i2c->ports, head) {
nouveau_object_ref(NULL, (struct nouveau_object **)&port);
@ -547,13 +573,10 @@ nouveau_i2c_create_(struct nouveau_object *parent,
}
}
ret = nouveau_event_create(4, index, &i2c->ntfy);
ret = nvkm_event_init(&nouveau_i2c_intr_func, 4, index, &i2c->event);
if (ret)
return ret;
i2c->ntfy->priv = i2c;
i2c->ntfy->enable = nouveau_i2c_intr_enable;
i2c->ntfy->disable = nouveau_i2c_intr_disable;
return 0;
}

View File

@ -46,6 +46,8 @@
#include <subdev/gpio.h>
#include <engine/disp.h>
#include <nvif/event.h>
MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
static int nouveau_tv_disable = 0;
module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
@ -102,7 +104,7 @@ static void
nouveau_connector_destroy(struct drm_connector *connector)
{
struct nouveau_connector *nv_connector = nouveau_connector(connector);
nouveau_event_ref(NULL, &nv_connector->hpd);
nvkm_notify_fini(&nv_connector->hpd);
kfree(nv_connector->edid);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
@ -939,18 +941,19 @@ nouveau_connector_funcs_dp = {
.force = nouveau_connector_force
};
static void
nouveau_connector_hotplug_work(struct work_struct *work)
static int
nouveau_connector_hotplug(struct nvkm_notify *notify)
{
struct nouveau_connector *nv_connector =
container_of(work, typeof(*nv_connector), work);
container_of(notify, typeof(*nv_connector), hpd);
struct drm_connector *connector = &nv_connector->base;
struct nouveau_drm *drm = nouveau_drm(connector->dev);
const struct nvif_notify_conn_rep_v0 *rep = notify->data;
const char *name = connector->name;
if (nv_connector->status & NVKM_HPD_IRQ) {
if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) {
} else {
bool plugged = (nv_connector->status != NVKM_HPD_UNPLUG);
bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG);
NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
@ -961,16 +964,7 @@ nouveau_connector_hotplug_work(struct work_struct *work)
drm_helper_hpd_irq_event(connector->dev);
}
nouveau_event_get(nv_connector->hpd);
}
static int
nouveau_connector_hotplug(void *data, u32 type, int index)
{
struct nouveau_connector *nv_connector = data;
nv_connector->status = type;
schedule_work(&nv_connector->work);
return NVKM_EVENT_DROP;
return NVKM_NOTIFY_KEEP;
}
static ssize_t
@ -1226,16 +1220,19 @@ nouveau_connector_create(struct drm_device *dev, int index)
break;
}
ret = nouveau_event_new(pdisp->hpd, NVKM_HPD, index,
nouveau_connector_hotplug,
nv_connector, &nv_connector->hpd);
ret = nvkm_notify_init(&pdisp->hpd, nouveau_connector_hotplug, true,
&(struct nvif_notify_conn_req_v0) {
.mask = NVIF_NOTIFY_CONN_V0_ANY,
.conn = index,
},
sizeof(struct nvif_notify_conn_req_v0),
sizeof(struct nvif_notify_conn_rep_v0),
&nv_connector->hpd);
if (ret)
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
else
connector->polled = DRM_CONNECTOR_POLL_HPD;
INIT_WORK(&nv_connector->work, nouveau_connector_hotplug_work);
drm_connector_register(connector);
return connector;
}

View File

@ -67,9 +67,7 @@ struct nouveau_connector {
u8 index;
u8 *dcb;
struct nouveau_eventh *hpd;
u32 status;
struct work_struct work;
struct nvkm_notify hpd;
struct drm_dp_aux aux;

View File

@ -31,7 +31,7 @@ struct nouveau_crtc {
struct drm_crtc base;
int index;
struct nouveau_eventh *vblank;
struct nvkm_notify vblank;
uint32_t dpms_saved_fp_control;
uint32_t fp_users;

View File

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

View File

@ -165,12 +165,18 @@ nouveau_fence_done(struct nouveau_fence *fence)
return !fence->channel;
}
struct nouveau_fence_wait {
struct nouveau_fence_priv *priv;
struct nvkm_notify notify;
};
static int
nouveau_fence_wait_uevent_handler(void *data, u32 type, int index)
nouveau_fence_wait_uevent_handler(struct nvkm_notify *notify)
{
struct nouveau_fence_priv *priv = data;
wake_up_all(&priv->waiting);
return NVKM_EVENT_KEEP;
struct nouveau_fence_wait *wait =
container_of(notify, typeof(*wait), notify);
wake_up_all(&wait->priv->waiting);
return NVKM_NOTIFY_KEEP;
}
static int
@ -180,16 +186,16 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
struct nouveau_channel *chan = fence->channel;
struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device);
struct nouveau_fence_priv *priv = chan->drm->fence;
struct nouveau_eventh *handler;
struct nouveau_fence_wait wait = { .priv = priv };
int ret = 0;
ret = nouveau_event_new(pfifo->uevent, 1, 0,
nouveau_fence_wait_uevent_handler,
priv, &handler);
ret = nvkm_notify_init(&pfifo->uevent,
nouveau_fence_wait_uevent_handler, false,
NULL, 0, 0, &wait.notify);
if (ret)
return ret;
nouveau_event_get(handler);
nvkm_notify_get(&wait.notify);
if (fence->timeout) {
unsigned long timeout = fence->timeout - jiffies;
@ -221,7 +227,7 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
}
}
nouveau_event_ref(NULL, &handler);
nvkm_notify_fini(&wait.notify);
if (unlikely(ret < 0))
return ret;

View File

@ -0,0 +1,28 @@
#ifndef __NVIF_EVENT_H__
#define __NVIF_EVENT_H__
struct nvif_notify_head_req_v0 {
__u8 version;
__u8 head;
};
struct nvif_notify_head_rep_v0 {
__u8 version;
};
struct nvif_notify_conn_req_v0 {
__u8 version;
#define NVIF_NOTIFY_CONN_V0_PLUG 0x01
#define NVIF_NOTIFY_CONN_V0_UNPLUG 0x02
#define NVIF_NOTIFY_CONN_V0_IRQ 0x04
#define NVIF_NOTIFY_CONN_V0_ANY 0x07
__u8 mask;
__u8 conn;
};
struct nvif_notify_conn_rep_v0 {
__u8 version;
__u8 mask;
};
#endif

View File

@ -0,0 +1,24 @@
#ifndef __NVIF_UNPACK_H__
#define __NVIF_UNPACK_H__
#define nvif_unvers(d) ({ \
ret = (size == sizeof(d)) ? 0 : -ENOSYS; \
(ret == 0); \
})
#define nvif_unpack(d,vl,vh,m) ({ \
if ((vl) == 0 || ret == -ENOSYS) { \
int _size = sizeof(d); \
if (_size <= size && (d).version >= (vl) && \
(d).version <= (vh)) { \
data = (u8 *)data + _size; \
size = size - _size; \
ret = ((m) || !size) ? 0 : -E2BIG; \
} else { \
ret = -ENOSYS; \
} \
} \
(ret == 0); \
})
#endif