aboutsummaryrefslogtreecommitdiff
path: root/arch/s390/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/smp.c')
-rw-r--r--arch/s390/kernel/smp.c74
1 files changed, 45 insertions, 29 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index fd8e3111a4e8..56c16876b919 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -49,6 +49,7 @@
#include <asm/sclp.h>
#include <asm/cputime.h>
#include <asm/vdso.h>
+#include <asm/cpu.h>
#include "entry.h"
static struct task_struct *current_set[NR_CPUS];
@@ -70,6 +71,23 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices);
static void smp_ext_bitcall(int, ec_bit_sig);
+static int cpu_stopped(int cpu)
+{
+ __u32 status;
+
+ switch (signal_processor_ps(&status, 0, cpu, sigp_sense)) {
+ case sigp_order_code_accepted:
+ case sigp_status_stored:
+ /* Check for stopped and check stop state */
+ if (status & 0x50)
+ return 1;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
void smp_send_stop(void)
{
int cpu, rc;
@@ -86,7 +104,7 @@ void smp_send_stop(void)
rc = signal_processor(cpu, sigp_stop);
} while (rc == sigp_busy);
- while (!smp_cpu_not_running(cpu))
+ while (!cpu_stopped(cpu))
cpu_relax();
}
}
@@ -269,19 +287,6 @@ static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { }
#endif /* CONFIG_ZFCPDUMP */
-static int cpu_stopped(int cpu)
-{
- __u32 status;
-
- /* Check for stopped state */
- if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
- sigp_status_stored) {
- if (status & 0x40)
- return 1;
- }
- return 0;
-}
-
static int cpu_known(int cpu_id)
{
int cpu;
@@ -300,7 +305,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail)
logical_cpu = cpumask_first(&avail);
if (logical_cpu >= nr_cpu_ids)
return 0;
- for (cpu_id = 0; cpu_id <= 65535; cpu_id++) {
+ for (cpu_id = 0; cpu_id <= MAX_CPU_ADDRESS; cpu_id++) {
if (cpu_known(cpu_id))
continue;
__cpu_logical_map[logical_cpu] = cpu_id;
@@ -379,7 +384,7 @@ static void __init smp_detect_cpus(void)
/* Use sigp detection algorithm if sclp doesn't work. */
if (sclp_get_cpu_info(info)) {
smp_use_sigp_detection = 1;
- for (cpu = 0; cpu <= 65535; cpu++) {
+ for (cpu = 0; cpu <= MAX_CPU_ADDRESS; cpu++) {
if (cpu == boot_cpu_addr)
continue;
__cpu_logical_map[CPU_INIT_NO] = cpu;
@@ -635,7 +640,7 @@ int __cpu_disable(void)
void __cpu_die(unsigned int cpu)
{
/* Wait until target cpu is down */
- while (!smp_cpu_not_running(cpu))
+ while (!cpu_stopped(cpu))
cpu_relax();
smp_free_lowcore(cpu);
pr_info("Processor %d stopped\n", cpu);
@@ -687,13 +692,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
#ifndef CONFIG_64BIT
if (MACHINE_HAS_IEEE)
lowcore->extended_save_area_addr = (u32) save_area;
-#else
- if (vdso_alloc_per_cpu(smp_processor_id(), lowcore))
- BUG();
#endif
set_prefix((u32)(unsigned long) lowcore);
local_mcck_enable();
local_irq_enable();
+#ifdef CONFIG_64BIT
+ if (vdso_alloc_per_cpu(smp_processor_id(), &S390_lowcore))
+ BUG();
+#endif
for_each_possible_cpu(cpu)
if (cpu != smp_processor_id())
smp_create_idle(cpu);
@@ -856,13 +862,20 @@ static ssize_t show_idle_count(struct sys_device *dev,
{
struct s390_idle_data *idle;
unsigned long long idle_count;
+ unsigned int sequence;
idle = &per_cpu(s390_idle, dev->id);
- spin_lock(&idle->lock);
+repeat:
+ sequence = idle->sequence;
+ smp_rmb();
+ if (sequence & 1)
+ goto repeat;
idle_count = idle->idle_count;
if (idle->idle_enter)
idle_count++;
- spin_unlock(&idle->lock);
+ smp_rmb();
+ if (idle->sequence != sequence)
+ goto repeat;
return sprintf(buf, "%llu\n", idle_count);
}
static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL);
@@ -872,15 +885,22 @@ static ssize_t show_idle_time(struct sys_device *dev,
{
struct s390_idle_data *idle;
unsigned long long now, idle_time, idle_enter;
+ unsigned int sequence;
idle = &per_cpu(s390_idle, dev->id);
- spin_lock(&idle->lock);
now = get_clock();
+repeat:
+ sequence = idle->sequence;
+ smp_rmb();
+ if (sequence & 1)
+ goto repeat;
idle_time = idle->idle_time;
idle_enter = idle->idle_enter;
if (idle_enter != 0ULL && idle_enter < now)
idle_time += now - idle_enter;
- spin_unlock(&idle->lock);
+ smp_rmb();
+ if (idle->sequence != sequence)
+ goto repeat;
return sprintf(buf, "%llu\n", idle_time >> 12);
}
static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL);
@@ -908,11 +928,7 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
idle = &per_cpu(s390_idle, cpu);
- spin_lock_irq(&idle->lock);
- idle->idle_enter = 0;
- idle->idle_time = 0;
- idle->idle_count = 0;
- spin_unlock_irq(&idle->lock);
+ memset(idle, 0, sizeof(struct s390_idle_data));
if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
return NOTIFY_BAD;
break;