drm/nv50-nvc0: switch to tasklet for display isr bh
authorBen Skeggs <bskeggs@redhat.com>
Thu, 3 Feb 2011 10:06:14 +0000 (20:06 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 24 Feb 2011 20:44:59 +0000 (06:44 +1000)
We need to be able to have the bh run while possibly spinning waiting for
the EVO notifier to signal.  This apparently happens in some circumstances
with preempt disabled, so our workqueue was never being run.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_display.h

index da426b95cc82c200ebb88c59e44384c70741d4c2..8f6491845692ec68f798a32fcc39c769fd393e6d 100644 (file)
@@ -653,7 +653,6 @@ struct drm_nouveau_private {
        /* interrupt handling */
        void (*irq_handler[32])(struct drm_device *);
        bool msi_enabled;
-       struct work_struct irq_work;
 
        struct list_head vbl_waiting;
 
index c6c3e6ceb24e9878da076cc0c2ef43acec84c9b0..e295a17d68f4be1b122ab9c59049cdb45362c28f 100644 (file)
@@ -35,6 +35,7 @@
 #include "drm_crtc_helper.h"
 
 static void nv50_display_isr(struct drm_device *);
+static void nv50_display_bh(unsigned long);
 
 static inline int
 nv50_sor_nr(struct drm_device *dev)
@@ -339,7 +340,7 @@ int nv50_display_create(struct drm_device *dev)
                }
        }
 
-       INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
+       tasklet_init(&priv->tasklet, nv50_display_bh, (unsigned long)dev);
        nouveau_irq_register(dev, 26, nv50_display_isr);
 
        ret = nv50_display_init(dev);
@@ -354,7 +355,6 @@ int nv50_display_create(struct drm_device *dev)
 void
 nv50_display_destroy(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nv50_display *disp = nv50_display(dev);
 
        NV_DEBUG_KMS(dev, "\n");
@@ -363,7 +363,6 @@ nv50_display_destroy(struct drm_device *dev)
 
        nv50_display_disable(dev);
        nouveau_irq_unregister(dev, 26);
-       flush_work_sync(&dev_priv->irq_work);
        kfree(disp);
 }
 
@@ -770,12 +769,10 @@ ack:
        nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) | 8);
 }
 
-void
-nv50_display_irq_handler_bh(struct work_struct *work)
+static void
+nv50_display_bh(unsigned long data)
 {
-       struct drm_nouveau_private *dev_priv =
-               container_of(work, struct drm_nouveau_private, irq_work);
-       struct drm_device *dev = dev_priv->dev;
+       struct drm_device *dev = (struct drm_device *)data;
 
        for (;;) {
                uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
@@ -823,7 +820,7 @@ nv50_display_error_handler(struct drm_device *dev)
 static void
 nv50_display_isr(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv50_display *disp = nv50_display(dev);
        uint32_t delayed = 0;
 
        while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
@@ -851,8 +848,7 @@ nv50_display_isr(struct drm_device *dev)
                                  NV50_PDISPLAY_INTR_1_CLK_UNK40));
                if (clock) {
                        nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
-                       if (!work_pending(&dev_priv->irq_work))
-                               schedule_work(&dev_priv->irq_work);
+                       tasklet_schedule(&disp->tasklet);
                        delayed |= clock;
                        intr1 &= ~clock;
                }
index 97d3ed57fdef4d81ad7187d1407540d19e0a4281..ea37f230aee8609655b15a5ddca3fa82e1b3cb25 100644 (file)
@@ -38,6 +38,7 @@
 struct nv50_display {
        struct nouveau_channel *master;
 
+       struct tasklet_struct tasklet;
        struct {
                struct dcb_entry *dcb;
                u16 script;
@@ -52,7 +53,6 @@ nv50_display(struct drm_device *dev)
        return dev_priv->engine.display.priv;
 }
 
-void nv50_display_irq_handler_bh(struct work_struct *work);
 int nv50_display_early_init(struct drm_device *dev);
 void nv50_display_late_takedown(struct drm_device *dev);
 int nv50_display_create(struct drm_device *dev);