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 <patrik.r.jakobsson at gmail.com>
---
 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 13ec628..ab696ca 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 77bd7ab..d5421c0 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 {
-- 
1.8.1.2

Reply via email to