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@xxxxxxxxxxxxxxxxxx> --- 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 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel