Commit 51cb4b39 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/core: convert event handler apis to split create/enable semantics

This is a necessary step towards being able to work with the insane locking
requirements of the DRM core's vblank routines, and a nice cleanup as a
side-effect.

This is similar in spirit to the interfaces that Peter Hurley arrived at
with his nouveau_event rcu conversion series.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 7589563e
...@@ -37,39 +37,82 @@ nouveau_event_put_locked(struct nouveau_event *event, int index, ...@@ -37,39 +37,82 @@ nouveau_event_put_locked(struct nouveau_event *event, int index,
} }
void void
nouveau_event_put(struct nouveau_event *event, int index, nouveau_event_put(struct nouveau_eventh *handler)
struct nouveau_eventh *handler)
{ {
struct nouveau_event *event = handler->event;
unsigned long flags; unsigned long flags;
if (index >= event->index_nr)
return;
spin_lock_irqsave(&event->lock, flags); spin_lock_irqsave(&event->lock, flags);
nouveau_event_put_locked(event, index, handler); nouveau_event_put_locked(handler->event, handler->index, handler);
spin_unlock_irqrestore(&event->lock, flags); spin_unlock_irqrestore(&event->lock, flags);
} }
void void
nouveau_event_get(struct nouveau_event *event, int index, nouveau_event_get(struct nouveau_eventh *handler)
struct nouveau_eventh *handler)
{ {
struct nouveau_event *event = handler->event;
unsigned long flags; unsigned long flags;
if (index >= event->index_nr)
return;
spin_lock_irqsave(&event->lock, flags); spin_lock_irqsave(&event->lock, flags);
if (!__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) { if (!__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
list_add(&handler->head, &event->index[index].list); list_add(&handler->head, &event->index[handler->index].list);
if (!event->index[index].refs++) { if (!event->index[handler->index].refs++) {
if (event->enable) if (event->enable)
event->enable(event, index); event->enable(event, handler->index);
} }
} }
spin_unlock_irqrestore(&event->lock, flags); spin_unlock_irqrestore(&event->lock, flags);
} }
static void
nouveau_event_fini(struct nouveau_eventh *handler)
{
nouveau_event_put(handler);
}
static int
nouveau_event_init(struct nouveau_event *event, int index,
int (*func)(void *, int), void *priv,
struct nouveau_eventh *handler)
{
if (index >= event->index_nr)
return -EINVAL;
handler->event = event;
handler->flags = 0;
handler->index = index;
handler->func = func;
handler->priv = priv;
return 0;
}
int
nouveau_event_new(struct nouveau_event *event, int index,
int (*func)(void *, int), void *priv,
struct nouveau_eventh **phandler)
{
struct nouveau_eventh *handler;
int ret = -ENOMEM;
handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL);
if (handler) {
ret = nouveau_event_init(event, index, func, priv, handler);
if (ret)
kfree(handler);
}
return ret;
}
void
nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref)
{
BUG_ON(handler != NULL);
if (*ref) {
nouveau_event_fini(*ref);
kfree(*ref);
}
*ref = handler;
}
void void
nouveau_event_trigger(struct nouveau_event *event, int index) nouveau_event_trigger(struct nouveau_event *event, int index)
{ {
...@@ -81,7 +124,7 @@ nouveau_event_trigger(struct nouveau_event *event, int index) ...@@ -81,7 +124,7 @@ nouveau_event_trigger(struct nouveau_event *event, int index)
spin_lock_irqsave(&event->lock, flags); spin_lock_irqsave(&event->lock, flags);
list_for_each_entry_safe(handler, temp, &event->index[index].list, head) { list_for_each_entry_safe(handler, temp, &event->index[index].list, head) {
if (handler->func(handler, index) == NVKM_EVENT_DROP) { if (handler->func(handler->priv, index) == NVKM_EVENT_DROP) {
nouveau_event_put_locked(event, index, handler); nouveau_event_put_locked(event, index, handler);
} }
} }
......
...@@ -71,7 +71,7 @@ nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd, ...@@ -71,7 +71,7 @@ nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
return 0; return 0;
} }
static int int
nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd, nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
void *args, u32 size) void *args, u32 size)
{ {
...@@ -80,21 +80,20 @@ nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd, ...@@ -80,21 +80,20 @@ nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
return 0; return 0;
} }
static int int
nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd, nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
void *args, u32 size) void *args, u32 size)
{ {
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent); struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
struct nouveau_disp *disp = nouveau_disp(object); u32 head = *(u32 *)args;
u32 crtc = *(u32 *)args; if (head >= chan->vblank.nr_event)
if (crtc > 1)
return -EINVAL; return -EINVAL;
nouveau_event_get(disp->vblank, crtc, &chan->vblank.event); nouveau_event_get(chan->vblank.event[head]);
return 0; return 0;
} }
static int int
nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd, nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd,
void *args, u32 size) void *args, u32 size)
{ {
...@@ -125,10 +124,9 @@ nv50_software_sclass[] = { ...@@ -125,10 +124,9 @@ nv50_software_sclass[] = {
******************************************************************************/ ******************************************************************************/
static int static int
nv50_software_vblsem_release(struct nouveau_eventh *event, int head) nv50_software_vblsem_release(void *data, int head)
{ {
struct nv50_software_chan *chan = struct nv50_software_chan *chan = data;
container_of(event, typeof(*chan), vblank.event);
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_bar *bar = nouveau_bar(priv);
...@@ -147,23 +145,51 @@ nv50_software_vblsem_release(struct nouveau_eventh *event, int head) ...@@ -147,23 +145,51 @@ nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
return NVKM_EVENT_DROP; return NVKM_EVENT_DROP;
} }
void
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);
}
nouveau_software_context_destroy(&chan->base);
}
int int
nv50_software_context_ctor(struct nouveau_object *parent, nv50_software_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject) struct nouveau_object **pobject)
{ {
struct nouveau_disp *pdisp = nouveau_disp(parent);
struct nv50_software_cclass *pclass = (void *)oclass; struct nv50_software_cclass *pclass = (void *)oclass;
struct nv50_software_chan *chan; struct nv50_software_chan *chan;
int ret; int ret, i;
ret = nouveau_software_context_create(parent, engine, oclass, &chan); ret = nouveau_software_context_create(parent, engine, oclass, &chan);
*pobject = nv_object(chan); *pobject = nv_object(chan);
if (ret) if (ret)
return ret; return ret;
chan->vblank.nr_event = pdisp->vblank->index_nr;
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, i, pclass->vblank,
chan, &chan->vblank.event[i]);
if (ret)
return ret;
}
chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
chan->vblank.event.func = pclass->vblank;
return 0; return 0;
} }
......
...@@ -19,13 +19,14 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *, ...@@ -19,13 +19,14 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
struct nv50_software_cclass { struct nv50_software_cclass {
struct nouveau_oclass base; struct nouveau_oclass base;
int (*vblank)(struct nouveau_eventh *, int); int (*vblank)(void *, int);
}; };
struct nv50_software_chan { struct nv50_software_chan {
struct nouveau_software_chan base; struct nouveau_software_chan base;
struct { struct {
struct nouveau_eventh event; struct nouveau_eventh **event;
int nr_event;
u32 channel; u32 channel;
u32 ctxdma; u32 ctxdma;
u64 offset; u64 offset;
...@@ -37,5 +38,10 @@ int nv50_software_context_ctor(struct nouveau_object *, ...@@ -37,5 +38,10 @@ int nv50_software_context_ctor(struct nouveau_object *,
struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32, struct nouveau_oclass *, void *, u32,
struct nouveau_object **); struct nouveau_object **);
void nv50_software_context_dtor(struct nouveau_object *);
int nv50_software_mthd_vblsem_value(struct nouveau_object *, u32, void *, u32);
int nv50_software_mthd_vblsem_release(struct nouveau_object *, u32, void *, u32);
int nv50_software_mthd_flip(struct nouveau_object *, u32, void *, u32);
#endif #endif
...@@ -54,40 +54,6 @@ nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd, ...@@ -54,40 +54,6 @@ nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
return 0; return 0;
} }
static int
nvc0_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
chan->vblank.value = *(u32 *)args;
return 0;
}
static int
nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
struct nouveau_disp *disp = nouveau_disp(object);
u32 crtc = *(u32 *)args;
if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3)
return -EINVAL;
nouveau_event_get(disp->vblank, crtc, &chan->vblank.event);
return 0;
}
static int
nvc0_software_mthd_flip(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
if (chan->base.flip)
return chan->base.flip(chan->base.flip_data);
return -EINVAL;
}
static int static int
nvc0_software_mthd_mp_control(struct nouveau_object *object, u32 mthd, nvc0_software_mthd_mp_control(struct nouveau_object *object, u32 mthd,
void *args, u32 size) void *args, u32 size)
...@@ -118,9 +84,9 @@ static struct nouveau_omthds ...@@ -118,9 +84,9 @@ static struct nouveau_omthds
nvc0_software_omthds[] = { nvc0_software_omthds[] = {
{ 0x0400, 0x0400, nvc0_software_mthd_vblsem_offset }, { 0x0400, 0x0400, nvc0_software_mthd_vblsem_offset },
{ 0x0404, 0x0404, nvc0_software_mthd_vblsem_offset }, { 0x0404, 0x0404, nvc0_software_mthd_vblsem_offset },
{ 0x0408, 0x0408, nvc0_software_mthd_vblsem_value }, { 0x0408, 0x0408, nv50_software_mthd_vblsem_value },
{ 0x040c, 0x040c, nvc0_software_mthd_vblsem_release }, { 0x040c, 0x040c, nv50_software_mthd_vblsem_release },
{ 0x0500, 0x0500, nvc0_software_mthd_flip }, { 0x0500, 0x0500, nv50_software_mthd_flip },
{ 0x0600, 0x0600, nvc0_software_mthd_mp_control }, { 0x0600, 0x0600, nvc0_software_mthd_mp_control },
{ 0x0644, 0x0644, nvc0_software_mthd_mp_control }, { 0x0644, 0x0644, nvc0_software_mthd_mp_control },
{ 0x06ac, 0x06ac, nvc0_software_mthd_mp_control }, { 0x06ac, 0x06ac, nvc0_software_mthd_mp_control },
...@@ -138,10 +104,9 @@ nvc0_software_sclass[] = { ...@@ -138,10 +104,9 @@ nvc0_software_sclass[] = {
******************************************************************************/ ******************************************************************************/
static int static int
nvc0_software_vblsem_release(struct nouveau_eventh *event, int head) nvc0_software_vblsem_release(void *data, int head)
{ {
struct nv50_software_chan *chan = struct nv50_software_chan *chan = data;
container_of(event, typeof(*chan), vblank.event);
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_bar *bar = nouveau_bar(priv);
......
...@@ -9,10 +9,12 @@ ...@@ -9,10 +9,12 @@
#define NVKM_EVENT_ENABLE 0 #define NVKM_EVENT_ENABLE 0
struct nouveau_eventh { struct nouveau_eventh {
struct nouveau_event *event;
struct list_head head; struct list_head head;
unsigned long flags; unsigned long flags;
int index;
int (*func)(void *, int);
void *priv; void *priv;
int (*func)(struct nouveau_eventh *, int index);
}; };
struct nouveau_event { struct nouveau_event {
...@@ -33,9 +35,11 @@ int nouveau_event_create(int index_nr, struct nouveau_event **); ...@@ -33,9 +35,11 @@ int nouveau_event_create(int index_nr, struct nouveau_event **);
void nouveau_event_destroy(struct nouveau_event **); void nouveau_event_destroy(struct nouveau_event **);
void nouveau_event_trigger(struct nouveau_event *, int index); void nouveau_event_trigger(struct nouveau_event *, int index);
void nouveau_event_get(struct nouveau_event *, int index, int nouveau_event_new(struct nouveau_event *, int index,
struct nouveau_eventh *); int (*func)(void *, int), void *,
void nouveau_event_put(struct nouveau_event *, int index, struct nouveau_eventh **);
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 *);
#endif #endif
...@@ -100,6 +100,7 @@ static void ...@@ -100,6 +100,7 @@ static void
nouveau_connector_destroy(struct drm_connector *connector) nouveau_connector_destroy(struct drm_connector *connector)
{ {
struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_connector *nv_connector = nouveau_connector(connector);
nouveau_event_ref(NULL, &nv_connector->hpd_func);
kfree(nv_connector->edid); kfree(nv_connector->edid);
drm_sysfs_connector_remove(connector); drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
...@@ -932,10 +933,9 @@ nouveau_connector_hotplug_work(struct work_struct *work) ...@@ -932,10 +933,9 @@ nouveau_connector_hotplug_work(struct work_struct *work)
} }
static int static int
nouveau_connector_hotplug(struct nouveau_eventh *event, int index) nouveau_connector_hotplug(void *data, int index)
{ {
struct nouveau_connector *nv_connector = struct nouveau_connector *nv_connector = data;
container_of(event, struct nouveau_connector, hpd_func);
schedule_work(&nv_connector->hpd_work); schedule_work(&nv_connector->hpd_work);
return NVKM_EVENT_KEEP; return NVKM_EVENT_KEEP;
} }
...@@ -1007,10 +1007,16 @@ nouveau_connector_create(struct drm_device *dev, int index) ...@@ -1007,10 +1007,16 @@ nouveau_connector_create(struct drm_device *dev, int index)
ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)], ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)],
DCB_GPIO_UNUSED, &nv_connector->hpd); DCB_GPIO_UNUSED, &nv_connector->hpd);
nv_connector->hpd_func.func = nouveau_connector_hotplug;
if (ret) if (ret)
nv_connector->hpd.func = DCB_GPIO_UNUSED; nv_connector->hpd.func = DCB_GPIO_UNUSED;
if (nv_connector->hpd.func != DCB_GPIO_UNUSED) {
nouveau_event_new(gpio->events, nv_connector->hpd.line,
nouveau_connector_hotplug,
nv_connector,
&nv_connector->hpd_func);
}
nv_connector->type = nv_connector->dcb[0]; nv_connector->type = nv_connector->dcb[0];
if (drm_conntype_from_dcb(nv_connector->type) == if (drm_conntype_from_dcb(nv_connector->type) ==
DRM_MODE_CONNECTOR_Unknown) { DRM_MODE_CONNECTOR_Unknown) {
......
...@@ -69,7 +69,7 @@ struct nouveau_connector { ...@@ -69,7 +69,7 @@ struct nouveau_connector {
struct dcb_gpio_func hpd; struct dcb_gpio_func hpd;
struct work_struct hpd_work; struct work_struct hpd_work;
struct nouveau_eventh hpd_func; struct nouveau_eventh *hpd_func;
int dithering_mode; int dithering_mode;
int dithering_depth; int dithering_depth;
......
...@@ -38,12 +38,85 @@ ...@@ -38,12 +38,85 @@
#include "nouveau_fence.h" #include "nouveau_fence.h"
#include <subdev/bios/gpio.h>
#include <subdev/gpio.h>
#include <engine/disp.h> #include <engine/disp.h>
#include <core/class.h> #include <core/class.h>
static int
nouveau_display_vblank_handler(void *data, int head)
{
struct nouveau_drm *drm = data;
drm_handle_vblank(drm->dev, head);
return NVKM_EVENT_KEEP;
}
int
nouveau_display_vblank_enable(struct drm_device *dev, int head)
{
struct nouveau_display *disp = nouveau_display(dev);
if (disp) {
nouveau_event_get(disp->vblank[head]);
return 0;
}
return -EIO;
}
void
nouveau_display_vblank_disable(struct drm_device *dev, int head)
{
struct nouveau_display *disp = nouveau_display(dev);
if (disp)
nouveau_event_put(disp->vblank[head]);
}
static void
nouveau_display_vblank_fini(struct drm_device *dev)
{
struct nouveau_display *disp = nouveau_display(dev);
int i;
if (disp->vblank) {
for (i = 0; i < dev->mode_config.num_crtc; i++)
nouveau_event_ref(NULL, &disp->vblank[i]);
kfree(disp->vblank);
disp->vblank = NULL;
}
drm_vblank_cleanup(dev);
}
static int
nouveau_display_vblank_init(struct drm_device *dev)
{
struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_disp *pdisp = nouveau_disp(drm->device);
int ret, i;
disp->vblank = kzalloc(dev->mode_config.num_crtc *
sizeof(*disp->vblank), GFP_KERNEL);
if (!disp->vblank)
return -ENOMEM;
for (i = 0; i < dev->mode_config.num_crtc; i++) {
ret = nouveau_event_new(pdisp->vblank, i,
nouveau_display_vblank_handler,
drm, &disp->vblank[i]);
if (ret) {
nouveau_display_vblank_fini(dev);
return ret;
}
}
ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
if (ret) {
nouveau_display_vblank_fini(dev);
return ret;
}
return 0;
}
static void static void
nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
{ {
...@@ -227,9 +300,7 @@ static struct nouveau_drm_prop_enum_list dither_depth[] = { ...@@ -227,9 +300,7 @@ static struct nouveau_drm_prop_enum_list dither_depth[] = {
int int
nouveau_display_init(struct drm_device *dev) nouveau_display_init(struct drm_device *dev)
{ {
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
struct drm_connector *connector; struct drm_connector *connector;
int ret; int ret;
...@@ -243,10 +314,7 @@ nouveau_display_init(struct drm_device *dev) ...@@ -243,10 +314,7 @@ nouveau_display_init(struct drm_device *dev)
/* enable hotplug interrupts */ /* enable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_connector *conn = nouveau_connector(connector);
if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) { if (conn->hpd_func) nouveau_event_get(conn->hpd_func);
nouveau_event_get(gpio->events, conn->hpd.line,
&conn->hpd_func);
}
} }
return ret; return ret;
...@@ -255,18 +323,13 @@ nouveau_display_init(struct drm_device *dev) ...@@ -255,18 +323,13 @@ nouveau_display_init(struct drm_device *dev)
void void
nouveau_display_fini(struct drm_device *dev) nouveau_display_fini(struct drm_device *dev)
{ {
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
struct drm_connector *connector; struct drm_connector *connector;
/* disable hotplug interrupts */ /* disable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_connector *conn = nouveau_connector(connector);
if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) { if (conn->hpd_func) nouveau_event_put(conn->hpd_func);
nouveau_event_put(gpio->events, conn->hpd.line,
&conn->hpd_func);
}
} }
drm_kms_helper_poll_disable(dev); drm_kms_helper_poll_disable(dev);
...@@ -352,7 +415,7 @@ nouveau_display_create(struct drm_device *dev) ...@@ -352,7 +415,7 @@ nouveau_display_create(struct drm_device *dev)
goto disp_create_err; goto disp_create_err;
if (dev->mode_config.num_crtc) { if (dev->mode_config.num_crtc) {
ret = drm_vblank_init(dev, dev->mode_config.num_crtc); ret = nouveau_display_vblank_init(dev);
if (ret) if (ret)
goto vblank_err; goto vblank_err;
} }
...@@ -374,7 +437,7 @@ nouveau_display_destroy(struct drm_device *dev) ...@@ -374,7 +437,7 @@ nouveau_display_destroy(struct drm_device *dev)
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
nouveau_backlight_exit(dev); nouveau_backlight_exit(dev);
drm_vblank_cleanup(dev); nouveau_display_vblank_fini(dev);
drm_kms_helper_poll_fini(dev); drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev); drm_mode_config_cleanup(dev);
......
...@@ -36,6 +36,8 @@ struct nouveau_display { ...@@ -36,6 +36,8 @@ struct nouveau_display {
int (*init)(struct drm_device *); int (*init)(struct drm_device *);
void (*fini)(struct drm_device *); void (*fini)(struct drm_device *);
struct nouveau_eventh **vblank;
struct drm_property *dithering_mode; struct drm_property *dithering_mode;
struct drm_property *dithering_depth; struct drm_property *dithering_depth;
struct drm_property *underscan_property; struct drm_property *underscan_property;
...@@ -59,6 +61,8 @@ void nouveau_display_fini(struct drm_device *dev); ...@@ -59,6 +61,8 @@ void nouveau_display_fini(struct drm_device *dev);
int nouveau_display_suspend(struct drm_device *dev); int nouveau_display_suspend(struct drm_device *dev);
void nouveau_display_repin(struct drm_device *dev); void nouveau_display_repin(struct drm_device *dev);
void nouveau_display_resume(struct drm_device *dev); void nouveau_display_resume(struct drm_device *dev);
int nouveau_display_vblank_enable(struct drm_device *, int);
void nouveau_display_vblank_disable(struct drm_device *, int);
int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event, struct drm_pending_vblank_event *event,
......
...@@ -78,37 +78,6 @@ module_param_named(runpm, nouveau_runtime_pm, int, 0400); ...@@ -78,37 +78,6 @@ module_param_named(runpm, nouveau_runtime_pm, int, 0400);
static struct drm_driver driver; static struct drm_driver driver;
static int
nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head)
{
struct nouveau_drm *drm =
container_of(event, struct nouveau_drm, vblank[head]);
drm_handle_vblank(drm->dev, head);
return NVKM_EVENT_KEEP;
}
static int
nouveau_drm_vblank_enable(struct drm_device *dev, int head)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_disp *pdisp = nouveau_disp(drm->device);
if (WARN_ON_ONCE(head >= ARRAY_SIZE(drm->vblank)))
return -EIO;
drm->vblank[head].func = nouveau_drm_vblank_handler;
nouveau_event_get(pdisp->vblank, head, &drm->vblank[head]);
return 0;
}
static void
nouveau_drm_vblank_disable(struct drm_device *dev, int head)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_disp *pdisp = nouveau_disp(drm->device);
nouveau_event_put(pdisp->vblank, head, &drm->vblank[head]);
}
static u64 static u64
nouveau_name(struct pci_dev *pdev) nouveau_name(struct pci_dev *pdev)
{ {
...@@ -812,8 +781,8 @@ driver = { ...@@ -812,8 +781,8 @@ driver = {
#endif #endif
.get_vblank_counter = drm_vblank_count, .get_vblank_counter = drm_vblank_count,
.enable_vblank = nouveau_drm_vblank_enable, .enable_vblank = nouveau_display_vblank_enable,
.disable_vblank = nouveau_drm_vblank_disable, .disable_vblank = nouveau_display_vblank_disable,
.ioctls = nouveau_ioctls, .ioctls = nouveau_ioctls,
.num_ioctls = ARRAY_SIZE(nouveau_ioctls), .num_ioctls = ARRAY_SIZE(nouveau_ioctls),
......
...@@ -127,7 +127,6 @@ struct nouveau_drm { ...@@ -127,7 +127,6 @@ struct nouveau_drm {
struct nvbios vbios; struct nvbios vbios;
struct nouveau_display *display; struct nouveau_display *display;
struct backlight_device *backlight; struct backlight_device *backlight;
struct nouveau_eventh vblank[4];
/* power management */ /* power management */
struct nouveau_pm *pm; struct nouveau_pm *pm;
......
...@@ -166,9 +166,9 @@ nouveau_fence_done(struct nouveau_fence *fence) ...@@ -166,9 +166,9 @@ nouveau_fence_done(struct nouveau_fence *fence)
} }
static int static int
nouveau_fence_wait_uevent_handler(struct nouveau_eventh *handler, int index) nouveau_fence_wait_uevent_handler(void *data, int index)
{ {
struct nouveau_fence_priv *priv = handler->priv; struct nouveau_fence_priv *priv = data;
wake_up_all(&priv->waiting); wake_up_all(&priv->waiting);
return NVKM_EVENT_KEEP; return NVKM_EVENT_KEEP;
} }
...@@ -180,13 +180,16 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) ...@@ -180,13 +180,16 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
struct nouveau_channel *chan = fence->channel; struct nouveau_channel *chan = fence->channel;
struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device); struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device);
struct nouveau_fence_priv *priv = chan->drm->fence; struct nouveau_fence_priv *priv = chan->drm->fence;
struct nouveau_eventh handler = { struct nouveau_eventh *handler;
.func = nouveau_fence_wait_uevent_handler,
.priv = priv,
};
int ret = 0; int ret = 0;
nouveau_event_get(pfifo->uevent, 0, &handler); ret = nouveau_event_new(pfifo->uevent, 0,
nouveau_fence_wait_uevent_handler,
priv, &handler);
if (ret)
return ret;
nouveau_event_get(handler);
if (fence->timeout) { if (fence->timeout) {
unsigned long timeout = fence->timeout - jiffies; unsigned long timeout = fence->timeout - jiffies;
...@@ -218,7 +221,7 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr) ...@@ -218,7 +221,7 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
} }
} }
nouveau_event_put(pfifo->uevent, 0, &handler); nouveau_event_ref(NULL, &handler);
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment