diff options
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/s390_ext.c | 9 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/time.c | 103 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/vtime.c | 5 |
5 files changed, 40 insertions, 81 deletions
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index c1b383537fec..c49ab8c784d2 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <asm/lowcore.h> | 17 | #include <asm/lowcore.h> |
18 | #include <asm/s390_ext.h> | 18 | #include <asm/s390_ext.h> |
19 | #include <asm/irq_regs.h> | ||
19 | #include <asm/irq.h> | 20 | #include <asm/irq.h> |
20 | 21 | ||
21 | /* | 22 | /* |
@@ -114,26 +115,28 @@ void do_extint(struct pt_regs *regs, unsigned short code) | |||
114 | { | 115 | { |
115 | ext_int_info_t *p; | 116 | ext_int_info_t *p; |
116 | int index; | 117 | int index; |
118 | struct pt_regs *old_regs; | ||
117 | 119 | ||
118 | irq_enter(); | 120 | irq_enter(); |
121 | old_regs = set_irq_regs(regs); | ||
119 | asm volatile ("mc 0,0"); | 122 | asm volatile ("mc 0,0"); |
120 | if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) | 123 | if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) |
121 | /** | 124 | /** |
122 | * Make sure that the i/o interrupt did not "overtake" | 125 | * Make sure that the i/o interrupt did not "overtake" |
123 | * the last HZ timer interrupt. | 126 | * the last HZ timer interrupt. |
124 | */ | 127 | */ |
125 | account_ticks(regs); | 128 | account_ticks(); |
126 | kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; | 129 | kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; |
127 | index = ext_hash(code); | 130 | index = ext_hash(code); |
128 | for (p = ext_int_hash[index]; p; p = p->next) { | 131 | for (p = ext_int_hash[index]; p; p = p->next) { |
129 | if (likely(p->code == code)) { | 132 | if (likely(p->code == code)) { |
130 | if (likely(p->handler)) | 133 | if (likely(p->handler)) |
131 | p->handler(regs, code); | 134 | p->handler(code); |
132 | } | 135 | } |
133 | } | 136 | } |
137 | set_irq_regs(old_regs); | ||
134 | irq_exit(); | 138 | irq_exit(); |
135 | } | 139 | } |
136 | 140 | ||
137 | EXPORT_SYMBOL(register_external_interrupt); | 141 | EXPORT_SYMBOL(register_external_interrupt); |
138 | EXPORT_SYMBOL(unregister_external_interrupt); | 142 | EXPORT_SYMBOL(unregister_external_interrupt); |
139 | |||
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index a8e6199755d4..62822245f9be 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -339,7 +339,7 @@ void machine_power_off_smp(void) | |||
339 | * cpus are handled. | 339 | * cpus are handled. |
340 | */ | 340 | */ |
341 | 341 | ||
342 | void do_ext_call_interrupt(struct pt_regs *regs, __u16 code) | 342 | void do_ext_call_interrupt(__u16 code) |
343 | { | 343 | { |
344 | unsigned long bits; | 344 | unsigned long bits; |
345 | 345 | ||
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 4bf66cc4a267..6cceed4df73e 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -28,12 +28,14 @@ | |||
28 | #include <linux/profile.h> | 28 | #include <linux/profile.h> |
29 | #include <linux/timex.h> | 29 | #include <linux/timex.h> |
30 | #include <linux/notifier.h> | 30 | #include <linux/notifier.h> |
31 | #include <linux/clocksource.h> | ||
31 | 32 | ||
32 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
33 | #include <asm/delay.h> | 34 | #include <asm/delay.h> |
34 | #include <asm/s390_ext.h> | 35 | #include <asm/s390_ext.h> |
35 | #include <asm/div64.h> | 36 | #include <asm/div64.h> |
36 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
38 | #include <asm/irq_regs.h> | ||
37 | #include <asm/timer.h> | 39 | #include <asm/timer.h> |
38 | 40 | ||
39 | /* change this if you have some constant time drift */ | 41 | /* change this if you have some constant time drift */ |
@@ -81,78 +83,10 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime) | |||
81 | xtime->tv_nsec = ((todval * 1000) >> 12); | 83 | xtime->tv_nsec = ((todval * 1000) >> 12); |
82 | } | 84 | } |
83 | 85 | ||
84 | static inline unsigned long do_gettimeoffset(void) | ||
85 | { | ||
86 | __u64 now; | ||
87 | |||
88 | now = (get_clock() - jiffies_timer_cc) >> 12; | ||
89 | now -= (__u64) jiffies * USECS_PER_JIFFY; | ||
90 | return (unsigned long) now; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * This version of gettimeofday has microsecond resolution. | ||
95 | */ | ||
96 | void do_gettimeofday(struct timeval *tv) | ||
97 | { | ||
98 | unsigned long flags; | ||
99 | unsigned long seq; | ||
100 | unsigned long usec, sec; | ||
101 | |||
102 | do { | ||
103 | seq = read_seqbegin_irqsave(&xtime_lock, flags); | ||
104 | |||
105 | sec = xtime.tv_sec; | ||
106 | usec = xtime.tv_nsec / 1000 + do_gettimeoffset(); | ||
107 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); | ||
108 | |||
109 | while (usec >= 1000000) { | ||
110 | usec -= 1000000; | ||
111 | sec++; | ||
112 | } | ||
113 | |||
114 | tv->tv_sec = sec; | ||
115 | tv->tv_usec = usec; | ||
116 | } | ||
117 | |||
118 | EXPORT_SYMBOL(do_gettimeofday); | ||
119 | |||
120 | int do_settimeofday(struct timespec *tv) | ||
121 | { | ||
122 | time_t wtm_sec, sec = tv->tv_sec; | ||
123 | long wtm_nsec, nsec = tv->tv_nsec; | ||
124 | |||
125 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
126 | return -EINVAL; | ||
127 | |||
128 | write_seqlock_irq(&xtime_lock); | ||
129 | /* This is revolting. We need to set the xtime.tv_nsec | ||
130 | * correctly. However, the value in this location is | ||
131 | * is value at the last tick. | ||
132 | * Discover what correction gettimeofday | ||
133 | * would have done, and then undo it! | ||
134 | */ | ||
135 | nsec -= do_gettimeoffset() * 1000; | ||
136 | |||
137 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | ||
138 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | ||
139 | |||
140 | set_normalized_timespec(&xtime, sec, nsec); | ||
141 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
142 | |||
143 | ntp_clear(); | ||
144 | write_sequnlock_irq(&xtime_lock); | ||
145 | clock_was_set(); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | EXPORT_SYMBOL(do_settimeofday); | ||
150 | |||
151 | |||
152 | #ifdef CONFIG_PROFILING | 86 | #ifdef CONFIG_PROFILING |
153 | #define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs) | 87 | #define s390_do_profile() profile_tick(CPU_PROFILING) |
154 | #else | 88 | #else |
155 | #define s390_do_profile(regs) do { ; } while(0) | 89 | #define s390_do_profile() do { ; } while(0) |
156 | #endif /* CONFIG_PROFILING */ | 90 | #endif /* CONFIG_PROFILING */ |
157 | 91 | ||
158 | 92 | ||
@@ -160,7 +94,7 @@ EXPORT_SYMBOL(do_settimeofday); | |||
160 | * timer_interrupt() needs to keep up the real-time clock, | 94 | * timer_interrupt() needs to keep up the real-time clock, |
161 | * as well as call the "do_timer()" routine every clocktick | 95 | * as well as call the "do_timer()" routine every clocktick |
162 | */ | 96 | */ |
163 | void account_ticks(struct pt_regs *regs) | 97 | void account_ticks(void) |
164 | { | 98 | { |
165 | __u64 tmp; | 99 | __u64 tmp; |
166 | __u32 ticks; | 100 | __u32 ticks; |
@@ -221,10 +155,10 @@ void account_ticks(struct pt_regs *regs) | |||
221 | account_tick_vtime(current); | 155 | account_tick_vtime(current); |
222 | #else | 156 | #else |
223 | while (ticks--) | 157 | while (ticks--) |
224 | update_process_times(user_mode(regs)); | 158 | update_process_times(user_mode(get_irq_regs())); |
225 | #endif | 159 | #endif |
226 | 160 | ||
227 | s390_do_profile(regs); | 161 | s390_do_profile(); |
228 | } | 162 | } |
229 | 163 | ||
230 | #ifdef CONFIG_NO_IDLE_HZ | 164 | #ifdef CONFIG_NO_IDLE_HZ |
@@ -285,9 +219,11 @@ static inline void stop_hz_timer(void) | |||
285 | */ | 219 | */ |
286 | static inline void start_hz_timer(void) | 220 | static inline void start_hz_timer(void) |
287 | { | 221 | { |
222 | BUG_ON(!in_interrupt()); | ||
223 | |||
288 | if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) | 224 | if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) |
289 | return; | 225 | return; |
290 | account_ticks(task_pt_regs(current)); | 226 | account_ticks(); |
291 | cpu_clear(smp_processor_id(), nohz_cpu_mask); | 227 | cpu_clear(smp_processor_id(), nohz_cpu_mask); |
292 | } | 228 | } |
293 | 229 | ||
@@ -337,6 +273,22 @@ void init_cpu_timer(void) | |||
337 | 273 | ||
338 | extern void vtime_init(void); | 274 | extern void vtime_init(void); |
339 | 275 | ||
276 | static cycle_t read_tod_clock(void) | ||
277 | { | ||
278 | return get_clock(); | ||
279 | } | ||
280 | |||
281 | static struct clocksource clocksource_tod = { | ||
282 | .name = "tod", | ||
283 | .rating = 100, | ||
284 | .read = read_tod_clock, | ||
285 | .mask = -1ULL, | ||
286 | .mult = 1000, | ||
287 | .shift = 12, | ||
288 | .is_continuous = 1, | ||
289 | }; | ||
290 | |||
291 | |||
340 | /* | 292 | /* |
341 | * Initialize the TOD clock and the CPU timer of | 293 | * Initialize the TOD clock and the CPU timer of |
342 | * the boot cpu. | 294 | * the boot cpu. |
@@ -381,6 +333,9 @@ void __init time_init(void) | |||
381 | &ext_int_info_cc) != 0) | 333 | &ext_int_info_cc) != 0) |
382 | panic("Couldn't request external interrupt 0x1004"); | 334 | panic("Couldn't request external interrupt 0x1004"); |
383 | 335 | ||
336 | if (clocksource_register(&clocksource_tod) != 0) | ||
337 | panic("Could not register TOD clock source"); | ||
338 | |||
384 | init_cpu_timer(); | 339 | init_cpu_timer(); |
385 | 340 | ||
386 | #ifdef CONFIG_NO_IDLE_HZ | 341 | #ifdef CONFIG_NO_IDLE_HZ |
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 3eb4fab048b8..05bf3cc8530a 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -61,7 +61,7 @@ extern pgm_check_handler_t do_dat_exception; | |||
61 | #ifdef CONFIG_PFAULT | 61 | #ifdef CONFIG_PFAULT |
62 | extern int pfault_init(void); | 62 | extern int pfault_init(void); |
63 | extern void pfault_fini(void); | 63 | extern void pfault_fini(void); |
64 | extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code); | 64 | extern void pfault_interrupt(__u16 error_code); |
65 | static ext_int_info_t ext_int_pfault; | 65 | static ext_int_info_t ext_int_pfault; |
66 | #endif | 66 | #endif |
67 | extern pgm_check_handler_t do_monitor_call; | 67 | extern pgm_check_handler_t do_monitor_call; |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 2306cd83fca1..1d7d3938b2b1 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <asm/s390_ext.h> | 23 | #include <asm/s390_ext.h> |
24 | #include <asm/timer.h> | 24 | #include <asm/timer.h> |
25 | #include <asm/irq_regs.h> | ||
25 | 26 | ||
26 | static ext_int_info_t ext_int_info_timer; | 27 | static ext_int_info_t ext_int_info_timer; |
27 | DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); | 28 | DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); |
@@ -241,7 +242,7 @@ static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs) | |||
241 | /* | 242 | /* |
242 | * Handler for the virtual CPU timer. | 243 | * Handler for the virtual CPU timer. |
243 | */ | 244 | */ |
244 | static void do_cpu_timer_interrupt(struct pt_regs *regs, __u16 error_code) | 245 | static void do_cpu_timer_interrupt(__u16 error_code) |
245 | { | 246 | { |
246 | int cpu; | 247 | int cpu; |
247 | __u64 next, delta; | 248 | __u64 next, delta; |
@@ -274,7 +275,7 @@ static void do_cpu_timer_interrupt(struct pt_regs *regs, __u16 error_code) | |||
274 | list_move_tail(&event->entry, &cb_list); | 275 | list_move_tail(&event->entry, &cb_list); |
275 | } | 276 | } |
276 | spin_unlock(&vt_list->lock); | 277 | spin_unlock(&vt_list->lock); |
277 | do_callbacks(&cb_list, regs); | 278 | do_callbacks(&cb_list, get_irq_regs()); |
278 | 279 | ||
279 | /* next event is first in list */ | 280 | /* next event is first in list */ |
280 | spin_lock(&vt_list->lock); | 281 | spin_lock(&vt_list->lock); |