diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index 1a561d30821517f0bf0b4d93e2c59061c6d49a1c..b6a8c6def64cd7cfc353b0b28d31b2c61ca16ea7 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -44,9 +44,12 @@ struct nvd0_display { dma_addr_t handle; u32 *ptr; } evo[1]; + + struct tasklet_struct tasklet; struct { struct dcb_entry *dis; struct dcb_entry *ena; + u32 modeset; int crtc; int pclk; u16 cfg; @@ -1114,9 +1117,24 @@ nvd0_display_unk4_handler(struct drm_device *dev) nv_wr32(dev, 0x6101d0, 0x80000000); } +static void +nvd0_display_bh(unsigned long data) +{ + struct drm_device *dev = (struct drm_device *)data; + struct nvd0_display *disp = nvd0_display(dev); + + if (disp->irq.modeset & 0x00000001) + nvd0_display_unk1_handler(dev); + if (disp->irq.modeset & 0x00000002) + nvd0_display_unk2_handler(dev); + if (disp->irq.modeset & 0x00000004) + nvd0_display_unk4_handler(dev); +} + static void nvd0_display_intr(struct drm_device *dev) { + struct nvd0_display *disp = nvd0_display(dev); u32 intr = nv_rd32(dev, 0x610088); if (intr & 0x00000002) { @@ -1141,14 +1159,10 @@ nvd0_display_intr(struct drm_device *dev) u32 stat = nv_rd32(dev, 0x6100ac); if (stat & 0x00000007) { - nv_wr32(dev, 0x6100ac, (stat & 0x00000007)); + disp->irq.modeset = stat; + tasklet_schedule(&disp->tasklet); - if (stat & 0x00000001) - nvd0_display_unk1_handler(dev); - if (stat & 0x00000002) - nvd0_display_unk2_handler(dev); - if (stat & 0x00000004) - nvd0_display_unk4_handler(dev); + nv_wr32(dev, 0x6100ac, (stat & 0x00000007)); stat &= ~0x00000007; } @@ -1371,6 +1385,7 @@ nvd0_display_create(struct drm_device *dev) } /* setup interrupt handling */ + tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev); nouveau_irq_register(dev, 26, nvd0_display_intr); /* hash table and dma objects for the memory areas we care about */