Commit f13e435c authored by Ben Skeggs's avatar Ben Skeggs

drm/nv50-nvc0: switch to tasklet for display isr bh

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent c7ca4d1b
...@@ -653,7 +653,6 @@ struct drm_nouveau_private { ...@@ -653,7 +653,6 @@ struct drm_nouveau_private {
/* interrupt handling */ /* interrupt handling */
void (*irq_handler[32])(struct drm_device *); void (*irq_handler[32])(struct drm_device *);
bool msi_enabled; bool msi_enabled;
struct work_struct irq_work;
struct list_head vbl_waiting; struct list_head vbl_waiting;
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "drm_crtc_helper.h" #include "drm_crtc_helper.h"
static void nv50_display_isr(struct drm_device *); static void nv50_display_isr(struct drm_device *);
static void nv50_display_bh(unsigned long);
static inline int static inline int
nv50_sor_nr(struct drm_device *dev) nv50_sor_nr(struct drm_device *dev)
...@@ -339,7 +340,7 @@ int nv50_display_create(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); nouveau_irq_register(dev, 26, nv50_display_isr);
ret = nv50_display_init(dev); ret = nv50_display_init(dev);
...@@ -354,7 +355,6 @@ int nv50_display_create(struct drm_device *dev) ...@@ -354,7 +355,6 @@ int nv50_display_create(struct drm_device *dev)
void void
nv50_display_destroy(struct drm_device *dev) nv50_display_destroy(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_display *disp = nv50_display(dev); struct nv50_display *disp = nv50_display(dev);
NV_DEBUG_KMS(dev, "\n"); NV_DEBUG_KMS(dev, "\n");
...@@ -363,7 +363,6 @@ nv50_display_destroy(struct drm_device *dev) ...@@ -363,7 +363,6 @@ nv50_display_destroy(struct drm_device *dev)
nv50_display_disable(dev); nv50_display_disable(dev);
nouveau_irq_unregister(dev, 26); nouveau_irq_unregister(dev, 26);
flush_work_sync(&dev_priv->irq_work);
kfree(disp); kfree(disp);
} }
...@@ -770,12 +769,10 @@ nv50_display_unk40_handler(struct drm_device *dev) ...@@ -770,12 +769,10 @@ nv50_display_unk40_handler(struct drm_device *dev)
nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) | 8); nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) | 8);
} }
void static void
nv50_display_irq_handler_bh(struct work_struct *work) nv50_display_bh(unsigned long data)
{ {
struct drm_nouveau_private *dev_priv = struct drm_device *dev = (struct drm_device *)data;
container_of(work, struct drm_nouveau_private, irq_work);
struct drm_device *dev = dev_priv->dev;
for (;;) { for (;;) {
uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0); uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
...@@ -823,7 +820,7 @@ nv50_display_error_handler(struct drm_device *dev) ...@@ -823,7 +820,7 @@ nv50_display_error_handler(struct drm_device *dev)
static void static void
nv50_display_isr(struct drm_device *dev) 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; uint32_t delayed = 0;
while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
...@@ -851,8 +848,7 @@ nv50_display_isr(struct drm_device *dev) ...@@ -851,8 +848,7 @@ nv50_display_isr(struct drm_device *dev)
NV50_PDISPLAY_INTR_1_CLK_UNK40)); NV50_PDISPLAY_INTR_1_CLK_UNK40));
if (clock) { if (clock) {
nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
if (!work_pending(&dev_priv->irq_work)) tasklet_schedule(&disp->tasklet);
schedule_work(&dev_priv->irq_work);
delayed |= clock; delayed |= clock;
intr1 &= ~clock; intr1 &= ~clock;
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
struct nv50_display { struct nv50_display {
struct nouveau_channel *master; struct nouveau_channel *master;
struct tasklet_struct tasklet;
struct { struct {
struct dcb_entry *dcb; struct dcb_entry *dcb;
u16 script; u16 script;
...@@ -52,7 +53,6 @@ nv50_display(struct drm_device *dev) ...@@ -52,7 +53,6 @@ nv50_display(struct drm_device *dev)
return dev_priv->engine.display.priv; 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); int nv50_display_early_init(struct drm_device *dev);
void nv50_display_late_takedown(struct drm_device *dev); void nv50_display_late_takedown(struct drm_device *dev);
int nv50_display_create(struct drm_device *dev); int nv50_display_create(struct drm_device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment