Skip to content

Commit

Permalink
s390: add SMT support
Browse files Browse the repository at this point in the history
The multi-threading facility is introduced with the z13 processor family.
This patch adds code to detect the multi-threading facility. With the
facility enabled each core will surface multiple hardware threads to the
system. Each hardware threads looks like a normal CPU to the operating
system with all its registers and properties.

The SCLP interface reports the SMT topology indirectly via the maximum
thread id. Each reported CPU in the result of a read-scp-information
is a core representing a number of hardware threads.

To reflect the reduced CPU capacity if two hardware threads run on a
single core the MT utilization counter set is used to normalize the
raw cputime obtained by the CPU timer deltas. This scaled cputime is
reported via the taskstats interface. The normal /proc/stat numbers
are based on the raw cputime and are not affected by the normalization.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Martin Schwidefsky committed Jan 22, 2015
1 parent 1f6b83e commit 10ad34b
Show file tree
Hide file tree
Showing 18 changed files with 430 additions and 118 deletions.
15 changes: 12 additions & 3 deletions arch/s390/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -396,17 +396,26 @@ config HOTPLUG_CPU
can be controlled through /sys/devices/system/cpu/cpu#.
Say N if you want to disable CPU hotplug.

config SCHED_SMT
def_bool n

config SCHED_MC
def_bool n

config SCHED_BOOK
def_bool n

config SCHED_TOPOLOGY
def_bool y
prompt "Book scheduler support"
prompt "Topology scheduler support"
depends on SMP
select SCHED_SMT
select SCHED_MC
select SCHED_BOOK
help
Book scheduler support improves the CPU scheduler's decision making
when dealing with machines that have several books.
Topology scheduler support improves the CPU scheduler's decision
making when dealing with machines that have multi-threading,
multiple cores or multiple books.

source kernel/Kconfig.preempt

Expand Down
14 changes: 14 additions & 0 deletions arch/s390/include/asm/cpu_mf.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,20 @@ static inline int ecctr(u64 ctr, u64 *val)
return cc;
}

/* Store CPU counter multiple for the MT utilization counter set */
static inline int stcctm5(u64 num, u64 *val)
{
typedef struct { u64 _[num]; } addrtype;
int cc;

asm volatile (
" .insn rsy,0xeb0000000017,%2,5,%1\n"
" ipm %0\n"
" srl %0,28\n"
: "=d" (cc), "=Q" (*(addrtype *) val) : "d" (num) : "cc");
return cc;
}

/* Query sampling information */
static inline int qsi(struct hws_qsi_info_block *info)
{
Expand Down
3 changes: 2 additions & 1 deletion arch/s390/include/asm/reset.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ struct reset_call {

extern void register_reset_call(struct reset_call *reset);
extern void unregister_reset_call(struct reset_call *reset);
extern void s390_reset_system(void (*func)(void *), void *data);
extern void s390_reset_system(void (*fn_pre)(void),
void (*fn_post)(void *), void *data);
#endif /* _ASM_S390_RESET_H */
5 changes: 4 additions & 1 deletion arch/s390/include/asm/sclp.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct sclp_ipl_info {
};

struct sclp_cpu_entry {
u8 address;
u8 core_id;
u8 reserved0[2];
u8 : 3;
u8 siif : 1;
Expand All @@ -51,6 +51,9 @@ int sclp_cpu_deconfigure(u8 cpu);
unsigned long long sclp_get_rnmax(void);
unsigned long long sclp_get_rzm(void);
unsigned int sclp_get_max_cpu(void);
unsigned int sclp_get_mtid(u8 cpu_type);
unsigned int sclp_get_mtid_max(void);
unsigned int sclp_get_mtid_prev(void);
int sclp_sdias_blk_count(void);
int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
int sclp_chp_configure(struct chp_id chpid);
Expand Down
1 change: 1 addition & 0 deletions arch/s390/include/asm/sigp.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define SIGP_SET_ARCHITECTURE 18
#define SIGP_COND_EMERGENCY_SIGNAL 19
#define SIGP_SENSE_RUNNING 21
#define SIGP_SET_MULTI_THREADING 22
#define SIGP_STORE_ADDITIONAL_STATUS 23

/* SIGP condition codes */
Expand Down
4 changes: 4 additions & 0 deletions arch/s390/include/asm/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#define raw_smp_processor_id() (S390_lowcore.cpu_nr)

extern struct mutex smp_cpu_state_mutex;
extern unsigned int smp_cpu_mt_shift;
extern unsigned int smp_cpu_mtid;

extern int __cpu_up(unsigned int cpu, struct task_struct *tidle);

Expand All @@ -35,6 +37,8 @@ extern void smp_fill_possible_mask(void);

#else /* CONFIG_SMP */

#define smp_cpu_mtid 0

static inline void smp_call_ipl_cpu(void (*func)(void *), void *data)
{
func(data);
Expand Down
20 changes: 13 additions & 7 deletions arch/s390/include/asm/sysinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ struct sysinfo_2_2_2 {
unsigned short cpus_reserved;
char name[8];
unsigned int caf;
char reserved_2[16];
char reserved_2[8];
unsigned char mt_installed;
unsigned char mt_general;
unsigned char mt_psmtid;
char reserved_3[5];
unsigned short cpus_dedicated;
unsigned short cpus_shared;
};
Expand Down Expand Up @@ -120,26 +124,28 @@ struct sysinfo_3_2_2 {

extern int topology_max_mnest;

#define TOPOLOGY_CPU_BITS 64
#define TOPOLOGY_CORE_BITS 64
#define TOPOLOGY_NR_MAG 6

struct topology_cpu {
unsigned char reserved0[4];
struct topology_core {
unsigned char nl;
unsigned char reserved0[3];
unsigned char :6;
unsigned char pp:2;
unsigned char reserved1;
unsigned short origin;
unsigned long mask[TOPOLOGY_CPU_BITS / BITS_PER_LONG];
unsigned long mask[TOPOLOGY_CORE_BITS / BITS_PER_LONG];
};

struct topology_container {
unsigned char reserved[7];
unsigned char nl;
unsigned char reserved[6];
unsigned char id;
};

union topology_entry {
unsigned char nl;
struct topology_cpu cpu;
struct topology_core cpu;
struct topology_container container;
};

Expand Down
4 changes: 4 additions & 0 deletions arch/s390/include/asm/topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@ struct cpu;
#ifdef CONFIG_SCHED_BOOK

struct cpu_topology_s390 {
unsigned short thread_id;
unsigned short core_id;
unsigned short socket_id;
unsigned short book_id;
cpumask_t thread_mask;
cpumask_t core_mask;
cpumask_t book_mask;
};

extern struct cpu_topology_s390 cpu_topology[NR_CPUS];

#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
#define topology_thread_id(cpu) (cpu_topology[cpu].thread_id)
#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_mask)
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_mask)
#define topology_book_id(cpu) (cpu_topology[cpu].book_id)
Expand Down
3 changes: 2 additions & 1 deletion arch/s390/kernel/base.S
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ ENTRY(diag308_reset)
lg %r4,0(%r4) # Save PSW
sturg %r4,%r3 # Use sturg, because of large pages
lghi %r1,1
diag %r1,%r1,0x308
lghi %r0,0
diag %r0,%r1,0x308
.Lrestart_part2:
lhi %r0,0 # Load r0 with zero
lhi %r1,2 # Use mode 2 = ESAME (dump)
Expand Down
8 changes: 6 additions & 2 deletions arch/s390/kernel/dis.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ enum {
INSTR_RSI_RRP,
INSTR_RSL_LRDFU, INSTR_RSL_R0RD,
INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD,
INSTR_RSY_RDRM,
INSTR_RSY_RDRM, INSTR_RSY_RMRD,
INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD,
INSTR_RS_RURD,
INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM,
Expand Down Expand Up @@ -307,6 +307,7 @@ static const unsigned char formats[][7] = {
[INSTR_RSY_AARD] = { 0xff, A_8,A_12,D20_20,B_16,0,0 },
[INSTR_RSY_CCRD] = { 0xff, C_8,C_12,D20_20,B_16,0,0 },
[INSTR_RSY_RDRM] = { 0xff, R_8,D20_20,B_16,U4_12,0,0 },
[INSTR_RSY_RMRD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
[INSTR_RSY_RRRD] = { 0xff, R_8,R_12,D20_20,B_16,0,0 },
[INSTR_RSY_RURD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
[INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 },
Expand Down Expand Up @@ -450,7 +451,8 @@ enum {
LONG_INSN_VERLLV,
LONG_INSN_VESRAV,
LONG_INSN_VESRLV,
LONG_INSN_VSBCBI
LONG_INSN_VSBCBI,
LONG_INSN_STCCTM
};

static char *long_insn_name[] = {
Expand Down Expand Up @@ -530,6 +532,7 @@ static char *long_insn_name[] = {
[LONG_INSN_VESRAV] = "vesrav",
[LONG_INSN_VESRLV] = "vesrlv",
[LONG_INSN_VSBCBI] = "vsbcbi",
[LONG_INSN_STCCTM] = "stcctm",
};

static struct s390_insn opcode[] = {
Expand Down Expand Up @@ -1655,6 +1658,7 @@ static struct s390_insn opcode_eb[] = {
{ "lric", 0x60, INSTR_RSY_RDRM },
{ "stric", 0x61, INSTR_RSY_RDRM },
{ "mric", 0x62, INSTR_RSY_RDRM },
{ { 0, LONG_INSN_STCCTM }, 0x17, INSTR_RSY_RMRD },
#endif
{ "rll", 0x1d, INSTR_RSY_RRRD },
{ "mvclu", 0x8e, INSTR_RSY_RRRD },
Expand Down
11 changes: 8 additions & 3 deletions arch/s390/kernel/ipl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2074,7 +2074,8 @@ static void do_reset_calls(void)

u32 dump_prefix_page;

void s390_reset_system(void (*func)(void *), void *data)
void s390_reset_system(void (*fn_pre)(void),
void (*fn_post)(void *), void *data)
{
struct _lowcore *lc;

Expand Down Expand Up @@ -2112,7 +2113,11 @@ void s390_reset_system(void (*func)(void *), void *data)
/* Store status at absolute zero */
store_status();

/* Call function before reset */
if (fn_pre)
fn_pre();
do_reset_calls();
if (func)
func(data);
/* Call function after reset */
if (fn_post)
fn_post(data);
}
19 changes: 8 additions & 11 deletions arch/s390/kernel/machine_kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,18 @@ static int __init machine_kdump_pm_init(void)
return 0;
}
arch_initcall(machine_kdump_pm_init);
#endif

/*
* Start kdump: We expect here that a store status has been done on our CPU
*/
static void __do_machine_kdump(void *image)
{
#ifdef CONFIG_CRASH_DUMP
int (*start_kdump)(int) = (void *)((struct kimage *) image)->start;

setup_regs();
__load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA);
start_kdump(1);
#endif
}
#endif

/*
* Check if kdump checksums are valid: We call purgatory with parameter "0"
Expand Down Expand Up @@ -249,18 +246,18 @@ static void __do_machine_kexec(void *data)
*/
static void __machine_kexec(void *data)
{
struct kimage *image = data;

__arch_local_irq_stosm(0x04); /* enable DAT */
pfault_fini();
tracing_off();
debug_locks_off();
if (image->type == KEXEC_TYPE_CRASH) {
#ifdef CONFIG_CRASH_DUMP
if (((struct kimage *) data)->type == KEXEC_TYPE_CRASH) {

lgr_info_log();
s390_reset_system(__do_machine_kdump, data);
} else {
s390_reset_system(__do_machine_kexec, data);
}
s390_reset_system(setup_regs, __do_machine_kdump, data);
} else
#endif
s390_reset_system(NULL, __do_machine_kexec, data);
disabled_wait((unsigned long) __builtin_return_address(0));
}

Expand Down
Loading

0 comments on commit 10ad34b

Please sign in to comment.