diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/Kconfig | 3 | ||||
-rw-r--r-- | arch/s390/kernel/process.c | 15 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 53 | ||||
-rw-r--r-- | arch/s390/kernel/time.c | 2 | ||||
-rw-r--r-- | arch/s390/lib/uaccess_std.c | 8 |
5 files changed, 53 insertions, 28 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 92a4f7b4323a..b21444b681b6 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -100,7 +100,8 @@ config NR_CPUS int "Maximum number of CPUs (2-64)" range 2 64 depends on SMP - default "32" + default "32" if !64BIT + default "64" if 64BIT help This allows you to specify the maximum number of CPUs which this kernel will support. The maximum supported value is 64 and the diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index a6a4729e0e94..1c59ec161cf8 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -114,24 +114,27 @@ extern void s390_handle_mcck(void); static void default_idle(void) { int cpu, rc; + int nr_calls = 0; + void *hcpu; #ifdef CONFIG_SMP struct s390_idle_data *idle; #endif /* CPU is going idle. */ cpu = smp_processor_id(); - + hcpu = (void *)(long)cpu; local_irq_disable(); if (need_resched()) { local_irq_enable(); return; } - rc = atomic_notifier_call_chain(&idle_chain, - S390_CPU_IDLE, (void *)(long) cpu); - if (rc != NOTIFY_OK && rc != NOTIFY_DONE) - BUG(); - if (rc != NOTIFY_OK) { + rc = __atomic_notifier_call_chain(&idle_chain, S390_CPU_IDLE, hcpu, -1, + &nr_calls); + if (rc == NOTIFY_BAD) { + nr_calls--; + __atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, + hcpu, nr_calls, NULL); local_irq_enable(); return; } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 85060659fb12..818bd09c0260 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -626,13 +626,17 @@ static int __cpuinit smp_alloc_lowcore(int cpu) if (!lowcore) return -ENOMEM; async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); - if (!async_stack) - goto out_async_stack; panic_stack = __get_free_page(GFP_KERNEL); - if (!panic_stack) - goto out_panic_stack; - - *lowcore = S390_lowcore; + if (!panic_stack || !async_stack) + goto out; + /* + * Only need to copy the first 512 bytes from address 0. But since + * the compiler emits a warning if src == NULL for memcpy use copy_page + * instead. Copies more than needed but this code is not performance + * critical. + */ + copy_page(lowcore, &S390_lowcore); + memset((void *)lowcore + 512, 0, sizeof(*lowcore) - 512); lowcore->async_stack = async_stack + ASYNC_SIZE; lowcore->panic_stack = panic_stack + PAGE_SIZE; @@ -653,9 +657,8 @@ static int __cpuinit smp_alloc_lowcore(int cpu) out_save_area: free_page(panic_stack); #endif -out_panic_stack: +out: free_pages(async_stack, ASYNC_ORDER); -out_async_stack: free_pages((unsigned long) lowcore, lc_order); return -ENOMEM; } @@ -719,8 +722,8 @@ int __cpuinit __cpu_up(unsigned int cpu) cpu_lowcore->percpu_offset = __per_cpu_offset[cpu]; cpu_lowcore->current_task = (unsigned long) idle; cpu_lowcore->cpu_data.cpu_nr = cpu; - cpu_lowcore->softirq_pending = 0; - cpu_lowcore->ext_call_fast = 0; + cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce; + cpu_lowcore->ipl_device = S390_lowcore.ipl_device; eieio(); while (signal_processor(cpu, sigp_restart) == sigp_busy) @@ -797,23 +800,43 @@ void cpu_die(void) void __init smp_prepare_cpus(unsigned int max_cpus) { +#ifndef CONFIG_64BIT + unsigned long save_area = 0; +#endif + unsigned long async_stack, panic_stack; + struct _lowcore *lowcore; unsigned int cpu; + int lc_order; smp_detect_cpus(); /* request the 0x1201 emergency signal external interrupt */ if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0) panic("Couldn't request external interrupt 0x1201"); - memset(lowcore_ptr, 0, sizeof(lowcore_ptr)); print_cpu_info(&S390_lowcore.cpu_data); - smp_alloc_lowcore(smp_processor_id()); + /* Reallocate current lowcore, but keep its contents. */ + lc_order = sizeof(long) == 8 ? 1 : 0; + lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order); + panic_stack = __get_free_page(GFP_KERNEL); + async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); #ifndef CONFIG_64BIT if (MACHINE_HAS_IEEE) - ctl_set_bit(14, 29); /* enable extended save area */ + save_area = get_zeroed_page(GFP_KERNEL); #endif - set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]); - + local_irq_disable(); + local_mcck_disable(); + lowcore_ptr[smp_processor_id()] = lowcore; + *lowcore = S390_lowcore; + lowcore->panic_stack = panic_stack + PAGE_SIZE; + lowcore->async_stack = async_stack + ASYNC_SIZE; +#ifndef CONFIG_64BIT + if (MACHINE_HAS_IEEE) + lowcore->extended_save_area_addr = (u32) save_area; +#endif + set_prefix((u32)(unsigned long) lowcore); + local_mcck_enable(); + local_irq_enable(); for_each_possible_cpu(cpu) if (cpu != smp_processor_id()) smp_create_idle(cpu); diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 3bbac1293be4..76a5dd1b4ce9 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -744,7 +744,6 @@ static void etr_adjust_time(unsigned long long clock, unsigned long long delay) } } -#ifdef CONFIG_SMP static void etr_sync_cpu_start(void *dummy) { int *in_sync = dummy; @@ -777,7 +776,6 @@ static void etr_sync_cpu_start(void *dummy) static void etr_sync_cpu_end(void *dummy) { } -#endif /* CONFIG_SMP */ /* * Sync the TOD clock using the port refered to by aibp. This port diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c index 28c4500a58d0..d2ffbadb51a7 100644 --- a/arch/s390/lib/uaccess_std.c +++ b/arch/s390/lib/uaccess_std.c @@ -293,10 +293,10 @@ int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval) asm volatile( " sacf 256\n" - " cs %1,%4,0(%5)\n" - "0: lr %0,%1\n" - "1: sacf 0\n" - EX_TABLE(0b,1b) + "0: cs %1,%4,0(%5)\n" + "1: lr %0,%1\n" + "2: sacf 0\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) : "=d" (ret), "+d" (oldval), "=m" (*uaddr) : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) : "cc", "memory" ); |