From 778e26dee5e6b3be4611b1f99f8359cb64b27ce9 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Tue, 11 Mar 2014 18:51:20 +0100 Subject: [PATCH] drm/gma500: Move asle interrupt work into a work task Previously the backlight code was called from IRQ context which isn't allowed. This patch moves all the asle work into a work task which takes care of the locking bug reported by users. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=64221 Signed-off-by: Patrik Jakobsson --- drivers/gpu/drm/gma500/opregion.c | 25 +++++++++++++++++++++---- drivers/gpu/drm/gma500/psb_drv.h | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c index 13ec6283bf59..ab696ca7eeec 100644 --- a/drivers/gpu/drm/gma500/opregion.c +++ b/drivers/gpu/drm/gma500/opregion.c @@ -173,10 +173,13 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) return 0; } -void psb_intel_opregion_asle_intr(struct drm_device *dev) +static void psb_intel_opregion_asle_work(struct work_struct *work) { - struct drm_psb_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; + struct psb_intel_opregion *opregion = + container_of(work, struct psb_intel_opregion, asle_work); + struct drm_psb_private *dev_priv = + container_of(opregion, struct drm_psb_private, opregion); + struct opregion_asle *asle = opregion->asle; u32 asle_stat = 0; u32 asle_req; @@ -190,9 +193,18 @@ void psb_intel_opregion_asle_intr(struct drm_device *dev) } if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight(dev, asle->bclp); + asle_stat |= asle_set_backlight(dev_priv->dev, asle->bclp); asle->aslc = asle_stat; + +} + +void psb_intel_opregion_asle_intr(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + if (dev_priv->opregion.asle) + schedule_work(&dev_priv->opregion.asle_work); } #define ASLE_ALS_EN (1<<0) @@ -282,6 +294,8 @@ void psb_intel_opregion_fini(struct drm_device *dev) unregister_acpi_notifier(&psb_intel_opregion_notifier); } + cancel_work_sync(&opregion->asle_work); + /* just clear all opregion memory pointers now */ iounmap(opregion->header); opregion->header = NULL; @@ -304,6 +318,9 @@ int psb_intel_opregion_setup(struct drm_device *dev) DRM_DEBUG_DRIVER("ACPI Opregion not supported\n"); return -ENOTSUPP; } + + INIT_WORK(&opregion->asle_work, psb_intel_opregion_asle_work); + DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy); base = acpi_os_ioremap(opregion_phy, 8*1024); if (!base) diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 77bd7aba8298..d5421c072b6b 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -266,6 +266,7 @@ struct psb_intel_opregion { struct opregion_asle *asle; void *vbt; u32 __iomem *lid_state; + struct work_struct asle_work; }; struct sdvo_device_mapping { -- GitLab