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

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



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 255b329c
Loading
Loading
Loading
Loading
+58 −25
Original line number Diff line number Diff line
@@ -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)) {
	u32 m, t;

	if (!__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags))
		return;

	spin_lock_irqsave(&event->refs_lock, flags);
		if (!--event->index[handler->index].refs) {
	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)) {
	u32 m, t;

	if (__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags))
		return;

	spin_lock_irqsave(&event->refs_lock, flags);
		if (!event->index[handler->index].refs++) {
	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,9 +146,14 @@ 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)
	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;
}
+1 −1
Original line number Diff line number Diff line
@@ -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);
}
+4 −4
Original line number Diff line number Diff line
@@ -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);
	}

+4 −4
Original line number Diff line number Diff line
@@ -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;
	}
+3 −3
Original line number Diff line number Diff line
@@ -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));
		}
Loading