Commit 10ad34bc authored by Martin Schwidefsky's avatar Martin Schwidefsky

s390: add SMT support

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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 1f6b83e5
...@@ -396,17 +396,26 @@ config HOTPLUG_CPU ...@@ -396,17 +396,26 @@ config HOTPLUG_CPU
can be controlled through /sys/devices/system/cpu/cpu#. can be controlled through /sys/devices/system/cpu/cpu#.
Say N if you want to disable CPU hotplug. Say N if you want to disable CPU hotplug.
config SCHED_SMT
def_bool n
config SCHED_MC config SCHED_MC
def_bool n def_bool n
config SCHED_BOOK config SCHED_BOOK
def_bool n
config SCHED_TOPOLOGY
def_bool y def_bool y
prompt "Book scheduler support" prompt "Topology scheduler support"
depends on SMP depends on SMP
select SCHED_SMT
select SCHED_MC select SCHED_MC
select SCHED_BOOK
help help
Book scheduler support improves the CPU scheduler's decision making Topology scheduler support improves the CPU scheduler's decision
when dealing with machines that have several books. making when dealing with machines that have multi-threading,
multiple cores or multiple books.
source kernel/Kconfig.preempt source kernel/Kconfig.preempt
......
...@@ -189,6 +189,20 @@ static inline int ecctr(u64 ctr, u64 *val) ...@@ -189,6 +189,20 @@ static inline int ecctr(u64 ctr, u64 *val)
return cc; 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 */ /* Query sampling information */
static inline int qsi(struct hws_qsi_info_block *info) static inline int qsi(struct hws_qsi_info_block *info)
{ {
......
...@@ -15,5 +15,6 @@ struct reset_call { ...@@ -15,5 +15,6 @@ struct reset_call {
extern void register_reset_call(struct reset_call *reset); extern void register_reset_call(struct reset_call *reset);
extern void unregister_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 */ #endif /* _ASM_S390_RESET_H */
...@@ -27,7 +27,7 @@ struct sclp_ipl_info { ...@@ -27,7 +27,7 @@ struct sclp_ipl_info {
}; };
struct sclp_cpu_entry { struct sclp_cpu_entry {
u8 address; u8 core_id;
u8 reserved0[2]; u8 reserved0[2];
u8 : 3; u8 : 3;
u8 siif : 1; u8 siif : 1;
...@@ -51,6 +51,9 @@ int sclp_cpu_deconfigure(u8 cpu); ...@@ -51,6 +51,9 @@ int sclp_cpu_deconfigure(u8 cpu);
unsigned long long sclp_get_rnmax(void); unsigned long long sclp_get_rnmax(void);
unsigned long long sclp_get_rzm(void); unsigned long long sclp_get_rzm(void);
unsigned int sclp_get_max_cpu(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_blk_count(void);
int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
int sclp_chp_configure(struct chp_id chpid); int sclp_chp_configure(struct chp_id chpid);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define SIGP_SET_ARCHITECTURE 18 #define SIGP_SET_ARCHITECTURE 18
#define SIGP_COND_EMERGENCY_SIGNAL 19 #define SIGP_COND_EMERGENCY_SIGNAL 19
#define SIGP_SENSE_RUNNING 21 #define SIGP_SENSE_RUNNING 21
#define SIGP_SET_MULTI_THREADING 22
#define SIGP_STORE_ADDITIONAL_STATUS 23 #define SIGP_STORE_ADDITIONAL_STATUS 23
/* SIGP condition codes */ /* SIGP condition codes */
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#define raw_smp_processor_id() (S390_lowcore.cpu_nr) #define raw_smp_processor_id() (S390_lowcore.cpu_nr)
extern struct mutex smp_cpu_state_mutex; 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); extern int __cpu_up(unsigned int cpu, struct task_struct *tidle);
...@@ -35,6 +37,8 @@ extern void smp_fill_possible_mask(void); ...@@ -35,6 +37,8 @@ extern void smp_fill_possible_mask(void);
#else /* CONFIG_SMP */ #else /* CONFIG_SMP */
#define smp_cpu_mtid 0
static inline void smp_call_ipl_cpu(void (*func)(void *), void *data) static inline void smp_call_ipl_cpu(void (*func)(void *), void *data)
{ {
func(data); func(data);
......
...@@ -90,7 +90,11 @@ struct sysinfo_2_2_2 { ...@@ -90,7 +90,11 @@ struct sysinfo_2_2_2 {
unsigned short cpus_reserved; unsigned short cpus_reserved;
char name[8]; char name[8];
unsigned int caf; 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_dedicated;
unsigned short cpus_shared; unsigned short cpus_shared;
}; };
...@@ -120,26 +124,28 @@ struct sysinfo_3_2_2 { ...@@ -120,26 +124,28 @@ struct sysinfo_3_2_2 {
extern int topology_max_mnest; extern int topology_max_mnest;
#define TOPOLOGY_CPU_BITS 64 #define TOPOLOGY_CORE_BITS 64
#define TOPOLOGY_NR_MAG 6 #define TOPOLOGY_NR_MAG 6
struct topology_cpu { struct topology_core {
unsigned char reserved0[4]; unsigned char nl;
unsigned char reserved0[3];
unsigned char :6; unsigned char :6;
unsigned char pp:2; unsigned char pp:2;
unsigned char reserved1; unsigned char reserved1;
unsigned short origin; unsigned short origin;
unsigned long mask[TOPOLOGY_CPU_BITS / BITS_PER_LONG]; unsigned long mask[TOPOLOGY_CORE_BITS / BITS_PER_LONG];
}; };
struct topology_container { struct topology_container {
unsigned char reserved[7]; unsigned char nl;
unsigned char reserved[6];
unsigned char id; unsigned char id;
}; };
union topology_entry { union topology_entry {
unsigned char nl; unsigned char nl;
struct topology_cpu cpu; struct topology_core cpu;
struct topology_container container; struct topology_container container;
}; };
......
...@@ -9,9 +9,11 @@ struct cpu; ...@@ -9,9 +9,11 @@ struct cpu;
#ifdef CONFIG_SCHED_BOOK #ifdef CONFIG_SCHED_BOOK
struct cpu_topology_s390 { struct cpu_topology_s390 {
unsigned short thread_id;
unsigned short core_id; unsigned short core_id;
unsigned short socket_id; unsigned short socket_id;
unsigned short book_id; unsigned short book_id;
cpumask_t thread_mask;
cpumask_t core_mask; cpumask_t core_mask;
cpumask_t book_mask; cpumask_t book_mask;
}; };
...@@ -19,6 +21,8 @@ struct cpu_topology_s390 { ...@@ -19,6 +21,8 @@ struct cpu_topology_s390 {
extern struct cpu_topology_s390 cpu_topology[NR_CPUS]; extern struct cpu_topology_s390 cpu_topology[NR_CPUS];
#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id) #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_id(cpu) (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_mask) #define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_mask)
#define topology_book_id(cpu) (cpu_topology[cpu].book_id) #define topology_book_id(cpu) (cpu_topology[cpu].book_id)
......
...@@ -97,7 +97,8 @@ ENTRY(diag308_reset) ...@@ -97,7 +97,8 @@ ENTRY(diag308_reset)
lg %r4,0(%r4) # Save PSW lg %r4,0(%r4) # Save PSW
sturg %r4,%r3 # Use sturg, because of large pages sturg %r4,%r3 # Use sturg, because of large pages
lghi %r1,1 lghi %r1,1
diag %r1,%r1,0x308 lghi %r0,0
diag %r0,%r1,0x308
.Lrestart_part2: .Lrestart_part2:
lhi %r0,0 # Load r0 with zero lhi %r0,0 # Load r0 with zero
lhi %r1,2 # Use mode 2 = ESAME (dump) lhi %r1,2 # Use mode 2 = ESAME (dump)
......
...@@ -137,7 +137,7 @@ enum { ...@@ -137,7 +137,7 @@ enum {
INSTR_RSI_RRP, INSTR_RSI_RRP,
INSTR_RSL_LRDFU, INSTR_RSL_R0RD, INSTR_RSL_LRDFU, INSTR_RSL_R0RD,
INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD, 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_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD,
INSTR_RS_RURD, INSTR_RS_RURD,
INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM, INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM,
...@@ -307,6 +307,7 @@ static const unsigned char formats[][7] = { ...@@ -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_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_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_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_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_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 }, [INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 },
...@@ -450,7 +451,8 @@ enum { ...@@ -450,7 +451,8 @@ enum {
LONG_INSN_VERLLV, LONG_INSN_VERLLV,
LONG_INSN_VESRAV, LONG_INSN_VESRAV,
LONG_INSN_VESRLV, LONG_INSN_VESRLV,
LONG_INSN_VSBCBI LONG_INSN_VSBCBI,
LONG_INSN_STCCTM
}; };
static char *long_insn_name[] = { static char *long_insn_name[] = {
...@@ -530,6 +532,7 @@ static char *long_insn_name[] = { ...@@ -530,6 +532,7 @@ static char *long_insn_name[] = {
[LONG_INSN_VESRAV] = "vesrav", [LONG_INSN_VESRAV] = "vesrav",
[LONG_INSN_VESRLV] = "vesrlv", [LONG_INSN_VESRLV] = "vesrlv",
[LONG_INSN_VSBCBI] = "vsbcbi", [LONG_INSN_VSBCBI] = "vsbcbi",
[LONG_INSN_STCCTM] = "stcctm",
}; };
static struct s390_insn opcode[] = { static struct s390_insn opcode[] = {
...@@ -1655,6 +1658,7 @@ static struct s390_insn opcode_eb[] = { ...@@ -1655,6 +1658,7 @@ static struct s390_insn opcode_eb[] = {
{ "lric", 0x60, INSTR_RSY_RDRM }, { "lric", 0x60, INSTR_RSY_RDRM },
{ "stric", 0x61, INSTR_RSY_RDRM }, { "stric", 0x61, INSTR_RSY_RDRM },
{ "mric", 0x62, INSTR_RSY_RDRM }, { "mric", 0x62, INSTR_RSY_RDRM },
{ { 0, LONG_INSN_STCCTM }, 0x17, INSTR_RSY_RMRD },
#endif #endif
{ "rll", 0x1d, INSTR_RSY_RRRD }, { "rll", 0x1d, INSTR_RSY_RRRD },
{ "mvclu", 0x8e, INSTR_RSY_RRRD }, { "mvclu", 0x8e, INSTR_RSY_RRRD },
......
...@@ -2074,7 +2074,8 @@ static void do_reset_calls(void) ...@@ -2074,7 +2074,8 @@ static void do_reset_calls(void)
u32 dump_prefix_page; 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; struct _lowcore *lc;
...@@ -2112,7 +2113,11 @@ void s390_reset_system(void (*func)(void *), void *data) ...@@ -2112,7 +2113,11 @@ void s390_reset_system(void (*func)(void *), void *data)
/* Store status at absolute zero */ /* Store status at absolute zero */
store_status(); store_status();
/* Call function before reset */
if (fn_pre)
fn_pre();
do_reset_calls(); do_reset_calls();
if (func) /* Call function after reset */
func(data); if (fn_post)
fn_post(data);
} }
...@@ -103,21 +103,18 @@ static int __init machine_kdump_pm_init(void) ...@@ -103,21 +103,18 @@ static int __init machine_kdump_pm_init(void)
return 0; return 0;
} }
arch_initcall(machine_kdump_pm_init); arch_initcall(machine_kdump_pm_init);
#endif
/* /*
* Start kdump: We expect here that a store status has been done on our CPU * Start kdump: We expect here that a store status has been done on our CPU
*/ */
static void __do_machine_kdump(void *image) static void __do_machine_kdump(void *image)
{ {
#ifdef CONFIG_CRASH_DUMP
int (*start_kdump)(int) = (void *)((struct kimage *) image)->start; 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); __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA);
start_kdump(1); start_kdump(1);
#endif
} }
#endif
/* /*
* Check if kdump checksums are valid: We call purgatory with parameter "0" * Check if kdump checksums are valid: We call purgatory with parameter "0"
...@@ -249,18 +246,18 @@ static void __do_machine_kexec(void *data) ...@@ -249,18 +246,18 @@ static void __do_machine_kexec(void *data)
*/ */
static void __machine_kexec(void *data) static void __machine_kexec(void *data)
{ {
struct kimage *image = data;
__arch_local_irq_stosm(0x04); /* enable DAT */ __arch_local_irq_stosm(0x04); /* enable DAT */
pfault_fini(); pfault_fini();
tracing_off(); tracing_off();
debug_locks_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(); lgr_info_log();
s390_reset_system(__do_machine_kdump, data); s390_reset_system(setup_regs, __do_machine_kdump, data);
} else { } else
s390_reset_system(__do_machine_kexec, data); #endif
} s390_reset_system(NULL, __do_machine_kexec, data);
disabled_wait((unsigned long) __builtin_return_address(0)); disabled_wait((unsigned long) __builtin_return_address(0));
} }
......
This diff is collapsed.
...@@ -194,6 +194,14 @@ static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info) ...@@ -194,6 +194,14 @@ static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info)
seq_printf(m, "LPAR CPUs Reserved: %d\n", info->cpus_reserved); seq_printf(m, "LPAR CPUs Reserved: %d\n", info->cpus_reserved);
seq_printf(m, "LPAR CPUs Dedicated: %d\n", info->cpus_dedicated); seq_printf(m, "LPAR CPUs Dedicated: %d\n", info->cpus_dedicated);
seq_printf(m, "LPAR CPUs Shared: %d\n", info->cpus_shared); seq_printf(m, "LPAR CPUs Shared: %d\n", info->cpus_shared);
if (info->mt_installed & 0x80) {
seq_printf(m, "LPAR CPUs G-MTID: %d\n",
info->mt_general & 0x1f);
seq_printf(m, "LPAR CPUs S-MTID: %d\n",
info->mt_installed & 0x1f);
seq_printf(m, "LPAR CPUs PS-MTID: %d\n",
info->mt_psmtid & 0x1f);
}
} }
static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info) static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info)
......
...@@ -59,32 +59,50 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) ...@@ -59,32 +59,50 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
return mask; return mask;
} }
static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu, static cpumask_t cpu_thread_map(unsigned int cpu)
{
cpumask_t mask;
int i;
cpumask_copy(&mask, cpumask_of(cpu));
if (!topology_enabled || !MACHINE_HAS_TOPOLOGY)
return mask;
cpu -= cpu % (smp_cpu_mtid + 1);
for (i = 0; i <= smp_cpu_mtid; i++)
if (cpu_present(cpu + i))
cpumask_set_cpu(cpu + i, &mask);
return mask;
}
static struct mask_info *add_cpus_to_mask(struct topology_core *tl_core,
struct mask_info *book, struct mask_info *book,
struct mask_info *socket, struct mask_info *socket,
int one_socket_per_cpu) int one_socket_per_cpu)
{ {
unsigned int cpu; unsigned int core;
for_each_set_bit(cpu, &tl_cpu->mask[0], TOPOLOGY_CPU_BITS) { for_each_set_bit(core, &tl_core->mask[0], TOPOLOGY_CORE_BITS) {
unsigned int rcpu; unsigned int rcore;
int lcpu; int lcpu, i;
rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin; rcore = TOPOLOGY_CORE_BITS - 1 - core + tl_core->origin;
lcpu = smp_find_processor_id(rcpu); lcpu = smp_find_processor_id(rcore << smp_cpu_mt_shift);
if (lcpu < 0) if (lcpu < 0)
continue; continue;
cpumask_set_cpu(lcpu, &book->mask); for (i = 0; i <= smp_cpu_mtid; i++) {
cpu_topology[lcpu].book_id = book->id; cpu_topology[lcpu + i].book_id = book->id;
cpumask_set_cpu(lcpu, &socket->mask); cpu_topology[lcpu + i].core_id = rcore;
cpu_topology[lcpu].core_id = rcpu; cpu_topology[lcpu + i].thread_id = lcpu + i;
if (one_socket_per_cpu) { cpumask_set_cpu(lcpu + i, &book->mask);
cpu_topology[lcpu].socket_id = rcpu; cpumask_set_cpu(lcpu + i, &socket->mask);
socket = socket->next; if (one_socket_per_cpu)
} else { cpu_topology[lcpu + i].socket_id = rcore;
cpu_topology[lcpu].socket_id = socket->id; else
cpu_topology[lcpu + i].socket_id = socket->id;
smp_cpu_set_polarization(lcpu + i, tl_core->pp);
} }
smp_cpu_set_polarization(lcpu, tl_cpu->pp); if (one_socket_per_cpu)
socket = socket->next;
} }
return socket; return socket;
} }
...@@ -108,7 +126,7 @@ static void clear_masks(void) ...@@ -108,7 +126,7 @@ static void clear_masks(void)
static union topology_entry *next_tle(union topology_entry *tle) static union topology_entry *next_tle(union topology_entry *tle)
{ {
if (!tle->nl) if (!tle->nl)
return (union topology_entry *)((struct topology_cpu *)tle + 1); return (union topology_entry *)((struct topology_core *)tle + 1);
return (union topology_entry *)((struct topology_container *)tle + 1); return (union topology_entry *)((struct topology_container *)tle + 1);
} }
...@@ -231,9 +249,11 @@ static void update_cpu_masks(void) ...@@ -231,9 +249,11 @@ static void update_cpu_masks(void)
spin_lock_irqsave(&topology_lock, flags); spin_lock_irqsave(&topology_lock, flags);
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
cpu_topology[cpu].thread_mask = cpu_thread_map(cpu);
cpu_topology[cpu].core_mask = cpu_group_map(&socket_info, cpu); cpu_topology[cpu].core_mask = cpu_group_map(&socket_info, cpu);
cpu_topology[cpu].book_mask = cpu_group_map(&book_info, cpu); cpu_topology[cpu].book_mask = cpu_group_map(&book_info, cpu);
if (!MACHINE_HAS_TOPOLOGY) { if (!MACHINE_HAS_TOPOLOGY) {
cpu_topology[cpu].thread_id = cpu;
cpu_topology[cpu].core_id = cpu; cpu_topology[cpu].core_id = cpu;
cpu_topology[cpu].socket_id = cpu; cpu_topology[cpu].socket_id = cpu;
cpu_topology[cpu].book_id = cpu; cpu_topology[cpu].book_id = cpu;
...@@ -445,6 +465,12 @@ int topology_cpu_init(struct cpu *cpu) ...@@ -445,6 +465,12 @@ int topology_cpu_init(struct cpu *cpu)
return sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group); return sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group);
} }
const struct cpumask *cpu_thread_mask(int cpu)
{
return &cpu_topology[cpu].thread_mask;
}
const struct cpumask *cpu_coregroup_mask(int cpu) const struct cpumask *cpu_coregroup_mask(int cpu)
{ {
return &cpu_topology[cpu].core_mask; return &cpu_topology[cpu].core_mask;
...@@ -456,6 +482,7 @@ static const struct cpumask *cpu_book_mask(int cpu) ...@@ -456,6 +482,7 @@ static const struct cpumask *cpu_book_mask(int cpu)
} }
static struct sched_domain_topology_level s390_topology[] = { static struct sched_domain_topology_level s390_topology[] = {
{ cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
{ cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
{ cpu_book_mask, SD_INIT_NAME(BOOK) }, { cpu_book_mask, SD_INIT_NAME(BOOK) },
{ cpu_cpu_mask, SD_INIT_NAME(DIE) }, { cpu_cpu_mask, SD_INIT_NAME(DIE) },
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <asm/cputime.h> #include <asm/cputime.h>
#include <asm/vtimer.h> #include <asm/vtimer.h>
#include <asm/vtime.h> #include <asm/vtime.h>
#include <asm/cpu_mf.h>
#include <asm/smp.h>
static void virt_timer_expire(void); static void virt_timer_expire(void);
...@@ -23,6 +25,10 @@ static DEFINE_SPINLOCK(virt_timer_lock); ...@@ -23,6 +25,10 @@ static DEFINE_SPINLOCK(virt_timer_lock);
static atomic64_t virt_timer_current; static atomic64_t virt_timer_current;
static atomic64_t virt_timer_elapsed; static atomic64_t virt_timer_elapsed;
static DEFINE_PER_CPU(u64, mt_cycles[32]);
static DEFINE_PER_CPU(u64, mt_scaling_mult) = { 1 };
static DEFINE_PER_CPU(u64, mt_scaling_div) = { 1 };
static inline u64 get_vtimer(void) static inline u64 get_vtimer(void)
{ {
u64 timer; u64 timer;
...@@ -61,6 +67,8 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset) ...@@ -61,6 +67,8 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset)
{ {
struct thread_info *ti = task_thread_info(tsk); struct thread_info *ti = task_thread_info(tsk);
u64 timer, clock, user, system, steal; u64 timer, clock, user, system, steal;
u64 user_scaled, system_scaled;
int i;
timer = S390_lowcore.last_update_timer; timer = S390_lowcore.last_update_timer;
clock = S390_lowcore.last_update_clock; clock = S390_lowcore.last_update_clock;
...@@ -76,15 +84,49 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset) ...@@ -76,15 +84,49 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset)
S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
S390_lowcore.steal_timer += S390_lowcore.last_update_clock - clock; S390_lowcore.steal_timer += S390_lowcore.last_update_clock - clock;
/* Do MT utilization calculation */
if (smp_cpu_mtid) {
u64 cycles_new[32], *cycles_old;
u64 delta, mult, div;
cycles_old = this_cpu_ptr(mt_cycles);
if (stcctm5(smp_cpu_mtid + 1, cycles_new) < 2) {
mult = div = 0;
for (i = 0; i <= smp_cpu_mtid; i++) {
delta = cycles_new[i] - cycles_old[i];
mult += delta;
div += (i + 1) * delta;
}
if (mult > 0) {
/* Update scaling factor */
__this_cpu_write(mt_scaling_mult, mult);
__this_cpu_write(mt_scaling_div, div);
memcpy(cycles_old, cycles_new,
sizeof(u64) * (smp_cpu_mtid + 1));
}
}
}
user = S390_lowcore.user_timer - ti->user_timer; user = S390_lowcore.user_timer - ti->user_timer;
S390_lowcore.steal_timer -= user; S390_lowcore.steal_timer -= user;
ti->user_timer = S390_lowcore.user_timer; ti->user_timer = S390_lowcore.user_timer;
account_user_time(tsk, user, user);
system = S390_lowcore.system_timer - ti->system_timer; system = S390_lowcore.system_timer - ti->system_timer;
S390_lowcore.steal_timer -= system; S390_lowcore.steal_timer -= system;
ti->system_timer = S390_lowcore.system_timer; ti->system_timer = S390_lowcore.system_timer;
account_system_time(tsk, hardirq_offset, system, system);
user_scaled = user;
system_scaled = system;
/* Do MT utilization scaling */
if (smp_cpu_mtid) {
u64 mult = __this_cpu_read(mt_scaling_mult);
u64 div = __this_cpu_read(mt_scaling_div);
user_scaled = (user_scaled * mult) / div;
system_scaled = (system_scaled * mult) / div;
}
account_user_time(tsk, user, user_scaled);
account_system_time(tsk, hardirq_offset, system, system_scaled);
steal = S390_lowcore.steal_timer; steal = S390_lowcore.steal_timer;
if ((s64) steal > 0) { if ((s64) steal > 0) {
...@@ -126,7 +168,7 @@ void vtime_account_user(struct task_struct *tsk) ...@@ -126,7 +168,7 @@ void vtime_account_user(struct task_struct *tsk)
void vtime_account_irq_enter(struct task_struct *tsk) void vtime_account_irq_enter(struct task_struct *tsk)
{ {
struct thread_info *ti = task_thread_info(tsk); struct thread_info *ti = task_thread_info(tsk);
u64 timer, system; u64 timer, system, system_scaled;
timer = S390_lowcore.last_update_timer; timer = S390_lowcore.last_update_timer;
S390_lowcore.last_update_timer = get_vtimer(); S390_lowcore.last_update_timer = get_vtimer();
...@@ -135,7 +177,15 @@ void vtime_account_irq_enter(struct task_struct *tsk) ...@@ -135,7 +177,15 @@ void vtime_account_irq_enter(struct task_struct *tsk)
system = S390_lowcore.system_timer - ti->system_timer; system = S390_lowcore.system_timer - ti->system_timer;
S390_lowcore.steal_timer -= system; S390_lowcore.steal_timer -= system;
ti->system_timer = S390_lowcore.system_timer; ti->system_timer = S390_lowcore.system_timer;
account_system_time(tsk, 0, system, system); system_scaled = system;
/* Do MT utilization scaling */
if (smp_cpu_mtid) {
u64 mult = __this_cpu_read(mt_scaling_mult);
u64 div = __this_cpu_read(mt_scaling_div);
system_scaled = (system_scaled * mult) / div;
}
account_system_time(tsk, 0, system, system_scaled);
virt_timer_forward(system); virt_timer_forward(system);
} }
......
...@@ -20,26 +20,31 @@ struct read_info_sccb { ...@@ -20,26 +20,31 @@ struct read_info_sccb {
struct sccb_header header; /* 0-7 */ struct sccb_header header; /* 0-7 */
u16 rnmax; /* 8-9 */ u16 rnmax; /* 8-9 */
u8 rnsize; /* 10 */ u8 rnsize; /* 10 */
u8 _reserved0[16 - 11]; /* 11-15 */ u8 _pad_11[16 - 11]; /* 11-15 */
u16 ncpurl; /* 16-17 */ u16 ncpurl; /* 16-17 */
u16 cpuoff; /* 18-19 */ u16 cpuoff; /* 18-19 */
u8 _reserved7[24 - 20]; /* 20-23 */ u8 _pad_20[24 - 20]; /* 20-23 */
u8 loadparm[8]; /* 24-31 */ u8 loadparm[8]; /* 24-31 */
u8 _reserved1[48 - 32]; /* 32-47 */ u8 _pad_32[42 - 32]; /* 32-41 */
u8 fac42; /* 42 */
u8 fac43; /* 43 */
u8 _pad_44[48 - 44]; /* 44-47 */
u64 facilities; /* 48-55 */ u64 facilities; /* 48-55 */
u8 _reserved2a[76 - 56]; /* 56-75 */ u8 _pad_56[66 - 56]; /* 56-65 */
u8 fac66; /* 66 */
u8 _pad_67[76 - 67]; /* 67-83 */
u32 ibc; /* 76-79 */ u32 ibc; /* 76-79 */
u8 _reserved2b[84 - 80]; /* 80-83 */ u8 _pad80[84 - 80]; /* 80-83 */
u8 fac84; /* 84 */ u8 fac84; /* 84 */
u8 fac85; /* 85 */ u8 fac85; /* 85 */
u8 _reserved3[91 - 86]; /* 86-90 */ u8 _pad_86[91 - 86]; /* 86-90 */
u8 flags; /* 91 */ u8 flags; /* 91 */
u8 _reserved4[100 - 92]; /* 92-99 */ u8 _pad_92[100 - 92]; /* 92-99 */
u32 rnsize2; /* 100-103 */ u32 rnsize2; /* 100-103 */
u64 rnmax2; /* 104-111 */ u64 rnmax2; /* 104-111 */
u8 _reserved5[120 - 112]; /* 112-119 */ u8 _pad_112[120 - 112]; /* 112-119 */
u16 hcpua; /* 120-121 */ u16 hcpua; /* 120-121 */
u8 _reserved6[4096 - 122]; /* 122-4095 */ u8 _pad_122[4096 - 122]; /* 122-4095 */
} __packed __aligned(PAGE_SIZE); } __packed __aligned(PAGE_SIZE);
static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata; static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
...@@ -50,6 +55,10 @@ static unsigned int sclp_max_cpu; ...@@ -50,6 +55,10 @@ static unsigned int sclp_max_cpu;
static struct sclp_ipl_info sclp_ipl_info; static struct sclp_ipl_info sclp_ipl_info;
static unsigned char sclp_siif; static unsigned char sclp_siif;
static u32 sclp_ibc; static u32 sclp_ibc;
static unsigned int sclp_mtid;
static unsigned int sclp_mtid_cp;
static unsigned int sclp_mtid_max;
static unsigned int sclp_mtid_prev;
u64 sclp_facilities; u64 sclp_facilities;
u8 sclp_fac84; u8 sclp_fac84;
...@@ -128,7 +137,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) ...@@ -128,7 +137,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
boot_cpu_address = stap(); boot_cpu_address = stap();
cpue = (void *)sccb + sccb->cpuoff; cpue = (void *)sccb + sccb->cpuoff;
for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) { for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
if (boot_cpu_address != cpue->address) if (boot_cpu_address != cpue->core_id)
continue; continue;
sclp_siif = cpue->siif; sclp_siif = cpue->siif;
break; break;
...@@ -139,6 +148,11 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) ...@@ -139,6 +148,11 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
if (sccb->flags & 0x2) if (sccb->flags & 0x2)
sclp_ipl_info.has_dump = 1; sclp_ipl_info.has_dump = 1;
memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN); memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
sclp_mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0;
sclp_mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0;
sclp_mtid_max = max(sclp_mtid, sclp_mtid_cp);
sclp_mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
} }
bool __init sclp_has_linemode(void) bool __init sclp_has_linemode(void)
...@@ -178,6 +192,21 @@ unsigned int sclp_get_ibc(void) ...@@ -178,6 +192,21 @@ unsigned int sclp_get_ibc(void)
} }
EXPORT_SYMBOL(sclp_get_ibc); EXPORT_SYMBOL(sclp_get_ibc);
unsigned int sclp_get_mtid(u8 cpu_type)
{
return cpu_type ? sclp_mtid : sclp_mtid_cp;
}
unsigned int sclp_get_mtid_max(void)
{
return sclp_mtid_max;
}
unsigned int sclp_get_mtid_prev(void)
{
return sclp_mtid_prev;
}
/* /*
* This function will be called after sclp_facilities_detect(), which gets * This function will be called after sclp_facilities_detect(), which gets
* called from early.c code. The sclp_facilities_detect() function retrieves * called from early.c code. The sclp_facilities_detect() function retrieves
......
...@@ -938,7 +938,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) ...@@ -938,7 +938,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
{ {
struct subchannel_id uninitialized_var(schid); struct subchannel_id uninitialized_var(schid);
s390_reset_system(NULL, NULL); s390_reset_system(NULL, NULL, NULL);
if (reipl_find_schid(devid, &schid) != 0) if (reipl_find_schid(devid, &schid) != 0)
panic("IPL Device not found\n"); panic("IPL Device not found\n");
do_reipl_asm(*((__u32*)&schid)); do_reipl_asm(*((__u32*)&schid));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment