This commit was manufactured by cvs2svn to create branch
[linux-2.6.git] / drivers / dump / dump_arm.c
1 /*
2  * Architecture specific (ARM/XScale) functions for Linux crash dumps.
3  *
4  * Created by: Fleming Feng (fleming.feng@intel.com)
5  *
6  * Copyright(C) 2003 Intel Corp. All rights reserved.
7  *
8  * This code is released under version 2 of the GNU GPL.
9  */
10
11 /*
12  * The hooks for dumping the kernel virtual memory to disk are in this
13  * file.  Any time a modification is made to the virtual memory mechanism,
14  * these routines must be changed to use the new mechanisms.
15  */
16 #include <linux/init.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/smp.h>
20 #include <linux/fs.h>
21 #include <linux/vmalloc.h>
22 #include <linux/dump.h>
23 #include <linux/mm.h>
24 #include <asm/processor.h>
25 #include <asm/hardirq.h>
26 #include <asm/kdebug.h>
27
28 static __s32    saved_irq_count;        /* saved preempt_count() flags */
29
30 static int alloc_dha_stack(void)
31 {
32         int i;
33         void *ptr;
34         
35         if (dump_header_asm.dha_stack[0])
36                 return 0;
37
38         ptr = vmalloc(THREAD_SIZE * num_online_cpus());
39         if (!ptr) {
40                 printk("vmalloc for dha_stacks failed\n");
41                 return -ENOMEM;
42         }
43
44         for( i = 0; i < num_online_cpus(); i++){
45                 dump_header_asm.dha_stack[i] = (u32)((unsigned long)ptr +
46                                                      (i * THREAD_SIZE));
47         }
48
49         return 0;
50 }
51
52 static int free_dha_stack(void) 
53 {
54         if (dump_header_asm.dha_stack[0]){
55                 vfree((void*)dump_header_asm.dha_stack[0]);
56                 dump_header_asm.dha_stack[0] = 0;
57         }
58         return 0;
59 }
60
61 void __dump_save_regs(struct pt_regs* dest_regs, const struct pt_regs* regs)
62 {
63
64         /* Here, because the arm version uses _dump_regs_t,
65          * instead of pt_regs in dump_header_asm, while the
66          * the function is defined inside architecture independent
67          * header file include/linux/dump.h, the size of block of
68          * memory copied is not equal to pt_regs.
69          */
70
71         memcpy(dest_regs, regs, sizeof(_dump_regs_t));
72
73 }
74
75 #ifdef CONFIG_SMP
76 /* FIXME: This is reserved for possible future usage for SMP system 
77  * based on ARM/XScale. Currently, there is no information for an 
78  * SMP system based on ARM/XScale, they are not used!
79  */
80 /* save registers on other processor */
81 void
82 __dump_save_other_cpus(void)
83 {
84
85         /* Dummy now! */
86
87         return;
88         
89 }
90 #else   /* !CONFIG_SMP */
91 #define save_other_cpu_state() do { } while (0)
92 #endif  /* !CONFIG_SMP */
93
94 /* 
95  * Kludge - dump from interrupt context is unreliable (Fixme)
96  *
97  * We do this so that softirqs initiated for dump i/o 
98  * get processed and we don't hang while waiting for i/o
99  * to complete or in any irq synchronization attempt.
100  *
101  * This is not quite legal of course, as it has the side 
102  * effect of making all interrupts & softirqs triggered 
103  * while dump is in progress complete before currently 
104  * pending softirqs and the currently executing interrupt 
105  * code. 
106  */
107 static inline void
108 irq_bh_save(void)
109 {
110         saved_irq_count = irq_count();
111         preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
112 }
113
114 static inline void
115 irq_bh_restore(void)
116 {
117         preempt_count() |= saved_irq_count;
118 }
119
120 /*
121  * Name: __dump_irq_enable
122  * Func: Reset system so interrupts are enabled.
123  *       This is used for dump methods that requires interrupts
124  *       Eventually, all methods will have interrupts disabled
125  *       and this code can be removed.
126  *       
127  *       Re-enable interrupts
128  */
129 int
130 __dump_irq_enable(void)
131 {
132         irq_bh_save();
133         local_irq_enable();
134         return 0;
135 }
136
137 /* Name: __dump_irq_restore
138  * Func: Resume the system state in an architecture-specific way.
139  */
140 void 
141 __dump_irq_restore(void)
142 {
143         local_irq_disable();
144         irq_bh_restore();
145 }
146         
147
148 /*
149  * Name: __dump_configure_header()
150  * Func: Meant to fill in arch specific header fields except per-cpu state
151  *       already captured in dump_lcrash_configure_header.
152  */
153 int
154 __dump_configure_header(const struct pt_regs *regs)
155 {
156         return (0);
157 }
158
159 /*
160  * Name: dump_die_event
161  * Func: Called from notify_die
162  */
163 static int dump_die_event(struct notifier_block* this,
164                           unsigned long event,
165                           void* arg)
166 {
167         const struct die_args* args = (const struct die_args*)arg;
168
169         switch(event){
170                 case DIE_PANIC: 
171                 case DIE_OOPS:
172                 case DIE_WATCHDOG:
173                         dump_execute(args->str, args->regs);
174                         break;          
175         }
176         return NOTIFY_DONE;
177
178 }
179
180 static struct notifier_block dump_die_block = {
181         .notifier_call = dump_die_event,
182 };
183
184 /* Name: __dump_init()
185  * Func: Initialize the dumping routine process.
186  */
187 void
188 __dump_init(uint64_t local_memory_start)
189 {
190         /* hook into PANIC and OOPS */
191         register_die_notifier(&dump_die_block);
192 }
193
194 /*
195  * Name: __dump_open()
196  * Func: Open the dump device (architecture specific).  This is in
197  *       case it's necessary in the future.
198  */
199 void
200 __dump_open(void)
201 {
202
203         alloc_dha_stack();
204
205         return;
206 }
207
208 /*
209  * Name: __dump_cleanup()
210  * Func: Free any architecture specific data structures. This is called
211  *       when the dump module is being removed.
212  */
213 void
214 __dump_cleanup(void)
215 {
216         free_dha_stack();
217         unregister_die_notifier(&dump_die_block);
218
219         /* return */
220         return;
221 }
222
223 /* 
224  * Name: __dump_page_valid()
225  * Func: Check if page is valid to dump.
226  */
227 int
228 __dump_page_valid(unsigned long index)
229 {
230         if(!pfn_valid(index))
231                 return 0;
232         else
233                 return 1;
234 }
235
236 /* 
237  * Name: manual_handle_crashdump 
238  * Func: Interface for the lkcd dump command. Calls dump_execute()
239  */
240 int
241 manual_handle_crashdump(void) {
242         
243         _dump_regs_t regs;      
244
245         get_current_general_regs(&regs);
246         get_current_cp14_regs(&regs);
247         get_current_cp15_regs(&regs);
248         dump_execute("manual", &regs);
249         return 0;
250 }