Nouveau Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Hurley <peter@hurleysoftware.com>
To: Dave Airlie <airlied@linux.ie>, Ben Skeggs <bskeggs@redhat.com>
Cc: nouveau@lists.freedesktop.org,
	Peter Hurley <peter@hurleysoftware.com>,
	dri-devel@lists.freedesktop.org
Subject: [PATCH 5/9] drm/nouveau: Add install/remove semantics for event handlers
Date: Tue, 27 Aug 2013 16:12:58 -0400	[thread overview]
Message-ID: <1377634382-13872-6-git-send-email-peter@hurleysoftware.com> (raw)
In-Reply-To: <1377634382-13872-1-git-send-email-peter@hurleysoftware.com>

Complete migration of nouveau_event_get/_put from add/remove
semantics to enable/disable semantics.

Introduce nouveau_event_handler_install/_remove interface to
add/remove non-local-scope event handlers (ie., those stored in
parent containers). This change in semantics makes explicit the
handler lifetime, and distinguishes "one-of" event handlers
(such as gpio) from "many temporary" event handlers (such as uevent).

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
---
 drivers/gpu/drm/nouveau/core/core/event.c          | 63 +++++++++++++++++++---
 .../gpu/drm/nouveau/core/engine/software/nv50.c    | 31 +++++++++--
 .../gpu/drm/nouveau/core/engine/software/nvc0.c    | 31 +++++++++--
 drivers/gpu/drm/nouveau/core/include/core/event.h  |  6 +++
 .../gpu/drm/nouveau/core/include/engine/software.h |  2 +-
 drivers/gpu/drm/nouveau/nouveau_connector.c        | 10 +++-
 drivers/gpu/drm/nouveau/nouveau_drm.c              | 17 +++++-
 7 files changed, 140 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/core/core/event.c b/drivers/gpu/drm/nouveau/core/core/event.c
index 0a65ede..4cd1ebe 100644
--- a/drivers/gpu/drm/nouveau/core/core/event.c
+++ b/drivers/gpu/drm/nouveau/core/core/event.c
@@ -23,19 +23,60 @@
 #include <core/os.h>
 #include <core/event.h>
 
+void
+nouveau_event_handler_install(struct nouveau_event *event, int index,
+			      int (*func)(struct nouveau_eventh*, int),
+			      void *priv, struct nouveau_eventh *handler)
+{
+	unsigned long flags;
+
+	if (index >= event->index_nr)
+		return;
+
+	handler->func = func;
+	handler->priv = priv;
+
+	spin_lock_irqsave(&event->lock, flags);
+	list_add(&handler->head, &event->index[index].list);
+	spin_unlock_irqrestore(&event->lock, flags);
+}
+
+void
+nouveau_event_handler_remove(struct nouveau_event *event, int index,
+			     struct nouveau_eventh *handler)
+{
+	unsigned long flags;
+
+	if (index >= event->index_nr)
+		return;
+
+	spin_lock_irqsave(&event->lock, flags);
+	list_del(&handler->head);
+	spin_unlock_irqrestore(&event->lock, flags);
+}
+
 int
 nouveau_event_handler_create(struct nouveau_event *event, int index,
 			     int (*func)(struct nouveau_eventh*, int),
 			     void *priv, struct nouveau_eventh **phandler)
 {
 	struct nouveau_eventh *handler;
+	unsigned long flags;
 
 	handler = *phandler = kzalloc(sizeof(*handler), GFP_KERNEL);
 	if (!handler)
 		return -ENOMEM;
 	handler->func = func;
 	handler->priv = priv;
-	nouveau_event_get(event, index, handler);
+	__set_bit(NVKM_EVENT_ENABLE, &handler->flags);
+
+	spin_lock_irqsave(&event->lock, flags);
+	list_add(&handler->head, &event->index[index].list);
+	if (!event->index[index].refs++) {
+		if (event->enable)
+			event->enable(event, index);
+	}
+	spin_unlock_irqrestore(&event->lock, flags);
 	return 0;
 }
 
@@ -43,7 +84,18 @@ void
 nouveau_event_handler_destroy(struct nouveau_event *event, int index,
 			      struct nouveau_eventh *handler)
 {
-	nouveau_event_put(event, index, handler);
+	unsigned long flags;
+
+	if (index >= event->index_nr)
+		return;
+
+	spin_lock_irqsave(&event->lock, flags);
+	if (!--event->index[index].refs) {
+		if (event->disable)
+			event->disable(event, index);
+	}
+	list_del(&handler->head);
+	spin_unlock_irqrestore(&event->lock, flags);
 	kfree(handler);
 }
 
@@ -56,7 +108,6 @@ nouveau_event_put_locked(struct nouveau_event *event, int index,
 			if (event->disable)
 				event->disable(event, index);
 		}
-		list_del(&handler->head);
 	}
 }
 
@@ -85,7 +136,6 @@ nouveau_event_get(struct nouveau_event *event, int index,
 
 	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++) {
 			if (event->enable)
 				event->enable(event, index);
@@ -105,8 +155,9 @@ 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) {
-			nouveau_event_put_locked(event, index, handler);
+		if (test_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
+			if (handler->func(handler, index) == NVKM_EVENT_DROP)
+				nouveau_event_put_locked(event, index, handler);
 		}
 	}
 	spin_unlock_irqrestore(&event->lock, flags);
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
index c48e749..dfce1f5 100644
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
@@ -97,7 +97,7 @@ nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
 	if (crtc > 1)
 		return -EINVAL;
 
-	nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
+	nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event[crtc]);
 	return 0;
 }
 
@@ -135,7 +135,7 @@ static int
 nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
 {
 	struct nouveau_software_chan *chan =
-		container_of(event, struct nouveau_software_chan, vblank.event);
+		container_of(event, struct nouveau_software_chan, vblank.event[head]);
 	struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
 	struct nouveau_bar *bar = nouveau_bar(priv);
 
@@ -161,7 +161,8 @@ nv50_software_context_ctor(struct nouveau_object *parent,
 			   struct nouveau_object **pobject)
 {
 	struct nv50_software_chan *chan;
-	int ret;
+	struct nouveau_disp *disp = nouveau_disp(engine);
+	int ret, i;
 
 	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
 	*pobject = nv_object(chan);
@@ -169,16 +170,36 @@ nv50_software_context_ctor(struct nouveau_object *parent,
 		return ret;
 
 	chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
-	chan->base.vblank.event.func = nv50_software_vblsem_release;
+	for (i = 0; i < ARRAY_SIZE(chan->base.vblank.event); i++) {
+		nouveau_event_handler_install(disp->vblank, i,
+					      nv50_software_vblsem_release,
+					      NULL,
+					      &chan->base.vblank.event[i]);
+	}
 	return 0;
 }
 
+void
+nv50_software_context_dtor(struct nouveau_object *object)
+{
+	struct nv50_software_chan *chan = (void *)object;
+	struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
+	struct nouveau_disp *disp = nouveau_disp(priv);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chan->base.vblank.event); i++) {
+		nouveau_event_handler_remove(disp->vblank, i,
+					     &chan->base.vblank.event[i]);
+	}
+	_nouveau_software_context_dtor(object);
+}
+
 static struct nouveau_oclass
 nv50_software_cclass = {
 	.handle = NV_ENGCTX(SW, 0x50),
 	.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nv50_software_context_ctor,
-		.dtor = _nouveau_software_context_dtor,
+		.dtor = nv50_software_context_dtor,
 		.init = _nouveau_software_context_init,
 		.fini = _nouveau_software_context_fini,
 	},
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
index d698e71..d1f52c0 100644
--- a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
@@ -80,7 +80,7 @@ nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
 	if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3)
 		return -EINVAL;
 
-	nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event);
+	nouveau_event_get(disp->vblank, crtc, &chan->base.vblank.event[crtc]);
 	return 0;
 }
 
@@ -147,7 +147,7 @@ static int
 nvc0_software_vblsem_release(struct nouveau_eventh *event, int head)
 {
 	struct nouveau_software_chan *chan =
-		container_of(event, struct nouveau_software_chan, vblank.event);
+		container_of(event, struct nouveau_software_chan, vblank.event[head]);
 	struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine;
 	struct nouveau_bar *bar = nouveau_bar(priv);
 
@@ -167,7 +167,8 @@ nvc0_software_context_ctor(struct nouveau_object *parent,
 			   struct nouveau_object **pobject)
 {
 	struct nvc0_software_chan *chan;
-	int ret;
+	struct nouveau_disp *disp = nouveau_disp(engine);
+	int ret, i;
 
 	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
 	*pobject = nv_object(chan);
@@ -175,16 +176,36 @@ nvc0_software_context_ctor(struct nouveau_object *parent,
 		return ret;
 
 	chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
-	chan->base.vblank.event.func = nvc0_software_vblsem_release;
+	for (i = 0; i < ARRAY_SIZE(chan->base.vblank.event); i++) {
+		nouveau_event_handler_install(disp->vblank, i,
+					      nvc0_software_vblsem_release,
+					      NULL,
+					      &chan->base.vblank.event[i]);
+	}
 	return 0;
 }
 
+void
+nvc0_software_context_dtor(struct nouveau_object *object)
+{
+	struct nvc0_software_chan *chan = (void *)object;
+	struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine;
+	struct nouveau_disp *disp = nouveau_disp(priv);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chan->base.vblank.event); i++) {
+		nouveau_event_handler_remove(disp->vblank, i,
+					     &chan->base.vblank.event[i]);
+	}
+	_nouveau_software_context_dtor(object);
+}
+
 static struct nouveau_oclass
 nvc0_software_cclass = {
 	.handle = NV_ENGCTX(SW, 0xc0),
 	.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nvc0_software_context_ctor,
-		.dtor = _nouveau_software_context_dtor,
+		.dtor = nvc0_software_context_dtor,
 		.init = _nouveau_software_context_init,
 		.fini = _nouveau_software_context_fini,
 	},
diff --git a/drivers/gpu/drm/nouveau/core/include/core/event.h b/drivers/gpu/drm/nouveau/core/include/core/event.h
index 3e704d5..45e8a0f 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/event.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/event.h
@@ -44,4 +44,10 @@ int nouveau_event_handler_create(struct nouveau_event *, int index,
 void nouveau_event_handler_destroy(struct nouveau_event *, int index,
 				   struct nouveau_eventh *);
 
+void nouveau_event_handler_install(struct nouveau_event *, int index,
+				   int (*func)(struct nouveau_eventh*, int),
+				   void *priv, struct nouveau_eventh *);
+void nouveau_event_handler_remove(struct nouveau_event *, int index,
+				  struct nouveau_eventh *);
+
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/software.h b/drivers/gpu/drm/nouveau/core/include/engine/software.h
index 4579948..bc26ea8 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/software.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/software.h
@@ -9,7 +9,7 @@ struct nouveau_software_chan {
 	struct nouveau_engctx base;
 
 	struct {
-		struct nouveau_eventh event;
+		struct nouveau_eventh event[4];
 		u32 channel;
 		u32 ctxdma;
 		u64 offset;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 4da776f..13b38ed 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -98,6 +98,11 @@ static void
 nouveau_connector_destroy(struct drm_connector *connector)
 {
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
+	struct nouveau_drm *drm = nouveau_drm(connector->dev);
+	struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
+
+	nouveau_event_handler_remove(gpio->events, nv_connector->hpd.line,
+				     &nv_connector->hpd_func);
 	kfree(nv_connector->edid);
 	drm_sysfs_connector_remove(connector);
 	drm_connector_cleanup(connector);
@@ -990,7 +995,10 @@ 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;
+		nouveau_event_handler_install(gpio->events,
+					      nv_connector->hpd.line,
+					      nouveau_connector_hotplug, NULL,
+					      &nv_connector->hpd_func);
 		if (ret)
 			nv_connector->hpd.func = DCB_GPIO_UNUSED;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index ccea2c4..4187cad 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -88,7 +88,6 @@ nouveau_drm_vblank_enable(struct drm_device *dev, int head)
 
 	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;
 }
@@ -298,7 +297,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 	struct pci_dev *pdev = dev->pdev;
 	struct nouveau_device *device;
 	struct nouveau_drm *drm;
-	int ret;
+	struct nouveau_disp *disp;
+	int ret, i;
 
 	ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
 	if (ret)
@@ -352,6 +352,13 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 	if (nv_device(drm->device)->chipset == 0xc1)
 		nv_mask(device, 0x00088080, 0x00000800, 0x00000000);
 
+	disp = nouveau_disp(device);
+	for (i = 0; i < ARRAY_SIZE(drm->vblank); i++) {
+		nouveau_event_handler_install(disp->vblank, i,
+					      nouveau_drm_vblank_handler,
+					      NULL, &drm->vblank[i]);
+	}
+
 	nouveau_vga_init(drm);
 	nouveau_agp_init(drm);
 
@@ -404,6 +411,8 @@ static int
 nouveau_drm_unload(struct drm_device *dev)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
+	struct nouveau_disp *disp = nouveau_disp(drm->device);
+	int i;
 
 	nouveau_fbcon_fini(dev);
 	nouveau_accel_fini(drm);
@@ -420,6 +429,10 @@ nouveau_drm_unload(struct drm_device *dev)
 	nouveau_agp_fini(drm);
 	nouveau_vga_fini(drm);
 
+	for (i = 0; i < ARRAY_SIZE(drm->vblank); i++)
+		nouveau_event_handler_remove(disp->vblank, i,
+					     &drm->vblank[i]);
+
 	nouveau_cli_destroy(&drm->client);
 	return 0;
 }
-- 
1.8.1.2

  parent reply	other threads:[~2013-08-27 20:12 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-27 20:12 [PATCH 0/9] drm/nouveau: Cleanup event/handler design Peter Hurley
2013-08-27 20:12 ` [PATCH 1/9] drm/nouveau: Add priv field for event handlers Peter Hurley
2013-08-27 20:12 ` [PATCH 2/9] drm/nouveau: Move event index check from critical section Peter Hurley
2013-08-27 20:12 ` [PATCH 3/9] drm/nouveau: Allocate local event handlers Peter Hurley
2013-08-27 20:12 ` [PATCH 4/9] drm/nouveau: Allow asymmetric nouveau_event_get/_put Peter Hurley
2013-08-27 20:12 ` Peter Hurley [this message]
2013-08-27 20:12 ` [PATCH 6/9] drm/nouveau: Convert event handler list to RCU Peter Hurley
2013-08-27 20:13 ` [PATCH 7/9] drm/nouveau: Fold nouveau_event_put_locked into caller Peter Hurley
2013-08-27 20:13 ` [PATCH 8/9] drm/nouveau: Simplify event interface Peter Hurley
2013-08-27 20:13 ` [PATCH 9/9] drm/nouveau: Simplify event handler interface Peter Hurley
2013-08-28  7:15 ` [PATCH 0/9] drm/nouveau: Cleanup event/handler design Ben Skeggs
     [not found]   ` <CACAvsv6atUc=QO2gHEbHK4-+uCh=GUtCqtVKVkZxmS-S8EQppg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-08-30  1:23     ` Peter Hurley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1377634382-13872-6-git-send-email-peter@hurleysoftware.com \
    --to=peter@hurleysoftware.com \
    --cc=airlied@linux.ie \
    --cc=bskeggs@redhat.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=nouveau@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox