Commit 8e8832e8 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/core: allow event source to handle multiple event types per index

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 255b329c
......@@ -28,14 +28,20 @@ nouveau_event_put(struct nouveau_eventh *handler)
{
struct nouveau_event *event = handler->event;
unsigned long flags;
if (__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
spin_lock_irqsave(&event->refs_lock, flags);
if (!--event->index[handler->index].refs) {
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, handler->index);
event->disable(event, 1 << t, handler->index);
}
spin_unlock_irqrestore(&event->refs_lock, flags);
}
spin_unlock_irqrestore(&event->refs_lock, flags);
}
void
......@@ -43,14 +49,20 @@ nouveau_event_get(struct nouveau_eventh *handler)
{
struct nouveau_event *event = handler->event;
unsigned long flags;
if (!__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
spin_lock_irqsave(&event->refs_lock, flags);
if (!event->index[handler->index].refs++) {
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, handler->index);
event->enable(event, 1 << t, handler->index);
}
spin_unlock_irqrestore(&event->refs_lock, flags);
}
spin_unlock_irqrestore(&event->refs_lock, flags);
}
static void
......@@ -65,38 +77,47 @@ nouveau_event_fini(struct nouveau_eventh *handler)
}
static int
nouveau_event_init(struct nouveau_event *event, int index,
int (*func)(void *, int), void *priv,
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->index[index].list);
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, int index,
int (*func)(void *, int), void *priv,
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, index, func, priv, handler);
ret = nouveau_event_init(event, types, index, func, priv, handler);
if (ret)
kfree(handler);
}
......@@ -116,7 +137,7 @@ nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref)
}
void
nouveau_event_trigger(struct nouveau_event *event, int index)
nouveau_event_trigger(struct nouveau_event *event, u32 types, int index)
{
struct nouveau_eventh *handler;
unsigned long flags;
......@@ -125,10 +146,15 @@ nouveau_event_trigger(struct nouveau_event *event, int index)
return;
spin_lock_irqsave(&event->list_lock, flags);
list_for_each_entry(handler, &event->index[index].list, head) {
if (test_bit(NVKM_EVENT_ENABLE, &handler->flags) &&
handler->func(handler->priv, index) == NVKM_EVENT_DROP)
nouveau_event_put(handler);
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);
}
spin_unlock_irqrestore(&event->list_lock, flags);
}
......@@ -144,20 +170,27 @@ nouveau_event_destroy(struct nouveau_event **pevent)
}
int
nouveau_event_create(int index_nr, struct nouveau_event **pevent)
nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **pevent)
{
struct nouveau_event *event;
int i;
event = *pevent = kzalloc(sizeof(*event) + index_nr *
sizeof(event->index[0]), GFP_KERNEL);
event = *pevent = kzalloc(sizeof(*event) + (index_nr * types_nr) *
sizeof(event->refs[0]), GFP_KERNEL);
if (!event)
return -ENOMEM;
event->list = kmalloc(sizeof(*event->list) * index_nr, GFP_KERNEL);
if (!event->list) {
kfree(event);
return -ENOMEM;
}
spin_lock_init(&event->list_lock);
spin_lock_init(&event->refs_lock);
for (i = 0; i < index_nr; i++)
INIT_LIST_HEAD(&event->index[i].list);
INIT_LIST_HEAD(&event->list[i]);
event->types_nr = types_nr;
event->index_nr = index_nr;
return 0;
}
......@@ -48,5 +48,5 @@ nouveau_disp_create_(struct nouveau_object *parent,
if (ret)
return ret;
return nouveau_event_create(heads, &disp->vblank);
return nouveau_event_create(1, heads, &disp->vblank);
}
......@@ -86,13 +86,13 @@ nv04_disp_sclass[] = {
******************************************************************************/
static void
nv04_disp_vblank_enable(struct nouveau_event *event, int head)
nv04_disp_vblank_enable(struct nouveau_event *event, int type, int head)
{
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001);
}
static void
nv04_disp_vblank_disable(struct nouveau_event *event, int head)
nv04_disp_vblank_disable(struct nouveau_event *event, int type, int head)
{
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000);
}
......@@ -106,12 +106,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
u32 pvideo;
if (crtc0 & 0x00000001) {
nouveau_event_trigger(priv->base.vblank, 0);
nouveau_event_trigger(priv->base.vblank, 1, 0);
nv_wr32(priv, 0x600100, 0x00000001);
}
if (crtc1 & 0x00000001) {
nouveau_event_trigger(priv->base.vblank, 1);
nouveau_event_trigger(priv->base.vblank, 1, 1);
nv_wr32(priv, 0x602100, 0x00000001);
}
......
......@@ -829,13 +829,13 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
}
static void
nv50_disp_base_vblank_enable(struct nouveau_event *event, int head)
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 head)
nv50_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
{
nv_mask(event->priv, 0x61002c, (4 << head), 0);
}
......@@ -1610,13 +1610,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
}
if (intr1 & 0x00000004) {
nouveau_event_trigger(priv->base.vblank, 0);
nouveau_event_trigger(priv->base.vblank, 1, 0);
nv_wr32(priv, 0x610024, 0x00000004);
intr1 &= ~0x00000004;
}
if (intr1 & 0x00000008) {
nouveau_event_trigger(priv->base.vblank, 1);
nouveau_event_trigger(priv->base.vblank, 1, 1);
nv_wr32(priv, 0x610024, 0x00000008);
intr1 &= ~0x00000008;
}
......
......@@ -748,13 +748,13 @@ nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
}
static void
nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head)
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 head)
nvd0_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
{
nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
}
......@@ -1317,7 +1317,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, i);
nouveau_event_trigger(priv->base.vblank, 1, i);
nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
nv_rd32(priv, 0x6100c0 + (i * 0x800));
}
......
......@@ -91,7 +91,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
if (!chan->user)
return -EFAULT;
nouveau_event_trigger(priv->cevent, 0);
nouveau_event_trigger(priv->cevent, 1, 0);
chan->size = size;
return 0;
......@@ -194,11 +194,11 @@ nouveau_fifo_create_(struct nouveau_object *parent,
if (!priv->channel)
return -ENOMEM;
ret = nouveau_event_create(1, &priv->cevent);
ret = nouveau_event_create(1, 1, &priv->cevent);
if (ret)
return ret;
ret = nouveau_event_create(1, &priv->uevent);
ret = nouveau_event_create(1, 1, &priv->uevent);
if (ret)
return ret;
......
......@@ -539,7 +539,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
}
if (status & 0x40000000) {
nouveau_event_trigger(priv->base.uevent, 0);
nouveau_event_trigger(priv->base.uevent, 1, 0);
nv_wr32(priv, 0x002100, 0x40000000);
status &= ~0x40000000;
}
......
......@@ -389,14 +389,14 @@ nv84_fifo_cclass = {
******************************************************************************/
static void
nv84_fifo_uevent_enable(struct nouveau_event *event, int index)
nv84_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
{
struct nv84_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x40000000, 0x40000000);
}
static void
nv84_fifo_uevent_disable(struct nouveau_event *event, int index)
nv84_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
{
struct nv84_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x40000000, 0x00000000);
......
......@@ -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, 0);
nouveau_event_trigger(priv->base.uevent, 1, 0);
ints &= ~1;
}
if (ints) {
......@@ -827,14 +827,14 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
}
static void
nvc0_fifo_uevent_enable(struct nouveau_event *event, int index)
nvc0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
{
struct nvc0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
}
static void
nvc0_fifo_uevent_disable(struct nouveau_event *event, int index)
nvc0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
{
struct nvc0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
......
......@@ -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, 0);
nouveau_event_trigger(priv->base.uevent, 1, 0);
}
static void
......@@ -952,14 +952,14 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
}
static void
nve0_fifo_uevent_enable(struct nouveau_event *event, int index)
nve0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
{
struct nve0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
}
static void
nve0_fifo_uevent_disable(struct nouveau_event *event, int index)
nve0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
{
struct nve0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
......
......@@ -124,7 +124,7 @@ nv50_software_sclass[] = {
******************************************************************************/
static int
nv50_software_vblsem_release(void *data, int head)
nv50_software_vblsem_release(void *data, u32 type, int head)
{
struct nv50_software_chan *chan = data;
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
......@@ -183,7 +183,7 @@ nv50_software_context_ctor(struct nouveau_object *parent,
return -ENOMEM;
for (i = 0; i < chan->vblank.nr_event; i++) {
ret = nouveau_event_new(pdisp->vblank, i, pclass->vblank,
ret = nouveau_event_new(pdisp->vblank, 1, i, pclass->vblank,
chan, &chan->vblank.event[i]);
if (ret)
return ret;
......
......@@ -19,7 +19,7 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
struct nv50_software_cclass {
struct nouveau_oclass base;
int (*vblank)(void *, int);
int (*vblank)(void *, u32, int);
};
struct nv50_software_chan {
......
......@@ -104,7 +104,7 @@ nvc0_software_sclass[] = {
******************************************************************************/
static int
nvc0_software_vblsem_release(void *data, int head)
nvc0_software_vblsem_release(void *data, u32 type, int head)
{
struct nv50_software_chan *chan = data;
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
......
......@@ -12,32 +12,33 @@ struct nouveau_eventh {
struct nouveau_event *event;
struct list_head head;
unsigned long flags;
u32 types;
int index;
int (*func)(void *, int);
int (*func)(void *, u32, int);
void *priv;
};
struct nouveau_event {
spinlock_t list_lock;
spinlock_t refs_lock;
void *priv;
void (*enable)(struct nouveau_event *, int index);
void (*disable)(struct nouveau_event *, int index);
int (*check)(struct nouveau_event *, u32 type, int index);
void (*enable)(struct nouveau_event *, int type, int index);
void (*disable)(struct nouveau_event *, int type, int index);
int types_nr;
int index_nr;
struct {
struct list_head list;
int refs;
} index[];
spinlock_t list_lock;
struct list_head *list;
spinlock_t refs_lock;
int refs[];
};
int nouveau_event_create(int index_nr, struct nouveau_event **);
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 *, int index);
void nouveau_event_trigger(struct nouveau_event *, u32 types, int index);
int nouveau_event_new(struct nouveau_event *, int index,
int (*func)(void *, int), void *,
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 *);
......
......@@ -125,7 +125,7 @@ nouveau_gpio_create_(struct nouveau_object *parent,
if (ret)
return ret;
ret = nouveau_event_create(lines, &gpio->events);
ret = nouveau_event_create(1, lines, &gpio->events);
if (ret)
return ret;
......
......@@ -93,7 +93,7 @@ nv10_gpio_intr(struct nouveau_subdev *subdev)
for (i = 0; (hi | lo) && i < 32; i++) {
if ((hi | lo) & (1 << i))
nouveau_event_trigger(priv->base.events, i);
nouveau_event_trigger(priv->base.events, 1, i);
}
nv_wr32(priv, 0x001104, intr);
......
......@@ -112,7 +112,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
for (i = 0; (hi | lo) && i < 32; i++) {
if ((hi | lo) & (1 << i))
nouveau_event_trigger(priv->base.events, i);
nouveau_event_trigger(priv->base.events, 1, i);
}
nv_wr32(priv, 0xe054, intr0);
......
......@@ -40,7 +40,7 @@ nve0_gpio_intr(struct nouveau_subdev *subdev)
for (i = 0; (hi | lo) && i < 32; i++) {
if ((hi | lo) & (1 << i))
nouveau_event_trigger(priv->base.events, i);
nouveau_event_trigger(priv->base.events, 1, i);
}
nv_wr32(priv, 0xdc00, intr0);
......
......@@ -934,7 +934,7 @@ nouveau_connector_hotplug_work(struct work_struct *work)
}
static int
nouveau_connector_hotplug(void *data, int index)
nouveau_connector_hotplug(void *data, u32 type, int index)
{
struct nouveau_connector *nv_connector = data;
schedule_work(&nv_connector->hpd_work);
......@@ -1013,7 +1013,8 @@ nouveau_connector_create(struct drm_device *dev, int index)
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_event_new(gpio->events, 1,
nv_connector->hpd.line,
nouveau_connector_hotplug,
nv_connector,
&nv_connector->hpd_func);
......
......@@ -42,7 +42,7 @@
#include <core/class.h>
static int
nouveau_display_vblank_handler(void *data, int head)
nouveau_display_vblank_handler(void *data, u32 type, int head)
{
struct nouveau_drm *drm = data;
drm_handle_vblank(drm->dev, head);
......@@ -178,7 +178,7 @@ nouveau_display_vblank_init(struct drm_device *dev)
return -ENOMEM;
for (i = 0; i < dev->mode_config.num_crtc; i++) {
ret = nouveau_event_new(pdisp->vblank, i,
ret = nouveau_event_new(pdisp->vblank, 1, i,
nouveau_display_vblank_handler,
drm, &disp->vblank[i]);
if (ret) {
......
......@@ -166,7 +166,7 @@ nouveau_fence_done(struct nouveau_fence *fence)
}
static int
nouveau_fence_wait_uevent_handler(void *data, int index)
nouveau_fence_wait_uevent_handler(void *data, u32 type, int index)
{
struct nouveau_fence_priv *priv = data;
wake_up_all(&priv->waiting);
......@@ -183,7 +183,7 @@ nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
struct nouveau_eventh *handler;
int ret = 0;
ret = nouveau_event_new(pfifo->uevent, 0,
ret = nouveau_event_new(pfifo->uevent, 1, 0,
nouveau_fence_wait_uevent_handler,
priv, &handler);
if (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