summary refs log tree commit diff
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-14 16:22:26 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-14 16:22:26 -0800
commit586592478b1fa8bb8cd6875a9191468e9b1a8b13 (patch)
treeb93ea8074b11ffa3c10ec4c0ed910479a6564bb0 /arch/s390/kernel
parent0b03beface02d519693edb8020f9811c67d5c88f (diff)
parent343dbdb7cb8997a2cb0fd804d6563b8a6de8d49b (diff)
downloadlinux-586592478b1fa8bb8cd6875a9191468e9b1a8b13.tar.gz
Merge tag 's390-5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Heiko Carstens:

 - Add support for the hugetlb_cma command line option to allocate
   gigantic hugepages using CMA

 - Add arch_get_random_long() support.

 - Add ap bus userspace notifications.

 - Increase default size of vmalloc area to 512GB and otherwise let it
   increase dynamically by the size of physical memory. This should fix
   all occurrences where the vmalloc area was not large enough.

 - Completely get rid of set_fs() (aka select SET_FS) and rework address
   space handling while doing that; making address space handling much
   more simple.

 - Reimplement getcpu vdso syscall in C.

 - Add support for extended SCLP responses (> 4k). This allows e.g. to
   handle also potential large system configurations.

 - Simplify KASAN by removing 3-level page table support and only
   supporting 4-levels from now on.

 - Improve debug-ability of the kernel decompressor code, which now
   prints also stack traces and symbols in case of problems to the
   console.

 - Remove more power management leftovers.

 - Other various fixes and improvements all over the place.

* tag 's390-5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (62 commits)
  s390/mm: add support to allocate gigantic hugepages using CMA
  s390/crypto: add arch_get_random_long() support
  s390/smp: perform initial CPU reset also for SMT siblings
  s390/mm: use invalid asce for user space when switching to init_mm
  s390/idle: fix accounting with machine checks
  s390/idle: add missing mt_cycles calculation
  s390/boot: add build-id to decompressor
  s390/kexec_file: fix diag308 subcode when loading crash kernel
  s390/cio: fix use-after-free in ccw_device_destroy_console
  s390/cio: remove pm support from ccw bus driver
  s390/cio: remove pm support from css-bus driver
  s390/cio: remove pm support from IO subchannel drivers
  s390/cio: remove pm support from chsc subchannel driver
  s390/vmur: remove unused pm related functions
  s390/tape: remove unsupported PM functions
  s390/cio: remove pm support from eadm-sch drivers
  s390: remove pm support from console drivers
  s390/dasd: remove unused pm related functions
  s390/zfcp: remove pm support from zfcp driver
  s390/ap: let bus_register() add the AP bus sysfs attributes
  ...
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/asm-offsets.c7
-rw-r--r--arch/s390/kernel/base.S22
-rw-r--r--arch/s390/kernel/early.c4
-rw-r--r--arch/s390/kernel/entry.S141
-rw-r--r--arch/s390/kernel/entry.h1
-rw-r--r--arch/s390/kernel/ftrace.c63
-rw-r--r--arch/s390/kernel/head64.S7
-rw-r--r--arch/s390/kernel/mcount.S8
-rw-r--r--arch/s390/kernel/process.c14
-rw-r--r--arch/s390/kernel/setup.c50
-rw-r--r--arch/s390/kernel/smp.c32
-rw-r--r--arch/s390/kernel/time.c44
-rw-r--r--arch/s390/kernel/vdso.c58
-rw-r--r--arch/s390/kernel/vdso64/Makefile5
-rw-r--r--arch/s390/kernel/vdso64/getcpu.S31
-rw-r--r--arch/s390/kernel/vdso64/getcpu.c21
-rw-r--r--arch/s390/kernel/vdso64/vdso.h14
-rw-r--r--arch/s390/kernel/vdso64/vdso64.lds.S1
-rw-r--r--arch/s390/kernel/vdso64/vdso64_generic.c1
-rw-r--r--arch/s390/kernel/vdso64/vdso_user_wrapper.S1
-rw-r--r--arch/s390/kernel/vmlinux.lds.S3
21 files changed, 184 insertions, 344 deletions
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 483051e10db3..79724d861dc9 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -13,7 +13,6 @@
 #include <linux/purgatory.h>
 #include <linux/pgtable.h>
 #include <asm/idle.h>
-#include <asm/vdso.h>
 #include <asm/gmap.h>
 #include <asm/nmi.h>
 #include <asm/stacktrace.h>
@@ -48,6 +47,7 @@ int main(void)
 	OFFSET(__PT_INT_PARM, pt_regs, int_parm);
 	OFFSET(__PT_INT_PARM_LONG, pt_regs, int_parm_long);
 	OFFSET(__PT_FLAGS, pt_regs, flags);
+	OFFSET(__PT_CR1, pt_regs, cr1);
 	DEFINE(__PT_SIZE, sizeof(struct pt_regs));
 	BLANK();
 	/* stack_frame offsets */
@@ -59,8 +59,6 @@ int main(void)
 	OFFSET(__SF_SIE_REASON, stack_frame, empty1[3]);
 	OFFSET(__SF_SIE_FLAGS, stack_frame, empty1[4]);
 	BLANK();
-	OFFSET(__VDSO_GETCPU_VAL, vdso_per_cpu_data, getcpu_val);
-	BLANK();
 	/* idle data offsets */
 	OFFSET(__CLOCK_IDLE_ENTER, s390_idle_data, clock_idle_enter);
 	OFFSET(__CLOCK_IDLE_EXIT, s390_idle_data, clock_idle_exit);
@@ -138,12 +136,11 @@ int main(void)
 	OFFSET(__LC_RESTART_FN, lowcore, restart_fn);
 	OFFSET(__LC_RESTART_DATA, lowcore, restart_data);
 	OFFSET(__LC_RESTART_SOURCE, lowcore, restart_source);
+	OFFSET(__LC_KERNEL_ASCE, lowcore, kernel_asce);
 	OFFSET(__LC_USER_ASCE, lowcore, user_asce);
-	OFFSET(__LC_VDSO_ASCE, lowcore, vdso_asce);
 	OFFSET(__LC_LPP, lowcore, lpp);
 	OFFSET(__LC_CURRENT_PID, lowcore, current_pid);
 	OFFSET(__LC_PERCPU_OFFSET, lowcore, percpu_offset);
-	OFFSET(__LC_VDSO_PER_CPU, lowcore, vdso_per_cpu_data);
 	OFFSET(__LC_MACHINE_FLAGS, lowcore, machine_flags);
 	OFFSET(__LC_PREEMPT_COUNT, lowcore, preempt_count);
 	OFFSET(__LC_GMAP, lowcore, gmap);
diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S
index b79e0fd571f8..d255c69c1779 100644
--- a/arch/s390/kernel/base.S
+++ b/arch/s390/kernel/base.S
@@ -11,32 +11,10 @@
 #include <asm/asm-offsets.h>
 #include <asm/nospec-insn.h>
 #include <asm/ptrace.h>
-#include <asm/sigp.h>
 
 	GEN_BR_THUNK %r9
 	GEN_BR_THUNK %r14
 
-ENTRY(s390_base_ext_handler)
-	stmg	%r0,%r15,__LC_SAVE_AREA_ASYNC
-	basr	%r13,0
-0:	aghi	%r15,-STACK_FRAME_OVERHEAD
-	larl	%r1,s390_base_ext_handler_fn
-	lg	%r9,0(%r1)
-	ltgr	%r9,%r9
-	jz	1f
-	BASR_EX	%r14,%r9
-1:	lmg	%r0,%r15,__LC_SAVE_AREA_ASYNC
-	ni	__LC_EXT_OLD_PSW+1,0xfd	# clear wait state bit
-	lpswe	__LC_EXT_OLD_PSW
-ENDPROC(s390_base_ext_handler)
-
-	.section .bss
-	.align 8
-	.globl s390_base_ext_handler_fn
-s390_base_ext_handler_fn:
-	.quad	0
-	.previous
-
 ENTRY(s390_base_pgm_handler)
 	stmg	%r0,%r15,__LC_SAVE_AREA_SYNC
 	basr	%r13,0
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 705844f73934..cc89763a4d3c 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -169,12 +169,10 @@ static noinline __init void setup_lowcore_early(void)
 {
 	psw_t psw;
 
+	psw.addr = (unsigned long)s390_base_pgm_handler;
 	psw.mask = PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA;
 	if (IS_ENABLED(CONFIG_KASAN))
 		psw.mask |= PSW_MASK_DAT;
-	psw.addr = (unsigned long) s390_base_ext_handler;
-	S390_lowcore.external_new_psw = psw;
-	psw.addr = (unsigned long) s390_base_pgm_handler;
 	S390_lowcore.program_new_psw = psw;
 	s390_base_pgm_handler_fn = early_pgm_check_handler;
 	S390_lowcore.preempt_count = INIT_PREEMPT_COUNT;
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 92beb1444644..8bb9ebb71c4b 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -55,7 +55,7 @@ _TIF_WORK	= (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
 		   _TIF_UPROBE | _TIF_GUARDED_STORAGE | _TIF_PATCH_PENDING)
 _TIF_TRACE	= (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
 		   _TIF_SYSCALL_TRACEPOINT)
-_CIF_WORK	= (_CIF_ASCE_PRIMARY | _CIF_ASCE_SECONDARY | _CIF_FPU)
+_CIF_WORK	= (_CIF_FPU)
 _PIF_WORK	= (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
 
 _LPP_OFFSET	= __LC_LPP
@@ -90,6 +90,12 @@ _LPP_OFFSET	= __LC_LPP
 #endif
 	.endm
 
+	.macro	DEBUG_USER_ASCE
+#ifdef CONFIG_DEBUG_USER_ASCE
+	brasl	%r14,debug_user_asce
+#endif
+	.endm
+
 	.macro	CHECK_VMAP_STACK savearea,oklabel
 #ifdef CONFIG_VMAP_STACK
 	lgr	%r14,%r15
@@ -110,9 +116,9 @@ _LPP_OFFSET	= __LC_LPP
 #endif
 	.endm
 
-	.macro	SWITCH_ASYNC savearea,timer
+	.macro	SWITCH_ASYNC savearea,timer,clock
 	tmhh	%r8,0x0001		# interrupting from user ?
-	jnz	2f
+	jnz	4f
 #if IS_ENABLED(CONFIG_KVM)
 	lgr	%r14,%r9
 	larl	%r13,.Lsie_gmap
@@ -125,10 +131,26 @@ _LPP_OFFSET	= __LC_LPP
 #endif
 0:	larl	%r13,.Lpsw_idle_exit
 	cgr	%r13,%r9
-	jne	1f
+	jne	3f
 
-	mvc	__CLOCK_IDLE_EXIT(8,%r2), __LC_INT_CLOCK
-	mvc	__TIMER_IDLE_EXIT(8,%r2), __LC_ASYNC_ENTER_TIMER
+	larl	%r1,smp_cpu_mtid
+	llgf	%r1,0(%r1)
+	ltgr	%r1,%r1
+	jz	2f			# no SMT, skip mt_cycles calculation
+	.insn	rsy,0xeb0000000017,%r1,5,__SF_EMPTY+80(%r15)
+	larl	%r3,mt_cycles
+	ag	%r3,__LC_PERCPU_OFFSET
+	la	%r4,__SF_EMPTY+16(%r15)
+1:	lg	%r0,0(%r3)
+	slg	%r0,0(%r4)
+	alg	%r0,64(%r4)
+	stg	%r0,0(%r3)
+	la	%r3,8(%r3)
+	la	%r4,8(%r4)
+	brct	%r1,1b
+
+2:	mvc	__CLOCK_IDLE_EXIT(8,%r2), \clock
+	mvc	__TIMER_IDLE_EXIT(8,%r2), \timer
 	# account system time going idle
 	ni	__LC_CPU_FLAGS+7,255-_CIF_ENABLED_WAIT
 
@@ -146,17 +168,17 @@ _LPP_OFFSET	= __LC_LPP
 	mvc	__LC_LAST_UPDATE_TIMER(8),__TIMER_IDLE_EXIT(%r2)
 
 	nihh	%r8,0xfcfd		# clear wait state and irq bits
-1:	lg	%r14,__LC_ASYNC_STACK	# are we already on the target stack?
+3:	lg	%r14,__LC_ASYNC_STACK	# are we already on the target stack?
 	slgr	%r14,%r15
 	srag	%r14,%r14,STACK_SHIFT
-	jnz	3f
+	jnz	5f
 	CHECK_STACK \savearea
 	aghi	%r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
-	j	4f
-2:	UPDATE_VTIME %r14,%r15,\timer
+	j	6f
+4:	UPDATE_VTIME %r14,%r15,\timer
 	BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
-3:	lg	%r15,__LC_ASYNC_STACK	# load async stack
-4:	la	%r11,STACK_FRAME_OVERHEAD(%r15)
+5:	lg	%r15,__LC_ASYNC_STACK	# load async stack
+6:	la	%r11,STACK_FRAME_OVERHEAD(%r15)
 	.endm
 
 	.macro UPDATE_VTIME w1,w2,enter_timer
@@ -327,7 +349,7 @@ ENTRY(sie64a)
 	BPENTER	__SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
 .Lsie_skip:
 	ni	__SIE_PROG0C+3(%r14),0xfe	# no longer in SIE
-	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
+	lctlg	%c1,%c1,__LC_KERNEL_ASCE	# load primary asce
 .Lsie_done:
 # some program checks are suppressing. C code (e.g. do_protection_exception)
 # will rewind the PSW by the ILC, which is often 4 bytes in case of SIE. There
@@ -380,6 +402,7 @@ ENTRY(system_call)
 	lg	%r12,__LC_CURRENT
 	lghi	%r14,_PIF_SYSCALL
 .Lsysc_per:
+	lctlg	%c1,%c1,__LC_KERNEL_ASCE
 	lghi	%r13,__TASK_thread
 	lg	%r15,__LC_KERNEL_STACK
 	la	%r11,STACK_FRAME_OVERHEAD(%r15)	# pointer to pt_regs
@@ -427,11 +450,9 @@ ENTRY(system_call)
 	jnz	.Lsysc_work
 	TSTMSK	__TI_flags(%r12),_TIF_WORK
 	jnz	.Lsysc_work			# check for work
-	TSTMSK	__LC_CPU_FLAGS,(_CIF_WORK-_CIF_FPU)
-	jnz	.Lsysc_work
+	DEBUG_USER_ASCE
+	lctlg	%c1,%c1,__LC_USER_ASCE
 	BPEXIT	__TI_flags(%r12),_TIF_ISOLATE_BP
-.Lsysc_restore:
-	DISABLE_INTS
 	TSTMSK	__LC_CPU_FLAGS, _CIF_FPU
 	jz	.Lsysc_skip_fpu
 	brasl	%r14,load_fpu_regs
@@ -469,8 +490,6 @@ ENTRY(system_call)
 	jo	.Lsysc_sigpending
 	TSTMSK	__TI_flags(%r12),_TIF_NOTIFY_RESUME
 	jo	.Lsysc_notify_resume
-	TSTMSK	__LC_CPU_FLAGS,(_CIF_ASCE_PRIMARY|_CIF_ASCE_SECONDARY)
-	jnz	.Lsysc_asce
 	j	.Lsysc_return
 
 #
@@ -481,26 +500,6 @@ ENTRY(system_call)
 	jg	schedule
 
 #
-# _CIF_ASCE_PRIMARY and/or _CIF_ASCE_SECONDARY set, load user space asce
-#
-.Lsysc_asce:
-	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE_SECONDARY
-	lctlg	%c7,%c7,__LC_VDSO_ASCE		# load secondary asce
-	TSTMSK	__LC_CPU_FLAGS,_CIF_ASCE_PRIMARY
-	jz	.Lsysc_return
-#ifndef CONFIG_HAVE_MARCH_Z10_FEATURES
-	tm	__LC_STFLE_FAC_LIST+3,0x10	# has MVCOS ?
-	jnz	.Lsysc_set_fs_fixup
-	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE_PRIMARY
-	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
-	j	.Lsysc_return
-.Lsysc_set_fs_fixup:
-#endif
-	larl	%r14,.Lsysc_return
-	jg	set_fs_fixup
-
-
-#
 # _TIF_SIGPENDING is set, call do_signal
 #
 .Lsysc_sigpending:
@@ -636,8 +635,11 @@ ENTRY(pgm_check_handler)
 0:	lg	%r12,__LC_CURRENT
 	lghi	%r11,0
 	lmg	%r8,%r9,__LC_PGM_OLD_PSW
-	tmhh	%r8,0x0001		# test problem state bit
-	jnz	3f			# -> fault in user space
+	tmhh	%r8,0x0001		# coming from user space?
+	jno	.Lpgm_skip_asce
+	lctlg	%c1,%c1,__LC_KERNEL_ASCE
+	j	3f
+.Lpgm_skip_asce:
 #if IS_ENABLED(CONFIG_KVM)
 	# cleanup critical section for program checks in sie64a
 	lgr	%r14,%r9
@@ -648,7 +650,7 @@ ENTRY(pgm_check_handler)
 	jhe	1f
 	lg	%r14,__SF_SIE_CONTROL(%r15)	# get control block pointer
 	ni	__SIE_PROG0C+3(%r14),0xfe	# no longer in SIE
-	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
+	lctlg	%c1,%c1,__LC_KERNEL_ASCE	# load primary asce
 	larl	%r9,sie_exit			# skip forward to sie_exit
 	lghi	%r11,_PIF_GUEST_FAULT
 #endif
@@ -709,10 +711,20 @@ ENTRY(pgm_check_handler)
 .Lpgm_return:
 	LOCKDEP_SYS_EXIT
 	tm	__PT_PSW+1(%r11),0x01	# returning to user ?
-	jno	.Lsysc_restore
+	jno	.Lpgm_restore
 	TSTMSK	__PT_FLAGS(%r11),_PIF_SYSCALL
 	jo	.Lsysc_do_syscall
 	j	.Lsysc_tif
+.Lpgm_restore:
+	DISABLE_INTS
+	TSTMSK	__LC_CPU_FLAGS, _CIF_FPU
+	jz	.Lpgm_skip_fpu
+	brasl	%r14,load_fpu_regs
+.Lpgm_skip_fpu:
+	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r11)
+	stpt	__LC_EXIT_TIMER
+	lmg	%r0,%r15,__PT_R0(%r11)
+	b	__LC_RETURN_LPSWE
 
 #
 # PER event in supervisor state, must be kprobes
@@ -745,7 +757,7 @@ ENTRY(io_int_handler)
 	stmg	%r8,%r15,__LC_SAVE_AREA_ASYNC
 	lg	%r12,__LC_CURRENT
 	lmg	%r8,%r9,__LC_IO_OLD_PSW
-	SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
+	SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER,__LC_INT_CLOCK
 	stmg	%r0,%r7,__PT_R0(%r11)
 	# clear user controlled registers to prevent speculative use
 	xgr	%r0,%r0
@@ -759,6 +771,10 @@ ENTRY(io_int_handler)
 	xgr	%r10,%r10
 	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
 	stmg	%r8,%r9,__PT_PSW(%r11)
+	tm	__PT_PSW+1(%r11),0x01	# coming from user space?
+	jno	.Lio_skip_asce
+	lctlg	%c1,%c1,__LC_KERNEL_ASCE
+.Lio_skip_asce:
 	mvc	__PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
 	xc	__PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
 	TSTMSK	__LC_CPU_FLAGS,_CIF_IGNORE_IRQ
@@ -790,6 +806,8 @@ ENTRY(io_int_handler)
 	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r11)
 	tm	__PT_PSW+1(%r11),0x01	# returning to user ?
 	jno	.Lio_exit_kernel
+	DEBUG_USER_ASCE
+	lctlg	%c1,%c1,__LC_USER_ASCE
 	BPEXIT	__TI_flags(%r12),_TIF_ISOLATE_BP
 	stpt	__LC_EXIT_TIMER
 .Lio_exit_kernel:
@@ -855,30 +873,9 @@ ENTRY(io_int_handler)
 	jo	.Lio_guarded_storage
 	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
 	jo	.Lio_vxrs
-	TSTMSK	__LC_CPU_FLAGS,(_CIF_ASCE_PRIMARY|_CIF_ASCE_SECONDARY)
-	jnz	.Lio_asce
 	j	.Lio_return
 
 #
-# _CIF_ASCE_PRIMARY and/or CIF_ASCE_SECONDARY set, load user space asce
-#
-.Lio_asce:
-	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE_SECONDARY
-	lctlg	%c7,%c7,__LC_VDSO_ASCE		# load secondary asce
-	TSTMSK	__LC_CPU_FLAGS,_CIF_ASCE_PRIMARY
-	jz	.Lio_return
-#ifndef CONFIG_HAVE_MARCH_Z10_FEATURES
-	tm	__LC_STFLE_FAC_LIST+3,0x10	# has MVCOS ?
-	jnz	.Lio_set_fs_fixup
-	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE_PRIMARY
-	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
-	j	.Lio_return
-.Lio_set_fs_fixup:
-#endif
-	larl	%r14,.Lio_return
-	jg	set_fs_fixup
-
-#
 # CIF_FPU is set, restore floating-point controls and floating-point registers.
 #
 .Lio_vxrs:
@@ -945,7 +942,7 @@ ENTRY(ext_int_handler)
 	stmg	%r8,%r15,__LC_SAVE_AREA_ASYNC
 	lg	%r12,__LC_CURRENT
 	lmg	%r8,%r9,__LC_EXT_OLD_PSW
-	SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
+	SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER,__LC_INT_CLOCK
 	stmg	%r0,%r7,__PT_R0(%r11)
 	# clear user controlled registers to prevent speculative use
 	xgr	%r0,%r0
@@ -959,6 +956,10 @@ ENTRY(ext_int_handler)
 	xgr	%r10,%r10
 	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
 	stmg	%r8,%r9,__PT_PSW(%r11)
+	tm	__PT_PSW+1(%r11),0x01	# coming from user space?
+	jno	.Lext_skip_asce
+	lctlg	%c1,%c1,__LC_KERNEL_ASCE
+.Lext_skip_asce:
 	lghi	%r1,__LC_EXT_PARAMS2
 	mvc	__PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
 	mvc	__PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
@@ -1167,7 +1168,7 @@ ENTRY(mcck_int_handler)
 	TSTMSK	__LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID
 	jno	.Lmcck_panic
 4:	ssm	__LC_PGM_NEW_PSW	# turn dat on, keep irqs off
-	SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_MCCK_ENTER_TIMER
+	SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_MCCK_ENTER_TIMER,__LC_MCCK_CLOCK
 .Lmcck_skip:
 	lghi	%r14,__LC_GPREGS_SAVE_AREA+64
 	stmg	%r0,%r7,__PT_R0(%r11)
@@ -1183,6 +1184,9 @@ ENTRY(mcck_int_handler)
 	xgr	%r10,%r10
 	mvc	__PT_R8(64,%r11),0(%r14)
 	stmg	%r8,%r9,__PT_PSW(%r11)
+	la	%r14,4095
+	mvc	__PT_CR1(8,%r11),__LC_CREGS_SAVE_AREA-4095+8(%r14)
+	lctlg	%c1,%c1,__LC_KERNEL_ASCE
 	xc	__PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
 	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
 	lgr	%r2,%r11		# pass pointer to pt_regs
@@ -1198,6 +1202,7 @@ ENTRY(mcck_int_handler)
 	brasl	%r14,s390_handle_mcck
 	TRACE_IRQS_ON
 .Lmcck_return:
+	lctlg	%c1,%c1,__PT_CR1(%r11)
 	lmg	%r0,%r10,__PT_R0(%r11)
 	mvc	__LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW
 	tm	__LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
@@ -1274,7 +1279,7 @@ ENDPROC(stack_overflow)
 1:	BPENTER	__SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
 	lg	%r9,__SF_SIE_CONTROL(%r15)	# get control block pointer
 	ni	__SIE_PROG0C+3(%r9),0xfe	# no longer in SIE
-	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
+	lctlg	%c1,%c1,__LC_KERNEL_ASCE
 	larl	%r9,sie_exit			# skip forward to sie_exit
 	BR_EX	%r14,%r11
 
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index d2ca3fe51f8e..a16c33b32ab0 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -83,7 +83,6 @@ long sys_s390_sthyi(unsigned long function_code, void __user *buffer, u64 __user
 DECLARE_PER_CPU(u64, mt_cycles[8]);
 
 void gs_load_bc_cb(struct pt_regs *regs);
-void set_fs_fixup(void);
 
 unsigned long stack_alloc(void);
 void stack_free(unsigned long stack);
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
index b388e87a08bf..ebc1284a618b 100644
--- a/arch/s390/kernel/ftrace.c
+++ b/arch/s390/kernel/ftrace.c
@@ -22,56 +22,26 @@
 #include "entry.h"
 
 /*
- * The mcount code looks like this:
- *	stg	%r14,8(%r15)		# offset 0
- *	larl	%r1,<&counter>		# offset 6
- *	brasl	%r14,_mcount		# offset 12
- *	lg	%r14,8(%r15)		# offset 18
- * Total length is 24 bytes. Only the first instruction will be patched
- * by ftrace_make_call / ftrace_make_nop.
- * The enabled ftrace code block looks like this:
+ * To generate function prologue either gcc's hotpatch feature (since gcc 4.8)
+ * or a combination of -pg -mrecord-mcount -mnop-mcount -mfentry flags
+ * (since gcc 9 / clang 10) is used.
+ * In both cases the original and also the disabled function prologue contains
+ * only a single six byte instruction and looks like this:
+ * >	brcl	0,0			# offset 0
+ * To enable ftrace the code gets patched like above and afterwards looks
+ * like this:
  * >	brasl	%r0,ftrace_caller	# offset 0
- *	larl	%r1,<&counter>		# offset 6
- *	brasl	%r14,_mcount		# offset 12
- *	lg	%r14,8(%r15)		# offset 18
+ *
+ * The instruction will be patched by ftrace_make_call / ftrace_make_nop.
  * The ftrace function gets called with a non-standard C function call ABI
  * where r0 contains the return address. It is also expected that the called
  * function only clobbers r0 and r1, but restores r2-r15.
  * For module code we can't directly jump to ftrace caller, but need a
  * trampoline (ftrace_plt), which clobbers also r1.
- * The return point of the ftrace function has offset 24, so execution
- * continues behind the mcount block.
- * The disabled ftrace code block looks like this:
- * >	jg	.+24			# offset 0
- *	larl	%r1,<&counter>		# offset 6
- *	brasl	%r14,_mcount		# offset 12
- *	lg	%r14,8(%r15)		# offset 18
- * The jg instruction branches to offset 24 to skip as many instructions
- * as possible.
- * In case we use gcc's hotpatch feature the original and also the disabled
- * function prologue contains only a single six byte instruction and looks
- * like this:
- * >	brcl	0,0			# offset 0
- * To enable ftrace the code gets patched like above and afterwards looks
- * like this:
- * >	brasl	%r0,ftrace_caller	# offset 0
  */
 
 unsigned long ftrace_plt;
 
-static inline void ftrace_generate_orig_insn(struct ftrace_insn *insn)
-{
-#if defined(CC_USING_HOTPATCH) || defined(CC_USING_NOP_MCOUNT)
-	/* brcl 0,0 */
-	insn->opc = 0xc004;
-	insn->disp = 0;
-#else
-	/* stg r14,8(r15) */
-	insn->opc = 0xe3e0;
-	insn->disp = 0xf0080024;
-#endif
-}
-
 int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
 		       unsigned long addr)
 {
@@ -85,15 +55,10 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
 
 	if (copy_from_kernel_nofault(&old, (void *) rec->ip, sizeof(old)))
 		return -EFAULT;
-	if (addr == MCOUNT_ADDR) {
-		/* Initial code replacement */
-		ftrace_generate_orig_insn(&orig);
-		ftrace_generate_nop_insn(&new);
-	} else {
-		/* Replace ftrace call with a nop. */
-		ftrace_generate_call_insn(&orig, rec->ip);
-		ftrace_generate_nop_insn(&new);
-	}
+	/* Replace ftrace call with a nop. */
+	ftrace_generate_call_insn(&orig, rec->ip);
+	ftrace_generate_nop_insn(&new);
+
 	/* Verify that the to be replaced code matches what we expect. */
 	if (memcmp(&orig, &old, sizeof(old)))
 		return -EINVAL;
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 8b88dbbda7df..0c253886da78 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -18,12 +18,7 @@
 
 __HEAD
 ENTRY(startup_continue)
-	tm	__LC_STFLE_FAC_LIST+5,0x80	# LPP available ?
-	jz	0f
-	xc	__LC_LPP+1(7,0),__LC_LPP+1	# clear lpp and current_pid
-	mvi	__LC_LPP,0x80			#   and set LPP_MAGIC
-	.insn	s,0xb2800000,__LC_LPP		# load program parameter
-0:	larl	%r1,tod_clock_base
+	larl	%r1,tod_clock_base
 	mvc	0(16,%r1),__LC_BOOT_CLOCK
 	larl	%r13,.LPG1		# get base
 #
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S
index 7458dcfd6464..faf64c2f90f5 100644
--- a/arch/s390/kernel/mcount.S
+++ b/arch/s390/kernel/mcount.S
@@ -33,11 +33,6 @@ ENDPROC(ftrace_stub)
 #define TRACED_FUNC_FRAME_SIZE	STACK_FRAME_OVERHEAD
 #endif
 
-ENTRY(_mcount)
-	BR_EX	%r14
-ENDPROC(_mcount)
-EXPORT_SYMBOL(_mcount)
-
 ENTRY(ftrace_caller)
 	.globl	ftrace_regs_caller
 	.set	ftrace_regs_caller,ftrace_caller
@@ -46,9 +41,6 @@ ENTRY(ftrace_caller)
 	ipm	%r14				# don't put any instructions
 	sllg	%r14,%r14,16			# clobbering CC before this point
 	lgr	%r1,%r15
-#if !(defined(CC_USING_HOTPATCH) || defined(CC_USING_NOP_MCOUNT))
-	aghi	%r0,MCOUNT_RETURN_FIXUP
-#endif
 	# allocate stack frame for ftrace_caller to contain traced function
 	aghi	%r15,-TRACED_FUNC_FRAME_SIZE
 	stg	%r1,__SF_BACKCHAIN(%r15)
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index ec801d3bbb37..bc3ca54edfb4 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -94,7 +94,6 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
 	/* Save access registers to new thread structure. */
 	save_access_regs(&p->thread.acrs[0]);
 	/* start new process with ar4 pointing to the correct address space */
-	p->thread.mm_segment = get_fs();
 	/* Don't copy debug registers */
 	memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
 	memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
@@ -208,16 +207,3 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
 	ret = PAGE_ALIGN(mm->brk + brk_rnd());
 	return (ret > mm->brk) ? ret : mm->brk;
 }
-
-void set_fs_fixup(void)
-{
-	struct pt_regs *regs = current_pt_regs();
-	static bool warned;
-
-	set_fs(USER_DS);
-	if (warned)
-		return;
-	WARN(1, "Unbalanced set_fs - int code: 0x%x\n", regs->int_code);
-	show_registers(regs);
-	warned = true;
-}
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 4d843e64496f..1f16a03be995 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -49,6 +49,7 @@
 #include <linux/memory.h>
 #include <linux/compat.h>
 #include <linux/start_kernel.h>
+#include <linux/hugetlb.h>
 
 #include <asm/boot_data.h>
 #include <asm/ipl.h>
@@ -94,10 +95,8 @@ char elf_platform[ELF_PLATFORM_SIZE];
 unsigned long int_hwcap = 0;
 
 int __bootdata(noexec_disabled);
-int __bootdata(memory_end_set);
-unsigned long __bootdata(memory_end);
+unsigned long __bootdata(ident_map_size);
 unsigned long __bootdata(vmalloc_size);
-unsigned long __bootdata(max_physmem_end);
 struct mem_detect_info __bootdata(mem_detect);
 
 struct exception_table_entry *__bootdata_preserved(__start_dma_ex_table);
@@ -336,6 +335,7 @@ int __init arch_early_irq_init(void)
 	if (!stack)
 		panic("Couldn't allocate async stack");
 	S390_lowcore.async_stack = stack + STACK_INIT_OFFSET;
+	udelay_enable();
 	return 0;
 }
 
@@ -556,24 +556,25 @@ static void __init setup_resources(void)
 #endif
 }
 
-static void __init setup_memory_end(void)
+static void __init setup_ident_map_size(void)
 {
 	unsigned long vmax, tmp;
 
 	/* Choose kernel address space layout: 3 or 4 levels. */
-	tmp = (memory_end ?: max_physmem_end) / PAGE_SIZE;
+	tmp = ident_map_size / PAGE_SIZE;
 	tmp = tmp * (sizeof(struct page) + PAGE_SIZE);
 	if (tmp + vmalloc_size + MODULES_LEN <= _REGION2_SIZE)
 		vmax = _REGION2_SIZE; /* 3-level kernel page table */
 	else
 		vmax = _REGION1_SIZE; /* 4-level kernel page table */
+	/* module area is at the end of the kernel address space. */
+	MODULES_END = vmax;
 	if (is_prot_virt_host())
-		adjust_to_uv_max(&vmax);
+		adjust_to_uv_max(&MODULES_END);
 #ifdef CONFIG_KASAN
-	vmax = kasan_vmax;
+	vmax = _REGION1_SIZE;
+	MODULES_END = kasan_vmax;
 #endif
-	/* module area is at the end of the kernel address space. */
-	MODULES_END = vmax;
 	MODULES_VADDR = MODULES_END - MODULES_LEN;
 	VMALLOC_END = MODULES_VADDR;
 	VMALLOC_START = VMALLOC_END - vmalloc_size;
@@ -587,22 +588,22 @@ static void __init setup_memory_end(void)
 	tmp = min(tmp, 1UL << MAX_PHYSMEM_BITS);
 	vmemmap = (struct page *) tmp;
 
-	/* Take care that memory_end is set and <= vmemmap */
-	memory_end = min(memory_end ?: max_physmem_end, (unsigned long)vmemmap);
+	/* Take care that ident_map_size <= vmemmap */
+	ident_map_size = min(ident_map_size, (unsigned long)vmemmap);
 #ifdef CONFIG_KASAN
-	memory_end = min(memory_end, KASAN_SHADOW_START);
+	ident_map_size = min(ident_map_size, KASAN_SHADOW_START);
 #endif
-	vmemmap_size = SECTION_ALIGN_UP(memory_end / PAGE_SIZE) * sizeof(struct page);
+	vmemmap_size = SECTION_ALIGN_UP(ident_map_size / PAGE_SIZE) * sizeof(struct page);
 #ifdef CONFIG_KASAN
 	/* move vmemmap above kasan shadow only if stands in a way */
 	if (KASAN_SHADOW_END > (unsigned long)vmemmap &&
 	    (unsigned long)vmemmap + vmemmap_size > KASAN_SHADOW_START)
 		vmemmap = max(vmemmap, (struct page *)KASAN_SHADOW_END);
 #endif
-	max_pfn = max_low_pfn = PFN_DOWN(memory_end);
-	memblock_remove(memory_end, ULONG_MAX);
+	max_pfn = max_low_pfn = PFN_DOWN(ident_map_size);
+	memblock_remove(ident_map_size, ULONG_MAX);
 
-	pr_notice("The maximum memory size is %luMB\n", memory_end >> 20);
+	pr_notice("The maximum memory size is %luMB\n", ident_map_size >> 20);
 }
 
 #ifdef CONFIG_CRASH_DUMP
@@ -632,12 +633,11 @@ static struct notifier_block kdump_mem_nb = {
 #endif
 
 /*
- * Make sure that the area behind memory_end is protected
+ * Make sure that the area above identity mapping is protected
  */
-static void __init reserve_memory_end(void)
+static void __init reserve_above_ident_map(void)
 {
-	if (memory_end_set)
-		memblock_reserve(memory_end, ULONG_MAX);
+	memblock_reserve(ident_map_size, ULONG_MAX);
 }
 
 /*
@@ -674,7 +674,7 @@ static void __init reserve_crashkernel(void)
 	phys_addr_t low, high;
 	int rc;
 
-	rc = parse_crashkernel(boot_command_line, memory_end, &crash_size,
+	rc = parse_crashkernel(boot_command_line, ident_map_size, &crash_size,
 			       &crash_base);
 
 	crash_base = ALIGN(crash_base, KEXEC_CRASH_MEM_ALIGN);
@@ -1128,7 +1128,7 @@ void __init setup_arch(char **cmdline_p)
 	setup_control_program_code();
 
 	/* Do some memory reservations *before* memory is added to memblock */
-	reserve_memory_end();
+	reserve_above_ident_map();
 	reserve_oldmem();
 	reserve_kernel();
 	reserve_initrd();
@@ -1143,10 +1143,12 @@ void __init setup_arch(char **cmdline_p)
 	remove_oldmem();
 
 	setup_uv();
-	setup_memory_end();
+	setup_ident_map_size();
 	setup_memory();
-	dma_contiguous_reserve(memory_end);
+	dma_contiguous_reserve(ident_map_size);
 	vmcp_cma_reserve();
+	if (MACHINE_HAS_EDAT2)
+		hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT);
 
 	check_initrd();
 	reserve_crashkernel();
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 390d97daa2b3..27c763014114 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -47,7 +47,6 @@
 #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>
@@ -55,6 +54,7 @@
 #include <asm/nmi.h>
 #include <asm/stacktrace.h>
 #include <asm/topology.h>
+#include <asm/vdso.h>
 #include "entry.h"
 
 enum {
@@ -217,14 +217,10 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
 	lc->return_mcck_lpswe = gen_lpswe(__LC_RETURN_MCCK_PSW);
 	if (nmi_alloc_per_cpu(lc))
 		goto out_async;
-	if (vdso_alloc_per_cpu(lc))
-		goto out_mcesa;
 	lowcore_ptr[cpu] = lc;
 	pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, (u32)(unsigned long) lc);
 	return 0;
 
-out_mcesa:
-	nmi_free_per_cpu(lc);
 out_async:
 	stack_free(async_stack);
 out:
@@ -245,7 +241,6 @@ static void pcpu_free_lowcore(struct pcpu *pcpu)
 
 	pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0);
 	lowcore_ptr[pcpu - pcpu_devices] = NULL;
-	vdso_free_per_cpu(pcpu->lowcore);
 	nmi_free_per_cpu(pcpu->lowcore);
 	stack_free(async_stack);
 	if (pcpu == &pcpu_devices[0])
@@ -265,13 +260,13 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
 	lc->spinlock_index = 0;
 	lc->percpu_offset = __per_cpu_offset[cpu];
 	lc->kernel_asce = S390_lowcore.kernel_asce;
-	lc->user_asce = S390_lowcore.kernel_asce;
+	lc->user_asce = s390_invalid_asce;
 	lc->machine_flags = S390_lowcore.machine_flags;
 	lc->user_timer = lc->system_timer =
 		lc->steal_timer = lc->avg_steal_timer = 0;
 	__ctl_store(lc->cregs_save_area, 0, 15);
 	lc->cregs_save_area[1] = lc->kernel_asce;
-	lc->cregs_save_area[7] = lc->vdso_asce;
+	lc->cregs_save_area[7] = lc->user_asce;
 	save_access_regs((unsigned int *) lc->access_regs_save_area);
 	memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
 	       sizeof(lc->stfle_fac_list));
@@ -859,13 +854,12 @@ static void smp_init_secondary(void)
 
 	S390_lowcore.last_update_clock = get_tod_clock();
 	restore_access_regs(S390_lowcore.access_regs_save_area);
-	set_cpu_flag(CIF_ASCE_PRIMARY);
-	set_cpu_flag(CIF_ASCE_SECONDARY);
 	cpu_init();
 	rcu_cpu_starting(cpu);
 	preempt_disable();
 	init_cpu_timer();
 	vtime_init();
+	vdso_getcpu_init();
 	pfault_init();
 	notify_cpu_starting(cpu);
 	if (topology_cpu_dedicated(cpu))
@@ -896,24 +890,12 @@ static void __no_sanitize_address smp_start_secondary(void *cpuvoid)
 /* Upping and downing of CPUs */
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
-	struct pcpu *pcpu;
-	int base, i, rc;
+	struct pcpu *pcpu = pcpu_devices + cpu;
+	int rc;
 
-	pcpu = pcpu_devices + cpu;
 	if (pcpu->state != CPU_STATE_CONFIGURED)
 		return -EIO;
-	base = smp_get_base_cpu(cpu);
-	for (i = 0; i <= smp_cpu_mtid; i++) {
-		if (base + i < nr_cpu_ids)
-			if (cpu_online(base + i))
-				break;
-	}
-	/*
-	 * If this is the first CPU of the core to get online
-	 * do an initial CPU reset.
-	 */
-	if (i > smp_cpu_mtid &&
-	    pcpu_sigp_retry(pcpu_devices + base, SIGP_INITIAL_CPU_RESET, 0) !=
+	if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) !=
 	    SIGP_CC_ORDER_CODE_ACCEPTED)
 		return -EIO;
 
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 0ac30ee2c633..c59cb44fbb7d 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -927,41 +927,25 @@ static ssize_t online_store(struct device *dev,
  */
 static DEVICE_ATTR_RW(online);
 
-static struct device_attribute *stp_attributes[] = {
-	&dev_attr_ctn_id,
-	&dev_attr_ctn_type,
-	&dev_attr_dst_offset,
-	&dev_attr_leap_seconds,
-	&dev_attr_online,
-	&dev_attr_leap_seconds_scheduled,
-	&dev_attr_stratum,
-	&dev_attr_time_offset,
-	&dev_attr_time_zone_offset,
-	&dev_attr_timing_mode,
-	&dev_attr_timing_state,
+static struct attribute *stp_dev_attrs[] = {
+	&dev_attr_ctn_id.attr,
+	&dev_attr_ctn_type.attr,
+	&dev_attr_dst_offset.attr,
+	&dev_attr_leap_seconds.attr,
+	&dev_attr_online.attr,
+	&dev_attr_leap_seconds_scheduled.attr,
+	&dev_attr_stratum.attr,
+	&dev_attr_time_offset.attr,
+	&dev_attr_time_zone_offset.attr,
+	&dev_attr_timing_mode.attr,
+	&dev_attr_timing_state.attr,
 	NULL
 };
+ATTRIBUTE_GROUPS(stp_dev);
 
 static int __init stp_init_sysfs(void)
 {
-	struct device_attribute **attr;
-	int rc;
-
-	rc = subsys_system_register(&stp_subsys, NULL);
-	if (rc)
-		goto out;
-	for (attr = stp_attributes; *attr; attr++) {
-		rc = device_create_file(stp_subsys.dev_root, *attr);
-		if (rc)
-			goto out_unreg;
-	}
-	return 0;
-out_unreg:
-	for (; attr >= stp_attributes; attr--)
-		device_remove_file(stp_subsys.dev_root, *attr);
-	bus_unregister(&stp_subsys);
-out:
-	return rc;
+	return subsys_system_register(&stp_subsys, stp_dev_groups);
 }
 
 device_initcall(stp_init_sysfs);
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index f9da5b149141..aef2edff9959 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -29,6 +29,7 @@
 #include <asm/sections.h>
 #include <asm/vdso.h>
 #include <asm/facility.h>
+#include <asm/timex.h>
 
 extern char vdso64_start, vdso64_end;
 static void *vdso64_kbase = &vdso64_start;
@@ -99,60 +100,10 @@ static union {
 	u8			page[PAGE_SIZE];
 } vdso_data_store __page_aligned_data;
 struct vdso_data *vdso_data = (struct vdso_data *)&vdso_data_store.data;
-/*
- * Allocate/free per cpu vdso data.
- */
-#define SEGMENT_ORDER	2
 
-int vdso_alloc_per_cpu(struct lowcore *lowcore)
+void vdso_getcpu_init(void)
 {
-	unsigned long segment_table, page_table, page_frame;
-	struct vdso_per_cpu_data *vd;
-
-	segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER);
-	page_table = get_zeroed_page(GFP_KERNEL);
-	page_frame = get_zeroed_page(GFP_KERNEL);
-	if (!segment_table || !page_table || !page_frame)
-		goto out;
-	arch_set_page_dat(virt_to_page(segment_table), SEGMENT_ORDER);
-	arch_set_page_dat(virt_to_page(page_table), 0);
-
-	/* Initialize per-cpu vdso data page */
-	vd = (struct vdso_per_cpu_data *) page_frame;
-	vd->cpu_nr = lowcore->cpu_nr;
-	vd->node_id = cpu_to_node(vd->cpu_nr);
-
-	/* Set up page table for the vdso address space */
-	memset64((u64 *)segment_table, _SEGMENT_ENTRY_EMPTY, _CRST_ENTRIES);
-	memset64((u64 *)page_table, _PAGE_INVALID, PTRS_PER_PTE);
-
-	*(unsigned long *) segment_table = _SEGMENT_ENTRY + page_table;
-	*(unsigned long *) page_table = _PAGE_PROTECT + page_frame;
-
-	lowcore->vdso_asce = segment_table +
-		_ASCE_TABLE_LENGTH + _ASCE_USER_BITS + _ASCE_TYPE_SEGMENT;
-	lowcore->vdso_per_cpu_data = page_frame;
-
-	return 0;
-
-out:
-	free_page(page_frame);
-	free_page(page_table);
-	free_pages(segment_table, SEGMENT_ORDER);
-	return -ENOMEM;
-}
-
-void vdso_free_per_cpu(struct lowcore *lowcore)
-{
-	unsigned long segment_table, page_table, page_frame;
-
-	segment_table = lowcore->vdso_asce & PAGE_MASK;
-	page_table = *(unsigned long *) segment_table;
-	page_frame = *(unsigned long *) page_table;
-
-	free_page(page_frame);
-	free_page(page_table);
-	free_pages(segment_table, SEGMENT_ORDER);
+	set_tod_programmable_field(smp_processor_id());
 }
 
 /*
@@ -225,6 +176,7 @@ static int __init vdso_init(void)
 {
 	int i;
 
+	vdso_getcpu_init();
 	/* Calculate the size of the 64 bit vDSO */
 	vdso64_pages = ((&vdso64_end - &vdso64_start
 			 + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
@@ -240,8 +192,6 @@ static int __init vdso_init(void)
 	}
 	vdso64_pagelist[vdso64_pages - 1] = virt_to_page(vdso_data);
 	vdso64_pagelist[vdso64_pages] = NULL;
-	if (vdso_alloc_per_cpu(&S390_lowcore))
-		BUG();
 
 	get_page(virt_to_page(vdso_data));
 
diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile
index 13cc5a3f9abf..a6e0fb6b91d6 100644
--- a/arch/s390/kernel/vdso64/Makefile
+++ b/arch/s390/kernel/vdso64/Makefile
@@ -6,8 +6,9 @@ ARCH_REL_TYPE_ABS := R_390_COPY|R_390_GLOB_DAT|R_390_JMP_SLOT|R_390_RELATIVE
 ARCH_REL_TYPE_ABS += R_390_GOT|R_390_PLT
 
 include $(srctree)/lib/vdso/Makefile
-obj-vdso64 = vdso_user_wrapper.o note.o getcpu.o
-obj-cvdso64 = vdso64_generic.o
+obj-vdso64 = vdso_user_wrapper.o note.o
+obj-cvdso64 = vdso64_generic.o getcpu.o
+CFLAGS_REMOVE_getcpu.o = -pg $(CC_FLAGS_FTRACE) $(CC_FLAGS_EXPOLINE)
 CFLAGS_REMOVE_vdso64_generic.o = -pg $(CC_FLAGS_FTRACE) $(CC_FLAGS_EXPOLINE)
 
 # Build rules
diff --git a/arch/s390/kernel/vdso64/getcpu.S b/arch/s390/kernel/vdso64/getcpu.S
deleted file mode 100644
index 3c04f7328500..000000000000
--- a/arch/s390/kernel/vdso64/getcpu.S
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Userland implementation of getcpu() for 64 bits processes in a
- * s390 kernel for use in the vDSO
- *
- *  Copyright IBM Corp. 2016
- *  Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
- */
-#include <asm/vdso.h>
-#include <asm/asm-offsets.h>
-#include <asm/dwarf.h>
-
-	.text
-	.align 4
-	.globl __kernel_getcpu
-	.type  __kernel_getcpu,@function
-__kernel_getcpu:
-	CFI_STARTPROC
-	sacf	256
-	lm	%r4,%r5,__VDSO_GETCPU_VAL(%r0)
-	sacf	0
-	ltgr	%r2,%r2
-	jz	2f
-	st	%r5,0(%r2)
-2:	ltgr	%r3,%r3
-	jz	3f
-	st	%r4,0(%r3)
-3:	lghi	%r2,0
-	br	%r14
-	CFI_ENDPROC
-	.size	__kernel_getcpu,.-__kernel_getcpu
diff --git a/arch/s390/kernel/vdso64/getcpu.c b/arch/s390/kernel/vdso64/getcpu.c
new file mode 100644
index 000000000000..5b2bc7494d5b
--- /dev/null
+++ b/arch/s390/kernel/vdso64/getcpu.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright IBM Corp. 2020 */
+
+#include <linux/compiler.h>
+#include <linux/getcpu.h>
+#include <asm/timex.h>
+#include "vdso.h"
+
+int __s390_vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused)
+{
+	__u16 todval[8];
+
+	/* CPU number is stored in the programmable field of the TOD clock */
+	get_tod_clock_ext((char *)todval);
+	if (cpu)
+		*cpu = todval[7];
+	/* NUMA node is always zero */
+	if (node)
+		*node = 0;
+	return 0;
+}
diff --git a/arch/s390/kernel/vdso64/vdso.h b/arch/s390/kernel/vdso64/vdso.h
new file mode 100644
index 000000000000..34c7a2312f9d
--- /dev/null
+++ b/arch/s390/kernel/vdso64/vdso.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ARCH_S390_KERNEL_VDSO64_VDSO_H
+#define __ARCH_S390_KERNEL_VDSO64_VDSO_H
+
+#include <vdso/datapage.h>
+
+struct getcpu_cache;
+
+int __s390_vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused);
+int __s390_vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz);
+int __s390_vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts);
+int __s390_vdso_clock_getres(clockid_t clock, struct __kernel_timespec *ts);
+
+#endif /* __ARCH_S390_KERNEL_VDSO64_VDSO_H */
diff --git a/arch/s390/kernel/vdso64/vdso64.lds.S b/arch/s390/kernel/vdso64/vdso64.lds.S
index 7ddb116b5e2e..7bde3909290f 100644
--- a/arch/s390/kernel/vdso64/vdso64.lds.S
+++ b/arch/s390/kernel/vdso64/vdso64.lds.S
@@ -136,7 +136,6 @@ VERSION
 		__kernel_clock_gettime;
 		__kernel_clock_getres;
 		__kernel_getcpu;
-
 	local: *;
 	};
 }
diff --git a/arch/s390/kernel/vdso64/vdso64_generic.c b/arch/s390/kernel/vdso64/vdso64_generic.c
index a8cef7e4d137..a9aa75643c08 100644
--- a/arch/s390/kernel/vdso64/vdso64_generic.c
+++ b/arch/s390/kernel/vdso64/vdso64_generic.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "../../../../lib/vdso/gettimeofday.c"
+#include "vdso.h"
 
 int __s390_vdso_gettimeofday(struct __kernel_old_timeval *tv,
 			     struct timezone *tz)
diff --git a/arch/s390/kernel/vdso64/vdso_user_wrapper.S b/arch/s390/kernel/vdso64/vdso_user_wrapper.S
index a775d7e52872..f773505c7e63 100644
--- a/arch/s390/kernel/vdso64/vdso_user_wrapper.S
+++ b/arch/s390/kernel/vdso64/vdso_user_wrapper.S
@@ -36,3 +36,4 @@ __kernel_\func:
 vdso_func gettimeofday
 vdso_func clock_getres
 vdso_func clock_gettime
+vdso_func getcpu
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 177ccfbda40a..4c0e19145cc6 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -10,7 +10,8 @@
  * Put .bss..swapper_pg_dir as the first thing in .bss. This will
  * make sure it has 16k alignment.
  */
-#define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir)
+#define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir) \
+			   *(.bss..invalid_pg_dir)
 
 /* Handle ro_after_init data on our own. */
 #define RO_AFTER_INIT_DATA