[PATCH 10/16] drm/gma500: Move asle interrupt work into a work task

Patrik Jakobsson patrik.r.jakobsson at gmail.com
Mon Mar 17 16:09:29 PDT 2014


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



More information about the dri-devel mailing list