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:
parent
4d681b666d
commit
79ca27706a
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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, ¬ify->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, ¬ify->flags))
|
||||
flush_work(¬ify->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, ¬ify->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, ¬ify->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, ¬ify->flags)) {
|
||||
memcpy((void *)notify->data, data, size);
|
||||
schedule_work(¬ify->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(¬ify->event->list_lock, flags);
|
||||
list_del(¬ify->head);
|
||||
spin_unlock_irqrestore(¬ify->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(¬ify->work, nvkm_notify_work);
|
||||
set_bit(NVKM_NOTIFY_WORK, ¬ify->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(¬ify->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)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../../../nvif/event.h
|
|
@ -0,0 +1 @@
|
|||
../../../nvif/unpack.h
|
|
@ -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) */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue