From 057c5cb35ece6ae3a4c2cb849f3948c5ad6add32 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 19 Feb 2008 15:29:25 +0100 Subject: [S390] Let NR_CPUS default to 32/64 on s390/s390x. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 92a4f7b4323..b21444b681b 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 -- cgit v1.2.3 From 11ab244c9faead91683a12e4cb10d26b279bb4aa Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 19 Feb 2008 15:29:26 +0100 Subject: [S390] Make sure enabled wait psw is loaded in default_idle. If both NO_IDLE_HZ and VIRT_TIMER are disabled default_idle won't load an enabled wait psw and busy loop instead. This is because the idle_chain is empty and the return value of atomic_notifier_call_chain will be NOTIFY_DONE, which causes default_idle to return instead of loading an enabled wait psw. Fix this by calling __atomic_notifier_call_chain instead and add proper return value handling. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/process.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index a6a4729e0e9..1c59ec161cf 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; } -- cgit v1.2.3 From 591bb4f637e48950d35e2ca01e6b962c519d96e5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 19 Feb 2008 15:29:29 +0100 Subject: [S390] Initialize per cpu lowcores on cpu hotplug. Just copy the first 512 read-only bytes of the current cpu lowcore if a new cpu gets onlined. The rest is zeroed out and must be explicitly initialized. Current code just copies the entire lowcore and initializes the needed fields. This should reveal bugs in future enhancements quite early. Also when the lowcore of the first cpu is replaced this is now done atomically (no interrupts, no machine checks). Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/smp.c | 53 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 15 deletions(-) (limited to 'arch') diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 85060659fb1..818bd09c026 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); -- cgit v1.2.3 From 06cb92ffe418c4a9d5a70c5dff4f283e8e8df6e4 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 19 Feb 2008 15:29:31 +0100 Subject: [S390] etr: fix compile error on !SMP Since a5fbb6d1064be885d2a6b82f625186753cf74848 "KVM: fix !SMP build error" smp_call_function isn't a define anymore that folds into nothing but a define that calls up_smp_call_function with all parameters. Hence we cannot #ifdef out the unused code anymore... This seems to be the preferred method, so do this for s390 as well. arch/s390/kernel/time.c: In function 'etr_sync_clock': arch/s390/kernel/time.c:825: error: 'clock_sync_cpu_start' undeclared arch/s390/kernel/time.c:862: error: 'clock_sync_cpu_end' undeclared Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/time.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch') diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 3bbac1293be..76a5dd1b4ce 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 -- cgit v1.2.3 From d5b02b3ff1d9a2e1074f559c84ed378cfa6fc3c0 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 19 Feb 2008 15:29:34 +0100 Subject: [S390] Fix futex_atomic_cmpxchg_std inline assembly. Add missing exception table entry so that the kernel can handle proctection exceptions as well on the cs instruction. Currently only specification exceptions are handled correctly. The missing entry allows user space to crash the kernel. Cc: stable Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/lib/uaccess_std.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c index 28c4500a58d..d2ffbadb51a 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" ); -- cgit v1.2.3