Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d586c86d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull second set of s390 patches from Martin Schwidefsky:
 "The second part of Heikos uaccess rework, the page table walker for
  uaccess is now a thing of the past (yay!)

  The code change to fix the theoretical TLB flush problem allows us to
  add a TLB flush optimization for zEC12, this machine has new
  instructions that allow to do CPU local TLB flushes for single pages
  and for all pages of a specific address space.

  Plus the usual bug fixing and some more cleanup"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/uaccess: rework uaccess code - fix locking issues
  s390/mm,tlb: optimize TLB flushing for zEC12
  s390/mm,tlb: safeguard against speculative TLB creation
  s390/irq: Use defines for external interruption codes
  s390/irq: Add defines for external interruption codes
  s390/sclp: add timeout for queued requests
  kvm/s390: also set guest pages back to stable on kexec/kdump
  lcs: Add missing destroy_timer_on_stack()
  s390/tape: Add missing destroy_timer_on_stack()
  s390/tape: Use del_timer_sync()
  s390/3270: fix crash with multiple reset device requests
  s390/bitops,atomic: add missing memory barriers
  s390/zcrypt: add length check for aligned data to avoid overflow in msg-type 6
parents e9f37d3a 457f2180
Loading
Loading
Loading
Loading
+42 −28
Original line number Diff line number Diff line
@@ -15,23 +15,29 @@

#include <linux/compiler.h>
#include <linux/types.h>
#include <asm/barrier.h>
#include <asm/cmpxchg.h>

#define ATOMIC_INIT(i)  { (i) }

#define __ATOMIC_NO_BARRIER	"\n"

#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES

#define __ATOMIC_OR	"lao"
#define __ATOMIC_AND	"lan"
#define __ATOMIC_ADD	"laa"
#define __ATOMIC_BARRIER "bcr	14,0\n"

#define __ATOMIC_LOOP(ptr, op_val, op_string)				\
#define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier)		\
({									\
	int old_val;							\
									\
	typecheck(atomic_t *, ptr);					\
	asm volatile(							\
		__barrier						\
		op_string "	%0,%2,%1\n"				\
		__barrier						\
		: "=d" (old_val), "+Q" ((ptr)->counter)			\
		: "d" (op_val)						\
		: "cc", "memory");					\
@@ -43,8 +49,9 @@
#define __ATOMIC_OR	"or"
#define __ATOMIC_AND	"nr"
#define __ATOMIC_ADD	"ar"
#define __ATOMIC_BARRIER "\n"

#define __ATOMIC_LOOP(ptr, op_val, op_string)				\
#define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier)		\
({									\
	int old_val, new_val;						\
									\
@@ -82,7 +89,7 @@ static inline void atomic_set(atomic_t *v, int i)

static inline int atomic_add_return(int i, atomic_t *v)
{
	return __ATOMIC_LOOP(v, i, __ATOMIC_ADD) + i;
	return __ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_BARRIER) + i;
}

static inline void atomic_add(int i, atomic_t *v)
@@ -94,12 +101,10 @@ static inline void atomic_add(int i, atomic_t *v)
			: "+Q" (v->counter)
			: "i" (i)
			: "cc", "memory");
	} else {
		atomic_add_return(i, v);
		return;
	}
#else
	atomic_add_return(i, v);
#endif
	__ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_NO_BARRIER);
}

#define atomic_add_negative(_i, _v)	(atomic_add_return(_i, _v) < 0)
@@ -115,12 +120,12 @@ static inline void atomic_add(int i, atomic_t *v)

static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
{
	__ATOMIC_LOOP(v, ~mask, __ATOMIC_AND);
	__ATOMIC_LOOP(v, ~mask, __ATOMIC_AND, __ATOMIC_NO_BARRIER);
}

static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
{
	__ATOMIC_LOOP(v, mask, __ATOMIC_OR);
	__ATOMIC_LOOP(v, mask, __ATOMIC_OR, __ATOMIC_NO_BARRIER);
}

#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
@@ -157,19 +162,24 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)

#ifdef CONFIG_64BIT

#define __ATOMIC64_NO_BARRIER	"\n"

#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES

#define __ATOMIC64_OR	"laog"
#define __ATOMIC64_AND	"lang"
#define __ATOMIC64_ADD	"laag"
#define __ATOMIC64_BARRIER "bcr	14,0\n"

#define __ATOMIC64_LOOP(ptr, op_val, op_string)				\
#define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier)		\
({									\
	long long old_val;						\
									\
	typecheck(atomic64_t *, ptr);					\
	asm volatile(							\
		__barrier						\
		op_string "	%0,%2,%1\n"				\
		__barrier						\
		: "=d" (old_val), "+Q" ((ptr)->counter)			\
		: "d" (op_val)						\
		: "cc", "memory");					\
@@ -181,8 +191,9 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
#define __ATOMIC64_OR	"ogr"
#define __ATOMIC64_AND	"ngr"
#define __ATOMIC64_ADD	"agr"
#define __ATOMIC64_BARRIER "\n"

#define __ATOMIC64_LOOP(ptr, op_val, op_string)				\
#define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier)		\
({									\
	long long old_val, new_val;					\
									\
@@ -220,17 +231,32 @@ static inline void atomic64_set(atomic64_t *v, long long i)

static inline long long atomic64_add_return(long long i, atomic64_t *v)
{
	return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD) + i;
	return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_BARRIER) + i;
}

static inline void atomic64_add(long long i, atomic64_t *v)
{
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
	if (__builtin_constant_p(i) && (i > -129) && (i < 128)) {
		asm volatile(
			"agsi	%0,%1\n"
			: "+Q" (v->counter)
			: "i" (i)
			: "cc", "memory");
		return;
	}
#endif
	__ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_NO_BARRIER);
}

static inline void atomic64_clear_mask(unsigned long mask, atomic64_t *v)
{
	__ATOMIC64_LOOP(v, ~mask, __ATOMIC64_AND);
	__ATOMIC64_LOOP(v, ~mask, __ATOMIC64_AND, __ATOMIC64_NO_BARRIER);
}

static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v)
{
	__ATOMIC64_LOOP(v, mask, __ATOMIC64_OR);
	__ATOMIC64_LOOP(v, mask, __ATOMIC64_OR, __ATOMIC64_NO_BARRIER);
}

#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
@@ -334,24 +360,12 @@ static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v)
	} while (atomic64_cmpxchg(v, old, new) != old);
}

#endif /* CONFIG_64BIT */

static inline void atomic64_add(long long i, atomic64_t *v)
{
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
	if (__builtin_constant_p(i) && (i > -129) && (i < 128)) {
		asm volatile(
			"agsi	%0,%1\n"
			: "+Q" (v->counter)
			: "i" (i)
			: "cc", "memory");
	} else {
	atomic64_add_return(i, v);
}
#else
	atomic64_add_return(i, v);
#endif
}

#endif /* CONFIG_64BIT */

static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u)
{
+23 −18
Original line number Diff line number Diff line
@@ -47,14 +47,18 @@

#include <linux/typecheck.h>
#include <linux/compiler.h>
#include <asm/barrier.h>

#define __BITOPS_NO_BARRIER	"\n"

#ifndef CONFIG_64BIT

#define __BITOPS_OR		"or"
#define __BITOPS_AND		"nr"
#define __BITOPS_XOR		"xr"
#define __BITOPS_BARRIER	"\n"

#define __BITOPS_LOOP(__addr, __val, __op_string)		\
#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier)	\
({								\
	unsigned long __old, __new;				\
								\
@@ -67,7 +71,7 @@
		"	jl	0b"				\
		: "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\
		: "d" (__val)					\
		: "cc");					\
		: "cc", "memory");				\
	__old;							\
})

@@ -78,17 +82,20 @@
#define __BITOPS_OR		"laog"
#define __BITOPS_AND		"lang"
#define __BITOPS_XOR		"laxg"
#define __BITOPS_BARRIER	"bcr	14,0\n"

#define __BITOPS_LOOP(__addr, __val, __op_string)		\
#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier)	\
({								\
	unsigned long __old;					\
								\
	typecheck(unsigned long *, (__addr));			\
	asm volatile(						\
		__barrier					\
		__op_string "	%0,%2,%1\n"			\
		__barrier					\
		: "=d" (__old),	"+Q" (*(__addr))		\
		: "d" (__val)					\
		: "cc");					\
		: "cc", "memory");				\
	__old;							\
})

@@ -97,8 +104,9 @@
#define __BITOPS_OR		"ogr"
#define __BITOPS_AND		"ngr"
#define __BITOPS_XOR		"xgr"
#define __BITOPS_BARRIER	"\n"

#define __BITOPS_LOOP(__addr, __val, __op_string)		\
#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier)	\
({								\
	unsigned long __old, __new;				\
								\
@@ -111,7 +119,7 @@
		"	jl	0b"				\
		: "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\
		: "d" (__val)					\
		: "cc");					\
		: "cc", "memory");				\
	__old;							\
})

@@ -149,12 +157,12 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *ptr)
			"oi	%0,%b1\n"
			: "+Q" (*caddr)
			: "i" (1 << (nr & 7))
			: "cc");
			: "cc", "memory");
		return;
	}
#endif
	mask = 1UL << (nr & (BITS_PER_LONG - 1));
	__BITOPS_LOOP(addr, mask, __BITOPS_OR);
	__BITOPS_LOOP(addr, mask, __BITOPS_OR, __BITOPS_NO_BARRIER);
}

static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
@@ -170,12 +178,12 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
			"ni	%0,%b1\n"
			: "+Q" (*caddr)
			: "i" (~(1 << (nr & 7)))
			: "cc");
			: "cc", "memory");
		return;
	}
#endif
	mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
	__BITOPS_LOOP(addr, mask, __BITOPS_AND);
	__BITOPS_LOOP(addr, mask, __BITOPS_AND, __BITOPS_NO_BARRIER);
}

static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
@@ -191,12 +199,12 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
			"xi	%0,%b1\n"
			: "+Q" (*caddr)
			: "i" (1 << (nr & 7))
			: "cc");
			: "cc", "memory");
		return;
	}
#endif
	mask = 1UL << (nr & (BITS_PER_LONG - 1));
	__BITOPS_LOOP(addr, mask, __BITOPS_XOR);
	__BITOPS_LOOP(addr, mask, __BITOPS_XOR, __BITOPS_NO_BARRIER);
}

static inline int
@@ -206,8 +214,7 @@ test_and_set_bit(unsigned long nr, volatile unsigned long *ptr)
	unsigned long old, mask;

	mask = 1UL << (nr & (BITS_PER_LONG - 1));
	old = __BITOPS_LOOP(addr, mask, __BITOPS_OR);
	barrier();
	old = __BITOPS_LOOP(addr, mask, __BITOPS_OR, __BITOPS_BARRIER);
	return (old & mask) != 0;
}

@@ -218,8 +225,7 @@ test_and_clear_bit(unsigned long nr, volatile unsigned long *ptr)
	unsigned long old, mask;

	mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
	old = __BITOPS_LOOP(addr, mask, __BITOPS_AND);
	barrier();
	old = __BITOPS_LOOP(addr, mask, __BITOPS_AND, __BITOPS_BARRIER);
	return (old & ~mask) != 0;
}

@@ -230,8 +236,7 @@ test_and_change_bit(unsigned long nr, volatile unsigned long *ptr)
	unsigned long old, mask;

	mask = 1UL << (nr & (BITS_PER_LONG - 1));
	old = __BITOPS_LOOP(addr, mask, __BITOPS_XOR);
	barrier();
	old = __BITOPS_LOOP(addr, mask, __BITOPS_XOR, __BITOPS_BARRIER);
	return (old & mask) != 0;
}

+61 −5
Original line number Diff line number Diff line
#ifndef _ASM_S390_FUTEX_H
#define _ASM_S390_FUTEX_H

#include <linux/futex.h>
#include <linux/uaccess.h>
#include <linux/futex.h>
#include <asm/mmu_context.h>
#include <asm/errno.h>

int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval);
int __futex_atomic_op_inuser(int op, u32 __user *uaddr, int oparg, int *old);
#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg)	\
	asm volatile(							\
		"   sacf  256\n"					\
		"0: l     %1,0(%6)\n"					\
		"1:"insn						\
		"2: cs    %1,%2,0(%6)\n"				\
		"3: jl    1b\n"						\
		"   lhi   %0,0\n"					\
		"4: sacf  768\n"					\
		EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b)		\
		: "=d" (ret), "=&d" (oldval), "=&d" (newval),		\
		  "=m" (*uaddr)						\
		: "0" (-EFAULT), "d" (oparg), "a" (uaddr),		\
		  "m" (*uaddr) : "cc");

static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
@@ -14,13 +27,37 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
	int cmp = (encoded_op >> 24) & 15;
	int oparg = (encoded_op << 8) >> 20;
	int cmparg = (encoded_op << 20) >> 20;
	int oldval, ret;
	int oldval = 0, newval, ret;

	update_primary_asce(current);
	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
		oparg = 1 << oparg;

	pagefault_disable();
	ret = __futex_atomic_op_inuser(op, uaddr, oparg, &oldval);
	switch (op) {
	case FUTEX_OP_SET:
		__futex_atomic_op("lr %2,%5\n",
				  ret, oldval, newval, uaddr, oparg);
		break;
	case FUTEX_OP_ADD:
		__futex_atomic_op("lr %2,%1\nar %2,%5\n",
				  ret, oldval, newval, uaddr, oparg);
		break;
	case FUTEX_OP_OR:
		__futex_atomic_op("lr %2,%1\nor %2,%5\n",
				  ret, oldval, newval, uaddr, oparg);
		break;
	case FUTEX_OP_ANDN:
		__futex_atomic_op("lr %2,%1\nnr %2,%5\n",
				  ret, oldval, newval, uaddr, oparg);
		break;
	case FUTEX_OP_XOR:
		__futex_atomic_op("lr %2,%1\nxr %2,%5\n",
				  ret, oldval, newval, uaddr, oparg);
		break;
	default:
		ret = -ENOSYS;
	}
	pagefault_enable();

	if (!ret) {
@@ -37,4 +74,23 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
	return ret;
}

static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
						u32 oldval, u32 newval)
{
	int ret;

	update_primary_asce(current);
	asm volatile(
		"   sacf 256\n"
		"0: cs   %1,%4,0(%5)\n"
		"1: la   %0,0\n"
		"2: sacf 768\n"
		EX_TABLE(0b,2b) EX_TABLE(1b,2b)
		: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
		: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
		: "cc", "memory");
	*uval = oldval;
	return ret;
}

#endif /* _ASM_S390_FUTEX_H */
+16 −2
Original line number Diff line number Diff line
@@ -16,6 +16,20 @@
/* This number is used when no interrupt has been assigned */
#define NO_IRQ		0

/* External interruption codes */
#define EXT_IRQ_INTERRUPT_KEY	0x0040
#define EXT_IRQ_CLK_COMP	0x1004
#define EXT_IRQ_CPU_TIMER	0x1005
#define EXT_IRQ_WARNING_TRACK	0x1007
#define EXT_IRQ_MALFUNC_ALERT	0x1200
#define EXT_IRQ_EMERGENCY_SIG	0x1201
#define EXT_IRQ_EXTERNAL_CALL	0x1202
#define EXT_IRQ_TIMING_ALERT	0x1406
#define EXT_IRQ_MEASURE_ALERT	0x1407
#define EXT_IRQ_SERVICE_SIG	0x2401
#define EXT_IRQ_CP_SERVICE	0x2603
#define EXT_IRQ_IUCV		0x4000

#ifndef __ASSEMBLY__

#include <linux/hardirq.h>
@@ -77,8 +91,8 @@ struct ext_code {

typedef void (*ext_int_handler_t)(struct ext_code, unsigned int, unsigned long);

int register_external_interrupt(u16 code, ext_int_handler_t handler);
int unregister_external_interrupt(u16 code, ext_int_handler_t handler);
int register_external_irq(u16 code, ext_int_handler_t handler);
int unregister_external_irq(u16 code, ext_int_handler_t handler);

enum irq_subclass {
	IRQ_SUBCLASS_MEASUREMENT_ALERT = 5,
+2 −0
Original line number Diff line number Diff line
#ifndef __MMU_H
#define __MMU_H

#include <linux/cpumask.h>
#include <linux/errno.h>

typedef struct {
	cpumask_t cpu_attach_mask;
	atomic_t attach_count;
	unsigned int flush_mm;
	spinlock_t list_lock;
Loading