Browse Source

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

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Ben Skeggs 11 years ago
parent
commit
8e8832e8a8

+ 58 - 25
drivers/gpu/drm/nouveau/core/core/event.c

@@ -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;
 }

+ 1 - 1
drivers/gpu/drm/nouveau/core/engine/disp/base.c

@@ -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
drivers/gpu/drm/nouveau/core/engine/disp/nv04.c

@@ -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
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c

@@ -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
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c

@@ -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));
 		}

+ 3 - 3
drivers/gpu/drm/nouveau/core/engine/fifo/base.c

@@ -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;
 

+ 1 - 1
drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c

@@ -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;
 			}

+ 2 - 2
drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c

@@ -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);

+ 3 - 3
drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c

@@ -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);

+ 3 - 3
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c

@@ -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);

+ 2 - 2
drivers/gpu/drm/nouveau/core/engine/software/nv50.c

@@ -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;

+ 1 - 1
drivers/gpu/drm/nouveau/core/engine/software/nv50.h

@@ -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 {

+ 1 - 1
drivers/gpu/drm/nouveau/core/engine/software/nvc0.c

@@ -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;

+ 15 - 14
drivers/gpu/drm/nouveau/core/include/core/event.h

@@ -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 *);

+ 1 - 1
drivers/gpu/drm/nouveau/core/subdev/gpio/base.c

@@ -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;
 

+ 1 - 1
drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c

@@ -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);

+ 1 - 1
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c

@@ -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);

+ 1 - 1
drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c

@@ -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);

+ 3 - 2
drivers/gpu/drm/nouveau/nouveau_connector.c

@@ -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);

+ 2 - 2
drivers/gpu/drm/nouveau/nouveau_display.c

@@ -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) {

+ 2 - 2
drivers/gpu/drm/nouveau/nouveau_fence.c

@@ -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)