changed Makefile and profiles, added patches for kernel 2.6.24
[openwrt.git] / target / linux / s3c24xx / patches-2.6.24 / 1271-always-call-resume-dependencies.patch.patch
diff --git a/target/linux/s3c24xx/patches-2.6.24/1271-always-call-resume-dependencies.patch.patch b/target/linux/s3c24xx/patches-2.6.24/1271-always-call-resume-dependencies.patch.patch
new file mode 100644 (file)
index 0000000..f484734
--- /dev/null
@@ -0,0 +1,255 @@
+From 36879992de8774cbf8686740bbda383cc6fbdcbb Mon Sep 17 00:00:00 2001
+From: \\\\\\\"Mike (mwester)\\\\\\ <mwester@dls.net>
+Date: Mon, 11 Aug 2008 20:16:09 +0100
+Subject: [PATCH] always-call-resume-dependencies.patch
+
+Attached is a patch that has greatly reduced the frequency of failures
+to resume (due to an oops from the glamo resume handler), and the
+dreaded "white screen after resume".  I can't say that it fixes all of
+these, although I have yet to see the white-screen since applying this
+patch and suspending/resuming several hundred times (with the 30-second
+suspend on the 2008.8 image and the endless stream of GSM error messages
+generated by something in that image, it has proved to be very useful to
+do an automated stress test!)
+
+This patch will apply to stable, and should make stable slightly more,
+well, "stable".
+
+[Feel free to remove the debug messages if someone feels strongly about
+that; I left them in because I think they might be useful in triaging
+further crashes; I'm not at all convinced that this patch will fix all
+the cases of resume failures.]
+
+[[And, yes, this is ugly, really ugly.]]
+
+[[[Oh yeah - there's still one extreme case that will result in an oops:
+ if a dependent driver is built as a module, and it is unloaded, and it
+happened that the preceding suspend/resume was aborted, and that abort
+happened between the dependent driver and the driver upon which it is
+dependent, then a list entry will be left behind referencing the
+unloaded module.  There's just no good way to fix that given the way the
+resume dependency plumbing is connected up right now, so just avoid
+using modules for any of the drivers involved in the resume dependency
+stuff.]]]
+
+Regards,
+Mike (mwester)
+commit 905d2fc9c45f622418ce9ef4e67c23453aab7571
+Author: Mike Westerhof <mwester@dls.net>
+Date:   Mon Aug 11 11:11:25 2008 -0500
+
+    always-call-resume-dependencies.patch
+
+    Ensure that a dependent resume handler is always executed,
+    even if the resume handler for driver upon which it is
+    dependent never suspends (and therefore never resumes either).
+    Also make sure that we do not end up with duplicate
+    dependencies registered, something that can happen if the
+    suspend is aborted due to driver failure or an early resume
+    (such as occurs when the GSM interrupts during suspend).
+
+    Signed-off-by: Mike Westerhof <mwester@dls.net>
+---
+ drivers/i2c/chips/pcf50633.c      |    6 +++++
+ drivers/mfd/glamo/glamo-core.c    |    5 ++++
+ drivers/mfd/glamo/glamo-core.h    |    1 +
+ drivers/serial/s3c2410.c          |    7 ++++++
+ include/linux/resume-dependency.h |   38 ++++++++++++++++++++++++++++++++++++-
+ 5 files changed, 56 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
+index 98c254c..b90ea8c 100644
+--- a/drivers/i2c/chips/pcf50633.c
++++ b/drivers/i2c/chips/pcf50633.c
+@@ -183,6 +183,7 @@ struct pcf50633_data {
+       } standby_regs;
+       struct resume_dependency resume_dependency;
++      int is_suspended;
+ #endif
+ };
+@@ -2366,6 +2367,8 @@ void pcf50633_register_resume_dependency(struct pcf50633_data *pcf,
+                                       struct resume_dependency *dep)
+ {
+       register_resume_dependency(&pcf->resume_dependency, dep);
++      if (pcf->is_suspended)
++              activate_all_resume_dependencies(&pcf->resume_dependency);
+ }
+ EXPORT_SYMBOL_GPL(pcf50633_register_resume_dependency);
+@@ -2462,6 +2465,8 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
+       mutex_unlock(&pcf->lock);
++      pcf->is_suspended = 1;
++      activate_all_resume_dependencies(&pcf->resume_dependency);
+       return 0;
+ }
+@@ -2590,6 +2595,7 @@ static int pcf50633_resume(struct device *dev)
+       get_device(&pcf->client.dev);
+       pcf50633_work(&pcf->work);
++      pcf->is_suspended = 0;
+       callback_all_resume_dependencies(&pcf->resume_dependency);
+       return 0;
+diff --git a/drivers/mfd/glamo/glamo-core.c b/drivers/mfd/glamo/glamo-core.c
+index c094a8c..e310382 100644
+--- a/drivers/mfd/glamo/glamo-core.c
++++ b/drivers/mfd/glamo/glamo-core.c
+@@ -1248,6 +1248,8 @@ void glamo_register_resume_dependency(struct resume_dependency *
+ {
+       register_resume_dependency(&glamo_handle->resume_dependency,
+                                                            resume_dependency);
++      if (glamo_handle->is_suspended)
++              activate_all_resume_dependencies(&glamo_handle->resume_dependency);
+ }
+ EXPORT_SYMBOL_GPL(glamo_register_resume_dependency);
+@@ -1255,12 +1257,15 @@ EXPORT_SYMBOL_GPL(glamo_register_resume_dependency);
+ static int glamo_suspend(struct platform_device *pdev, pm_message_t state)
+ {
+       glamo_power(glamo_handle, GLAMO_POWER_SUSPEND);
++      glamo_handle->is_suspended = 1;
++      activate_all_resume_dependencies(&glamo_handle->resume_dependency);
+       return 0;
+ }
+ static int glamo_resume(struct platform_device *pdev)
+ {
+       glamo_power(glamo_handle, GLAMO_POWER_ON);
++      glamo_handle->is_suspended = 0;
+       callback_all_resume_dependencies(&glamo_handle->resume_dependency);
+       return 0;
+diff --git a/drivers/mfd/glamo/glamo-core.h b/drivers/mfd/glamo/glamo-core.h
+index d3f4309..ac5eacf 100644
+--- a/drivers/mfd/glamo/glamo-core.h
++++ b/drivers/mfd/glamo/glamo-core.h
+@@ -32,6 +32,7 @@ struct glamo_core {
+       struct resume_dependency resume_dependency;
+       u32 engine_enabled_bitfield;
+       u32 engine_enabled_bitfield_suspend;
++      int is_suspended;
+ };
+ struct glamo_script {
+diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
+index 2a388cf..3b1c07b 100644
+--- a/drivers/serial/s3c2410.c
++++ b/drivers/serial/s3c2410.c
+@@ -116,6 +116,7 @@ struct s3c24xx_uart_port {
+       struct uart_port                port;
+       struct resume_dependency        resume_dependency;
++      int                             is_suspended;
+ };
+@@ -1188,10 +1189,13 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
+ static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
+ {
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
++      struct s3c24xx_uart_port *ourport = to_ourport(port);
+       if (port)
+               uart_suspend_port(&s3c24xx_uart_drv, port);
++      activate_all_resume_dependencies(&ourport->resume_dependency);
++      ourport->is_suspended = 1;
+       return 0;
+ }
+@@ -1202,6 +1206,8 @@ void s3c24xx_serial_register_resume_dependency(struct resume_dependency *
+       register_resume_dependency(&ourport->resume_dependency,
+                                                            resume_dependency);
++      if (ourport->is_suspended)
++              activate_all_resume_dependencies(&ourport->resume_dependency);
+ }
+ EXPORT_SYMBOL(s3c24xx_serial_register_resume_dependency);
+@@ -1218,6 +1224,7 @@ static int s3c24xx_serial_resume(struct platform_device *dev)
+               uart_resume_port(&s3c24xx_uart_drv, port);
+       }
++      ourport->is_suspended = 0;
+       callback_all_resume_dependencies(&ourport->resume_dependency);
+       return 0;
+diff --git a/include/linux/resume-dependency.h b/include/linux/resume-dependency.h
+index e0c0f33..959cadd 100644
+--- a/include/linux/resume-dependency.h
++++ b/include/linux/resume-dependency.h
+@@ -38,6 +38,7 @@ struct resume_dependency {
+  */
+ #define init_resume_dependency_list(_head) \
++      printk(KERN_ERR "##### init_resume_dependency_list(head=%p)\n", (_head)); \
+       INIT_LIST_HEAD(&(_head)->list);
+@@ -48,7 +49,18 @@ struct resume_dependency {
+  */
+ #define register_resume_dependency(_head, _dep) { \
+-      (_dep)->called_flag = 0; \
++      struct list_head *_pos, *_q; \
++      struct resume_dependency *_d; \
++\
++      printk(KERN_ERR "##### register_resume_dependency(head=%p, dep=%p)\n", (_head), (_dep)); \
++      (_dep)->called_flag = 1; \
++      list_for_each_safe(_pos, _q, &((_head)->list)) { \
++              _d = list_entry(_pos, struct resume_dependency, list); \
++              if (_d == (_dep)) { \
++                      list_del(_pos); \
++                      printk(KERN_ERR "#####   duplicate dependency removed first\n"); \
++              } \
++      } \
+       list_add(&(_dep)->list, &(_head)->list); \
+ }
+@@ -61,14 +73,38 @@ struct resume_dependency {
+       struct list_head *_pos, *_q; \
+       struct resume_dependency *_dep; \
+ \
++      printk(KERN_ERR "##### callback_all_resume_dependencies(head=%p)\n", (_head)); \
+       list_for_each_safe(_pos, _q, &((_head)->list)) { \
+               _dep = list_entry(_pos, struct resume_dependency, list); \
++              printk(KERN_ERR "#####   callback list entry (head=%p, dep=%p)\n", (_head), (_dep)); \
+               _dep->called_flag = 1; \
++              printk(KERN_ERR "#####      callback=%p(context=%p))\n", (_dep->callback),(_dep->context)); \
+               (_dep->callback)(_dep->context); \
+               list_del(_pos); \
+       } \
+ }
++/* When a dependency is added, it is not actually active; the dependent resume
++ * handler will function as normal.  The dependency is activated by the suspend
++ * handler for the driver that will be doing the callbacks.  This ensures that
++ * if the suspend is aborted for any reason (error, driver busy, etc), that all
++ * suspended drivers will resume, even if the driver upon which they are dependent
++ * did not suspend, and hence will not resume, and thus would be unable to perform
++ * the callbacks.
++ */
++
++#define activate_all_resume_dependencies(_head) { \
++      struct list_head *_pos, *_q; \
++      struct resume_dependency *_dep; \
++\
++      printk(KERN_ERR "##### activate_all_resume_dependencies(head=%p)\n", (_head)); \
++      list_for_each_safe(_pos, _q, &((_head)->list)) { \
++              _dep = list_entry(_pos, struct resume_dependency, list); \
++              printk(KERN_ERR "#####   activating callback list entry (head=%p, dep=%p)\n", (_head), (_dep)); \
++              _dep->called_flag = 0; \
++      } \
++}
++
+ /* if your resume action is dependent on multiple drivers being resumed already,
+  * register the same callback with each driver you are dependent on, and check
+  * .called_flag for all of the struct resume_dependency.  When they are all 1
+-- 
+1.5.6.5
+
This page took 0.032036 seconds and 4 git commands to generate.