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 ...
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SMP related functions
|
||||
*
|
||||
* Copyright IBM Corp. 1999,2012
|
||||
* Copyright IBM Corp. 1999, 2012
|
||||
* Author(s): Denis Joseph Barrow,
|
||||
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
|
||||
* Heiko Carstens <heiko.carstens@de.ibm.com>,
|
||||
@@ -38,39 +38,15 @@
|
||||
#include <asm/setup.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/vtimer.h>
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/os_info.h>
|
||||
#include <asm/sigp.h>
|
||||
#include "entry.h"
|
||||
|
||||
enum {
|
||||
sigp_sense = 1,
|
||||
sigp_external_call = 2,
|
||||
sigp_emergency_signal = 3,
|
||||
sigp_start = 4,
|
||||
sigp_stop = 5,
|
||||
sigp_restart = 6,
|
||||
sigp_stop_and_store_status = 9,
|
||||
sigp_initial_cpu_reset = 11,
|
||||
sigp_cpu_reset = 12,
|
||||
sigp_set_prefix = 13,
|
||||
sigp_store_status_at_address = 14,
|
||||
sigp_store_extended_status_at_address = 15,
|
||||
sigp_set_architecture = 18,
|
||||
sigp_conditional_emergency_signal = 19,
|
||||
sigp_sense_running = 21,
|
||||
};
|
||||
|
||||
enum {
|
||||
sigp_order_code_accepted = 0,
|
||||
sigp_status_stored = 1,
|
||||
sigp_busy = 2,
|
||||
sigp_not_operational = 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
ec_schedule = 0,
|
||||
ec_call_function,
|
||||
@@ -124,7 +100,7 @@ static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status)
|
||||
|
||||
while (1) {
|
||||
cc = __pcpu_sigp(addr, order, parm, status);
|
||||
if (cc != sigp_busy)
|
||||
if (cc != SIGP_CC_BUSY)
|
||||
return cc;
|
||||
cpu_relax();
|
||||
}
|
||||
@@ -136,7 +112,7 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
|
||||
|
||||
for (retry = 0; ; retry++) {
|
||||
cc = __pcpu_sigp(pcpu->address, order, parm, &pcpu->status);
|
||||
if (cc != sigp_busy)
|
||||
if (cc != SIGP_CC_BUSY)
|
||||
break;
|
||||
if (retry >= 3)
|
||||
udelay(10);
|
||||
@@ -146,20 +122,19 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
|
||||
|
||||
static inline int pcpu_stopped(struct pcpu *pcpu)
|
||||
{
|
||||
if (__pcpu_sigp(pcpu->address, sigp_sense,
|
||||
0, &pcpu->status) != sigp_status_stored)
|
||||
if (__pcpu_sigp(pcpu->address, SIGP_SENSE,
|
||||
0, &pcpu->status) != SIGP_CC_STATUS_STORED)
|
||||
return 0;
|
||||
/* Check for stopped and check stop state */
|
||||
return !!(pcpu->status & 0x50);
|
||||
return !!(pcpu->status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
|
||||
}
|
||||
|
||||
static inline int pcpu_running(struct pcpu *pcpu)
|
||||
{
|
||||
if (__pcpu_sigp(pcpu->address, sigp_sense_running,
|
||||
0, &pcpu->status) != sigp_status_stored)
|
||||
if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING,
|
||||
0, &pcpu->status) != SIGP_CC_STATUS_STORED)
|
||||
return 1;
|
||||
/* Check for running status */
|
||||
return !(pcpu->status & 0x400);
|
||||
/* Status stored condition code is equivalent to cpu not running. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -181,7 +156,7 @@ static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
|
||||
|
||||
set_bit(ec_bit, &pcpu->ec_mask);
|
||||
order = pcpu_running(pcpu) ?
|
||||
sigp_external_call : sigp_emergency_signal;
|
||||
SIGP_EXTERNAL_CALL : SIGP_EMERGENCY_SIGNAL;
|
||||
pcpu_sigp_retry(pcpu, order, 0);
|
||||
}
|
||||
|
||||
@@ -214,7 +189,7 @@ static int __cpuinit pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
|
||||
goto out;
|
||||
#endif
|
||||
lowcore_ptr[cpu] = lc;
|
||||
pcpu_sigp_retry(pcpu, sigp_set_prefix, (u32)(unsigned long) lc);
|
||||
pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, (u32)(unsigned long) lc);
|
||||
return 0;
|
||||
out:
|
||||
if (pcpu != &pcpu_devices[0]) {
|
||||
@@ -229,7 +204,7 @@ out:
|
||||
|
||||
static void pcpu_free_lowcore(struct pcpu *pcpu)
|
||||
{
|
||||
pcpu_sigp_retry(pcpu, sigp_set_prefix, 0);
|
||||
pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0);
|
||||
lowcore_ptr[pcpu - pcpu_devices] = NULL;
|
||||
#ifndef CONFIG_64BIT
|
||||
if (MACHINE_HAS_IEEE) {
|
||||
@@ -288,7 +263,7 @@ static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data)
|
||||
lc->restart_fn = (unsigned long) func;
|
||||
lc->restart_data = (unsigned long) data;
|
||||
lc->restart_source = -1UL;
|
||||
pcpu_sigp_retry(pcpu, sigp_restart, 0);
|
||||
pcpu_sigp_retry(pcpu, SIGP_RESTART, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -298,26 +273,26 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
|
||||
void *data, unsigned long stack)
|
||||
{
|
||||
struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices];
|
||||
struct {
|
||||
unsigned long stack;
|
||||
void *func;
|
||||
void *data;
|
||||
unsigned long source;
|
||||
} restart = { stack, func, data, stap() };
|
||||
unsigned long source_cpu = stap();
|
||||
|
||||
__load_psw_mask(psw_kernel_bits);
|
||||
if (pcpu->address == restart.source)
|
||||
if (pcpu->address == source_cpu)
|
||||
func(data); /* should not return */
|
||||
/* Stop target cpu (if func returns this stops the current cpu). */
|
||||
pcpu_sigp_retry(pcpu, sigp_stop, 0);
|
||||
pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
|
||||
/* Restart func on the target cpu and stop the current cpu. */
|
||||
memcpy_absolute(&lc->restart_stack, &restart, sizeof(restart));
|
||||
mem_assign_absolute(lc->restart_stack, stack);
|
||||
mem_assign_absolute(lc->restart_fn, (unsigned long) func);
|
||||
mem_assign_absolute(lc->restart_data, (unsigned long) data);
|
||||
mem_assign_absolute(lc->restart_source, source_cpu);
|
||||
asm volatile(
|
||||
"0: sigp 0,%0,6 # sigp restart to target cpu\n"
|
||||
"0: sigp 0,%0,%2 # sigp restart to target cpu\n"
|
||||
" brc 2,0b # busy, try again\n"
|
||||
"1: sigp 0,%1,5 # sigp stop to current cpu\n"
|
||||
"1: sigp 0,%1,%3 # sigp stop to current cpu\n"
|
||||
" brc 2,1b # busy, try again\n"
|
||||
: : "d" (pcpu->address), "d" (restart.source) : "0", "1", "cc");
|
||||
: : "d" (pcpu->address), "d" (source_cpu),
|
||||
"K" (SIGP_RESTART), "K" (SIGP_STOP)
|
||||
: "0", "1", "cc");
|
||||
for (;;) ;
|
||||
}
|
||||
|
||||
@@ -388,8 +363,8 @@ void smp_emergency_stop(cpumask_t *cpumask)
|
||||
for_each_cpu(cpu, cpumask) {
|
||||
struct pcpu *pcpu = pcpu_devices + cpu;
|
||||
set_bit(ec_stop_cpu, &pcpu->ec_mask);
|
||||
while (__pcpu_sigp(pcpu->address, sigp_emergency_signal,
|
||||
0, NULL) == sigp_busy &&
|
||||
while (__pcpu_sigp(pcpu->address, SIGP_EMERGENCY_SIGNAL,
|
||||
0, NULL) == SIGP_CC_BUSY &&
|
||||
get_clock() < end)
|
||||
cpu_relax();
|
||||
}
|
||||
@@ -425,7 +400,7 @@ void smp_send_stop(void)
|
||||
/* stop all processors */
|
||||
for_each_cpu(cpu, &cpumask) {
|
||||
struct pcpu *pcpu = pcpu_devices + cpu;
|
||||
pcpu_sigp_retry(pcpu, sigp_stop, 0);
|
||||
pcpu_sigp_retry(pcpu, SIGP_STOP, 0);
|
||||
while (!pcpu_stopped(pcpu))
|
||||
cpu_relax();
|
||||
}
|
||||
@@ -436,7 +411,7 @@ void smp_send_stop(void)
|
||||
*/
|
||||
void smp_stop_cpu(void)
|
||||
{
|
||||
pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0);
|
||||
pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
|
||||
for (;;) ;
|
||||
}
|
||||
|
||||
@@ -590,7 +565,7 @@ static void __init smp_get_save_area(int cpu, u16 address)
|
||||
}
|
||||
#endif
|
||||
/* Get the registers of a non-boot cpu. */
|
||||
__pcpu_sigp_relax(address, sigp_stop_and_store_status, 0, NULL);
|
||||
__pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL);
|
||||
memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area));
|
||||
}
|
||||
|
||||
@@ -599,8 +574,8 @@ int smp_store_status(int cpu)
|
||||
struct pcpu *pcpu;
|
||||
|
||||
pcpu = pcpu_devices + cpu;
|
||||
if (__pcpu_sigp_relax(pcpu->address, sigp_stop_and_store_status,
|
||||
0, NULL) != sigp_order_code_accepted)
|
||||
if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS,
|
||||
0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
@@ -621,8 +596,8 @@ static struct sclp_cpu_info *smp_get_cpu_info(void)
|
||||
if (info && (use_sigp_detection || sclp_get_cpu_info(info))) {
|
||||
use_sigp_detection = 1;
|
||||
for (address = 0; address <= MAX_CPU_ADDRESS; address++) {
|
||||
if (__pcpu_sigp_relax(address, sigp_sense, 0, NULL) ==
|
||||
sigp_not_operational)
|
||||
if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) ==
|
||||
SIGP_CC_NOT_OPERATIONAL)
|
||||
continue;
|
||||
info->cpu[info->configured].address = address;
|
||||
info->configured++;
|
||||
@@ -732,8 +707,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
|
||||
pcpu = pcpu_devices + cpu;
|
||||
if (pcpu->state != CPU_STATE_CONFIGURED)
|
||||
return -EIO;
|
||||
if (pcpu_sigp_retry(pcpu, sigp_initial_cpu_reset, 0) !=
|
||||
sigp_order_code_accepted)
|
||||
if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) !=
|
||||
SIGP_CC_ORDER_CODE_ACCEPTED)
|
||||
return -EIO;
|
||||
|
||||
rc = pcpu_alloc_lowcore(pcpu, cpu);
|
||||
@@ -793,7 +768,7 @@ void __cpu_die(unsigned int cpu)
|
||||
void __noreturn cpu_die(void)
|
||||
{
|
||||
idle_task_exit();
|
||||
pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0);
|
||||
pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
|
||||
for (;;) ;
|
||||
}
|
||||
|
||||
@@ -940,7 +915,7 @@ static ssize_t show_idle_count(struct device *dev,
|
||||
do {
|
||||
sequence = ACCESS_ONCE(idle->sequence);
|
||||
idle_count = ACCESS_ONCE(idle->idle_count);
|
||||
if (ACCESS_ONCE(idle->idle_enter))
|
||||
if (ACCESS_ONCE(idle->clock_idle_enter))
|
||||
idle_count++;
|
||||
} while ((sequence & 1) || (idle->sequence != sequence));
|
||||
return sprintf(buf, "%llu\n", idle_count);
|
||||
@@ -958,8 +933,8 @@ static ssize_t show_idle_time(struct device *dev,
|
||||
now = get_clock();
|
||||
sequence = ACCESS_ONCE(idle->sequence);
|
||||
idle_time = ACCESS_ONCE(idle->idle_time);
|
||||
idle_enter = ACCESS_ONCE(idle->idle_enter);
|
||||
idle_exit = ACCESS_ONCE(idle->idle_exit);
|
||||
idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
|
||||
idle_exit = ACCESS_ONCE(idle->clock_idle_exit);
|
||||
} while ((sequence & 1) || (idle->sequence != sequence));
|
||||
idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0;
|
||||
return sprintf(buf, "%llu\n", idle_time >> 12);
|
||||
@@ -982,14 +957,11 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
|
||||
unsigned int cpu = (unsigned int)(long)hcpu;
|
||||
struct cpu *c = &pcpu_devices[cpu].cpu;
|
||||
struct device *s = &c->dev;
|
||||
struct s390_idle_data *idle;
|
||||
int err = 0;
|
||||
|
||||
switch (action) {
|
||||
case CPU_ONLINE:
|
||||
case CPU_ONLINE_FROZEN:
|
||||
idle = &per_cpu(s390_idle, cpu);
|
||||
memset(idle, 0, sizeof(struct s390_idle_data));
|
||||
err = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
|
||||
break;
|
||||
case CPU_DEAD:
|
||||
|
Reference in New Issue
Block a user