aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Kconfig5
-rw-r--r--arch/powerpc/kernel/process.c6
-rw-r--r--arch/powerpc/kernel/traps.c76
-rw-r--r--arch/powerpc/platforms/powermac/time.c38
-rw-r--r--arch/powerpc/sysdev/Makefile3
-rw-r--r--arch/powerpc/sysdev/timer.c70
6 files changed, 135 insertions, 63 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 20aae16cbadf..20a8fdcaacbf 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -11,6 +11,11 @@ config PPC64
11 This option selects whether a 32-bit or a 64-bit kernel 11 This option selects whether a 32-bit or a 64-bit kernel
12 will be built. 12 will be built.
13 13
14config PPC_PM_NEEDS_RTC_LIB
15 bool
16 select RTC_LIB
17 default y if PM
18
14config PPC32 19config PPC32
15 bool 20 bool
16 default y if !PPC64 21 default y if !PPC64
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 0df049215503..d7d7602e348f 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -402,11 +402,11 @@ static void printbits(unsigned long val, struct regbit *bits)
402} 402}
403 403
404#ifdef CONFIG_PPC64 404#ifdef CONFIG_PPC64
405#define REG "%016lX" 405#define REG "%016lx"
406#define REGS_PER_LINE 4 406#define REGS_PER_LINE 4
407#define LAST_VOLATILE 13 407#define LAST_VOLATILE 13
408#else 408#else
409#define REG "%08lX" 409#define REG "%08lx"
410#define REGS_PER_LINE 8 410#define REGS_PER_LINE 8
411#define LAST_VOLATILE 12 411#define LAST_VOLATILE 12
412#endif 412#endif
@@ -421,7 +421,7 @@ void show_regs(struct pt_regs * regs)
421 regs, regs->trap, print_tainted(), init_utsname()->release); 421 regs, regs->trap, print_tainted(), init_utsname()->release);
422 printk("MSR: "REG" ", regs->msr); 422 printk("MSR: "REG" ", regs->msr);
423 printbits(regs->msr, msr_bits); 423 printbits(regs->msr, msr_bits);
424 printk(" CR: %08lX XER: %08lX\n", regs->ccr, regs->xer); 424 printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer);
425 trap = TRAP(regs); 425 trap = TRAP(regs);
426 if (trap == 0x300 || trap == 0x600) 426 if (trap == 0x300 || trap == 0x600)
427 printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr); 427 printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr);
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 17724fb2067f..f7862224fe85 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -90,21 +90,11 @@ EXPORT_SYMBOL(unregister_die_notifier);
90 * Trap & Exception support 90 * Trap & Exception support
91 */ 91 */
92 92
93static DEFINE_SPINLOCK(die_lock);
94
95int die(const char *str, struct pt_regs *regs, long err)
96{
97 static int die_counter;
98
99 if (debugger(regs))
100 return 1;
101
102 console_verbose();
103 spin_lock_irq(&die_lock);
104 bust_spinlocks(1);
105#ifdef CONFIG_PMAC_BACKLIGHT 93#ifdef CONFIG_PMAC_BACKLIGHT
94static void pmac_backlight_unblank(void)
95{
106 mutex_lock(&pmac_backlight_mutex); 96 mutex_lock(&pmac_backlight_mutex);
107 if (machine_is(powermac) && pmac_backlight) { 97 if (pmac_backlight) {
108 struct backlight_properties *props; 98 struct backlight_properties *props;
109 99
110 props = &pmac_backlight->props; 100 props = &pmac_backlight->props;
@@ -113,26 +103,67 @@ int die(const char *str, struct pt_regs *regs, long err)
113 backlight_update_status(pmac_backlight); 103 backlight_update_status(pmac_backlight);
114 } 104 }
115 mutex_unlock(&pmac_backlight_mutex); 105 mutex_unlock(&pmac_backlight_mutex);
106}
107#else
108static inline void pmac_backlight_unblank(void) { }
116#endif 109#endif
117 printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); 110
111int die(const char *str, struct pt_regs *regs, long err)
112{
113 static struct {
114 spinlock_t lock;
115 u32 lock_owner;
116 int lock_owner_depth;
117 } die = {
118 .lock = __SPIN_LOCK_UNLOCKED(die.lock),
119 .lock_owner = -1,
120 .lock_owner_depth = 0
121 };
122 static int die_counter;
123 unsigned long flags;
124
125 if (debugger(regs))
126 return 1;
127
128 oops_enter();
129
130 if (die.lock_owner != raw_smp_processor_id()) {
131 console_verbose();
132 spin_lock_irqsave(&die.lock, flags);
133 die.lock_owner = smp_processor_id();
134 die.lock_owner_depth = 0;
135 bust_spinlocks(1);
136 if (machine_is(powermac))
137 pmac_backlight_unblank();
138 } else {
139 local_save_flags(flags);
140 }
141
142 if (++die.lock_owner_depth < 3) {
143 printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
118#ifdef CONFIG_PREEMPT 144#ifdef CONFIG_PREEMPT
119 printk("PREEMPT "); 145 printk("PREEMPT ");
120#endif 146#endif
121#ifdef CONFIG_SMP 147#ifdef CONFIG_SMP
122 printk("SMP NR_CPUS=%d ", NR_CPUS); 148 printk("SMP NR_CPUS=%d ", NR_CPUS);
123#endif 149#endif
124#ifdef CONFIG_DEBUG_PAGEALLOC 150#ifdef CONFIG_DEBUG_PAGEALLOC
125 printk("DEBUG_PAGEALLOC "); 151 printk("DEBUG_PAGEALLOC ");
126#endif 152#endif
127#ifdef CONFIG_NUMA 153#ifdef CONFIG_NUMA
128 printk("NUMA "); 154 printk("NUMA ");
129#endif 155#endif
130 printk("%s\n", ppc_md.name ? "" : ppc_md.name); 156 printk("%s\n", ppc_md.name ? ppc_md.name : "");
157
158 print_modules();
159 show_regs(regs);
160 } else {
161 printk("Recursive die() failure, output suppressed\n");
162 }
131 163
132 print_modules();
133 show_regs(regs);
134 bust_spinlocks(0); 164 bust_spinlocks(0);
135 spin_unlock_irq(&die_lock); 165 die.lock_owner = -1;
166 spin_unlock_irqrestore(&die.lock, flags);
136 167
137 if (kexec_should_crash(current) || 168 if (kexec_should_crash(current) ||
138 kexec_sr_activated(smp_processor_id())) 169 kexec_sr_activated(smp_processor_id()))
@@ -145,6 +176,7 @@ int die(const char *str, struct pt_regs *regs, long err)
145 if (panic_on_oops) 176 if (panic_on_oops)
146 panic("Fatal exception"); 177 panic("Fatal exception");
147 178
179 oops_exit();
148 do_exit(err); 180 do_exit(err);
149 181
150 return 0; 182 return 0;
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index a4173906e945..bf9da56942e8 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -297,49 +297,11 @@ int __init via_calibrate_decr(void)
297} 297}
298#endif 298#endif
299 299
300#ifdef CONFIG_PM
301/*
302 * Reset the time after a sleep.
303 */
304static int
305time_sleep_notify(struct pmu_sleep_notifier *self, int when)
306{
307 static unsigned long time_diff;
308 unsigned long flags;
309 unsigned long seq;
310 struct timespec tv;
311
312 switch (when) {
313 case PBOOK_SLEEP_NOW:
314 do {
315 seq = read_seqbegin_irqsave(&xtime_lock, flags);
316 time_diff = xtime.tv_sec - pmac_get_boot_time();
317 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
318 break;
319 case PBOOK_WAKE:
320 tv.tv_sec = pmac_get_boot_time() + time_diff;
321 tv.tv_nsec = 0;
322 do_settimeofday(&tv);
323 break;
324 }
325 return PBOOK_SLEEP_OK;
326}
327
328static struct pmu_sleep_notifier time_sleep_notifier = {
329 time_sleep_notify, SLEEP_LEVEL_MISC,
330};
331#endif /* CONFIG_PM */
332
333/* 300/*
334 * Query the OF and get the decr frequency. 301 * Query the OF and get the decr frequency.
335 */ 302 */
336void __init pmac_calibrate_decr(void) 303void __init pmac_calibrate_decr(void)
337{ 304{
338#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
339 /* XXX why here? */
340 pmu_register_sleep_notifier(&time_sleep_notifier);
341#endif
342
343 generic_calibrate_decr(); 305 generic_calibrate_decr();
344 306
345#ifdef CONFIG_PPC32 307#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 26ca3ffbc1de..e57379d22b61 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -14,6 +14,9 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o
14obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o 14obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
15obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ 15obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
16 16
17# contains only the suspend handler for time
18obj-$(CONFIG_PM) += timer.o
19
17ifeq ($(CONFIG_PPC_MERGE),y) 20ifeq ($(CONFIG_PPC_MERGE),y)
18obj-$(CONFIG_PPC_I8259) += i8259.o 21obj-$(CONFIG_PPC_I8259) += i8259.o
19obj-$(CONFIG_PPC_83xx) += ipic.o 22obj-$(CONFIG_PPC_83xx) += ipic.o
diff --git a/arch/powerpc/sysdev/timer.c b/arch/powerpc/sysdev/timer.c
new file mode 100644
index 000000000000..bdbf8fe520e4
--- /dev/null
+++ b/arch/powerpc/sysdev/timer.c
@@ -0,0 +1,70 @@
1/*
2 * Common code to keep time when machine suspends.
3 *
4 * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
5 *
6 * GPLv2
7 */
8
9#include <linux/time.h>
10#include <asm/rtc.h>
11
12static unsigned long suspend_rtc_time;
13
14/*
15 * Reset the time after a sleep.
16 */
17static int timer_resume(struct sys_device *dev)
18{
19 struct timeval tv;
20 struct timespec ts;
21 struct rtc_time cur_rtc_tm;
22 unsigned long cur_rtc_time, diff;
23
24 /* get current RTC time and convert to seconds */
25 get_rtc_time(&cur_rtc_tm);
26 rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time);
27
28 diff = cur_rtc_time - suspend_rtc_time;
29
30 /* adjust time of day by seconds that elapsed while
31 * we were suspended */
32 do_gettimeofday(&tv);
33 ts.tv_sec = tv.tv_sec + diff;
34 ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
35 do_settimeofday(&ts);
36
37 return 0;
38}
39
40static int timer_suspend(struct sys_device *dev, pm_message_t state)
41{
42 struct rtc_time suspend_rtc_tm;
43 WARN_ON(!ppc_md.get_rtc_time);
44
45 get_rtc_time(&suspend_rtc_tm);
46 rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time);
47
48 return 0;
49}
50
51static struct sysdev_class timer_sysclass = {
52 .resume = timer_resume,
53 .suspend = timer_suspend,
54 set_kset_name("timer"),
55};
56
57static struct sys_device device_timer = {
58 .id = 0,
59 .cls = &timer_sysclass,
60};
61
62static int time_init_device(void)
63{
64 int error = sysdev_class_register(&timer_sysclass);
65 if (!error)
66 error = sysdev_register(&device_timer);
67 return error;
68}
69
70device_initcall(time_init_device);