changed Makefile and profiles, added patches for kernel 2.6.24
[openwrt.git] / target / linux / s3c24xx / patches-2.6.26 / 0192-introduce-resume-exception-capture.patch.patch
1 From 081a639e9274072fbd34ee778188332ed972734e Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Fri, 25 Jul 2008 23:06:16 +0100
4 Subject: [PATCH] introduce-resume-exception-capture.patch
5
6 This patch introduces a new resume debugging concept: if we
7 get an OOPS inbetween starting suspend and finishing resume, it
8 uses a new "emergency spew" device similar to BUT NOT REQUIRING
9 CONFIG_DEBUG_LL to dump the syslog buffer and then the OOPS
10 on the debug device defined by the existing CONFIG_DEBUG_S3C_UART
11 index.  But neither CONFIG_DEBUG_LL nor the S3C low level configs
12 are needed to use this feature.
13
14 Another difference between this feature and CONFIG_DEBUG_LL is that
15 it does not affect resume timing, ordering or UART traffic UNLESS
16 there is an OOPS during resume.
17
18 The patch adds three global exports, one to say if we are inside
19 suspend / resume, and two callbacks for printk() to use to init
20 and dump the emergency data.  The callbacks are set in s3c serial
21 device init, but the whole structure is arch independent.
22
23 Signed-off-by: Andy Green <andy@openmoko.com>
24 ---
25  drivers/serial/s3c2410.c |   77 +++++++++++++++++++++++++++++++++++++++++++++-
26  include/linux/kernel.h   |    2 +
27  include/linux/suspend.h  |    6 +++
28  kernel/power/main.c      |    7 ++++
29  kernel/printk.c          |   42 +++++++++++++++++++++++++
30  5 files changed, 133 insertions(+), 1 deletions(-)
31
32 diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
33 index 32cceae..f20f63b 100644
34 --- a/drivers/serial/s3c2410.c
35 +++ b/drivers/serial/s3c2410.c
36 @@ -81,6 +81,7 @@
37  
38  #include <asm/plat-s3c/regs-serial.h>
39  #include <asm/arch/regs-gpio.h>
40 +#include <asm/arch/regs-clock.h>
41  
42  /* structures */
43  
44 @@ -1170,7 +1171,13 @@ static int s3c24xx_serial_init(struct platform_driver *drv,
45                                struct s3c24xx_uart_info *info)
46  {
47         dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
48 -       return platform_driver_register(drv);
49 +        /* set up the emergency debug UART functions */
50 +
51 +        printk_emergency_debug_spew_init = s3c24xx_serial_force_debug_port_up;
52 +        printk_emergency_debug_spew_send_string = s3c2410_printascii;
53 +
54 +        dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
55 +        return platform_driver_register(drv);
56  }
57  
58  
59 @@ -1647,6 +1654,74 @@ static struct platform_driver s3c2412_serial_drv = {
60         },
61  };
62  
63 +static void s3c24xx_serial_force_debug_port_up(void)
64 +{
65 +       struct s3c24xx_uart_port *ourport = &s3c24xx_serial_ports[
66 +                                                        CONFIG_DEBUG_S3C_UART];
67 +       struct s3c24xx_uart_clksrc *clksrc = NULL;
68 +       struct clk *clk = NULL;
69 +       unsigned long tmp;
70 +
71 +       s3c24xx_serial_getclk(&ourport->port, &clksrc, &clk, 115200);
72 +
73 +       tmp = __raw_readl(S3C2410_CLKCON);
74 +
75 +       /* re-start uart clocks */
76 +       tmp |= S3C2410_CLKCON_UART0;
77 +       tmp |= S3C2410_CLKCON_UART1;
78 +       tmp |= S3C2410_CLKCON_UART2;
79 +
80 +       __raw_writel(tmp, S3C2410_CLKCON);
81 +       udelay(10);
82 +
83 +       s3c24xx_serial_setsource(&ourport->port, clksrc);
84 +
85 +       if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
86 +               clk_disable(ourport->baudclk);
87 +               ourport->baudclk  = NULL;
88 +       }
89 +
90 +       clk_enable(clk);
91 +
92 +       ourport->clksrc = clksrc;
93 +       ourport->baudclk = clk;
94 +}
95 +
96 +static void s3c2410_printascii(const char *sz)
97 +{
98 +       struct s3c24xx_uart_port *ourport = &s3c24xx_serial_ports[
99 +                                                        CONFIG_DEBUG_S3C_UART];
100 +       struct uart_port *port = &ourport->port;
101 +
102 +       /* 8 N 1 */
103 +       wr_regl(port, S3C2410_ULCON, (rd_regl(port, S3C2410_ULCON)) | 3);
104 +       /* polling mode */
105 +       wr_regl(port, S3C2410_UCON, (rd_regl(port, S3C2410_UCON) & ~0xc0f) | 5);
106 +       /* disable FIFO */
107 +       wr_regl(port, S3C2410_UFCON, (rd_regl(port, S3C2410_UFCON) & ~0x01));
108 +       /* fix baud rate */
109 +       wr_regl(port, S3C2410_UBRDIV, 26);
110 +
111 +       while (*sz) {
112 +               int timeout = 10000000;
113 +
114 +               /* spin on it being busy */
115 +               while ((!(rd_regl(port, S3C2410_UTRSTAT) & 2)) && timeout--)
116 +                       ;
117 +
118 +               /* transmit register */
119 +               wr_regl(port, S3C2410_UTXH, *sz);
120 +
121 +               sz++;
122 +       }
123 +}
124 +
125 +
126 +/* s3c24xx_serial_resetport
127 + *
128 + * wrapper to call the specific reset for this port (reset the fifos
129 + * and the settings)
130 +*/
131  
132  static inline int s3c2412_serial_init(void)
133  {
134 diff --git a/include/linux/kernel.h b/include/linux/kernel.h
135 index 2e70006..fcad89e 100644
136 --- a/include/linux/kernel.h
137 +++ b/include/linux/kernel.h
138 @@ -198,6 +198,8 @@ extern int __ratelimit(int ratelimit_jiffies, int ratelimit_burst);
139  extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst);
140  extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
141                                    unsigned int interval_msec);
142 +extern void (*printk_emergency_debug_spew_init)(void);
143 +extern void (*printk_emergency_debug_spew_send_string)(const char *);
144  #else
145  static inline int vprintk(const char *s, va_list args)
146         __attribute__ ((format (printf, 1, 0)));
147 diff --git a/include/linux/suspend.h b/include/linux/suspend.h
148 index a697742..8164615 100644
149 --- a/include/linux/suspend.h
150 +++ b/include/linux/suspend.h
151 @@ -140,6 +140,12 @@ struct pbe {
152         struct pbe *next;
153  };
154  
155 +/**
156 + * global indication we are somewhere between start of suspend and end of
157 + * resume, nonzero is true
158 + */
159 +extern int global_inside_suspend;
160 +
161  /* mm/page_alloc.c */
162  extern void mark_free_pages(struct zone *zone);
163  
164 diff --git a/kernel/power/main.c b/kernel/power/main.c
165 index 6a6d5eb..1169648 100644
166 --- a/kernel/power/main.c
167 +++ b/kernel/power/main.c
168 @@ -130,6 +130,9 @@ static inline int suspend_test(int level) { return 0; }
169  
170  #endif /* CONFIG_PM_SLEEP */
171  
172 +int global_inside_suspend;
173 +EXPORT_SYMBOL(global_inside_suspend);
174 +
175  #ifdef CONFIG_SUSPEND
176  
177  /* This is just an arbitrary number */
178 @@ -258,6 +261,8 @@ int suspend_devices_and_enter(suspend_state_t state)
179         if (!suspend_ops)
180                 return -ENOSYS;
181  
182 +       global_inside_suspend = 1;
183 +
184         if (suspend_ops->begin) {
185                 error = suspend_ops->begin(state);
186                 if (error)
187 @@ -297,6 +302,8 @@ int suspend_devices_and_enter(suspend_state_t state)
188   Close:
189         if (suspend_ops->end)
190                 suspend_ops->end();
191 +       global_inside_suspend = 0;
192 +
193         return error;
194  }
195  
196 diff --git a/kernel/printk.c b/kernel/printk.c
197 index e2129e8..00df30e 100644
198 --- a/kernel/printk.c
199 +++ b/kernel/printk.c
200 @@ -32,8 +32,12 @@
201  #include <linux/security.h>
202  #include <linux/bootmem.h>
203  #include <linux/syscalls.h>
204 +#include <linux/jiffies.h>
205 +#include <linux/suspend.h>
206  
207  #include <asm/uaccess.h>
208 +#include <asm/plat-s3c24xx/neo1973.h>
209 +#include <asm/arch/gta02.h>
210  
211  /*
212   * Architectures can override it:
213 @@ -67,6 +71,12 @@ int console_printk[4] = {
214  int oops_in_progress;
215  EXPORT_SYMBOL(oops_in_progress);
216  
217 +void (*printk_emergency_debug_spew_init)(void) = NULL;
218 +EXPORT_SYMBOL(printk_emergency_debug_spew_init);
219 +
220 +void (*printk_emergency_debug_spew_send_string)(const char *) = NULL;
221 +EXPORT_SYMBOL(printk_emergency_debug_spew_send_string);
222 +
223  /*
224   * console_sem protects the console_drivers list, and also
225   * provides serialisation for access to the entire console
226 @@ -718,6 +728,38 @@ asmlinkage int vprintk(const char *fmt, va_list args)
227         printed_len += vscnprintf(printk_buf + printed_len,
228                                   sizeof(printk_buf) - printed_len, fmt, args);
229  
230 +       /* if you're debugging resume, the normal methods can change resume
231 +        * ordering behaviours because their debugging output is synchronous
232 +        * (ie, CONFIG_DEBUG_LL).  If your problem is an OOPS, this code
233 +        * will not affect the speed and duration and ordering of resume
234 +        * actions, but will give you a chance to read the full undumped
235 +        * syslog AND the OOPS data when it happens
236 +        *
237 +        * if you support it, your debug device init can override the exported
238 +        * emergency_debug_spew_init and emergency_debug_spew_send_string to
239 +        * usually force polling or bitbanging on your debug console device
240 +        */
241 +       if (oops_in_progress && global_inside_suspend &&
242 +           printk_emergency_debug_spew_init &&
243 +           printk_emergency_debug_spew_send_string) {
244 +               unsigned long cur_index;
245 +               char ch[2];
246 +
247 +               if (global_inside_suspend == 1) {
248 +                       (printk_emergency_debug_spew_init)();
249 +
250 +                       ch[1] = '\0';
251 +                       cur_index = con_start;
252 +                       while (cur_index != log_end) {
253 +                               ch[0] = LOG_BUF(cur_index);
254 +                               (printk_emergency_debug_spew_send_string)(ch);
255 +                               cur_index++;
256 +                       }
257 +                       global_inside_suspend++; /* only once */
258 +               }
259 +               (printk_emergency_debug_spew_send_string)(printk_buf);
260 +       }
261 +
262         /*
263          * Copy the output into log_buf.  If the caller didn't provide
264          * appropriate log level tags, we insert them here
265 -- 
266 1.5.6.3
267