This commit was manufactured by cvs2svn to create tag 'before-xenU'.
[linux-2.6.git] / drivers / dump / dump_ppc64.c
1 /*
2  * Architecture specific (ppc64) functions for Linux crash dumps.
3  *
4  * Created by: Matt Robinson (yakker@sgi.com)
5  *
6  * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
7  * 
8  * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
9  * Copyright 2000 TurboLinux, Inc.  All rights reserved.
10  * Copyright 2003, 2004 IBM Corporation
11  * 
12  * This code is released under version 2 of the GNU GPL.
13  */
14
15 /*
16  * The hooks for dumping the kernel virtual memory to disk are in this
17  * file.  Any time a modification is made to the virtual memory mechanism,
18  * these routines must be changed to use the new mechanisms.
19  */
20 #include <linux/types.h>
21 #include <linux/fs.h>
22 #include <linux/dump.h>
23 #include <linux/mm.h>
24 #include <linux/vmalloc.h>
25 #include <linux/delay.h>
26 #include <linux/syscalls.h> 
27 #include <linux/ioctl32.h>
28 #include <asm/hardirq.h>
29 #include "dump_methods.h"
30 #include <linux/irq.h>
31 #include <asm/machdep.h>
32 #include <asm/uaccess.h>
33 #include <asm/irq.h>
34 #include <asm/page.h>
35 #if defined(CONFIG_KDB) && !defined(CONFIG_DUMP_MODULE)
36 #include <linux/kdb.h>
37 #endif
38
39 extern cpumask_t irq_affinity[];
40
41 static cpumask_t saved_affinity[NR_IRQS];
42
43 static __s32         saved_irq_count;   /* saved preempt_count() flags */
44
45 static int alloc_dha_stack(void)
46 {
47         int i;
48         void *ptr;
49
50         if (dump_header_asm.dha_stack[0])
51                 return 0;
52
53         ptr = (void *)vmalloc(THREAD_SIZE * num_online_cpus());
54         if (!ptr) {
55                 return -ENOMEM;
56         }
57
58         for (i = 0; i < num_online_cpus(); i++) {
59                 dump_header_asm.dha_stack[i] = 
60                         (uint64_t)((unsigned long)ptr + (i * THREAD_SIZE));
61         }
62         return 0;
63 }
64
65 static int free_dha_stack(void)
66 {
67         if (dump_header_asm.dha_stack[0]) {
68                 vfree((void*)dump_header_asm.dha_stack[0]);
69                 dump_header_asm.dha_stack[0] = 0;
70         }
71         return 0;
72 }
73 #ifdef CONFIG_SMP
74 static int dump_expect_ipi[NR_CPUS];
75 static atomic_t waiting_for_dump_ipi;
76
77 extern void stop_this_cpu(void *);
78 static int
79 dump_ipi_handler(struct pt_regs *regs) 
80 {
81         int cpu = smp_processor_id();
82
83         if (!dump_expect_ipi[cpu])
84                 return 0;
85         dump_save_this_cpu(regs);
86         atomic_dec(&waiting_for_dump_ipi);
87
88  level_changed:
89         switch (dump_silence_level) {
90         case DUMP_HARD_SPIN_CPUS:       /* Spin until dump is complete */
91                 while (dump_oncpu) {
92                         barrier();      /* paranoia */
93                         if (dump_silence_level != DUMP_HARD_SPIN_CPUS)
94                                 goto level_changed;
95                         cpu_relax();    /* kill time nicely */
96                 }
97                 break;
98
99         case DUMP_HALT_CPUS:            /* Execute halt */
100                 stop_this_cpu(NULL);
101                 break;
102         
103         case DUMP_SOFT_SPIN_CPUS:
104                 /* Mark the task so it spins in schedule */
105                 set_tsk_thread_flag(current, TIF_NEED_RESCHED);
106                 break;
107         }
108
109         return 1;
110 }
111
112 /* save registers on other processors
113  * If the other cpus don't respond we simply do not get their states.
114  */
115 void 
116 __dump_save_other_cpus(void)
117 {
118         int i, cpu = smp_processor_id();
119         int other_cpus = num_online_cpus()-1;
120         
121         if (other_cpus > 0) {
122                 atomic_set(&waiting_for_dump_ipi, other_cpus);
123                 for (i = 0; i < NR_CPUS; i++)
124                         dump_expect_ipi[i] = (i != cpu && cpu_online(i));
125
126                 dump_send_ipi(dump_ipi_handler);
127                 /*
128                  * may be we dont need to wait for NMI to be processed.
129                  * just write out the header at the end of dumping, if
130                  * this IPI is not processed until then, there probably
131                  * is a problem and we just fail to capture state of
132                  * other cpus.
133                  */
134                 while (atomic_read(&waiting_for_dump_ipi) > 0) {
135                         cpu_relax();
136                 }
137                 dump_send_ipi(NULL);    /* clear handler */
138         }
139 }
140
141 /*
142  * Restore old irq affinities.
143  */
144 static void
145 __dump_reset_irq_affinity(void)
146 {
147         int i;
148         irq_desc_t *irq_d;
149
150         memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
151
152         for_each_irq(i) {
153                 irq_d = get_irq_desc(i);
154                 if (irq_d->handler == NULL) {
155                         continue;
156                 }
157                 if (irq_d->handler->set_affinity != NULL) {
158                         irq_d->handler->set_affinity(i, saved_affinity[i]);
159                 }
160         }
161 }
162
163 /*
164  * Routine to save the old irq affinities and change affinities of all irqs to
165  * the dumping cpu.
166  *
167  * NB: Need to be expanded to multiple nodes.
168  */
169 static void
170 __dump_set_irq_affinity(void)
171 {
172         int i;
173         cpumask_t cpu = CPU_MASK_NONE;
174         irq_desc_t *irq_d;
175
176         cpu_set(smp_processor_id(), cpu);
177
178         memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(unsigned long));
179
180         for_each_irq(i) {
181                 irq_d = get_irq_desc(i);
182                 if (irq_d->handler == NULL) {
183                         continue;
184                 }
185                 irq_affinity[i] = cpu;
186                 if (irq_d->handler->set_affinity != NULL) {
187                         irq_d->handler->set_affinity(i, irq_affinity[i]);
188                 }
189         }
190 }
191 #else /* !CONFIG_SMP */
192 #define __dump_save_other_cpus() do { } while (0)
193 #define __dump_set_irq_affinity()      do { } while (0)
194 #define __dump_reset_irq_affinity()    do { } while (0)
195 #endif /* !CONFIG_SMP */
196
197 void
198 __dump_save_regs(struct pt_regs *dest_regs, const struct pt_regs *regs)
199 {
200         if (regs) {
201                 memcpy(dest_regs, regs, sizeof(struct pt_regs));
202         } 
203 }
204
205 /*
206  * Name: __dump_configure_header()
207  * Func: Configure the dump header with all proper values.
208  */
209 int
210 __dump_configure_header(const struct pt_regs *regs)
211 {
212         return (0);
213 }
214
215 #if defined(CONFIG_KDB) && !defined(CONFIG_DUMP_MODULE)
216 int
217 kdb_sysdump(int argc, const char **argv, const char **envp, struct pt_regs *regs)
218 {
219         kdb_printf("Dumping to disk...\n");
220         dump("dump from kdb", regs);
221         kdb_printf("Dump Complete\n");
222         return 0;
223 }
224 #endif
225
226 static int dw_long(unsigned int fd, unsigned int cmd, unsigned long arg,
227                   struct file *f)
228 {
229         mm_segment_t old_fs = get_fs();
230         int err;
231         unsigned long val;
232
233         set_fs (KERNEL_DS);
234         err = sys_ioctl(fd, cmd, (unsigned long)&val);
235         set_fs (old_fs);
236         if (!err && put_user((unsigned int) val, (u32 *)arg))
237                 return -EFAULT;
238         return err;
239 }
240
241 /*
242  * Name: __dump_init()
243  * Func: Initialize the dumping routine process.  This is in case
244  *       it's necessary in the future.
245  */
246 void
247 __dump_init(uint64_t local_memory_start)
248 {
249         int ret;
250
251         ret = register_ioctl32_conversion(DIOSDUMPDEV, NULL);
252         ret |= register_ioctl32_conversion(DIOGDUMPDEV, NULL);
253         ret |= register_ioctl32_conversion(DIOSDUMPLEVEL, NULL);
254         ret |= register_ioctl32_conversion(DIOGDUMPLEVEL, dw_long);
255         ret |= register_ioctl32_conversion(DIOSDUMPFLAGS, NULL);
256         ret |= register_ioctl32_conversion(DIOGDUMPFLAGS, dw_long);
257         ret |= register_ioctl32_conversion(DIOSDUMPCOMPRESS, NULL);
258         ret |= register_ioctl32_conversion(DIOGDUMPCOMPRESS, dw_long);
259         ret |= register_ioctl32_conversion(DIOSTARGETIP, NULL);
260         ret |= register_ioctl32_conversion(DIOGTARGETIP, NULL);
261         ret |= register_ioctl32_conversion(DIOSTARGETPORT, NULL);
262         ret |= register_ioctl32_conversion(DIOGTARGETPORT, NULL);
263         ret |= register_ioctl32_conversion(DIOSSOURCEPORT, NULL);
264         ret |= register_ioctl32_conversion(DIOGSOURCEPORT, NULL);
265         ret |= register_ioctl32_conversion(DIOSETHADDR, NULL);
266         ret |= register_ioctl32_conversion(DIOGETHADDR, NULL);
267         ret |= register_ioctl32_conversion(DIOGDUMPOKAY, dw_long);
268         ret |= register_ioctl32_conversion(DIOSDUMPTAKE, NULL);
269         if (ret) {
270                 printk(KERN_ERR "LKCD: registering ioctl32 translations failed\n");
271         }
272
273 #if defined(FIXME) && defined(CONFIG_KDB) && !defined(CONFIG_DUMP_MODULE)
274         /* This won't currently work because interrupts are off in kdb
275          * and the dump process doesn't understand how to recover.
276          */
277         /* ToDo: add a command to query/set dump configuration */
278         kdb_register_repeat("sysdump", kdb_sysdump, "", "use lkcd to dump the system to disk (if configured)", 0, KDB_REPEAT_NONE);
279 #endif
280
281         /* return */
282         return;
283 }
284
285 /*
286  * Name: __dump_open()
287  * Func: Open the dump device (architecture specific).  This is in
288  *       case it's necessary in the future.
289  */
290 void
291 __dump_open(void)
292 {
293         alloc_dha_stack();
294 }
295
296
297 /*
298  * Name: __dump_cleanup()
299  * Func: Free any architecture specific data structures. This is called
300  *       when the dump module is being removed.
301  */
302 void
303 __dump_cleanup(void)
304 {
305         int ret;
306
307         ret = unregister_ioctl32_conversion(DIOSDUMPDEV);
308         ret |= unregister_ioctl32_conversion(DIOGDUMPDEV);
309         ret |= unregister_ioctl32_conversion(DIOSDUMPLEVEL);
310         ret |= unregister_ioctl32_conversion(DIOGDUMPLEVEL);
311         ret |= unregister_ioctl32_conversion(DIOSDUMPFLAGS);
312         ret |= unregister_ioctl32_conversion(DIOGDUMPFLAGS);
313         ret |= unregister_ioctl32_conversion(DIOSDUMPCOMPRESS);
314         ret |= unregister_ioctl32_conversion(DIOGDUMPCOMPRESS);
315         ret |= unregister_ioctl32_conversion(DIOSTARGETIP);
316         ret |= unregister_ioctl32_conversion(DIOGTARGETIP);
317         ret |= unregister_ioctl32_conversion(DIOSTARGETPORT);
318         ret |= unregister_ioctl32_conversion(DIOGTARGETPORT);
319         ret |= unregister_ioctl32_conversion(DIOSSOURCEPORT);
320         ret |= unregister_ioctl32_conversion(DIOGSOURCEPORT);
321         ret |= unregister_ioctl32_conversion(DIOSETHADDR);
322         ret |= unregister_ioctl32_conversion(DIOGETHADDR);
323         ret |= unregister_ioctl32_conversion(DIOGDUMPOKAY);
324         ret |= unregister_ioctl32_conversion(DIOSDUMPTAKE);
325         if (ret) {
326                 printk(KERN_ERR "LKCD: Unregistering ioctl32 translations failed\n");
327         }
328         free_dha_stack();
329 }
330
331 /*
332  * Kludge - dump from interrupt context is unreliable (Fixme)
333  *
334  * We do this so that softirqs initiated for dump i/o
335  * get processed and we don't hang while waiting for i/o
336  * to complete or in any irq synchronization attempt.
337  *
338  * This is not quite legal of course, as it has the side
339  * effect of making all interrupts & softirqs triggered
340  * while dump is in progress complete before currently
341  * pending softirqs and the currently executing interrupt
342  * code.
343  */
344 static inline void
345 irq_bh_save(void)
346 {
347         saved_irq_count = irq_count();
348         preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
349 }
350
351 static inline void
352 irq_bh_restore(void)
353 {
354         preempt_count() |= saved_irq_count;
355 }
356
357 /*
358  * Name: __dump_irq_enable
359  * Func: Reset system so interrupts are enabled.
360  * This is used for dump methods that require interrupts
361  * Eventually, all methods will have interrupts disabled
362  * and this code can be removed.
363  *
364  * Change irq affinities
365  * Re-enable interrupts
366  */
367 int
368 __dump_irq_enable(void)
369 {
370         __dump_set_irq_affinity();
371         irq_bh_save();
372         local_irq_enable();
373         return 0;
374 }
375
376 /*
377  * Name: __dump_irq_restore
378  * Func: Resume the system state in an architecture-specific way.
379  */
380 void
381 __dump_irq_restore(void)
382 {
383         local_irq_disable();
384         __dump_reset_irq_affinity();
385         irq_bh_restore(); 
386 }
387
388 #if 0
389 /* Cheap progress hack.  It estimates pages to write and
390  * assumes all pages will go -- so it may get way off.
391  * As the progress is not displayed for other architectures, not used at this 
392  * moment.
393  */
394 void
395 __dump_progress_add_page(void)
396 {
397         unsigned long total_pages = nr_free_pages() + nr_inactive_pages + nr_active_pages;
398         unsigned int percent = (dump_header.dh_num_dump_pages * 100) / total_pages;
399         char buf[30];
400
401         if (percent > last_percent && percent <= 100) {
402                 sprintf(buf, "Dump %3d%%     ", percent);
403                 ppc64_dump_msg(0x2, buf);
404                 last_percent = percent;
405         }
406
407 }
408 #endif
409
410 extern int dump_page_is_ram(unsigned long);
411 /*
412  * Name: __dump_page_valid()
413  * Func: Check if page is valid to dump.
414  */
415 int
416 __dump_page_valid(unsigned long index)
417 {
418         if (!pfn_valid(index))
419                 return 0;
420
421         return dump_page_is_ram(index);
422 }
423
424 /*
425  * Name: manual_handle_crashdump()
426  * Func: Interface for the lkcd dump command. Calls dump_execute()
427  */
428 int
429 manual_handle_crashdump(void)
430 {
431         struct pt_regs regs;
432
433         get_current_regs(&regs);
434         dump_execute("manual", &regs);
435         return 0;
436 }