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: Martin Schwidefsky <schwidefsky@de.ibm.com>
diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h
index cb700d5..5243a86 100644
--- a/arch/s390/include/asm/cpu_mf.h
+++ b/arch/s390/include/asm/cpu_mf.h
@@ -189,6 +189,20 @@
 	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)
 {
diff --git a/arch/s390/include/asm/reset.h b/arch/s390/include/asm/reset.h
index 8045785..7278606 100644
--- a/arch/s390/include/asm/reset.h
+++ b/arch/s390/include/asm/reset.h
@@ -15,5 +15,6 @@
 
 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 */
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index b6f8066..edb453c 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -27,7 +27,7 @@
 };
 
 struct sclp_cpu_entry {
-	u8 address;
+	u8 core_id;
 	u8 reserved0[2];
 	u8 : 3;
 	u8 siif : 1;
@@ -51,6 +51,9 @@
 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);
diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h
index 4957611..c49d9c0 100644
--- a/arch/s390/include/asm/sigp.h
+++ b/arch/s390/include/asm/sigp.h
@@ -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 */
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index 762d4f8..b3bd028 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -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);
 
@@ -35,6 +37,8 @@
 
 #else /* CONFIG_SMP */
 
+#define smp_cpu_mtid	0
+
 static inline void smp_call_ipl_cpu(void (*func)(void *), void *data)
 {
 	func(data);
diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h
index f92428e..73f12d2 100644
--- a/arch/s390/include/asm/sysinfo.h
+++ b/arch/s390/include/asm/sysinfo.h
@@ -90,7 +90,11 @@
 	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;
 };
@@ -120,26 +124,28 @@
 
 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;
 };
 
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h
index 56af530..c4fbb95 100644
--- a/arch/s390/include/asm/topology.h
+++ b/arch/s390/include/asm/topology.h
@@ -9,9 +9,11 @@
 #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;
 };
@@ -19,6 +21,8 @@
 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)