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: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
7589563eb3
commit
51cb4b392a
|
@ -37,39 +37,82 @@ nouveau_event_put_locked(struct nouveau_event *event, int index,
|
|||
}
|
||||
|
||||
void
|
||||
nouveau_event_put(struct nouveau_event *event, int index,
|
||||
struct nouveau_eventh *handler)
|
||||
nouveau_event_put(struct nouveau_eventh *handler)
|
||||
{
|
||||
struct nouveau_event *event = handler->event;
|
||||
unsigned long flags;
|
||||
|
||||
if (index >= event->index_nr)
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_event_get(struct nouveau_event *event, int index,
|
||||
struct nouveau_eventh *handler)
|
||||
nouveau_event_get(struct nouveau_eventh *handler)
|
||||
{
|
||||
struct nouveau_event *event = handler->event;
|
||||
unsigned long flags;
|
||||
|
||||
if (index >= event->index_nr)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&event->lock, flags);
|
||||
if (!__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
|
||||
list_add(&handler->head, &event->index[index].list);
|
||||
if (!event->index[index].refs++) {
|
||||
list_add(&handler->head, &event->index[handler->index].list);
|
||||
if (!event->index[handler->index].refs++) {
|
||||
if (event->enable)
|
||||
event->enable(event, index);
|
||||
event->enable(event, handler->index);
|
||||
}
|
||||
}
|
||||
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
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
|
||||
void *args, u32 size)
|
||||
{
|
||||
|
@ -80,21 +80,20 @@ nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
nv50_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 (crtc > 1)
|
||||
u32 head = *(u32 *)args;
|
||||
if (head >= chan->vblank.nr_event)
|
||||
return -EINVAL;
|
||||
|
||||
nouveau_event_get(disp->vblank, crtc, &chan->vblank.event);
|
||||
nouveau_event_get(chan->vblank.event[head]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd,
|
||||
void *args, u32 size)
|
||||
{
|
||||
|
@ -125,10 +124,9 @@ nv50_software_sclass[] = {
|
|||
******************************************************************************/
|
||||
|
||||
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 =
|
||||
container_of(event, typeof(*chan), vblank.event);
|
||||
struct nv50_software_chan *chan = data;
|
||||
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
|
||||
|
@ -147,23 +145,51 @@ nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
|
|||
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
|
||||
nv50_software_context_ctor(struct nouveau_object *parent,
|
||||
struct nouveau_object *engine,
|
||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||
struct nouveau_object **pobject)
|
||||
{
|
||||
struct nouveau_disp *pdisp = nouveau_disp(parent);
|
||||
struct nv50_software_cclass *pclass = (void *)oclass;
|
||||
struct nv50_software_chan *chan;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
ret = nouveau_software_context_create(parent, engine, oclass, &chan);
|
||||
*pobject = nv_object(chan);
|
||||
if (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.event.func = pclass->vblank;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,14 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
|
|||
|
||||
struct nv50_software_cclass {
|
||||
struct nouveau_oclass base;
|
||||
int (*vblank)(struct nouveau_eventh *, int);
|
||||
int (*vblank)(void *, int);
|
||||
};
|
||||
|
||||
struct nv50_software_chan {
|
||||
struct nouveau_software_chan base;
|
||||
struct {
|
||||
struct nouveau_eventh event;
|
||||
struct nouveau_eventh **event;
|
||||
int nr_event;
|
||||
u32 channel;
|
||||
u32 ctxdma;
|
||||
u64 offset;
|
||||
|
@ -37,5 +38,10 @@ int nv50_software_context_ctor(struct nouveau_object *,
|
|||
struct nouveau_object *,
|
||||
struct nouveau_oclass *, void *, u32,
|
||||
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
|
||||
|
|
|
@ -54,40 +54,6 @@ nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
|
|||
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
|
||||
nvc0_software_mthd_mp_control(struct nouveau_object *object, u32 mthd,
|
||||
void *args, u32 size)
|
||||
|
@ -118,9 +84,9 @@ static struct nouveau_omthds
|
|||
nvc0_software_omthds[] = {
|
||||
{ 0x0400, 0x0400, nvc0_software_mthd_vblsem_offset },
|
||||
{ 0x0404, 0x0404, nvc0_software_mthd_vblsem_offset },
|
||||
{ 0x0408, 0x0408, nvc0_software_mthd_vblsem_value },
|
||||
{ 0x040c, 0x040c, nvc0_software_mthd_vblsem_release },
|
||||
{ 0x0500, 0x0500, nvc0_software_mthd_flip },
|
||||
{ 0x0408, 0x0408, nv50_software_mthd_vblsem_value },
|
||||
{ 0x040c, 0x040c, nv50_software_mthd_vblsem_release },
|
||||
{ 0x0500, 0x0500, nv50_software_mthd_flip },
|
||||
{ 0x0600, 0x0600, nvc0_software_mthd_mp_control },
|
||||
{ 0x0644, 0x0644, nvc0_software_mthd_mp_control },
|
||||
{ 0x06ac, 0x06ac, nvc0_software_mthd_mp_control },
|
||||
|
@ -138,10 +104,9 @@ nvc0_software_sclass[] = {
|
|||
******************************************************************************/
|
||||
|
||||
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 =
|
||||
container_of(event, typeof(*chan), vblank.event);
|
||||
struct nv50_software_chan *chan = data;
|
||||
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
|
||||
struct nouveau_bar *bar = nouveau_bar(priv);
|
||||
|
||||
|
|
|
@ -9,10 +9,12 @@
|
|||
#define NVKM_EVENT_ENABLE 0
|
||||
|
||||
struct nouveau_eventh {
|
||||
struct nouveau_event *event;
|
||||
struct list_head head;
|
||||
unsigned long flags;
|
||||
int index;
|
||||
int (*func)(void *, int);
|
||||
void *priv;
|
||||
int (*func)(struct nouveau_eventh *, int index);
|
||||
};
|
||||
|
||||
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_trigger(struct nouveau_event *, int index);
|
||||
|
||||
void nouveau_event_get(struct nouveau_event *, int index,
|
||||
struct nouveau_eventh *);
|
||||
void nouveau_event_put(struct nouveau_event *, int index,
|
||||
struct nouveau_eventh *);
|
||||
int nouveau_event_new(struct nouveau_event *, int index,
|
||||
int (*func)(void *, 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 *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -100,6 +100,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_func);
|
||||
kfree(nv_connector->edid);
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
|
@ -932,10 +933,9 @@ nouveau_connector_hotplug_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
static int
|
||||
nouveau_connector_hotplug(struct nouveau_eventh *event, int index)
|
||||
nouveau_connector_hotplug(void *data, int index)
|
||||
{
|
||||
struct nouveau_connector *nv_connector =
|
||||
container_of(event, struct nouveau_connector, hpd_func);
|
||||
struct nouveau_connector *nv_connector = data;
|
||||
schedule_work(&nv_connector->hpd_work);
|
||||
return NVKM_EVENT_KEEP;
|
||||
}
|
||||
|
@ -1007,10 +1007,16 @@ nouveau_connector_create(struct drm_device *dev, int index)
|
|||
|
||||
ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)],
|
||||
DCB_GPIO_UNUSED, &nv_connector->hpd);
|
||||
nv_connector->hpd_func.func = nouveau_connector_hotplug;
|
||||
if (ret)
|
||||
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];
|
||||
if (drm_conntype_from_dcb(nv_connector->type) ==
|
||||
DRM_MODE_CONNECTOR_Unknown) {
|
||||
|
|
|
@ -69,7 +69,7 @@ struct nouveau_connector {
|
|||
|
||||
struct dcb_gpio_func hpd;
|
||||
struct work_struct hpd_work;
|
||||
struct nouveau_eventh hpd_func;
|
||||
struct nouveau_eventh *hpd_func;
|
||||
|
||||
int dithering_mode;
|
||||
int dithering_depth;
|
||||
|
|
|
@ -38,12 +38,85 @@
|
|||
|
||||
#include "nouveau_fence.h"
|
||||
|
||||
#include <subdev/bios/gpio.h>
|
||||
#include <subdev/gpio.h>
|
||||
#include <engine/disp.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
|
||||
nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
|
||||
{
|
||||
|
@ -227,9 +300,7 @@ static struct nouveau_drm_prop_enum_list dither_depth[] = {
|
|||
int
|
||||
nouveau_display_init(struct drm_device *dev)
|
||||
{
|
||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
struct nouveau_display *disp = nouveau_display(dev);
|
||||
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
|
||||
struct drm_connector *connector;
|
||||
int ret;
|
||||
|
||||
|
@ -243,10 +314,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 (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
|
||||
nouveau_event_get(gpio->events, conn->hpd.line,
|
||||
&conn->hpd_func);
|
||||
}
|
||||
if (conn->hpd_func) nouveau_event_get(conn->hpd_func);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -255,18 +323,13 @@ nouveau_display_init(struct drm_device *dev)
|
|||
void
|
||||
nouveau_display_fini(struct drm_device *dev)
|
||||
{
|
||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
struct nouveau_display *disp = nouveau_display(dev);
|
||||
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
|
||||
struct drm_connector *connector;
|
||||
|
||||
/* disable hotplug interrupts */
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
struct nouveau_connector *conn = nouveau_connector(connector);
|
||||
if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
|
||||
nouveau_event_put(gpio->events, conn->hpd.line,
|
||||
&conn->hpd_func);
|
||||
}
|
||||
if (conn->hpd_func) nouveau_event_put(conn->hpd_func);
|
||||
}
|
||||
|
||||
drm_kms_helper_poll_disable(dev);
|
||||
|
@ -352,7 +415,7 @@ nouveau_display_create(struct drm_device *dev)
|
|||
goto disp_create_err;
|
||||
|
||||
if (dev->mode_config.num_crtc) {
|
||||
ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
|
||||
ret = nouveau_display_vblank_init(dev);
|
||||
if (ret)
|
||||
goto vblank_err;
|
||||
}
|
||||
|
@ -374,7 +437,7 @@ nouveau_display_destroy(struct drm_device *dev)
|
|||
struct nouveau_display *disp = nouveau_display(dev);
|
||||
|
||||
nouveau_backlight_exit(dev);
|
||||
drm_vblank_cleanup(dev);
|
||||
nouveau_display_vblank_fini(dev);
|
||||
|
||||
drm_kms_helper_poll_fini(dev);
|
||||
drm_mode_config_cleanup(dev);
|
||||
|
|
|
@ -36,6 +36,8 @@ struct nouveau_display {
|
|||
int (*init)(struct drm_device *);
|
||||
void (*fini)(struct drm_device *);
|
||||
|
||||
struct nouveau_eventh **vblank;
|
||||
|
||||
struct drm_property *dithering_mode;
|
||||
struct drm_property *dithering_depth;
|
||||
struct drm_property *underscan_property;
|
||||
|
@ -59,6 +61,8 @@ void nouveau_display_fini(struct drm_device *dev);
|
|||
int nouveau_display_suspend(struct drm_device *dev);
|
||||
void nouveau_display_repin(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,
|
||||
struct drm_pending_vblank_event *event,
|
||||
|
|
|
@ -78,37 +78,6 @@ module_param_named(runpm, nouveau_runtime_pm, int, 0400);
|
|||
|
||||
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
|
||||
nouveau_name(struct pci_dev *pdev)
|
||||
{
|
||||
|
@ -812,8 +781,8 @@ driver = {
|
|||
#endif
|
||||
|
||||
.get_vblank_counter = drm_vblank_count,
|
||||
.enable_vblank = nouveau_drm_vblank_enable,
|
||||
.disable_vblank = nouveau_drm_vblank_disable,
|
||||
.enable_vblank = nouveau_display_vblank_enable,
|
||||
.disable_vblank = nouveau_display_vblank_disable,
|
||||
|
||||
.ioctls = nouveau_ioctls,
|
||||
.num_ioctls = ARRAY_SIZE(nouveau_ioctls),
|
||||
|
|
|
@ -127,7 +127,6 @@ struct nouveau_drm {
|
|||
struct nvbios vbios;
|
||||
struct nouveau_display *display;
|
||||
struct backlight_device *backlight;
|
||||
struct nouveau_eventh vblank[4];
|
||||
|
||||
/* power management */
|
||||
struct nouveau_pm *pm;
|
||||
|
|
|
@ -166,9 +166,9 @@ nouveau_fence_done(struct nouveau_fence *fence)
|
|||
}
|
||||
|
||||
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);
|
||||
return NVKM_EVENT_KEEP;
|
||||
}
|
||||
|
@ -180,13 +180,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 = {
|
||||
.func = nouveau_fence_wait_uevent_handler,
|
||||
.priv = priv,
|
||||
};
|
||||
struct nouveau_eventh *handler;
|
||||
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) {
|
||||
unsigned long timeout = fence->timeout - jiffies;
|
||||
|
@ -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))
|
||||
return ret;
|
||||
|
||||
|
|
Loading…
Reference in New Issue