Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Martin Schwidefsky:
 "This patch set contains the main portion of the changes for 3.18 in
  regard to the s390 architecture.  It is a bit bigger than usual,
  mainly because of a new driver and the vector extension patches.

  The interesting bits are:
   - Quite a bit of work on the tracing front.  Uprobes is enabled and
     the ftrace code is reworked to get some of the lost performance
     back if CONFIG_FTRACE is enabled.
   - To improve boot time with CONFIG_DEBIG_PAGEALLOC, support for the
     IPTE range facility is added.
   - The rwlock code is re-factored to improve writer fairness and to be
     able to use the interlocked-access instructions.
   - The kernel part for the support of the vector extension is added.
   - The device driver to access the CD/DVD on the HMC is added, this
     will hopefully come in handy to improve the installation process.
   - Add support for control-unit initiated reconfiguration.
   - The crypto device driver is enhanced to enable the additional AP
     domains and to allow the new crypto hardware to be used.
   - Bug fixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (39 commits)
  s390/ftrace: simplify enabling/disabling of ftrace_graph_caller
  s390/ftrace: remove 31 bit ftrace support
  s390/kdump: add support for vector extension
  s390/disassembler: add vector instructions
  s390: add support for vector extension
  s390/zcrypt: Toleration of new crypto hardware
  s390/idle: consolidate idle functions and definitions
  s390/nohz: use a per-cpu flag for arch_needs_cpu
  s390/vtime: do not reset idle data on CPU hotplug
  s390/dasd: add support for control unit initiated reconfiguration
  s390/dasd: fix infinite loop during format
  s390/mm: make use of ipte range facility
  s390/setup: correct 4-level kernel page table detection
  s390/topology: call set_sched_topology early
  s390/uprobes: architecture backend for uprobes
  s390/uprobes: common library for kprobes and uprobes
  s390/rwlock: use the interlocked-access facility 1 instructions
  s390/rwlock: improve writer fairness
  s390/rwlock: remove interrupt-enabling rwlock variant.
  s390/mm: remove change bit override support
  ...
This commit is contained in:
Linus Torvalds
2014-10-14 03:47:00 +02:00
109 changed files with 4792 additions and 1026 deletions

View File

@@ -38,15 +38,6 @@
#define CREATE_TRACE_POINTS
#include <trace/events/syscalls.h>
enum s390_regset {
REGSET_GENERAL,
REGSET_FP,
REGSET_LAST_BREAK,
REGSET_TDB,
REGSET_SYSTEM_CALL,
REGSET_GENERAL_EXTENDED,
};
void update_cr_regs(struct task_struct *task)
{
struct pt_regs *regs = task_pt_regs(task);
@@ -55,27 +46,39 @@ void update_cr_regs(struct task_struct *task)
#ifdef CONFIG_64BIT
/* Take care of the enable/disable of transactional execution. */
if (MACHINE_HAS_TE) {
if (MACHINE_HAS_TE || MACHINE_HAS_VX) {
unsigned long cr, cr_new;
__ctl_store(cr, 0, 0);
/* Set or clear transaction execution TXC bit 8. */
cr_new = cr | (1UL << 55);
if (task->thread.per_flags & PER_FLAG_NO_TE)
cr_new &= ~(1UL << 55);
if (cr_new != cr)
__ctl_load(cr_new, 0, 0);
/* Set or clear transaction execution TDC bits 62 and 63. */
__ctl_store(cr, 2, 2);
cr_new = cr & ~3UL;
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
cr_new |= 1UL;
else
cr_new |= 2UL;
cr_new = cr;
if (MACHINE_HAS_TE) {
/* Set or clear transaction execution TXC bit 8. */
cr_new |= (1UL << 55);
if (task->thread.per_flags & PER_FLAG_NO_TE)
cr_new &= ~(1UL << 55);
}
if (MACHINE_HAS_VX) {
/* Enable/disable of vector extension */
cr_new &= ~(1UL << 17);
if (task->thread.vxrs)
cr_new |= (1UL << 17);
}
if (cr_new != cr)
__ctl_load(cr_new, 2, 2);
__ctl_load(cr_new, 0, 0);
if (MACHINE_HAS_TE) {
/* Set/clear transaction execution TDC bits 62/63. */
__ctl_store(cr, 2, 2);
cr_new = cr & ~3UL;
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
if (task->thread.per_flags &
PER_FLAG_TE_ABORT_RAND_TEND)
cr_new |= 1UL;
else
cr_new |= 2UL;
}
if (cr_new != cr)
__ctl_load(cr_new, 2, 2);
}
}
#endif
/* Copy user specified PER registers */
@@ -84,7 +87,8 @@ void update_cr_regs(struct task_struct *task)
new.end = thread->per_user.end;
/* merge TIF_SINGLE_STEP into user specified PER registers. */
if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
if (test_tsk_thread_flag(task, TIF_SINGLE_STEP) ||
test_tsk_thread_flag(task, TIF_UPROBE_SINGLESTEP)) {
if (test_tsk_thread_flag(task, TIF_BLOCK_STEP))
new.control |= PER_EVENT_BRANCH;
else
@@ -93,6 +97,8 @@ void update_cr_regs(struct task_struct *task)
new.control |= PER_CONTROL_SUSPENSION;
new.control |= PER_EVENT_TRANSACTION_END;
#endif
if (test_tsk_thread_flag(task, TIF_UPROBE_SINGLESTEP))
new.control |= PER_EVENT_IFETCH;
new.start = 0;
new.end = PSW_ADDR_INSN;
}
@@ -923,7 +929,15 @@ static int s390_fpregs_get(struct task_struct *target,
save_fp_ctl(&target->thread.fp_regs.fpc);
save_fp_regs(target->thread.fp_regs.fprs);
}
#ifdef CONFIG_64BIT
else if (target->thread.vxrs) {
int i;
for (i = 0; i < __NUM_VXRS_LOW; i++)
target->thread.fp_regs.fprs[i] =
*(freg_t *)(target->thread.vxrs + i);
}
#endif
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fp_regs, 0, -1);
}
@@ -957,9 +971,20 @@ static int s390_fpregs_set(struct task_struct *target,
target->thread.fp_regs.fprs,
offsetof(s390_fp_regs, fprs), -1);
if (rc == 0 && target == current) {
restore_fp_ctl(&target->thread.fp_regs.fpc);
restore_fp_regs(target->thread.fp_regs.fprs);
if (rc == 0) {
if (target == current) {
restore_fp_ctl(&target->thread.fp_regs.fpc);
restore_fp_regs(target->thread.fp_regs.fprs);
}
#ifdef CONFIG_64BIT
else if (target->thread.vxrs) {
int i;
for (i = 0; i < __NUM_VXRS_LOW; i++)
*(freg_t *)(target->thread.vxrs + i) =
target->thread.fp_regs.fprs[i];
}
#endif
}
return rc;
@@ -1015,6 +1040,95 @@ static int s390_tdb_set(struct task_struct *target,
return 0;
}
static int s390_vxrs_active(struct task_struct *target,
const struct user_regset *regset)
{
return !!target->thread.vxrs;
}
static int s390_vxrs_low_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
__u64 vxrs[__NUM_VXRS_LOW];
int i;
if (target->thread.vxrs) {
if (target == current)
save_vx_regs(target->thread.vxrs);
for (i = 0; i < __NUM_VXRS_LOW; i++)
vxrs[i] = *((__u64 *)(target->thread.vxrs + i) + 1);
} else
memset(vxrs, 0, sizeof(vxrs));
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
}
static int s390_vxrs_low_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
__u64 vxrs[__NUM_VXRS_LOW];
int i, rc;
if (!target->thread.vxrs) {
rc = alloc_vector_registers(target);
if (rc)
return rc;
} else if (target == current)
save_vx_regs(target->thread.vxrs);
rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
if (rc == 0) {
for (i = 0; i < __NUM_VXRS_LOW; i++)
*((__u64 *)(target->thread.vxrs + i) + 1) = vxrs[i];
if (target == current)
restore_vx_regs(target->thread.vxrs);
}
return rc;
}
static int s390_vxrs_high_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
__vector128 vxrs[__NUM_VXRS_HIGH];
if (target->thread.vxrs) {
if (target == current)
save_vx_regs(target->thread.vxrs);
memcpy(vxrs, target->thread.vxrs + __NUM_VXRS_LOW,
sizeof(vxrs));
} else
memset(vxrs, 0, sizeof(vxrs));
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
}
static int s390_vxrs_high_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
int rc;
if (!target->thread.vxrs) {
rc = alloc_vector_registers(target);
if (rc)
return rc;
} else if (target == current)
save_vx_regs(target->thread.vxrs);
rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
target->thread.vxrs + __NUM_VXRS_LOW, 0, -1);
if (rc == 0 && target == current)
restore_vx_regs(target->thread.vxrs);
return rc;
}
#endif
static int s390_system_call_get(struct task_struct *target,
@@ -1038,7 +1152,7 @@ static int s390_system_call_set(struct task_struct *target,
}
static const struct user_regset s390_regsets[] = {
[REGSET_GENERAL] = {
{
.core_note_type = NT_PRSTATUS,
.n = sizeof(s390_regs) / sizeof(long),
.size = sizeof(long),
@@ -1046,7 +1160,7 @@ static const struct user_regset s390_regsets[] = {
.get = s390_regs_get,
.set = s390_regs_set,
},
[REGSET_FP] = {
{
.core_note_type = NT_PRFPREG,
.n = sizeof(s390_fp_regs) / sizeof(long),
.size = sizeof(long),
@@ -1054,25 +1168,7 @@ static const struct user_regset s390_regsets[] = {
.get = s390_fpregs_get,
.set = s390_fpregs_set,
},
#ifdef CONFIG_64BIT
[REGSET_LAST_BREAK] = {
.core_note_type = NT_S390_LAST_BREAK,
.n = 1,
.size = sizeof(long),
.align = sizeof(long),
.get = s390_last_break_get,
.set = s390_last_break_set,
},
[REGSET_TDB] = {
.core_note_type = NT_S390_TDB,
.n = 1,
.size = 256,
.align = 1,
.get = s390_tdb_get,
.set = s390_tdb_set,
},
#endif
[REGSET_SYSTEM_CALL] = {
{
.core_note_type = NT_S390_SYSTEM_CALL,
.n = 1,
.size = sizeof(unsigned int),
@@ -1080,6 +1176,42 @@ static const struct user_regset s390_regsets[] = {
.get = s390_system_call_get,
.set = s390_system_call_set,
},
#ifdef CONFIG_64BIT
{
.core_note_type = NT_S390_LAST_BREAK,
.n = 1,
.size = sizeof(long),
.align = sizeof(long),
.get = s390_last_break_get,
.set = s390_last_break_set,
},
{
.core_note_type = NT_S390_TDB,
.n = 1,
.size = 256,
.align = 1,
.get = s390_tdb_get,
.set = s390_tdb_set,
},
{
.core_note_type = NT_S390_VXRS_LOW,
.n = __NUM_VXRS_LOW,
.size = sizeof(__u64),
.align = sizeof(__u64),
.active = s390_vxrs_active,
.get = s390_vxrs_low_get,
.set = s390_vxrs_low_set,
},
{
.core_note_type = NT_S390_VXRS_HIGH,
.n = __NUM_VXRS_HIGH,
.size = sizeof(__vector128),
.align = sizeof(__vector128),
.active = s390_vxrs_active,
.get = s390_vxrs_high_get,
.set = s390_vxrs_high_set,
},
#endif
};
static const struct user_regset_view user_s390_view = {
@@ -1244,7 +1376,7 @@ static int s390_compat_last_break_set(struct task_struct *target,
}
static const struct user_regset s390_compat_regsets[] = {
[REGSET_GENERAL] = {
{
.core_note_type = NT_PRSTATUS,
.n = sizeof(s390_compat_regs) / sizeof(compat_long_t),
.size = sizeof(compat_long_t),
@@ -1252,7 +1384,7 @@ static const struct user_regset s390_compat_regsets[] = {
.get = s390_compat_regs_get,
.set = s390_compat_regs_set,
},
[REGSET_FP] = {
{
.core_note_type = NT_PRFPREG,
.n = sizeof(s390_fp_regs) / sizeof(compat_long_t),
.size = sizeof(compat_long_t),
@@ -1260,23 +1392,7 @@ static const struct user_regset s390_compat_regsets[] = {
.get = s390_fpregs_get,
.set = s390_fpregs_set,
},
[REGSET_LAST_BREAK] = {
.core_note_type = NT_S390_LAST_BREAK,
.n = 1,
.size = sizeof(long),
.align = sizeof(long),
.get = s390_compat_last_break_get,
.set = s390_compat_last_break_set,
},
[REGSET_TDB] = {
.core_note_type = NT_S390_TDB,
.n = 1,
.size = 256,
.align = 1,
.get = s390_tdb_get,
.set = s390_tdb_set,
},
[REGSET_SYSTEM_CALL] = {
{
.core_note_type = NT_S390_SYSTEM_CALL,
.n = 1,
.size = sizeof(compat_uint_t),
@@ -1284,7 +1400,41 @@ static const struct user_regset s390_compat_regsets[] = {
.get = s390_system_call_get,
.set = s390_system_call_set,
},
[REGSET_GENERAL_EXTENDED] = {
{
.core_note_type = NT_S390_LAST_BREAK,
.n = 1,
.size = sizeof(long),
.align = sizeof(long),
.get = s390_compat_last_break_get,
.set = s390_compat_last_break_set,
},
{
.core_note_type = NT_S390_TDB,
.n = 1,
.size = 256,
.align = 1,
.get = s390_tdb_get,
.set = s390_tdb_set,
},
{
.core_note_type = NT_S390_VXRS_LOW,
.n = __NUM_VXRS_LOW,
.size = sizeof(__u64),
.align = sizeof(__u64),
.active = s390_vxrs_active,
.get = s390_vxrs_low_get,
.set = s390_vxrs_low_set,
},
{
.core_note_type = NT_S390_VXRS_HIGH,
.n = __NUM_VXRS_HIGH,
.size = sizeof(__vector128),
.align = sizeof(__vector128),
.active = s390_vxrs_active,
.get = s390_vxrs_high_get,
.set = s390_vxrs_high_set,
},
{
.core_note_type = NT_S390_HIGH_GPRS,
.n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t),
.size = sizeof(compat_long_t),