diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 12:49:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 12:49:09 -0400 |
commit | e017507f37d5cb8b541df165a824958bc333bec3 (patch) | |
tree | 87ab0986474486623d9957efda9f3f9ea3b14069 /arch/s390/kernel/smp.c | |
parent | 759e2a253aaefbb6da9253d517a5a8fe1801ce0f (diff) | |
parent | 27f6b416626a240e1b46f646d2e0c5266f4eac95 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 changes from Martin Schwidefsky:
"No new functions, a few changes to make the code more robust, some
cleanups and bug fixes."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (21 commits)
s390/vtimer: rework virtual timer interface
s390/dis: Add the servc instruction to the disassembler.
s390/comments: unify copyright messages and remove file names
s390/lgr: Add init check to lgr_info_log()
s390/cpu init: use __get_cpu_var instead of per_cpu
s390/idle: reduce size of s390_idle_data structure
s390/idle: fix sequence handling vs cpu hotplug
s390/ap: resend enable adapter interrupt request.
s390/hypfs: Add missing get_next_ino()
s390/dasd: add shutdown action
s390/ipl: Fix ipib handling for "dumpreipl" shutdown action
s390/smp: make absolute lowcore / cpu restart parameter accesses more robust
s390/vmlogrdr: cleanup driver attribute usage
s390/vmlogrdr: cleanup device attribute usage
s390/ccwgroup: remove unused ccwgroup_device member
s390/cio/chp: cleanup attribute usage
s390/sigp: use sigp order code defines in assembly code
s390/smp: use sigp cpu status definitions
s390/smp/kvm: unifiy sigp definitions
s390/smp: remove redundant check
...
Diffstat (limited to 'arch/s390/kernel/smp.c')
-rw-r--r-- | arch/s390/kernel/smp.c | 114 |
1 files changed, 43 insertions, 71 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 8dca9c248ac7..720fda1620f2 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SMP related functions | 2 | * SMP related functions |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 1999,2012 | 4 | * Copyright IBM Corp. 1999, 2012 |
5 | * Author(s): Denis Joseph Barrow, | 5 | * Author(s): Denis Joseph Barrow, |
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com>, | 6 | * Martin Schwidefsky <schwidefsky@de.ibm.com>, |
7 | * Heiko Carstens <heiko.carstens@de.ibm.com>, | 7 | * Heiko Carstens <heiko.carstens@de.ibm.com>, |
@@ -38,40 +38,16 @@ | |||
38 | #include <asm/setup.h> | 38 | #include <asm/setup.h> |
39 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
40 | #include <asm/tlbflush.h> | 40 | #include <asm/tlbflush.h> |
41 | #include <asm/timer.h> | 41 | #include <asm/vtimer.h> |
42 | #include <asm/lowcore.h> | 42 | #include <asm/lowcore.h> |
43 | #include <asm/sclp.h> | 43 | #include <asm/sclp.h> |
44 | #include <asm/vdso.h> | 44 | #include <asm/vdso.h> |
45 | #include <asm/debug.h> | 45 | #include <asm/debug.h> |
46 | #include <asm/os_info.h> | 46 | #include <asm/os_info.h> |
47 | #include <asm/sigp.h> | ||
47 | #include "entry.h" | 48 | #include "entry.h" |
48 | 49 | ||
49 | enum { | 50 | enum { |
50 | sigp_sense = 1, | ||
51 | sigp_external_call = 2, | ||
52 | sigp_emergency_signal = 3, | ||
53 | sigp_start = 4, | ||
54 | sigp_stop = 5, | ||
55 | sigp_restart = 6, | ||
56 | sigp_stop_and_store_status = 9, | ||
57 | sigp_initial_cpu_reset = 11, | ||
58 | sigp_cpu_reset = 12, | ||
59 | sigp_set_prefix = 13, | ||
60 | sigp_store_status_at_address = 14, | ||
61 | sigp_store_extended_status_at_address = 15, | ||
62 | sigp_set_architecture = 18, | ||
63 | sigp_conditional_emergency_signal = 19, | ||
64 | sigp_sense_running = 21, | ||
65 | }; | ||
66 | |||
67 | enum { | ||
68 | sigp_order_code_accepted = 0, | ||
69 | sigp_status_stored = 1, | ||
70 | sigp_busy = 2, | ||
71 | sigp_not_operational = 3, | ||
72 | }; | ||
73 | |||
74 | enum { | ||
75 | ec_schedule = 0, | 51 | ec_schedule = 0, |
76 | ec_call_function, | 52 | ec_call_function, |
77 | ec_call_function_single, | 53 | ec_call_function_single, |
@@ -124,7 +100,7 @@ static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status) | |||
124 | 100 | ||
125 | while (1) { | 101 | while (1) { |
126 | cc = __pcpu_sigp(addr, order, parm, status); | 102 | cc = __pcpu_sigp(addr, order, parm, status); |
127 | if (cc != sigp_busy) | 103 | if (cc != SIGP_CC_BUSY) |
128 | return cc; | 104 | return cc; |
129 | cpu_relax(); | 105 | cpu_relax(); |
130 | } | 106 | } |
@@ -136,7 +112,7 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm) | |||
136 | 112 | ||
137 | for (retry = 0; ; retry++) { | 113 | for (retry = 0; ; retry++) { |
138 | cc = __pcpu_sigp(pcpu->address, order, parm, &pcpu->status); | 114 | cc = __pcpu_sigp(pcpu->address, order, parm, &pcpu->status); |
139 | if (cc != sigp_busy) | 115 | if (cc != SIGP_CC_BUSY) |
140 | break; | 116 | break; |
141 | if (retry >= 3) | 117 | if (retry >= 3) |
142 | udelay(10); | 118 | udelay(10); |
@@ -146,20 +122,19 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm) | |||
146 | 122 | ||
147 | static inline int pcpu_stopped(struct pcpu *pcpu) | 123 | static inline int pcpu_stopped(struct pcpu *pcpu) |
148 | { | 124 | { |
149 | if (__pcpu_sigp(pcpu->address, sigp_sense, | 125 | if (__pcpu_sigp(pcpu->address, SIGP_SENSE, |
150 | 0, &pcpu->status) != sigp_status_stored) | 126 | 0, &pcpu->status) != SIGP_CC_STATUS_STORED) |
151 | return 0; | 127 | return 0; |
152 | /* Check for stopped and check stop state */ | 128 | return !!(pcpu->status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED)); |
153 | return !!(pcpu->status & 0x50); | ||
154 | } | 129 | } |
155 | 130 | ||
156 | static inline int pcpu_running(struct pcpu *pcpu) | 131 | static inline int pcpu_running(struct pcpu *pcpu) |
157 | { | 132 | { |
158 | if (__pcpu_sigp(pcpu->address, sigp_sense_running, | 133 | if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING, |
159 | 0, &pcpu->status) != sigp_status_stored) | 134 | 0, &pcpu->status) != SIGP_CC_STATUS_STORED) |
160 | return 1; | 135 | return 1; |
161 | /* Check for running status */ | 136 | /* Status stored condition code is equivalent to cpu not running. */ |
162 | return !(pcpu->status & 0x400); | 137 | return 0; |
163 | } | 138 | } |
164 | 139 | ||
165 | /* | 140 | /* |
@@ -181,7 +156,7 @@ static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit) | |||
181 | 156 | ||
182 | set_bit(ec_bit, &pcpu->ec_mask); | 157 | set_bit(ec_bit, &pcpu->ec_mask); |
183 | order = pcpu_running(pcpu) ? | 158 | order = pcpu_running(pcpu) ? |
184 | sigp_external_call : sigp_emergency_signal; | 159 | SIGP_EXTERNAL_CALL : SIGP_EMERGENCY_SIGNAL; |
185 | pcpu_sigp_retry(pcpu, order, 0); | 160 | pcpu_sigp_retry(pcpu, order, 0); |
186 | } | 161 | } |
187 | 162 | ||
@@ -214,7 +189,7 @@ static int __cpuinit pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) | |||
214 | goto out; | 189 | goto out; |
215 | #endif | 190 | #endif |
216 | lowcore_ptr[cpu] = lc; | 191 | lowcore_ptr[cpu] = lc; |
217 | pcpu_sigp_retry(pcpu, sigp_set_prefix, (u32)(unsigned long) lc); | 192 | pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, (u32)(unsigned long) lc); |
218 | return 0; | 193 | return 0; |
219 | out: | 194 | out: |
220 | if (pcpu != &pcpu_devices[0]) { | 195 | if (pcpu != &pcpu_devices[0]) { |
@@ -229,7 +204,7 @@ out: | |||
229 | 204 | ||
230 | static void pcpu_free_lowcore(struct pcpu *pcpu) | 205 | static void pcpu_free_lowcore(struct pcpu *pcpu) |
231 | { | 206 | { |
232 | pcpu_sigp_retry(pcpu, sigp_set_prefix, 0); | 207 | pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0); |
233 | lowcore_ptr[pcpu - pcpu_devices] = NULL; | 208 | lowcore_ptr[pcpu - pcpu_devices] = NULL; |
234 | #ifndef CONFIG_64BIT | 209 | #ifndef CONFIG_64BIT |
235 | if (MACHINE_HAS_IEEE) { | 210 | if (MACHINE_HAS_IEEE) { |
@@ -288,7 +263,7 @@ static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data) | |||
288 | lc->restart_fn = (unsigned long) func; | 263 | lc->restart_fn = (unsigned long) func; |
289 | lc->restart_data = (unsigned long) data; | 264 | lc->restart_data = (unsigned long) data; |
290 | lc->restart_source = -1UL; | 265 | lc->restart_source = -1UL; |
291 | pcpu_sigp_retry(pcpu, sigp_restart, 0); | 266 | pcpu_sigp_retry(pcpu, SIGP_RESTART, 0); |
292 | } | 267 | } |
293 | 268 | ||
294 | /* | 269 | /* |
@@ -298,26 +273,26 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), | |||
298 | void *data, unsigned long stack) | 273 | void *data, unsigned long stack) |
299 | { | 274 | { |
300 | struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices]; | 275 | struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices]; |
301 | struct { | 276 | unsigned long source_cpu = stap(); |
302 | unsigned long stack; | ||
303 | void *func; | ||
304 | void *data; | ||
305 | unsigned long source; | ||
306 | } restart = { stack, func, data, stap() }; | ||
307 | 277 | ||
308 | __load_psw_mask(psw_kernel_bits); | 278 | __load_psw_mask(psw_kernel_bits); |
309 | if (pcpu->address == restart.source) | 279 | if (pcpu->address == source_cpu) |
310 | func(data); /* should not return */ | 280 | func(data); /* should not return */ |
311 | /* Stop target cpu (if func returns this stops the current cpu). */ | 281 | /* Stop target cpu (if func returns this stops the current cpu). */ |
312 | pcpu_sigp_retry(pcpu, sigp_stop, 0); | 282 | pcpu_sigp_retry(pcpu, SIGP_STOP, 0); |
313 | /* Restart func on the target cpu and stop the current cpu. */ | 283 | /* Restart func on the target cpu and stop the current cpu. */ |
314 | memcpy_absolute(&lc->restart_stack, &restart, sizeof(restart)); | 284 | mem_assign_absolute(lc->restart_stack, stack); |
285 | mem_assign_absolute(lc->restart_fn, (unsigned long) func); | ||
286 | mem_assign_absolute(lc->restart_data, (unsigned long) data); | ||
287 | mem_assign_absolute(lc->restart_source, source_cpu); | ||
315 | asm volatile( | 288 | asm volatile( |
316 | "0: sigp 0,%0,6 # sigp restart to target cpu\n" | 289 | "0: sigp 0,%0,%2 # sigp restart to target cpu\n" |
317 | " brc 2,0b # busy, try again\n" | 290 | " brc 2,0b # busy, try again\n" |
318 | "1: sigp 0,%1,5 # sigp stop to current cpu\n" | 291 | "1: sigp 0,%1,%3 # sigp stop to current cpu\n" |
319 | " brc 2,1b # busy, try again\n" | 292 | " brc 2,1b # busy, try again\n" |
320 | : : "d" (pcpu->address), "d" (restart.source) : "0", "1", "cc"); | 293 | : : "d" (pcpu->address), "d" (source_cpu), |
294 | "K" (SIGP_RESTART), "K" (SIGP_STOP) | ||
295 | : "0", "1", "cc"); | ||
321 | for (;;) ; | 296 | for (;;) ; |
322 | } | 297 | } |
323 | 298 | ||
@@ -388,8 +363,8 @@ void smp_emergency_stop(cpumask_t *cpumask) | |||
388 | for_each_cpu(cpu, cpumask) { | 363 | for_each_cpu(cpu, cpumask) { |
389 | struct pcpu *pcpu = pcpu_devices + cpu; | 364 | struct pcpu *pcpu = pcpu_devices + cpu; |
390 | set_bit(ec_stop_cpu, &pcpu->ec_mask); | 365 | set_bit(ec_stop_cpu, &pcpu->ec_mask); |
391 | while (__pcpu_sigp(pcpu->address, sigp_emergency_signal, | 366 | while (__pcpu_sigp(pcpu->address, SIGP_EMERGENCY_SIGNAL, |
392 | 0, NULL) == sigp_busy && | 367 | 0, NULL) == SIGP_CC_BUSY && |
393 | get_clock() < end) | 368 | get_clock() < end) |
394 | cpu_relax(); | 369 | cpu_relax(); |
395 | } | 370 | } |
@@ -425,7 +400,7 @@ void smp_send_stop(void) | |||
425 | /* stop all processors */ | 400 | /* stop all processors */ |
426 | for_each_cpu(cpu, &cpumask) { | 401 | for_each_cpu(cpu, &cpumask) { |
427 | struct pcpu *pcpu = pcpu_devices + cpu; | 402 | struct pcpu *pcpu = pcpu_devices + cpu; |
428 | pcpu_sigp_retry(pcpu, sigp_stop, 0); | 403 | pcpu_sigp_retry(pcpu, SIGP_STOP, 0); |
429 | while (!pcpu_stopped(pcpu)) | 404 | while (!pcpu_stopped(pcpu)) |
430 | cpu_relax(); | 405 | cpu_relax(); |
431 | } | 406 | } |
@@ -436,7 +411,7 @@ void smp_send_stop(void) | |||
436 | */ | 411 | */ |
437 | void smp_stop_cpu(void) | 412 | void smp_stop_cpu(void) |
438 | { | 413 | { |
439 | pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0); | 414 | pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0); |
440 | for (;;) ; | 415 | for (;;) ; |
441 | } | 416 | } |
442 | 417 | ||
@@ -590,7 +565,7 @@ static void __init smp_get_save_area(int cpu, u16 address) | |||
590 | } | 565 | } |
591 | #endif | 566 | #endif |
592 | /* Get the registers of a non-boot cpu. */ | 567 | /* Get the registers of a non-boot cpu. */ |
593 | __pcpu_sigp_relax(address, sigp_stop_and_store_status, 0, NULL); | 568 | __pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL); |
594 | memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area)); | 569 | memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area)); |
595 | } | 570 | } |
596 | 571 | ||
@@ -599,8 +574,8 @@ int smp_store_status(int cpu) | |||
599 | struct pcpu *pcpu; | 574 | struct pcpu *pcpu; |
600 | 575 | ||
601 | pcpu = pcpu_devices + cpu; | 576 | pcpu = pcpu_devices + cpu; |
602 | if (__pcpu_sigp_relax(pcpu->address, sigp_stop_and_store_status, | 577 | if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS, |
603 | 0, NULL) != sigp_order_code_accepted) | 578 | 0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED) |
604 | return -EIO; | 579 | return -EIO; |
605 | return 0; | 580 | return 0; |
606 | } | 581 | } |
@@ -621,8 +596,8 @@ static struct sclp_cpu_info *smp_get_cpu_info(void) | |||
621 | if (info && (use_sigp_detection || sclp_get_cpu_info(info))) { | 596 | if (info && (use_sigp_detection || sclp_get_cpu_info(info))) { |
622 | use_sigp_detection = 1; | 597 | use_sigp_detection = 1; |
623 | for (address = 0; address <= MAX_CPU_ADDRESS; address++) { | 598 | for (address = 0; address <= MAX_CPU_ADDRESS; address++) { |
624 | if (__pcpu_sigp_relax(address, sigp_sense, 0, NULL) == | 599 | if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) == |
625 | sigp_not_operational) | 600 | SIGP_CC_NOT_OPERATIONAL) |
626 | continue; | 601 | continue; |
627 | info->cpu[info->configured].address = address; | 602 | info->cpu[info->configured].address = address; |
628 | info->configured++; | 603 | info->configured++; |
@@ -732,8 +707,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle) | |||
732 | pcpu = pcpu_devices + cpu; | 707 | pcpu = pcpu_devices + cpu; |
733 | if (pcpu->state != CPU_STATE_CONFIGURED) | 708 | if (pcpu->state != CPU_STATE_CONFIGURED) |
734 | return -EIO; | 709 | return -EIO; |
735 | if (pcpu_sigp_retry(pcpu, sigp_initial_cpu_reset, 0) != | 710 | if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) != |
736 | sigp_order_code_accepted) | 711 | SIGP_CC_ORDER_CODE_ACCEPTED) |
737 | return -EIO; | 712 | return -EIO; |
738 | 713 | ||
739 | rc = pcpu_alloc_lowcore(pcpu, cpu); | 714 | rc = pcpu_alloc_lowcore(pcpu, cpu); |
@@ -793,7 +768,7 @@ void __cpu_die(unsigned int cpu) | |||
793 | void __noreturn cpu_die(void) | 768 | void __noreturn cpu_die(void) |
794 | { | 769 | { |
795 | idle_task_exit(); | 770 | idle_task_exit(); |
796 | pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0); | 771 | pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0); |
797 | for (;;) ; | 772 | for (;;) ; |
798 | } | 773 | } |
799 | 774 | ||
@@ -940,7 +915,7 @@ static ssize_t show_idle_count(struct device *dev, | |||
940 | do { | 915 | do { |
941 | sequence = ACCESS_ONCE(idle->sequence); | 916 | sequence = ACCESS_ONCE(idle->sequence); |
942 | idle_count = ACCESS_ONCE(idle->idle_count); | 917 | idle_count = ACCESS_ONCE(idle->idle_count); |
943 | if (ACCESS_ONCE(idle->idle_enter)) | 918 | if (ACCESS_ONCE(idle->clock_idle_enter)) |
944 | idle_count++; | 919 | idle_count++; |
945 | } while ((sequence & 1) || (idle->sequence != sequence)); | 920 | } while ((sequence & 1) || (idle->sequence != sequence)); |
946 | return sprintf(buf, "%llu\n", idle_count); | 921 | return sprintf(buf, "%llu\n", idle_count); |
@@ -958,8 +933,8 @@ static ssize_t show_idle_time(struct device *dev, | |||
958 | now = get_clock(); | 933 | now = get_clock(); |
959 | sequence = ACCESS_ONCE(idle->sequence); | 934 | sequence = ACCESS_ONCE(idle->sequence); |
960 | idle_time = ACCESS_ONCE(idle->idle_time); | 935 | idle_time = ACCESS_ONCE(idle->idle_time); |
961 | idle_enter = ACCESS_ONCE(idle->idle_enter); | 936 | idle_enter = ACCESS_ONCE(idle->clock_idle_enter); |
962 | idle_exit = ACCESS_ONCE(idle->idle_exit); | 937 | idle_exit = ACCESS_ONCE(idle->clock_idle_exit); |
963 | } while ((sequence & 1) || (idle->sequence != sequence)); | 938 | } while ((sequence & 1) || (idle->sequence != sequence)); |
964 | idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; | 939 | idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; |
965 | return sprintf(buf, "%llu\n", idle_time >> 12); | 940 | return sprintf(buf, "%llu\n", idle_time >> 12); |
@@ -982,14 +957,11 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self, | |||
982 | unsigned int cpu = (unsigned int)(long)hcpu; | 957 | unsigned int cpu = (unsigned int)(long)hcpu; |
983 | struct cpu *c = &pcpu_devices[cpu].cpu; | 958 | struct cpu *c = &pcpu_devices[cpu].cpu; |
984 | struct device *s = &c->dev; | 959 | struct device *s = &c->dev; |
985 | struct s390_idle_data *idle; | ||
986 | int err = 0; | 960 | int err = 0; |
987 | 961 | ||
988 | switch (action) { | 962 | switch (action) { |
989 | case CPU_ONLINE: | 963 | case CPU_ONLINE: |
990 | case CPU_ONLINE_FROZEN: | 964 | case CPU_ONLINE_FROZEN: |
991 | idle = &per_cpu(s390_idle, cpu); | ||
992 | memset(idle, 0, sizeof(struct s390_idle_data)); | ||
993 | err = sysfs_create_group(&s->kobj, &cpu_online_attr_group); | 965 | err = sysfs_create_group(&s->kobj, &cpu_online_attr_group); |
994 | break; | 966 | break; |
995 | case CPU_DEAD: | 967 | case CPU_DEAD: |