提交 2ec4584e 编写于 作者: L Linus Torvalds

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

Pull s390 updates from Martin Schwidefsky:
 "The main bulk of the s390 patches for the 4.10 merge window:

   - Add support for the contiguous memory allocator.

   - The recovery for I/O errors in the dasd device driver is improved,
     the driver will now remove channel paths that are not working
     properly.

   - Additional fields are added to /proc/sysinfo, the extended
     partition name and the partition UUID.

   - New naming for PCI devices with system defined UIDs.

   - The last few remaining alloc_bootmem calls are converted to
     memblock.

   - The thread_info structure is stripped down and moved to the
     task_struct. The only field left in thread_info is the flags field.

   - Rework of the arch topology code to fix a fake numa issue.

   - Refactoring of the atomic primitives and add a new preempt_count
     implementation.

   - Clocksource steering for the STP sync check offsets.

   - The s390 specific headers are changed to make them usable with
     CLANG.

   - Bug fixes and cleanup"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (70 commits)
  s390/cpumf: Use configuration level indication for sampling data
  s390: provide memmove implementation
  s390: cleanup arch/s390/kernel Makefile
  s390: fix initrd corruptions with gcov/kcov instrumented kernels
  s390: exclude early C code from gcov profiling
  s390/dasd: channel path aware error recovery
  s390/dasd: extend dasd path handling
  s390: remove unused labels from entry.S
  s390/vmlogrdr: fix IUCV buffer allocation
  s390/crypto: unlock on error in prng_tdes_read()
  s390/sysinfo: show partition extended name and UUID if available
  s390/numa: pin all possible cpus to nodes early
  s390/numa: establish cpu to node mapping early
  s390/topology: use cpu_topology array instead of per cpu variable
  s390/smp: initialize cpu_present_mask in setup_arch
  s390/topology: always use s390 specific sched_domain_topology_level
  s390/smp: use smp_get_base_cpu() helper function
  s390/numa: always use logical cpu and core ids
  s390: Remove VLAIS in ptff() and clear_table()
  s390: fix machine check panic stack switch
  ...
...@@ -10557,7 +10557,7 @@ F: arch/s390/pci/ ...@@ -10557,7 +10557,7 @@ F: arch/s390/pci/
F: drivers/pci/hotplug/s390_pci_hpc.c F: drivers/pci/hotplug/s390_pci_hpc.c
S390 ZCRYPT DRIVER S390 ZCRYPT DRIVER
M: Ingo Tuchscherer <ingo.tuchscherer@de.ibm.com> M: Harald Freudenberger <freude@de.ibm.com>
L: linux-s390@vger.kernel.org L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/ W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported S: Supported
......
...@@ -136,6 +136,7 @@ config S390 ...@@ -136,6 +136,7 @@ config S390
select HAVE_CMPXCHG_LOCAL select HAVE_CMPXCHG_LOCAL
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_API_DEBUG select HAVE_DMA_API_DEBUG
select HAVE_DMA_CONTIGUOUS
select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE
select HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_DYNAMIC_FTRACE_WITH_REGS
select HAVE_EFFICIENT_UNALIGNED_ACCESS select HAVE_EFFICIENT_UNALIGNED_ACCESS
...@@ -169,6 +170,7 @@ config S390 ...@@ -169,6 +170,7 @@ config S390
select OLD_SIGSUSPEND3 select OLD_SIGSUSPEND3
select SPARSE_IRQ select SPARSE_IRQ
select SYSCTL_EXCEPTION_TRACE select SYSCTL_EXCEPTION_TRACE
select THREAD_INFO_IN_TASK
select TTY select TTY
select VIRT_CPU_ACCOUNTING select VIRT_CPU_ACCOUNTING
select ARCH_HAS_SCALED_CPUTIME select ARCH_HAS_SCALED_CPUTIME
......
...@@ -46,7 +46,7 @@ mover_end: ...@@ -46,7 +46,7 @@ mover_end:
.align 8 .align 8
.Lstack: .Lstack:
.quad 0x8000 + (1<<(PAGE_SHIFT+THREAD_ORDER)) .quad 0x8000 + (1<<(PAGE_SHIFT+THREAD_SIZE_ORDER))
.Loffset: .Loffset:
.quad 0x11000 .quad 0x11000
.Lmvsize: .Lmvsize:
......
...@@ -66,6 +66,8 @@ CONFIG_TRANSPARENT_HUGEPAGE=y ...@@ -66,6 +66,8 @@ CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_CLEANCACHE=y CONFIG_CLEANCACHE=y
CONFIG_FRONTSWAP=y CONFIG_FRONTSWAP=y
CONFIG_CMA=y CONFIG_CMA=y
CONFIG_CMA_DEBUG=y
CONFIG_CMA_DEBUGFS=y
CONFIG_MEM_SOFT_DIRTY=y CONFIG_MEM_SOFT_DIRTY=y
CONFIG_ZPOOL=m CONFIG_ZPOOL=m
CONFIG_ZBUD=m CONFIG_ZBUD=m
...@@ -366,6 +368,8 @@ CONFIG_BPF_JIT=y ...@@ -366,6 +368,8 @@ CONFIG_BPF_JIT=y
CONFIG_NET_PKTGEN=m CONFIG_NET_PKTGEN=m
CONFIG_NET_TCPPROBE=m CONFIG_NET_TCPPROBE=m
CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=0
CONFIG_CONNECTOR=y CONFIG_CONNECTOR=y
CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m
...@@ -438,7 +442,6 @@ CONFIG_TUN=m ...@@ -438,7 +442,6 @@ CONFIG_TUN=m
CONFIG_VETH=m CONFIG_VETH=m
CONFIG_VIRTIO_NET=m CONFIG_VIRTIO_NET=m
CONFIG_NLMON=m CONFIG_NLMON=m
CONFIG_VHOST_NET=m
# CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_VENDOR_ARC is not set
# CONFIG_NET_VENDOR_CHELSIO is not set # CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_INTEL is not set
...@@ -693,3 +696,4 @@ CONFIG_CMM=m ...@@ -693,3 +696,4 @@ CONFIG_CMM=m
CONFIG_APPLDATA_BASE=y CONFIG_APPLDATA_BASE=y
CONFIG_KVM=m CONFIG_KVM=m
CONFIG_KVM_S390_UCONTROL=y CONFIG_KVM_S390_UCONTROL=y
CONFIG_VHOST_NET=m
...@@ -362,6 +362,8 @@ CONFIG_BPF_JIT=y ...@@ -362,6 +362,8 @@ CONFIG_BPF_JIT=y
CONFIG_NET_PKTGEN=m CONFIG_NET_PKTGEN=m
CONFIG_NET_TCPPROBE=m CONFIG_NET_TCPPROBE=m
CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=0
CONFIG_CONNECTOR=y CONFIG_CONNECTOR=y
CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m
...@@ -434,7 +436,6 @@ CONFIG_TUN=m ...@@ -434,7 +436,6 @@ CONFIG_TUN=m
CONFIG_VETH=m CONFIG_VETH=m
CONFIG_VIRTIO_NET=m CONFIG_VIRTIO_NET=m
CONFIG_NLMON=m CONFIG_NLMON=m
CONFIG_VHOST_NET=m
# CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_VENDOR_ARC is not set
# CONFIG_NET_VENDOR_CHELSIO is not set # CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_INTEL is not set
...@@ -633,3 +634,4 @@ CONFIG_CMM=m ...@@ -633,3 +634,4 @@ CONFIG_CMM=m
CONFIG_APPLDATA_BASE=y CONFIG_APPLDATA_BASE=y
CONFIG_KVM=m CONFIG_KVM=m
CONFIG_KVM_S390_UCONTROL=y CONFIG_KVM_S390_UCONTROL=y
CONFIG_VHOST_NET=m
...@@ -362,6 +362,8 @@ CONFIG_BPF_JIT=y ...@@ -362,6 +362,8 @@ CONFIG_BPF_JIT=y
CONFIG_NET_PKTGEN=m CONFIG_NET_PKTGEN=m
CONFIG_NET_TCPPROBE=m CONFIG_NET_TCPPROBE=m
CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=0
CONFIG_CONNECTOR=y CONFIG_CONNECTOR=y
CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m
...@@ -434,7 +436,6 @@ CONFIG_TUN=m ...@@ -434,7 +436,6 @@ CONFIG_TUN=m
CONFIG_VETH=m CONFIG_VETH=m
CONFIG_VIRTIO_NET=m CONFIG_VIRTIO_NET=m
CONFIG_NLMON=m CONFIG_NLMON=m
CONFIG_VHOST_NET=m
# CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_VENDOR_ARC is not set
# CONFIG_NET_VENDOR_CHELSIO is not set # CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_INTEL is not set
...@@ -632,3 +633,4 @@ CONFIG_CMM=m ...@@ -632,3 +633,4 @@ CONFIG_CMM=m
CONFIG_APPLDATA_BASE=y CONFIG_APPLDATA_BASE=y
CONFIG_KVM=m CONFIG_KVM=m
CONFIG_KVM_S390_UCONTROL=y CONFIG_KVM_S390_UCONTROL=y
CONFIG_VHOST_NET=m
...@@ -507,8 +507,10 @@ static ssize_t prng_tdes_read(struct file *file, char __user *ubuf, ...@@ -507,8 +507,10 @@ static ssize_t prng_tdes_read(struct file *file, char __user *ubuf,
prng_data->prngws.byte_counter += n; prng_data->prngws.byte_counter += n;
prng_data->prngws.reseed_counter += n; prng_data->prngws.reseed_counter += n;
if (copy_to_user(ubuf, prng_data->buf, chunk)) if (copy_to_user(ubuf, prng_data->buf, chunk)) {
return -EFAULT; ret = -EFAULT;
break;
}
nbytes -= chunk; nbytes -= chunk;
ret += chunk; ret += chunk;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* *
* Copyright IBM Corp. 2006, 2008 * Copyright IBM Corp. 2006, 2008
* Author(s): Michael Holzheu <holzheu@de.ibm.com> * Author(s): Michael Holzheu <holzheu@de.ibm.com>
* License: GPL
*/ */
#define KMSG_COMPONENT "hypfs" #define KMSG_COMPONENT "hypfs"
...@@ -18,7 +19,8 @@ ...@@ -18,7 +19,8 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/module.h> #include <linux/init.h>
#include <linux/kobject.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/uio.h> #include <linux/uio.h>
...@@ -443,7 +445,6 @@ static struct file_system_type hypfs_type = { ...@@ -443,7 +445,6 @@ static struct file_system_type hypfs_type = {
.mount = hypfs_mount, .mount = hypfs_mount,
.kill_sb = hypfs_kill_super .kill_sb = hypfs_kill_super
}; };
MODULE_ALIAS_FS("s390_hypfs");
static const struct super_operations hypfs_s_ops = { static const struct super_operations hypfs_s_ops = {
.statfs = simple_statfs, .statfs = simple_statfs,
...@@ -497,21 +498,4 @@ static int __init hypfs_init(void) ...@@ -497,21 +498,4 @@ static int __init hypfs_init(void)
pr_err("Initialization of hypfs failed with rc=%i\n", rc); pr_err("Initialization of hypfs failed with rc=%i\n", rc);
return rc; return rc;
} }
device_initcall(hypfs_init)
static void __exit hypfs_exit(void)
{
unregister_filesystem(&hypfs_type);
sysfs_remove_mount_point(hypervisor_kobj, "s390");
hypfs_diag0c_exit();
hypfs_sprp_exit();
hypfs_vm_exit();
hypfs_diag_exit();
hypfs_dbfs_exit();
}
module_init(hypfs_init)
module_exit(hypfs_exit)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Holzheu <holzheu@de.ibm.com>");
MODULE_DESCRIPTION("s390 Hypervisor Filesystem");
generic-y += asm-offsets.h
generic-y += clkdev.h generic-y += clkdev.h
generic-y += dma-contiguous.h
generic-y += export.h generic-y += export.h
generic-y += irq_work.h generic-y += irq_work.h
generic-y += mcs_spinlock.h generic-y += mcs_spinlock.h
......
#include <generated/asm-offsets.h>
/* /*
* Copyright IBM Corp. 1999, 2009 * Copyright IBM Corp. 1999, 2016
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
* Denis Joseph Barrow, * Denis Joseph Barrow,
* Arnd Bergmann <arndb@de.ibm.com>, * Arnd Bergmann,
*
* Atomic operations that C can't guarantee us.
* Useful for resource counting etc.
* s390 uses 'Compare And Swap' for atomicity in SMP environment.
*
*/ */
#ifndef __ARCH_S390_ATOMIC__ #ifndef __ARCH_S390_ATOMIC__
...@@ -15,62 +10,12 @@ ...@@ -15,62 +10,12 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/atomic_ops.h>
#include <asm/barrier.h> #include <asm/barrier.h>
#include <asm/cmpxchg.h> #include <asm/cmpxchg.h>
#define ATOMIC_INIT(i) { (i) } #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_XOR "lax"
#define __ATOMIC_BARRIER "bcr 14,0\n"
#define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier) \
({ \
int old_val; \
\
typecheck(atomic_t *, ptr); \
asm volatile( \
op_string " %0,%2,%1\n" \
__barrier \
: "=d" (old_val), "+Q" ((ptr)->counter) \
: "d" (op_val) \
: "cc", "memory"); \
old_val; \
})
#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
#define __ATOMIC_OR "or"
#define __ATOMIC_AND "nr"
#define __ATOMIC_ADD "ar"
#define __ATOMIC_XOR "xr"
#define __ATOMIC_BARRIER "\n"
#define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier) \
({ \
int old_val, new_val; \
\
typecheck(atomic_t *, ptr); \
asm volatile( \
" l %0,%2\n" \
"0: lr %1,%0\n" \
op_string " %1,%3\n" \
" cs %0,%1,%2\n" \
" jl 0b" \
: "=&d" (old_val), "=&d" (new_val), "+Q" ((ptr)->counter)\
: "d" (op_val) \
: "cc", "memory"); \
old_val; \
})
#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
static inline int atomic_read(const atomic_t *v) static inline int atomic_read(const atomic_t *v)
{ {
int c; int c;
...@@ -90,27 +35,23 @@ static inline void atomic_set(atomic_t *v, int i) ...@@ -90,27 +35,23 @@ static inline void atomic_set(atomic_t *v, int i)
static inline int atomic_add_return(int i, atomic_t *v) static inline int atomic_add_return(int i, atomic_t *v)
{ {
return __ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_BARRIER) + i; return __atomic_add_barrier(i, &v->counter) + i;
} }
static inline int atomic_fetch_add(int i, atomic_t *v) static inline int atomic_fetch_add(int i, atomic_t *v)
{ {
return __ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_BARRIER); return __atomic_add_barrier(i, &v->counter);
} }
static inline void atomic_add(int i, atomic_t *v) static inline void atomic_add(int i, atomic_t *v)
{ {
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
if (__builtin_constant_p(i) && (i > -129) && (i < 128)) { if (__builtin_constant_p(i) && (i > -129) && (i < 128)) {
asm volatile( __atomic_add_const(i, &v->counter);
"asi %0,%1\n"
: "+Q" (v->counter)
: "i" (i)
: "cc", "memory");
return; return;
} }
#endif #endif
__ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_NO_BARRIER); __atomic_add(i, &v->counter);
} }
#define atomic_add_negative(_i, _v) (atomic_add_return(_i, _v) < 0) #define atomic_add_negative(_i, _v) (atomic_add_return(_i, _v) < 0)
...@@ -125,19 +66,19 @@ static inline void atomic_add(int i, atomic_t *v) ...@@ -125,19 +66,19 @@ static inline void atomic_add(int i, atomic_t *v)
#define atomic_dec_return(_v) atomic_sub_return(1, _v) #define atomic_dec_return(_v) atomic_sub_return(1, _v)
#define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0) #define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0)
#define ATOMIC_OPS(op, OP) \ #define ATOMIC_OPS(op) \
static inline void atomic_##op(int i, atomic_t *v) \ static inline void atomic_##op(int i, atomic_t *v) \
{ \ { \
__ATOMIC_LOOP(v, i, __ATOMIC_##OP, __ATOMIC_NO_BARRIER); \ __atomic_##op(i, &v->counter); \
} \ } \
static inline int atomic_fetch_##op(int i, atomic_t *v) \ static inline int atomic_fetch_##op(int i, atomic_t *v) \
{ \ { \
return __ATOMIC_LOOP(v, i, __ATOMIC_##OP, __ATOMIC_BARRIER); \ return __atomic_##op##_barrier(i, &v->counter); \
} }
ATOMIC_OPS(and, AND) ATOMIC_OPS(and)
ATOMIC_OPS(or, OR) ATOMIC_OPS(or)
ATOMIC_OPS(xor, XOR) ATOMIC_OPS(xor)
#undef ATOMIC_OPS #undef ATOMIC_OPS
...@@ -145,12 +86,7 @@ ATOMIC_OPS(xor, XOR) ...@@ -145,12 +86,7 @@ ATOMIC_OPS(xor, XOR)
static inline int atomic_cmpxchg(atomic_t *v, int old, int new) static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
{ {
asm volatile( return __atomic_cmpxchg(&v->counter, old, new);
" cs %0,%2,%1"
: "+d" (old), "+Q" (v->counter)
: "d" (new)
: "cc", "memory");
return old;
} }
static inline int __atomic_add_unless(atomic_t *v, int a, int u) static inline int __atomic_add_unless(atomic_t *v, int a, int u)
...@@ -168,65 +104,11 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) ...@@ -168,65 +104,11 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
return c; return c;
} }
#undef __ATOMIC_LOOP
#define ATOMIC64_INIT(i) { (i) } #define ATOMIC64_INIT(i) { (i) }
#define __ATOMIC64_NO_BARRIER "\n" static inline long atomic64_read(const atomic64_t *v)
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
#define __ATOMIC64_OR "laog"
#define __ATOMIC64_AND "lang"
#define __ATOMIC64_ADD "laag"
#define __ATOMIC64_XOR "laxg"
#define __ATOMIC64_BARRIER "bcr 14,0\n"
#define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier) \
({ \
long long old_val; \
\
typecheck(atomic64_t *, ptr); \
asm volatile( \
op_string " %0,%2,%1\n" \
__barrier \
: "=d" (old_val), "+Q" ((ptr)->counter) \
: "d" (op_val) \
: "cc", "memory"); \
old_val; \
})
#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
#define __ATOMIC64_OR "ogr"
#define __ATOMIC64_AND "ngr"
#define __ATOMIC64_ADD "agr"
#define __ATOMIC64_XOR "xgr"
#define __ATOMIC64_BARRIER "\n"
#define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier) \
({ \
long long old_val, new_val; \
\
typecheck(atomic64_t *, ptr); \
asm volatile( \
" lg %0,%2\n" \
"0: lgr %1,%0\n" \
op_string " %1,%3\n" \
" csg %0,%1,%2\n" \
" jl 0b" \
: "=&d" (old_val), "=&d" (new_val), "+Q" ((ptr)->counter)\
: "d" (op_val) \
: "cc", "memory"); \
old_val; \
})
#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
static inline long long atomic64_read(const atomic64_t *v)
{ {
long long c; long c;
asm volatile( asm volatile(
" lg %0,%1\n" " lg %0,%1\n"
...@@ -234,71 +116,60 @@ static inline long long atomic64_read(const atomic64_t *v) ...@@ -234,71 +116,60 @@ static inline long long atomic64_read(const atomic64_t *v)
return c; return c;
} }
static inline void atomic64_set(atomic64_t *v, long long i) static inline void atomic64_set(atomic64_t *v, long i)
{ {
asm volatile( asm volatile(
" stg %1,%0\n" " stg %1,%0\n"
: "=Q" (v->counter) : "d" (i)); : "=Q" (v->counter) : "d" (i));
} }
static inline long long atomic64_add_return(long long i, atomic64_t *v) static inline long atomic64_add_return(long i, atomic64_t *v)
{ {
return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_BARRIER) + i; return __atomic64_add_barrier(i, &v->counter) + i;
} }
static inline long long atomic64_fetch_add(long long i, atomic64_t *v) static inline long atomic64_fetch_add(long i, atomic64_t *v)
{ {
return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_BARRIER); return __atomic64_add_barrier(i, &v->counter);
} }
static inline void atomic64_add(long long i, atomic64_t *v) static inline void atomic64_add(long i, atomic64_t *v)
{ {
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
if (__builtin_constant_p(i) && (i > -129) && (i < 128)) { if (__builtin_constant_p(i) && (i > -129) && (i < 128)) {
asm volatile( __atomic64_add_const(i, &v->counter);
"agsi %0,%1\n"
: "+Q" (v->counter)
: "i" (i)
: "cc", "memory");
return; return;
} }
#endif #endif
__ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_NO_BARRIER); __atomic64_add(i, &v->counter);
} }
#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
static inline long long atomic64_cmpxchg(atomic64_t *v, static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new)
long long old, long long new)
{ {
asm volatile( return __atomic64_cmpxchg(&v->counter, old, new);
" csg %0,%2,%1"
: "+d" (old), "+Q" (v->counter)
: "d" (new)
: "cc", "memory");
return old;
} }
#define ATOMIC64_OPS(op, OP) \ #define ATOMIC64_OPS(op) \
static inline void atomic64_##op(long i, atomic64_t *v) \ static inline void atomic64_##op(long i, atomic64_t *v) \
{ \ { \
__ATOMIC64_LOOP(v, i, __ATOMIC64_##OP, __ATOMIC64_NO_BARRIER); \ __atomic64_##op(i, &v->counter); \
} \ } \
static inline long atomic64_fetch_##op(long i, atomic64_t *v) \ static inline long atomic64_fetch_##op(long i, atomic64_t *v) \
{ \ { \
return __ATOMIC64_LOOP(v, i, __ATOMIC64_##OP, __ATOMIC64_BARRIER); \ return __atomic64_##op##_barrier(i, &v->counter); \
} }
ATOMIC64_OPS(and, AND) ATOMIC64_OPS(and)
ATOMIC64_OPS(or, OR) ATOMIC64_OPS(or)
ATOMIC64_OPS(xor, XOR) ATOMIC64_OPS(xor)
#undef ATOMIC64_OPS #undef ATOMIC64_OPS
#undef __ATOMIC64_LOOP
static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u) static inline int atomic64_add_unless(atomic64_t *v, long i, long u)
{ {
long long c, old; long c, old;
c = atomic64_read(v); c = atomic64_read(v);
for (;;) { for (;;) {
...@@ -312,9 +183,9 @@ static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u) ...@@ -312,9 +183,9 @@ static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u)
return c != u; return c != u;
} }
static inline long long atomic64_dec_if_positive(atomic64_t *v) static inline long atomic64_dec_if_positive(atomic64_t *v)
{ {
long long c, old, dec; long c, old, dec;
c = atomic64_read(v); c = atomic64_read(v);
for (;;) { for (;;) {
...@@ -333,9 +204,9 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v) ...@@ -333,9 +204,9 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v)
#define atomic64_inc(_v) atomic64_add(1, _v) #define atomic64_inc(_v) atomic64_add(1, _v)
#define atomic64_inc_return(_v) atomic64_add_return(1, _v) #define atomic64_inc_return(_v) atomic64_add_return(1, _v)
#define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0) #define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0)
#define atomic64_sub_return(_i, _v) atomic64_add_return(-(long long)(_i), _v) #define atomic64_sub_return(_i, _v) atomic64_add_return(-(long)(_i), _v)
#define atomic64_fetch_sub(_i, _v) atomic64_fetch_add(-(long long)(_i), _v) #define atomic64_fetch_sub(_i, _v) atomic64_fetch_add(-(long)(_i), _v)
#define atomic64_sub(_i, _v) atomic64_add(-(long long)(_i), _v) #define atomic64_sub(_i, _v) atomic64_add(-(long)(_i), _v)
#define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0) #define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0)
#define atomic64_dec(_v) atomic64_sub(1, _v) #define atomic64_dec(_v) atomic64_sub(1, _v)
#define atomic64_dec_return(_v) atomic64_sub_return(1, _v) #define atomic64_dec_return(_v) atomic64_sub_return(1, _v)
......
/*
* Low level function for atomic operations
*
* Copyright IBM Corp. 1999, 2016
*/
#ifndef __ARCH_S390_ATOMIC_OPS__
#define __ARCH_S390_ATOMIC_OPS__
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
#define __ATOMIC_OP(op_name, op_type, op_string, op_barrier) \
static inline op_type op_name(op_type val, op_type *ptr) \
{ \
op_type old; \
\
asm volatile( \
op_string " %[old],%[val],%[ptr]\n" \
op_barrier \
: [old] "=d" (old), [ptr] "+Q" (*ptr) \
: [val] "d" (val) : "cc", "memory"); \
return old; \
} \
#define __ATOMIC_OPS(op_name, op_type, op_string) \
__ATOMIC_OP(op_name, op_type, op_string, "\n") \
__ATOMIC_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n")
__ATOMIC_OPS(__atomic_add, int, "laa")
__ATOMIC_OPS(__atomic_and, int, "lan")
__ATOMIC_OPS(__atomic_or, int, "lao")
__ATOMIC_OPS(__atomic_xor, int, "lax")
__ATOMIC_OPS(__atomic64_add, long, "laag")
__ATOMIC_OPS(__atomic64_and, long, "lang")
__ATOMIC_OPS(__atomic64_or, long, "laog")
__ATOMIC_OPS(__atomic64_xor, long, "laxg")
#undef __ATOMIC_OPS
#undef __ATOMIC_OP
static inline void __atomic_add_const(int val, int *ptr)
{
asm volatile(
" asi %[ptr],%[val]\n"
: [ptr] "+Q" (*ptr) : [val] "i" (val) : "cc");
}
static inline void __atomic64_add_const(long val, long *ptr)
{
asm volatile(
" agsi %[ptr],%[val]\n"
: [ptr] "+Q" (*ptr) : [val] "i" (val) : "cc");
}
#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
#define __ATOMIC_OP(op_name, op_string) \
static inline int op_name(int val, int *ptr) \
{ \
int old, new; \
\
asm volatile( \
"0: lr %[new],%[old]\n" \
op_string " %[new],%[val]\n" \
" cs %[old],%[new],%[ptr]\n" \
" jl 0b" \
: [old] "=d" (old), [new] "=&d" (new), [ptr] "+Q" (*ptr)\
: [val] "d" (val), "0" (*ptr) : "cc", "memory"); \
return old; \
}
#define __ATOMIC_OPS(op_name, op_string) \
__ATOMIC_OP(op_name, op_string) \
__ATOMIC_OP(op_name##_barrier, op_string)
__ATOMIC_OPS(__atomic_add, "ar")
__ATOMIC_OPS(__atomic_and, "nr")
__ATOMIC_OPS(__atomic_or, "or")
__ATOMIC_OPS(__atomic_xor, "xr")
#undef __ATOMIC_OPS
#define __ATOMIC64_OP(op_name, op_string) \
static inline long op_name(long val, long *ptr) \
{ \
long old, new; \
\
asm volatile( \
"0: lgr %[new],%[old]\n" \
op_string " %[new],%[val]\n" \
" csg %[old],%[new],%[ptr]\n" \
" jl 0b" \
: [old] "=d" (old), [new] "=&d" (new), [ptr] "+Q" (*ptr)\
: [val] "d" (val), "0" (*ptr) : "cc", "memory"); \
return old; \
}
#define __ATOMIC64_OPS(op_name, op_string) \
__ATOMIC64_OP(op_name, op_string) \
__ATOMIC64_OP(op_name##_barrier, op_string)
__ATOMIC64_OPS(__atomic64_add, "agr")
__ATOMIC64_OPS(__atomic64_and, "ngr")
__ATOMIC64_OPS(__atomic64_or, "ogr")
__ATOMIC64_OPS(__atomic64_xor, "xgr")
#undef __ATOMIC64_OPS
#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
static inline int __atomic_cmpxchg(int *ptr, int old, int new)
{
asm volatile(
" cs %[old],%[new],%[ptr]"
: [old] "+d" (old), [ptr] "+Q" (*ptr)
: [new] "d" (new) : "cc", "memory");
return old;
}
static inline long __atomic64_cmpxchg(long *ptr, long old, long new)
{
asm volatile(
" csg %[old],%[new],%[ptr]"
: [old] "+d" (old), [ptr] "+Q" (*ptr)
: [new] "d" (new) : "cc", "memory");
return old;
}
#endif /* __ARCH_S390_ATOMIC_OPS__ */
...@@ -42,57 +42,9 @@ ...@@ -42,57 +42,9 @@
#include <linux/typecheck.h> #include <linux/typecheck.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <asm/atomic_ops.h>
#include <asm/barrier.h> #include <asm/barrier.h>
#define __BITOPS_NO_BARRIER "\n"
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
#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, __barrier) \
({ \
unsigned long __old; \
\
typecheck(unsigned long *, (__addr)); \
asm volatile( \
__op_string " %0,%2,%1\n" \
__barrier \
: "=d" (__old), "+Q" (*(__addr)) \
: "d" (__val) \
: "cc", "memory"); \
__old; \
})
#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
#define __BITOPS_OR "ogr"
#define __BITOPS_AND "ngr"
#define __BITOPS_XOR "xgr"
#define __BITOPS_BARRIER "\n"
#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier) \
({ \
unsigned long __old, __new; \
\
typecheck(unsigned long *, (__addr)); \
asm volatile( \
" lg %0,%2\n" \
"0: lgr %1,%0\n" \
__op_string " %1,%3\n" \
" csg %0,%1,%2\n" \
" jl 0b" \
: "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\
: "d" (__val) \
: "cc", "memory"); \
__old; \
})
#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
#define __BITOPS_WORDS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG) #define __BITOPS_WORDS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
static inline unsigned long * static inline unsigned long *
...@@ -128,7 +80,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *ptr) ...@@ -128,7 +80,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *ptr)
} }
#endif #endif
mask = 1UL << (nr & (BITS_PER_LONG - 1)); mask = 1UL << (nr & (BITS_PER_LONG - 1));
__BITOPS_LOOP(addr, mask, __BITOPS_OR, __BITOPS_NO_BARRIER); __atomic64_or(mask, addr);
} }
static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr) static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
...@@ -149,7 +101,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr) ...@@ -149,7 +101,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
} }
#endif #endif
mask = ~(1UL << (nr & (BITS_PER_LONG - 1))); mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
__BITOPS_LOOP(addr, mask, __BITOPS_AND, __BITOPS_NO_BARRIER); __atomic64_and(mask, addr);
} }
static inline void change_bit(unsigned long nr, volatile unsigned long *ptr) static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
...@@ -170,7 +122,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *ptr) ...@@ -170,7 +122,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
} }
#endif #endif
mask = 1UL << (nr & (BITS_PER_LONG - 1)); mask = 1UL << (nr & (BITS_PER_LONG - 1));
__BITOPS_LOOP(addr, mask, __BITOPS_XOR, __BITOPS_NO_BARRIER); __atomic64_xor(mask, addr);
} }
static inline int static inline int
...@@ -180,7 +132,7 @@ test_and_set_bit(unsigned long nr, volatile unsigned long *ptr) ...@@ -180,7 +132,7 @@ test_and_set_bit(unsigned long nr, volatile unsigned long *ptr)
unsigned long old, mask; unsigned long old, mask;
mask = 1UL << (nr & (BITS_PER_LONG - 1)); mask = 1UL << (nr & (BITS_PER_LONG - 1));
old = __BITOPS_LOOP(addr, mask, __BITOPS_OR, __BITOPS_BARRIER); old = __atomic64_or_barrier(mask, addr);
return (old & mask) != 0; return (old & mask) != 0;
} }
...@@ -191,7 +143,7 @@ test_and_clear_bit(unsigned long nr, volatile unsigned long *ptr) ...@@ -191,7 +143,7 @@ test_and_clear_bit(unsigned long nr, volatile unsigned long *ptr)
unsigned long old, mask; unsigned long old, mask;
mask = ~(1UL << (nr & (BITS_PER_LONG - 1))); mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
old = __BITOPS_LOOP(addr, mask, __BITOPS_AND, __BITOPS_BARRIER); old = __atomic64_and_barrier(mask, addr);
return (old & ~mask) != 0; return (old & ~mask) != 0;
} }
...@@ -202,7 +154,7 @@ test_and_change_bit(unsigned long nr, volatile unsigned long *ptr) ...@@ -202,7 +154,7 @@ test_and_change_bit(unsigned long nr, volatile unsigned long *ptr)
unsigned long old, mask; unsigned long old, mask;
mask = 1UL << (nr & (BITS_PER_LONG - 1)); mask = 1UL << (nr & (BITS_PER_LONG - 1));
old = __BITOPS_LOOP(addr, mask, __BITOPS_XOR, __BITOPS_BARRIER); old = __atomic64_xor_barrier(mask, addr);
return (old & mask) != 0; return (old & mask) != 0;
} }
......
...@@ -104,7 +104,8 @@ struct hws_basic_entry { ...@@ -104,7 +104,8 @@ struct hws_basic_entry {
unsigned int P:1; /* 28 PSW Problem state */ unsigned int P:1; /* 28 PSW Problem state */
unsigned int AS:2; /* 29-30 PSW address-space control */ unsigned int AS:2; /* 29-30 PSW address-space control */
unsigned int I:1; /* 31 entry valid or invalid */ unsigned int I:1; /* 31 entry valid or invalid */
unsigned int:16; unsigned int CL:2; /* 32-33 Configuration Level */
unsigned int:14;
unsigned int prim_asn:16; /* primary ASN */ unsigned int prim_asn:16; /* primary ASN */
unsigned long long ia; /* Instruction Address */ unsigned long long ia; /* Instruction Address */
unsigned long long gpp; /* Guest Program Parameter */ unsigned long long gpp; /* Guest Program Parameter */
......
...@@ -193,7 +193,7 @@ extern char elf_platform[]; ...@@ -193,7 +193,7 @@ extern char elf_platform[];
do { \ do { \
set_personality(PER_LINUX | \ set_personality(PER_LINUX | \
(current->personality & (~PER_MASK))); \ (current->personality & (~PER_MASK))); \
current_thread_info()->sys_call_table = \ current->thread.sys_call_table = \
(unsigned long) &sys_call_table; \ (unsigned long) &sys_call_table; \
} while (0) } while (0)
#else /* CONFIG_COMPAT */ #else /* CONFIG_COMPAT */
...@@ -204,11 +204,11 @@ do { \ ...@@ -204,11 +204,11 @@ do { \
(current->personality & ~PER_MASK)); \ (current->personality & ~PER_MASK)); \
if ((ex).e_ident[EI_CLASS] == ELFCLASS32) { \ if ((ex).e_ident[EI_CLASS] == ELFCLASS32) { \
set_thread_flag(TIF_31BIT); \ set_thread_flag(TIF_31BIT); \
current_thread_info()->sys_call_table = \ current->thread.sys_call_table = \
(unsigned long) &sys_call_table_emu; \ (unsigned long) &sys_call_table_emu; \
} else { \ } else { \
clear_thread_flag(TIF_31BIT); \ clear_thread_flag(TIF_31BIT); \
current_thread_info()->sys_call_table = \ current->thread.sys_call_table = \
(unsigned long) &sys_call_table; \ (unsigned long) &sys_call_table; \
} \ } \
} while (0) } while (0)
......
/*
* Copyright IBM Corp. 2015
*/
#ifndef S390_GEN_FACILITIES_C
#error "This file can only be included by gen_facilities.c"
#endif
#include <linux/kconfig.h>
struct facility_def {
char *name;
int *bits;
};
static struct facility_def facility_defs[] = {
{
/*
* FACILITIES_ALS contains the list of facilities that are
* required to run a kernel that is compiled e.g. with
* -march=<machine>.
*/
.name = "FACILITIES_ALS",
.bits = (int[]){
#ifdef CONFIG_HAVE_MARCH_Z900_FEATURES
0, /* N3 instructions */
1, /* z/Arch mode installed */
#endif
#ifdef CONFIG_HAVE_MARCH_Z990_FEATURES
18, /* long displacement facility */
#endif
#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
7, /* stfle */
17, /* message security assist */
21, /* extended-immediate facility */
25, /* store clock fast */
#endif
#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
27, /* mvcos */
32, /* compare and swap and store */
33, /* compare and swap and store 2 */
34, /* general extension facility */
35, /* execute extensions */
#endif
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
45, /* fast-BCR, etc. */
#endif
#ifdef CONFIG_HAVE_MARCH_ZEC12_FEATURES
49, /* misc-instruction-extensions */
52, /* interlocked facility 2 */
#endif
#ifdef CONFIG_HAVE_MARCH_Z13_FEATURES
53, /* load-and-zero-rightmost-byte, etc. */
#endif
-1 /* END */
}
},
{
.name = "FACILITIES_KVM",
.bits = (int[]){
0, /* N3 instructions */
1, /* z/Arch mode installed */
2, /* z/Arch mode active */
3, /* DAT-enhancement */
4, /* idte segment table */
5, /* idte region table */
6, /* ASN-and-LX reuse */
7, /* stfle */
8, /* enhanced-DAT 1 */
9, /* sense-running-status */
10, /* conditional sske */
13, /* ipte-range */
14, /* nonquiescing key-setting */
73, /* transactional execution */
75, /* access-exception-fetch/store indication */
76, /* msa extension 3 */
77, /* msa extension 4 */
78, /* enhanced-DAT 2 */
-1 /* END */
}
},
};
...@@ -97,7 +97,7 @@ void __init save_area_add_vxrs(struct save_area *, __vector128 *vxrs); ...@@ -97,7 +97,7 @@ void __init save_area_add_vxrs(struct save_area *, __vector128 *vxrs);
extern void do_reipl(void); extern void do_reipl(void);
extern void do_halt(void); extern void do_halt(void);
extern void do_poff(void); extern void do_poff(void);
extern void ipl_save_parameters(void); extern void ipl_verify_parameters(void);
extern void ipl_update_parameters(void); extern void ipl_update_parameters(void);
extern size_t append_ipl_vmparm(char *, size_t); extern size_t append_ipl_vmparm(char *, size_t);
extern size_t append_ipl_scpdata(char *, size_t); extern size_t append_ipl_scpdata(char *, size_t);
......
...@@ -95,7 +95,7 @@ struct lowcore { ...@@ -95,7 +95,7 @@ struct lowcore {
/* Current process. */ /* Current process. */
__u64 current_task; /* 0x0310 */ __u64 current_task; /* 0x0310 */
__u64 thread_info; /* 0x0318 */ __u8 pad_0x318[0x320-0x318]; /* 0x0318 */
__u64 kernel_stack; /* 0x0320 */ __u64 kernel_stack; /* 0x0320 */
/* Interrupt, panic and restart stack. */ /* Interrupt, panic and restart stack. */
...@@ -126,7 +126,8 @@ struct lowcore { ...@@ -126,7 +126,8 @@ struct lowcore {
__u64 percpu_offset; /* 0x0378 */ __u64 percpu_offset; /* 0x0378 */
__u64 vdso_per_cpu_data; /* 0x0380 */ __u64 vdso_per_cpu_data; /* 0x0380 */
__u64 machine_flags; /* 0x0388 */ __u64 machine_flags; /* 0x0388 */
__u8 pad_0x0390[0x0398-0x0390]; /* 0x0390 */ __u32 preempt_count; /* 0x0390 */
__u8 pad_0x0394[0x0398-0x0394]; /* 0x0394 */
__u64 gmap; /* 0x0398 */ __u64 gmap; /* 0x0398 */
__u32 spinlock_lockval; /* 0x03a0 */ __u32 spinlock_lockval; /* 0x03a0 */
__u32 fpu_flags; /* 0x03a4 */ __u32 fpu_flags; /* 0x03a4 */
......
...@@ -46,6 +46,8 @@ struct clp_fh_list_entry { ...@@ -46,6 +46,8 @@ struct clp_fh_list_entry {
#define CLP_UTIL_STR_LEN 64 #define CLP_UTIL_STR_LEN 64
#define CLP_PFIP_NR_SEGMENTS 4 #define CLP_PFIP_NR_SEGMENTS 4
extern bool zpci_unique_uid;
/* List PCI functions request */ /* List PCI functions request */
struct clp_req_list_pci { struct clp_req_list_pci {
struct clp_req_hdr hdr; struct clp_req_hdr hdr;
...@@ -59,7 +61,8 @@ struct clp_rsp_list_pci { ...@@ -59,7 +61,8 @@ struct clp_rsp_list_pci {
u64 resume_token; u64 resume_token;
u32 reserved2; u32 reserved2;
u16 max_fn; u16 max_fn;
u8 reserved3; u8 : 7;
u8 uid_checking : 1;
u8 entry_size; u8 entry_size;
struct clp_fh_list_entry fh_list[CLP_FH_LIST_NR_ENTRIES]; struct clp_fh_list_entry fh_list[CLP_FH_LIST_NR_ENTRIES];
} __packed; } __packed;
......
...@@ -27,17 +27,17 @@ extern int page_table_allocate_pgste; ...@@ -27,17 +27,17 @@ extern int page_table_allocate_pgste;
static inline void clear_table(unsigned long *s, unsigned long val, size_t n) static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
{ {
typedef struct { char _[n]; } addrtype; struct addrtype { char _[256]; };
int i;
*s = val;
n = (n / 256) - 1; for (i = 0; i < n; i += 256) {
asm volatile( *s = val;
" mvc 8(248,%0),0(%0)\n" asm volatile(
"0: mvc 256(256,%0),0(%0)\n" "mvc 8(248,%[s]),0(%[s])\n"
" la %0,256(%0)\n" : "+m" (*(struct addrtype *) s)
" brct %1,0b\n" : [s] "a" (s));
: "+a" (s), "+d" (n), "=m" (*(addrtype *) s) s += 256 / sizeof(long);
: "m" (*(addrtype *) s)); }
} }
static inline void crst_table_init(unsigned long *crst, unsigned long entry) static inline void crst_table_init(unsigned long *crst, unsigned long entry)
......
#ifndef __ASM_PREEMPT_H
#define __ASM_PREEMPT_H
#include <asm/current.h>
#include <linux/thread_info.h>
#include <asm/atomic_ops.h>
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
#define PREEMPT_ENABLED (0 + PREEMPT_NEED_RESCHED)
static inline int preempt_count(void)
{
return READ_ONCE(S390_lowcore.preempt_count) & ~PREEMPT_NEED_RESCHED;
}
static inline void preempt_count_set(int pc)
{
int old, new;
do {
old = READ_ONCE(S390_lowcore.preempt_count);
new = (old & PREEMPT_NEED_RESCHED) |
(pc & ~PREEMPT_NEED_RESCHED);
} while (__atomic_cmpxchg(&S390_lowcore.preempt_count,
old, new) != old);
}
#define init_task_preempt_count(p) do { } while (0)
#define init_idle_preempt_count(p, cpu) do { \
S390_lowcore.preempt_count = PREEMPT_ENABLED; \
} while (0)
static inline void set_preempt_need_resched(void)
{
__atomic_and(~PREEMPT_NEED_RESCHED, &S390_lowcore.preempt_count);
}
static inline void clear_preempt_need_resched(void)
{
__atomic_or(PREEMPT_NEED_RESCHED, &S390_lowcore.preempt_count);
}
static inline bool test_preempt_need_resched(void)
{
return !(READ_ONCE(S390_lowcore.preempt_count) & PREEMPT_NEED_RESCHED);
}
static inline void __preempt_count_add(int val)
{
if (__builtin_constant_p(val) && (val >= -128) && (val <= 127))
__atomic_add_const(val, &S390_lowcore.preempt_count);
else
__atomic_add(val, &S390_lowcore.preempt_count);
}
static inline void __preempt_count_sub(int val)
{
__preempt_count_add(-val);
}
static inline bool __preempt_count_dec_and_test(void)
{
return __atomic_add(-1, &S390_lowcore.preempt_count) == 1;
}
static inline bool should_resched(int preempt_offset)
{
return unlikely(READ_ONCE(S390_lowcore.preempt_count) ==
preempt_offset);
}
#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
#define PREEMPT_ENABLED (0)
static inline int preempt_count(void)
{
return READ_ONCE(S390_lowcore.preempt_count);
}
static inline void preempt_count_set(int pc)
{
S390_lowcore.preempt_count = pc;
}
#define init_task_preempt_count(p) do { } while (0)
#define init_idle_preempt_count(p, cpu) do { \
S390_lowcore.preempt_count = PREEMPT_ENABLED; \
} while (0)
static inline void set_preempt_need_resched(void)
{
}
static inline void clear_preempt_need_resched(void)
{
}
static inline bool test_preempt_need_resched(void)
{
return false;
}
static inline void __preempt_count_add(int val)
{
S390_lowcore.preempt_count += val;
}
static inline void __preempt_count_sub(int val)
{
S390_lowcore.preempt_count -= val;
}
static inline bool __preempt_count_dec_and_test(void)
{
return !--S390_lowcore.preempt_count && tif_need_resched();
}
static inline bool should_resched(int preempt_offset)
{
return unlikely(preempt_count() == preempt_offset &&
tif_need_resched());
}
#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
#ifdef CONFIG_PREEMPT
extern asmlinkage void preempt_schedule(void);
#define __preempt_schedule() preempt_schedule()
extern asmlinkage void preempt_schedule_notrace(void);
#define __preempt_schedule_notrace() preempt_schedule_notrace()
#endif /* CONFIG_PREEMPT */
#endif /* __ASM_PREEMPT_H */
...@@ -110,14 +110,20 @@ typedef struct { ...@@ -110,14 +110,20 @@ typedef struct {
struct thread_struct { struct thread_struct {
unsigned int acrs[NUM_ACRS]; unsigned int acrs[NUM_ACRS];
unsigned long ksp; /* kernel stack pointer */ unsigned long ksp; /* kernel stack pointer */
unsigned long user_timer; /* task cputime in user space */
unsigned long system_timer; /* task cputime in kernel space */
unsigned long sys_call_table; /* system call table address */
mm_segment_t mm_segment; mm_segment_t mm_segment;
unsigned long gmap_addr; /* address of last gmap fault. */ unsigned long gmap_addr; /* address of last gmap fault. */
unsigned int gmap_write_flag; /* gmap fault write indication */ unsigned int gmap_write_flag; /* gmap fault write indication */
unsigned int gmap_int_code; /* int code of last gmap fault */ unsigned int gmap_int_code; /* int code of last gmap fault */
unsigned int gmap_pfault; /* signal of a pending guest pfault */ unsigned int gmap_pfault; /* signal of a pending guest pfault */
/* Per-thread information related to debugging */
struct per_regs per_user; /* User specified PER registers */ struct per_regs per_user; /* User specified PER registers */
struct per_event per_event; /* Cause of the last PER trap */ struct per_event per_event; /* Cause of the last PER trap */
unsigned long per_flags; /* Flags to control debug behavior */ unsigned long per_flags; /* Flags to control debug behavior */
unsigned int system_call; /* system call number in signal */
unsigned long last_break; /* last breaking-event-address. */
/* pfault_wait is used to block the process on a pfault event */ /* pfault_wait is used to block the process on a pfault event */
unsigned long pfault_wait; unsigned long pfault_wait;
struct list_head list; struct list_head list;
......
...@@ -101,7 +101,8 @@ struct zpci_report_error_header { ...@@ -101,7 +101,8 @@ struct zpci_report_error_header {
u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */ u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */
} __packed; } __packed;
int sclp_get_core_info(struct sclp_core_info *info); int _sclp_get_core_info_early(struct sclp_core_info *info);
int _sclp_get_core_info(struct sclp_core_info *info);
int sclp_core_configure(u8 core); int sclp_core_configure(u8 core);
int sclp_core_deconfigure(u8 core); int sclp_core_deconfigure(u8 core);
int sclp_sdias_blk_count(void); int sclp_sdias_blk_count(void);
...@@ -119,4 +120,11 @@ void sclp_early_detect(void); ...@@ -119,4 +120,11 @@ void sclp_early_detect(void);
void _sclp_print_early(const char *); void _sclp_print_early(const char *);
void sclp_ocf_cpc_name_copy(char *dst); void sclp_ocf_cpc_name_copy(char *dst);
static inline int sclp_get_core_info(struct sclp_core_info *info, int early)
{
if (early)
return _sclp_get_core_info_early(info);
return _sclp_get_core_info(info);
}
#endif /* _ASM_S390_SCLP_H */ #endif /* _ASM_S390_SCLP_H */
...@@ -96,7 +96,8 @@ struct tm_scsw { ...@@ -96,7 +96,8 @@ struct tm_scsw {
u32 dstat:8; u32 dstat:8;
u32 cstat:8; u32 cstat:8;
u32 fcxs:8; u32 fcxs:8;
u32 schxs:8; u32 ifob:1;
u32 sesq:7;
} __attribute__ ((packed)); } __attribute__ ((packed));
/** /**
...@@ -177,6 +178,9 @@ union scsw { ...@@ -177,6 +178,9 @@ union scsw {
#define SCHN_STAT_INTF_CTRL_CHK 0x02 #define SCHN_STAT_INTF_CTRL_CHK 0x02
#define SCHN_STAT_CHAIN_CHECK 0x01 #define SCHN_STAT_CHAIN_CHECK 0x01
#define SCSW_SESQ_DEV_NOFCX 3
#define SCSW_SESQ_PATH_NOFCX 4
/* /*
* architectured values for first sense byte * architectured values for first sense byte
*/ */
......
...@@ -36,6 +36,7 @@ extern void smp_yield_cpu(int cpu); ...@@ -36,6 +36,7 @@ extern void smp_yield_cpu(int cpu);
extern void smp_cpu_set_polarization(int cpu, int val); extern void smp_cpu_set_polarization(int cpu, int val);
extern int smp_cpu_get_polarization(int cpu); extern int smp_cpu_get_polarization(int cpu);
extern void smp_fill_possible_mask(void); extern void smp_fill_possible_mask(void);
extern void smp_detect_cpus(void);
#else /* CONFIG_SMP */ #else /* CONFIG_SMP */
...@@ -56,6 +57,7 @@ static inline int smp_store_status(int cpu) { return 0; } ...@@ -56,6 +57,7 @@ static inline int smp_store_status(int cpu) { return 0; }
static inline int smp_vcpu_scheduled(int cpu) { return 1; } static inline int smp_vcpu_scheduled(int cpu) { return 1; }
static inline void smp_yield_cpu(int cpu) { } static inline void smp_yield_cpu(int cpu) { }
static inline void smp_fill_possible_mask(void) { } static inline void smp_fill_possible_mask(void) { }
static inline void smp_detect_cpus(void) { }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
...@@ -69,6 +71,12 @@ static inline void smp_stop_cpu(void) ...@@ -69,6 +71,12 @@ static inline void smp_stop_cpu(void)
} }
} }
/* Return thread 0 CPU number as base CPU */
static inline int smp_get_base_cpu(int cpu)
{
return cpu - (cpu % (smp_cpu_mtid + 1));
}
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
extern int smp_rescan_cpus(void); extern int smp_rescan_cpus(void);
extern void __noreturn cpu_die(void); extern void __noreturn cpu_die(void);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define __HAVE_ARCH_MEMCHR /* inline & arch function */ #define __HAVE_ARCH_MEMCHR /* inline & arch function */
#define __HAVE_ARCH_MEMCMP /* arch function */ #define __HAVE_ARCH_MEMCMP /* arch function */
#define __HAVE_ARCH_MEMCPY /* gcc builtin & arch function */ #define __HAVE_ARCH_MEMCPY /* gcc builtin & arch function */
#define __HAVE_ARCH_MEMMOVE /* gcc builtin & arch function */
#define __HAVE_ARCH_MEMSCAN /* inline & arch function */ #define __HAVE_ARCH_MEMSCAN /* inline & arch function */
#define __HAVE_ARCH_MEMSET /* gcc builtin & arch function */ #define __HAVE_ARCH_MEMSET /* gcc builtin & arch function */
#define __HAVE_ARCH_STRCAT /* inline & arch function */ #define __HAVE_ARCH_STRCAT /* inline & arch function */
...@@ -32,6 +33,7 @@ ...@@ -32,6 +33,7 @@
extern int memcmp(const void *, const void *, size_t); extern int memcmp(const void *, const void *, size_t);
extern void *memcpy(void *, const void *, size_t); extern void *memcpy(void *, const void *, size_t);
extern void *memset(void *, int, size_t); extern void *memset(void *, int, size_t);
extern void *memmove(void *, const void *, size_t);
extern int strcmp(const char *,const char *); extern int strcmp(const char *,const char *);
extern size_t strlcat(char *, const char *, size_t); extern size_t strlcat(char *, const char *, size_t);
extern size_t strlcpy(char *, const char *, size_t); extern size_t strlcpy(char *, const char *, size_t);
...@@ -40,7 +42,6 @@ extern char *strncpy(char *, const char *, size_t); ...@@ -40,7 +42,6 @@ extern char *strncpy(char *, const char *, size_t);
extern char *strrchr(const char *, int); extern char *strrchr(const char *, int);
extern char *strstr(const char *, const char *); extern char *strstr(const char *, const char *);
#undef __HAVE_ARCH_MEMMOVE
#undef __HAVE_ARCH_STRCHR #undef __HAVE_ARCH_STRCHR
#undef __HAVE_ARCH_STRNCHR #undef __HAVE_ARCH_STRNCHR
#undef __HAVE_ARCH_STRNCMP #undef __HAVE_ARCH_STRNCMP
......
...@@ -107,6 +107,11 @@ struct sysinfo_2_2_2 { ...@@ -107,6 +107,11 @@ struct sysinfo_2_2_2 {
char reserved_3[5]; char reserved_3[5];
unsigned short cpus_dedicated; unsigned short cpus_dedicated;
unsigned short cpus_shared; unsigned short cpus_shared;
char reserved_4[3];
unsigned char vsne;
uuid_be uuid;
char reserved_5[160];
char ext_name[256];
}; };
#define LPAR_CHAR_DEDICATED (1 << 7) #define LPAR_CHAR_DEDICATED (1 << 7)
...@@ -127,7 +132,7 @@ struct sysinfo_3_2_2 { ...@@ -127,7 +132,7 @@ struct sysinfo_3_2_2 {
unsigned int caf; unsigned int caf;
char cpi[16]; char cpi[16];
char reserved_1[3]; char reserved_1[3];
char ext_name_encoding; unsigned char evmne;
unsigned int reserved_2; unsigned int reserved_2;
uuid_be uuid; uuid_be uuid;
} vm[8]; } vm[8];
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
/* /*
* Size of kernel stack for each process * Size of kernel stack for each process
*/ */
#define THREAD_ORDER 2 #define THREAD_SIZE_ORDER 2
#define ASYNC_ORDER 2 #define ASYNC_ORDER 2
#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
#define ASYNC_SIZE (PAGE_SIZE << ASYNC_ORDER) #define ASYNC_SIZE (PAGE_SIZE << ASYNC_ORDER)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
...@@ -30,15 +30,7 @@ ...@@ -30,15 +30,7 @@
* - if the contents of this structure are changed, the assembly constants must also be changed * - if the contents of this structure are changed, the assembly constants must also be changed
*/ */
struct thread_info { struct thread_info {
struct task_struct *task; /* main task structure */
unsigned long flags; /* low level flags */ unsigned long flags; /* low level flags */
unsigned long sys_call_table; /* System call table address */
unsigned int cpu; /* current CPU */
int preempt_count; /* 0 => preemptable, <0 => BUG */
unsigned int system_call;
__u64 user_timer;
__u64 system_timer;
unsigned long last_break; /* last breaking-event-address. */
}; };
/* /*
...@@ -46,26 +38,14 @@ struct thread_info { ...@@ -46,26 +38,14 @@ struct thread_info {
*/ */
#define INIT_THREAD_INFO(tsk) \ #define INIT_THREAD_INFO(tsk) \
{ \ { \
.task = &tsk, \
.flags = 0, \ .flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
} }
#define init_thread_info (init_thread_union.thread_info)
#define init_stack (init_thread_union.stack) #define init_stack (init_thread_union.stack)
/* how to get the thread information struct from C */
static inline struct thread_info *current_thread_info(void)
{
return (struct thread_info *) S390_lowcore.thread_info;
}
void arch_release_task_struct(struct task_struct *tsk); void arch_release_task_struct(struct task_struct *tsk);
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
#define THREAD_SIZE_ORDER THREAD_ORDER
#endif #endif
/* /*
......
...@@ -52,11 +52,9 @@ static inline void store_clock_comparator(__u64 *time) ...@@ -52,11 +52,9 @@ static inline void store_clock_comparator(__u64 *time)
void clock_comparator_work(void); void clock_comparator_work(void);
void __init ptff_init(void); void __init time_early_init(void);
extern unsigned char ptff_function_mask[16]; extern unsigned char ptff_function_mask[16];
extern unsigned long lpar_offset;
extern unsigned long initial_leap_seconds;
/* Function codes for the ptff instruction. */ /* Function codes for the ptff instruction. */
#define PTFF_QAF 0x00 /* query available functions */ #define PTFF_QAF 0x00 /* query available functions */
...@@ -100,21 +98,28 @@ struct ptff_qui { ...@@ -100,21 +98,28 @@ struct ptff_qui {
unsigned int pad_0x5c[41]; unsigned int pad_0x5c[41];
} __packed; } __packed;
static inline int ptff(void *ptff_block, size_t len, unsigned int func) /*
{ * ptff - Perform timing facility function
typedef struct { char _[len]; } addrtype; * @ptff_block: Pointer to ptff parameter block
register unsigned int reg0 asm("0") = func; * @len: Length of parameter block
register unsigned long reg1 asm("1") = (unsigned long) ptff_block; * @func: Function code
int rc; * Returns: Condition code (0 on success)
*/
asm volatile( #define ptff(ptff_block, len, func) \
" .word 0x0104\n" ({ \
" ipm %0\n" struct addrtype { char _[len]; }; \
" srl %0,28\n" register unsigned int reg0 asm("0") = func; \
: "=d" (rc), "+m" (*(addrtype *) ptff_block) register unsigned long reg1 asm("1") = (unsigned long) (ptff_block);\
: "d" (reg0), "d" (reg1) : "cc"); int rc; \
return rc; \
} asm volatile( \
" .word 0x0104\n" \
" ipm %0\n" \
" srl %0,28\n" \
: "=d" (rc), "+m" (*(struct addrtype *) reg1) \
: "d" (reg0), "d" (reg1) : "cc"); \
rc; \
})
static inline unsigned long long local_tick_disable(void) static inline unsigned long long local_tick_disable(void)
{ {
......
...@@ -22,21 +22,22 @@ struct cpu_topology_s390 { ...@@ -22,21 +22,22 @@ struct cpu_topology_s390 {
cpumask_t drawer_mask; cpumask_t drawer_mask;
}; };
DECLARE_PER_CPU(struct cpu_topology_s390, cpu_topology); extern struct cpu_topology_s390 cpu_topology[NR_CPUS];
extern cpumask_t cpus_with_topology;
#define topology_physical_package_id(cpu) (per_cpu(cpu_topology, cpu).socket_id)
#define topology_thread_id(cpu) (per_cpu(cpu_topology, cpu).thread_id) #define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
#define topology_sibling_cpumask(cpu) \ #define topology_thread_id(cpu) (cpu_topology[cpu].thread_id)
(&per_cpu(cpu_topology, cpu).thread_mask) #define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_mask)
#define topology_core_id(cpu) (per_cpu(cpu_topology, cpu).core_id) #define topology_core_id(cpu) (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu) (&per_cpu(cpu_topology, cpu).core_mask) #define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_mask)
#define topology_book_id(cpu) (per_cpu(cpu_topology, cpu).book_id) #define topology_book_id(cpu) (cpu_topology[cpu].book_id)
#define topology_book_cpumask(cpu) (&per_cpu(cpu_topology, cpu).book_mask) #define topology_book_cpumask(cpu) (&cpu_topology[cpu].book_mask)
#define topology_drawer_id(cpu) (per_cpu(cpu_topology, cpu).drawer_id) #define topology_drawer_id(cpu) (cpu_topology[cpu].drawer_id)
#define topology_drawer_cpumask(cpu) (&per_cpu(cpu_topology, cpu).drawer_mask) #define topology_drawer_cpumask(cpu) (&cpu_topology[cpu].drawer_mask)
#define mc_capable() 1 #define mc_capable() 1
void topology_init_early(void);
int topology_cpu_init(struct cpu *); int topology_cpu_init(struct cpu *);
int topology_set_cpu_management(int fc); int topology_set_cpu_management(int fc);
void topology_schedule_update(void); void topology_schedule_update(void);
...@@ -46,6 +47,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu); ...@@ -46,6 +47,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu);
#else /* CONFIG_SCHED_TOPOLOGY */ #else /* CONFIG_SCHED_TOPOLOGY */
static inline void topology_init_early(void) { }
static inline void topology_schedule_update(void) { } static inline void topology_schedule_update(void) { }
static inline int topology_cpu_init(struct cpu *cpu) { return 0; } static inline int topology_cpu_init(struct cpu *cpu) { return 0; }
static inline void topology_expect_change(void) { } static inline void topology_expect_change(void) { }
...@@ -65,7 +67,7 @@ static inline void topology_expect_change(void) { } ...@@ -65,7 +67,7 @@ static inline void topology_expect_change(void) { }
#define cpu_to_node cpu_to_node #define cpu_to_node cpu_to_node
static inline int cpu_to_node(int cpu) static inline int cpu_to_node(int cpu)
{ {
return per_cpu(cpu_topology, cpu).node_id; return cpu_topology[cpu].node_id;
} }
/* Returns a pointer to the cpumask of CPUs on node 'node'. */ /* Returns a pointer to the cpumask of CPUs on node 'node'. */
......
...@@ -37,14 +37,14 @@ ...@@ -37,14 +37,14 @@
#define get_ds() (KERNEL_DS) #define get_ds() (KERNEL_DS)
#define get_fs() (current->thread.mm_segment) #define get_fs() (current->thread.mm_segment)
#define set_fs(x) \ #define set_fs(x) \
({ \ { \
unsigned long __pto; \ unsigned long __pto; \
current->thread.mm_segment = (x); \ current->thread.mm_segment = (x); \
__pto = current->thread.mm_segment.ar4 ? \ __pto = current->thread.mm_segment.ar4 ? \
S390_lowcore.user_asce : S390_lowcore.kernel_asce; \ S390_lowcore.user_asce : S390_lowcore.kernel_asce; \
__ctl_load(__pto, 7, 7); \ __ctl_load(__pto, 7, 7); \
}) }
#define segment_eq(a,b) ((a).ar4 == (b).ar4) #define segment_eq(a,b) ((a).ar4 == (b).ar4)
......
...@@ -33,6 +33,8 @@ struct vdso_data { ...@@ -33,6 +33,8 @@ struct vdso_data {
__u32 ectg_available; /* ECTG instruction present 0x58 */ __u32 ectg_available; /* ECTG instruction present 0x58 */
__u32 tk_mult; /* Mult. used for xtime_nsec 0x5c */ __u32 tk_mult; /* Mult. used for xtime_nsec 0x5c */
__u32 tk_shift; /* Shift used for xtime_nsec 0x60 */ __u32 tk_shift; /* Shift used for xtime_nsec 0x60 */
__u32 ts_dir; /* TOD steering direction 0x64 */
__u64 ts_end; /* TOD steering end 0x68 */
}; };
struct vdso_per_cpu_data { struct vdso_per_cpu_data {
......
...@@ -12,6 +12,7 @@ header-y += dasd.h ...@@ -12,6 +12,7 @@ header-y += dasd.h
header-y += debug.h header-y += debug.h
header-y += errno.h header-y += errno.h
header-y += fcntl.h header-y += fcntl.h
header-y += hypfs.h
header-y += ioctl.h header-y += ioctl.h
header-y += ioctls.h header-y += ioctls.h
header-y += ipcbuf.h header-y += ipcbuf.h
...@@ -29,16 +30,16 @@ header-y += ptrace.h ...@@ -29,16 +30,16 @@ header-y += ptrace.h
header-y += qeth.h header-y += qeth.h
header-y += resource.h header-y += resource.h
header-y += schid.h header-y += schid.h
header-y += sclp_ctl.h
header-y += sembuf.h header-y += sembuf.h
header-y += setup.h header-y += setup.h
header-y += shmbuf.h header-y += shmbuf.h
header-y += sie.h
header-y += sigcontext.h header-y += sigcontext.h
header-y += siginfo.h header-y += siginfo.h
header-y += signal.h header-y += signal.h
header-y += socket.h header-y += socket.h
header-y += sockios.h header-y += sockios.h
header-y += sclp_ctl.h
header-y += sie.h
header-y += stat.h header-y += stat.h
header-y += statfs.h header-y += statfs.h
header-y += swab.h header-y += swab.h
......
...@@ -2,20 +2,47 @@ ...@@ -2,20 +2,47 @@
# Makefile for the linux kernel. # Makefile for the linux kernel.
# #
KCOV_INSTRUMENT_early.o := n
KCOV_INSTRUMENT_sclp.o := n
KCOV_INSTRUMENT_als.o := n
ifdef CONFIG_FUNCTION_TRACER ifdef CONFIG_FUNCTION_TRACER
# Don't trace early setup code and tracing code
CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE) # Do not trace tracer code
CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
# Do not trace early setup code
CFLAGS_REMOVE_als.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_sclp.o = $(CC_FLAGS_FTRACE)
endif
GCOV_PROFILE_als.o := n
GCOV_PROFILE_early.o := n
GCOV_PROFILE_sclp.o := n
KCOV_INSTRUMENT_als.o := n
KCOV_INSTRUMENT_early.o := n
KCOV_INSTRUMENT_sclp.o := n
UBSAN_SANITIZE_als.o := n
UBSAN_SANITIZE_early.o := n
UBSAN_SANITIZE_sclp.o := n
#
# Use -march=z900 for sclp.c and als.c to be able to print an error
# message if the kernel is started on a machine which is too old
#
ifneq ($(CC_FLAGS_MARCH),-march=z900)
CFLAGS_REMOVE_als.o += $(CC_FLAGS_MARCH)
CFLAGS_als.o += -march=z900
CFLAGS_REMOVE_sclp.o += $(CC_FLAGS_MARCH)
CFLAGS_sclp.o += -march=z900
AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH)
AFLAGS_head.o += -march=z900
endif endif
# #
# Passing null pointers is ok for smp code, since we access the lowcore here. # Passing null pointers is ok for smp code, since we access the lowcore here.
# #
CFLAGS_smp.o := -Wno-nonnull CFLAGS_smp.o := -Wno-nonnull
# #
# Disable tailcall optimizations for stack / callchain walking functions # Disable tailcall optimizations for stack / callchain walking functions
...@@ -30,27 +57,7 @@ CFLAGS_dumpstack.o += -fno-optimize-sibling-calls ...@@ -30,27 +57,7 @@ CFLAGS_dumpstack.o += -fno-optimize-sibling-calls
# #
CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
CFLAGS_sysinfo.o += -w CFLAGS_sysinfo.o += -w
#
# Use -march=z900 for sclp.c and als.c to be able to print an error
# message if the kernel is started on a machine which is too old
#
CFLAGS_REMOVE_sclp.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_als.o = $(CC_FLAGS_FTRACE)
ifneq ($(CC_FLAGS_MARCH),-march=z900)
CFLAGS_REMOVE_sclp.o += $(CC_FLAGS_MARCH)
CFLAGS_sclp.o += -march=z900
CFLAGS_REMOVE_als.o += $(CC_FLAGS_MARCH)
CFLAGS_als.o += -march=z900
AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH)
AFLAGS_head.o += -march=z900
endif
GCOV_PROFILE_sclp.o := n
GCOV_PROFILE_als.o := n
UBSAN_SANITIZE_als.o := n
UBSAN_SANITIZE_early.o := n
UBSAN_SANITIZE_sclp.o := n
obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
......
...@@ -25,12 +25,14 @@ ...@@ -25,12 +25,14 @@
int main(void) int main(void)
{ {
/* task struct offsets */ /* task struct offsets */
OFFSET(__TASK_thread_info, task_struct, stack); OFFSET(__TASK_stack, task_struct, stack);
OFFSET(__TASK_thread, task_struct, thread); OFFSET(__TASK_thread, task_struct, thread);
OFFSET(__TASK_pid, task_struct, pid); OFFSET(__TASK_pid, task_struct, pid);
BLANK(); BLANK();
/* thread struct offsets */ /* thread struct offsets */
OFFSET(__THREAD_ksp, thread_struct, ksp); OFFSET(__THREAD_ksp, thread_struct, ksp);
OFFSET(__THREAD_sysc_table, thread_struct, sys_call_table);
OFFSET(__THREAD_last_break, thread_struct, last_break);
OFFSET(__THREAD_FPU_fpc, thread_struct, fpu.fpc); OFFSET(__THREAD_FPU_fpc, thread_struct, fpu.fpc);
OFFSET(__THREAD_FPU_regs, thread_struct, fpu.regs); OFFSET(__THREAD_FPU_regs, thread_struct, fpu.regs);
OFFSET(__THREAD_per_cause, thread_struct, per_event.cause); OFFSET(__THREAD_per_cause, thread_struct, per_event.cause);
...@@ -39,14 +41,7 @@ int main(void) ...@@ -39,14 +41,7 @@ int main(void)
OFFSET(__THREAD_trap_tdb, thread_struct, trap_tdb); OFFSET(__THREAD_trap_tdb, thread_struct, trap_tdb);
BLANK(); BLANK();
/* thread info offsets */ /* thread info offsets */
OFFSET(__TI_task, thread_info, task); OFFSET(__TI_flags, task_struct, thread_info.flags);
OFFSET(__TI_flags, thread_info, flags);
OFFSET(__TI_sysc_table, thread_info, sys_call_table);
OFFSET(__TI_cpu, thread_info, cpu);
OFFSET(__TI_precount, thread_info, preempt_count);
OFFSET(__TI_user_timer, thread_info, user_timer);
OFFSET(__TI_system_timer, thread_info, system_timer);
OFFSET(__TI_last_break, thread_info, last_break);
BLANK(); BLANK();
/* pt_regs offsets */ /* pt_regs offsets */
OFFSET(__PT_ARGS, pt_regs, args); OFFSET(__PT_ARGS, pt_regs, args);
...@@ -79,6 +74,8 @@ int main(void) ...@@ -79,6 +74,8 @@ int main(void)
OFFSET(__VDSO_ECTG_OK, vdso_data, ectg_available); OFFSET(__VDSO_ECTG_OK, vdso_data, ectg_available);
OFFSET(__VDSO_TK_MULT, vdso_data, tk_mult); OFFSET(__VDSO_TK_MULT, vdso_data, tk_mult);
OFFSET(__VDSO_TK_SHIFT, vdso_data, tk_shift); OFFSET(__VDSO_TK_SHIFT, vdso_data, tk_shift);
OFFSET(__VDSO_TS_DIR, vdso_data, ts_dir);
OFFSET(__VDSO_TS_END, vdso_data, ts_end);
OFFSET(__VDSO_ECTG_BASE, vdso_per_cpu_data, ectg_timer_base); OFFSET(__VDSO_ECTG_BASE, vdso_per_cpu_data, ectg_timer_base);
OFFSET(__VDSO_ECTG_USER, vdso_per_cpu_data, ectg_user_time); OFFSET(__VDSO_ECTG_USER, vdso_per_cpu_data, ectg_user_time);
OFFSET(__VDSO_CPU_NR, vdso_per_cpu_data, cpu_nr); OFFSET(__VDSO_CPU_NR, vdso_per_cpu_data, cpu_nr);
...@@ -159,7 +156,6 @@ int main(void) ...@@ -159,7 +156,6 @@ int main(void)
OFFSET(__LC_INT_CLOCK, lowcore, int_clock); OFFSET(__LC_INT_CLOCK, lowcore, int_clock);
OFFSET(__LC_MCCK_CLOCK, lowcore, mcck_clock); OFFSET(__LC_MCCK_CLOCK, lowcore, mcck_clock);
OFFSET(__LC_CURRENT, lowcore, current_task); OFFSET(__LC_CURRENT, lowcore, current_task);
OFFSET(__LC_THREAD_INFO, lowcore, thread_info);
OFFSET(__LC_KERNEL_STACK, lowcore, kernel_stack); OFFSET(__LC_KERNEL_STACK, lowcore, kernel_stack);
OFFSET(__LC_ASYNC_STACK, lowcore, async_stack); OFFSET(__LC_ASYNC_STACK, lowcore, async_stack);
OFFSET(__LC_PANIC_STACK, lowcore, panic_stack); OFFSET(__LC_PANIC_STACK, lowcore, panic_stack);
...@@ -173,6 +169,7 @@ int main(void) ...@@ -173,6 +169,7 @@ int main(void)
OFFSET(__LC_PERCPU_OFFSET, lowcore, percpu_offset); OFFSET(__LC_PERCPU_OFFSET, lowcore, percpu_offset);
OFFSET(__LC_VDSO_PER_CPU, lowcore, vdso_per_cpu_data); OFFSET(__LC_VDSO_PER_CPU, lowcore, vdso_per_cpu_data);
OFFSET(__LC_MACHINE_FLAGS, lowcore, machine_flags); OFFSET(__LC_MACHINE_FLAGS, lowcore, machine_flags);
OFFSET(__LC_PREEMPT_COUNT, lowcore, preempt_count);
OFFSET(__LC_GMAP, lowcore, gmap); OFFSET(__LC_GMAP, lowcore, gmap);
OFFSET(__LC_PASTE, lowcore, paste); OFFSET(__LC_PASTE, lowcore, paste);
/* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */ /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */
......
...@@ -446,7 +446,7 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set, ...@@ -446,7 +446,7 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set,
/* set extra registers only for synchronous signals */ /* set extra registers only for synchronous signals */
regs->gprs[4] = regs->int_code & 127; regs->gprs[4] = regs->int_code & 127;
regs->gprs[5] = regs->int_parm_long; regs->gprs[5] = regs->int_parm_long;
regs->gprs[6] = task_thread_info(current)->last_break; regs->gprs[6] = current->thread.last_break;
} }
return 0; return 0;
...@@ -523,7 +523,7 @@ static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set, ...@@ -523,7 +523,7 @@ static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set,
regs->gprs[2] = ksig->sig; regs->gprs[2] = ksig->sig;
regs->gprs[3] = (__force __u64) &frame->info; regs->gprs[3] = (__force __u64) &frame->info;
regs->gprs[4] = (__force __u64) &frame->uc; regs->gprs[4] = (__force __u64) &frame->uc;
regs->gprs[5] = task_thread_info(current)->last_break; regs->gprs[5] = current->thread.last_break;
return 0; return 0;
} }
......
...@@ -293,6 +293,7 @@ static noinline __init void setup_lowcore_early(void) ...@@ -293,6 +293,7 @@ static noinline __init void setup_lowcore_early(void)
psw.addr = (unsigned long) s390_base_pgm_handler; psw.addr = (unsigned long) s390_base_pgm_handler;
S390_lowcore.program_new_psw = psw; S390_lowcore.program_new_psw = psw;
s390_base_pgm_handler_fn = early_pgm_check_handler; s390_base_pgm_handler_fn = early_pgm_check_handler;
S390_lowcore.preempt_count = INIT_PREEMPT_COUNT;
} }
static noinline __init void setup_facility_list(void) static noinline __init void setup_facility_list(void)
...@@ -391,7 +392,49 @@ static int __init cad_init(void) ...@@ -391,7 +392,49 @@ static int __init cad_init(void)
} }
early_initcall(cad_init); early_initcall(cad_init);
static __init void rescue_initrd(void) static __init void memmove_early(void *dst, const void *src, size_t n)
{
unsigned long addr;
long incr;
psw_t old;
if (!n)
return;
incr = 1;
if (dst > src) {
incr = -incr;
dst += n - 1;
src += n - 1;
}
old = S390_lowcore.program_new_psw;
S390_lowcore.program_new_psw.mask = __extract_psw();
asm volatile(
" larl %[addr],1f\n"
" stg %[addr],%[psw_pgm_addr]\n"
"0: mvc 0(1,%[dst]),0(%[src])\n"
" agr %[dst],%[incr]\n"
" agr %[src],%[incr]\n"
" brctg %[n],0b\n"
"1:\n"
: [addr] "=&d" (addr),
[psw_pgm_addr] "=&Q" (S390_lowcore.program_new_psw.addr),
[dst] "+&a" (dst), [src] "+&a" (src), [n] "+d" (n)
: [incr] "d" (incr)
: "cc", "memory");
S390_lowcore.program_new_psw = old;
}
static __init noinline void ipl_save_parameters(void)
{
void *src, *dst;
src = (void *)(unsigned long) S390_lowcore.ipl_parmblock_ptr;
dst = (void *) IPL_PARMBLOCK_ORIGIN;
memmove_early(dst, src, PAGE_SIZE);
S390_lowcore.ipl_parmblock_ptr = IPL_PARMBLOCK_ORIGIN;
}
static __init noinline void rescue_initrd(void)
{ {
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
unsigned long min_initrd_addr = (unsigned long) _end + (4UL << 20); unsigned long min_initrd_addr = (unsigned long) _end + (4UL << 20);
...@@ -405,7 +448,7 @@ static __init void rescue_initrd(void) ...@@ -405,7 +448,7 @@ static __init void rescue_initrd(void)
return; return;
if (INITRD_START >= min_initrd_addr) if (INITRD_START >= min_initrd_addr)
return; return;
memmove((void *) min_initrd_addr, (void *) INITRD_START, INITRD_SIZE); memmove_early((void *) min_initrd_addr, (void *) INITRD_START, INITRD_SIZE);
INITRD_START = min_initrd_addr; INITRD_START = min_initrd_addr;
#endif #endif
} }
...@@ -467,7 +510,8 @@ void __init startup_init(void) ...@@ -467,7 +510,8 @@ void __init startup_init(void)
ipl_save_parameters(); ipl_save_parameters();
rescue_initrd(); rescue_initrd();
clear_bss_section(); clear_bss_section();
ptff_init(); ipl_verify_parameters();
time_early_init();
init_kernel_storage_key(); init_kernel_storage_key();
lockdep_off(); lockdep_off();
setup_lowcore_early(); setup_lowcore_early();
......
...@@ -42,7 +42,7 @@ __PT_R13 = __PT_GPRS + 104 ...@@ -42,7 +42,7 @@ __PT_R13 = __PT_GPRS + 104
__PT_R14 = __PT_GPRS + 112 __PT_R14 = __PT_GPRS + 112
__PT_R15 = __PT_GPRS + 120 __PT_R15 = __PT_GPRS + 120
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER STACK_SHIFT = PAGE_SHIFT + THREAD_SIZE_ORDER
STACK_SIZE = 1 << STACK_SHIFT STACK_SIZE = 1 << STACK_SHIFT
STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
...@@ -123,8 +123,14 @@ _PIF_WORK = (_PIF_PER_TRAP) ...@@ -123,8 +123,14 @@ _PIF_WORK = (_PIF_PER_TRAP)
.macro LAST_BREAK scratch .macro LAST_BREAK scratch
srag \scratch,%r10,23 srag \scratch,%r10,23
#ifdef CONFIG_HAVE_MARCH_Z990_FEATURES
jz .+10 jz .+10
stg %r10,__TI_last_break(%r12) stg %r10,__TASK_thread+__THREAD_last_break(%r12)
#else
jz .+14
lghi \scratch,__TASK_thread
stg %r10,__THREAD_last_break(\scratch,%r12)
#endif
.endm .endm
.macro REENABLE_IRQS .macro REENABLE_IRQS
...@@ -186,14 +192,13 @@ ENTRY(__switch_to) ...@@ -186,14 +192,13 @@ ENTRY(__switch_to)
stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task
lgr %r1,%r2 lgr %r1,%r2
aghi %r1,__TASK_thread # thread_struct of prev task aghi %r1,__TASK_thread # thread_struct of prev task
lg %r5,__TASK_thread_info(%r3) # get thread_info of next lg %r5,__TASK_stack(%r3) # start of kernel stack of next
stg %r15,__THREAD_ksp(%r1) # store kernel stack of prev stg %r15,__THREAD_ksp(%r1) # store kernel stack of prev
lgr %r1,%r3 lgr %r1,%r3
aghi %r1,__TASK_thread # thread_struct of next task aghi %r1,__TASK_thread # thread_struct of next task
lgr %r15,%r5 lgr %r15,%r5
aghi %r15,STACK_INIT # end of kernel stack of next aghi %r15,STACK_INIT # end of kernel stack of next
stg %r3,__LC_CURRENT # store task struct of next stg %r3,__LC_CURRENT # store task struct of next
stg %r5,__LC_THREAD_INFO # store thread info of next
stg %r15,__LC_KERNEL_STACK # store end of kernel stack stg %r15,__LC_KERNEL_STACK # store end of kernel stack
lg %r15,__THREAD_ksp(%r1) # load kernel stack of next lg %r15,__THREAD_ksp(%r1) # load kernel stack of next
/* c4 is used in guest detection: arch/s390/kernel/perf_cpum_sf.c */ /* c4 is used in guest detection: arch/s390/kernel/perf_cpum_sf.c */
...@@ -274,7 +279,7 @@ ENTRY(system_call) ...@@ -274,7 +279,7 @@ ENTRY(system_call)
.Lsysc_stmg: .Lsysc_stmg:
stmg %r8,%r15,__LC_SAVE_AREA_SYNC stmg %r8,%r15,__LC_SAVE_AREA_SYNC
lg %r10,__LC_LAST_BREAK lg %r10,__LC_LAST_BREAK
lg %r12,__LC_THREAD_INFO lg %r12,__LC_CURRENT
lghi %r14,_PIF_SYSCALL lghi %r14,_PIF_SYSCALL
.Lsysc_per: .Lsysc_per:
lg %r15,__LC_KERNEL_STACK lg %r15,__LC_KERNEL_STACK
...@@ -288,7 +293,13 @@ ENTRY(system_call) ...@@ -288,7 +293,13 @@ ENTRY(system_call)
mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC
stg %r14,__PT_FLAGS(%r11) stg %r14,__PT_FLAGS(%r11)
.Lsysc_do_svc: .Lsysc_do_svc:
lg %r10,__TI_sysc_table(%r12) # address of system call table # load address of system call table
#ifdef CONFIG_HAVE_MARCH_Z990_FEATURES
lg %r10,__TASK_thread+__THREAD_sysc_table(%r12)
#else
lghi %r13,__TASK_thread
lg %r10,__THREAD_sysc_table(%r13,%r12)
#endif
llgh %r8,__PT_INT_CODE+2(%r11) llgh %r8,__PT_INT_CODE+2(%r11)
slag %r8,%r8,2 # shift and test for svc 0 slag %r8,%r8,2 # shift and test for svc 0
jnz .Lsysc_nr_ok jnz .Lsysc_nr_ok
...@@ -389,7 +400,6 @@ ENTRY(system_call) ...@@ -389,7 +400,6 @@ ENTRY(system_call)
TSTMSK __PT_FLAGS(%r11),_PIF_SYSCALL TSTMSK __PT_FLAGS(%r11),_PIF_SYSCALL
jno .Lsysc_return jno .Lsysc_return
lmg %r2,%r7,__PT_R2(%r11) # load svc arguments lmg %r2,%r7,__PT_R2(%r11) # load svc arguments
lg %r10,__TI_sysc_table(%r12) # address of system call table
lghi %r8,0 # svc 0 returns -ENOSYS lghi %r8,0 # svc 0 returns -ENOSYS
llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number
cghi %r1,NR_syscalls cghi %r1,NR_syscalls
...@@ -457,7 +467,7 @@ ENTRY(system_call) ...@@ -457,7 +467,7 @@ ENTRY(system_call)
# #
ENTRY(ret_from_fork) ENTRY(ret_from_fork)
la %r11,STACK_FRAME_OVERHEAD(%r15) la %r11,STACK_FRAME_OVERHEAD(%r15)
lg %r12,__LC_THREAD_INFO lg %r12,__LC_CURRENT
brasl %r14,schedule_tail brasl %r14,schedule_tail
TRACE_IRQS_ON TRACE_IRQS_ON
ssm __LC_SVC_NEW_PSW # reenable interrupts ssm __LC_SVC_NEW_PSW # reenable interrupts
...@@ -478,7 +488,7 @@ ENTRY(pgm_check_handler) ...@@ -478,7 +488,7 @@ ENTRY(pgm_check_handler)
stpt __LC_SYNC_ENTER_TIMER stpt __LC_SYNC_ENTER_TIMER
stmg %r8,%r15,__LC_SAVE_AREA_SYNC stmg %r8,%r15,__LC_SAVE_AREA_SYNC
lg %r10,__LC_LAST_BREAK lg %r10,__LC_LAST_BREAK
lg %r12,__LC_THREAD_INFO lg %r12,__LC_CURRENT
larl %r13,cleanup_critical larl %r13,cleanup_critical
lmg %r8,%r9,__LC_PGM_OLD_PSW lmg %r8,%r9,__LC_PGM_OLD_PSW
tmhh %r8,0x0001 # test problem state bit tmhh %r8,0x0001 # test problem state bit
...@@ -501,7 +511,7 @@ ENTRY(pgm_check_handler) ...@@ -501,7 +511,7 @@ ENTRY(pgm_check_handler)
2: LAST_BREAK %r14 2: LAST_BREAK %r14
UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
lg %r15,__LC_KERNEL_STACK lg %r15,__LC_KERNEL_STACK
lg %r14,__TI_task(%r12) lgr %r14,%r12
aghi %r14,__TASK_thread # pointer to thread_struct aghi %r14,__TASK_thread # pointer to thread_struct
lghi %r13,__LC_PGM_TDB lghi %r13,__LC_PGM_TDB
tm __LC_PGM_ILC+2,0x02 # check for transaction abort tm __LC_PGM_ILC+2,0x02 # check for transaction abort
...@@ -567,7 +577,7 @@ ENTRY(io_int_handler) ...@@ -567,7 +577,7 @@ ENTRY(io_int_handler)
stpt __LC_ASYNC_ENTER_TIMER stpt __LC_ASYNC_ENTER_TIMER
stmg %r8,%r15,__LC_SAVE_AREA_ASYNC stmg %r8,%r15,__LC_SAVE_AREA_ASYNC
lg %r10,__LC_LAST_BREAK lg %r10,__LC_LAST_BREAK
lg %r12,__LC_THREAD_INFO lg %r12,__LC_CURRENT
larl %r13,cleanup_critical larl %r13,cleanup_critical
lmg %r8,%r9,__LC_IO_OLD_PSW 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
...@@ -626,7 +636,7 @@ ENTRY(io_int_handler) ...@@ -626,7 +636,7 @@ ENTRY(io_int_handler)
jo .Lio_work_user # yes -> do resched & signal jo .Lio_work_user # yes -> do resched & signal
#ifdef CONFIG_PREEMPT #ifdef CONFIG_PREEMPT
# check for preemptive scheduling # check for preemptive scheduling
icm %r0,15,__TI_precount(%r12) icm %r0,15,__LC_PREEMPT_COUNT
jnz .Lio_restore # preemption is disabled jnz .Lio_restore # preemption is disabled
TSTMSK __TI_flags(%r12),_TIF_NEED_RESCHED TSTMSK __TI_flags(%r12),_TIF_NEED_RESCHED
jno .Lio_restore jno .Lio_restore
...@@ -741,7 +751,7 @@ ENTRY(ext_int_handler) ...@@ -741,7 +751,7 @@ ENTRY(ext_int_handler)
stpt __LC_ASYNC_ENTER_TIMER stpt __LC_ASYNC_ENTER_TIMER
stmg %r8,%r15,__LC_SAVE_AREA_ASYNC stmg %r8,%r15,__LC_SAVE_AREA_ASYNC
lg %r10,__LC_LAST_BREAK lg %r10,__LC_LAST_BREAK
lg %r12,__LC_THREAD_INFO lg %r12,__LC_CURRENT
larl %r13,cleanup_critical larl %r13,cleanup_critical
lmg %r8,%r9,__LC_EXT_OLD_PSW 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
...@@ -798,13 +808,10 @@ ENTRY(save_fpu_regs) ...@@ -798,13 +808,10 @@ ENTRY(save_fpu_regs)
TSTMSK __LC_CPU_FLAGS,_CIF_FPU TSTMSK __LC_CPU_FLAGS,_CIF_FPU
bor %r14 bor %r14
stfpc __THREAD_FPU_fpc(%r2) stfpc __THREAD_FPU_fpc(%r2)
.Lsave_fpu_regs_fpc_end:
lg %r3,__THREAD_FPU_regs(%r2) lg %r3,__THREAD_FPU_regs(%r2)
TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
jz .Lsave_fpu_regs_fp # no -> store FP regs jz .Lsave_fpu_regs_fp # no -> store FP regs
.Lsave_fpu_regs_vx_low:
VSTM %v0,%v15,0,%r3 # vstm 0,15,0(3) VSTM %v0,%v15,0,%r3 # vstm 0,15,0(3)
.Lsave_fpu_regs_vx_high:
VSTM %v16,%v31,256,%r3 # vstm 16,31,256(3) VSTM %v16,%v31,256,%r3 # vstm 16,31,256(3)
j .Lsave_fpu_regs_done # -> set CIF_FPU flag j .Lsave_fpu_regs_done # -> set CIF_FPU flag
.Lsave_fpu_regs_fp: .Lsave_fpu_regs_fp:
...@@ -851,9 +858,7 @@ load_fpu_regs: ...@@ -851,9 +858,7 @@ load_fpu_regs:
TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
lg %r4,__THREAD_FPU_regs(%r4) # %r4 <- reg save area lg %r4,__THREAD_FPU_regs(%r4) # %r4 <- reg save area
jz .Lload_fpu_regs_fp # -> no VX, load FP regs jz .Lload_fpu_regs_fp # -> no VX, load FP regs
.Lload_fpu_regs_vx:
VLM %v0,%v15,0,%r4 VLM %v0,%v15,0,%r4
.Lload_fpu_regs_vx_high:
VLM %v16,%v31,256,%r4 VLM %v16,%v31,256,%r4
j .Lload_fpu_regs_done j .Lload_fpu_regs_done
.Lload_fpu_regs_fp: .Lload_fpu_regs_fp:
...@@ -889,7 +894,7 @@ ENTRY(mcck_int_handler) ...@@ -889,7 +894,7 @@ ENTRY(mcck_int_handler)
spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
lg %r10,__LC_LAST_BREAK lg %r10,__LC_LAST_BREAK
lg %r12,__LC_THREAD_INFO lg %r12,__LC_CURRENT
larl %r13,cleanup_critical larl %r13,cleanup_critical
lmg %r8,%r9,__LC_MCK_OLD_PSW lmg %r8,%r9,__LC_MCK_OLD_PSW
TSTMSK __LC_MCCK_CODE,MCCK_CODE_SYSTEM_DAMAGE TSTMSK __LC_MCCK_CODE,MCCK_CODE_SYSTEM_DAMAGE
...@@ -948,7 +953,7 @@ ENTRY(mcck_int_handler) ...@@ -948,7 +953,7 @@ ENTRY(mcck_int_handler)
.Lmcck_panic: .Lmcck_panic:
lg %r15,__LC_PANIC_STACK lg %r15,__LC_PANIC_STACK
aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) la %r11,STACK_FRAME_OVERHEAD(%r15)
j .Lmcck_skip j .Lmcck_skip
# #
...@@ -1085,7 +1090,7 @@ cleanup_critical: ...@@ -1085,7 +1090,7 @@ cleanup_critical:
jhe 0f jhe 0f
# set up saved registers r10 and r12 # set up saved registers r10 and r12
stg %r10,16(%r11) # r10 last break stg %r10,16(%r11) # r10 last break
stg %r12,32(%r11) # r12 thread-info pointer stg %r12,32(%r11) # r12 task struct pointer
0: # check if the user time update has been done 0: # check if the user time update has been done
clg %r9,BASED(.Lcleanup_system_call_insn+24) clg %r9,BASED(.Lcleanup_system_call_insn+24)
jh 0f jh 0f
...@@ -1106,7 +1111,9 @@ cleanup_critical: ...@@ -1106,7 +1111,9 @@ cleanup_critical:
lg %r9,16(%r11) lg %r9,16(%r11)
srag %r9,%r9,23 srag %r9,%r9,23
jz 0f jz 0f
mvc __TI_last_break(8,%r12),16(%r11) lgr %r9,%r12
aghi %r9,__TASK_thread
mvc __THREAD_last_break(8,%r9),16(%r11)
0: # set up saved register r11 0: # set up saved register r11
lg %r15,__LC_KERNEL_STACK lg %r15,__LC_KERNEL_STACK
la %r9,STACK_FRAME_OVERHEAD(%r15) la %r9,STACK_FRAME_OVERHEAD(%r15)
......
...@@ -315,7 +315,7 @@ ENTRY(startup_kdump) ...@@ -315,7 +315,7 @@ ENTRY(startup_kdump)
jg startup_continue jg startup_continue
.Lstack: .Lstack:
.long 0x8000 + (1<<(PAGE_SHIFT+THREAD_ORDER)) .long 0x8000 + (1<<(PAGE_SHIFT+THREAD_SIZE_ORDER))
.align 8 .align 8
6: .long 0x7fffffff,0xffffffff 6: .long 0x7fffffff,0xffffffff
......
...@@ -32,11 +32,10 @@ ENTRY(startup_continue) ...@@ -32,11 +32,10 @@ ENTRY(startup_continue)
# #
# Setup stack # Setup stack
# #
larl %r15,init_thread_union larl %r14,init_task
stg %r15,__LC_THREAD_INFO # cache thread info in lowcore
lg %r14,__TI_task(%r15) # cache current in lowcore
stg %r14,__LC_CURRENT stg %r14,__LC_CURRENT
aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE larl %r15,init_thread_union
aghi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER) # init_task_union + THREAD_SIZE
stg %r15,__LC_KERNEL_STACK # set end of kernel stack stg %r15,__LC_KERNEL_STACK # set end of kernel stack
aghi %r15,-160 aghi %r15,-160
# #
......
...@@ -1991,10 +1991,9 @@ void __init ipl_update_parameters(void) ...@@ -1991,10 +1991,9 @@ void __init ipl_update_parameters(void)
diag308_set_works = 1; diag308_set_works = 1;
} }
void __init ipl_save_parameters(void) void __init ipl_verify_parameters(void)
{ {
struct cio_iplinfo iplinfo; struct cio_iplinfo iplinfo;
void *src, *dst;
if (cio_get_iplinfo(&iplinfo)) if (cio_get_iplinfo(&iplinfo))
return; return;
...@@ -2005,10 +2004,6 @@ void __init ipl_save_parameters(void) ...@@ -2005,10 +2004,6 @@ void __init ipl_save_parameters(void)
if (!iplinfo.is_qdio) if (!iplinfo.is_qdio)
return; return;
ipl_flags |= IPL_PARMBLOCK_VALID; ipl_flags |= IPL_PARMBLOCK_VALID;
src = (void *)(unsigned long)S390_lowcore.ipl_parmblock_ptr;
dst = (void *)IPL_PARMBLOCK_ORIGIN;
memmove(dst, src, PAGE_SIZE);
S390_lowcore.ipl_parmblock_ptr = IPL_PARMBLOCK_ORIGIN;
} }
static LIST_HEAD(rcall); static LIST_HEAD(rcall);
......
...@@ -168,7 +168,7 @@ void do_softirq_own_stack(void) ...@@ -168,7 +168,7 @@ void do_softirq_own_stack(void)
old = current_stack_pointer(); old = current_stack_pointer();
/* Check against async. stack address range. */ /* Check against async. stack address range. */
new = S390_lowcore.async_stack; new = S390_lowcore.async_stack;
if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) { if (((new - old) >> (PAGE_SHIFT + THREAD_SIZE_ORDER)) != 0) {
/* Need to switch to the async. stack. */ /* Need to switch to the async. stack. */
new -= STACK_FRAME_OVERHEAD; new -= STACK_FRAME_OVERHEAD;
((struct stack_frame *) new)->back_chain = old; ((struct stack_frame *) new)->back_chain = old;
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
*/ */
#include <linux/module.h> #include <linux/init.h>
#include <linux/export.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/facility.h> #include <asm/facility.h>
...@@ -183,4 +184,4 @@ static int __init lgr_init(void) ...@@ -183,4 +184,4 @@ static int __init lgr_init(void)
lgr_timer_set(); lgr_timer_set();
return 0; return 0;
} }
module_init(lgr_init); device_initcall(lgr_init);
...@@ -995,39 +995,36 @@ static int perf_push_sample(struct perf_event *event, struct sf_raw_sample *sfr) ...@@ -995,39 +995,36 @@ static int perf_push_sample(struct perf_event *event, struct sf_raw_sample *sfr)
regs.int_parm = CPU_MF_INT_SF_PRA; regs.int_parm = CPU_MF_INT_SF_PRA;
sde_regs = (struct perf_sf_sde_regs *) &regs.int_parm_long; sde_regs = (struct perf_sf_sde_regs *) &regs.int_parm_long;
regs.psw.addr = sfr->basic.ia; psw_bits(regs.psw).ia = sfr->basic.ia;
if (sfr->basic.T) psw_bits(regs.psw).t = sfr->basic.T;
regs.psw.mask |= PSW_MASK_DAT; psw_bits(regs.psw).w = sfr->basic.W;
if (sfr->basic.W) psw_bits(regs.psw).p = sfr->basic.P;
regs.psw.mask |= PSW_MASK_WAIT; psw_bits(regs.psw).as = sfr->basic.AS;
if (sfr->basic.P)
regs.psw.mask |= PSW_MASK_PSTATE;
switch (sfr->basic.AS) {
case 0x0:
regs.psw.mask |= PSW_ASC_PRIMARY;
break;
case 0x1:
regs.psw.mask |= PSW_ASC_ACCREG;
break;
case 0x2:
regs.psw.mask |= PSW_ASC_SECONDARY;
break;
case 0x3:
regs.psw.mask |= PSW_ASC_HOME;
break;
}
/* /*
* A non-zero guest program parameter indicates a guest * Use the hardware provided configuration level to decide if the
* sample. * sample belongs to a guest or host. If that is not available,
* Note that some early samples or samples from guests without * fall back to the following heuristics:
* A non-zero guest program parameter always indicates a guest
* sample. Some early samples or samples from guests without
* lpp usage would be misaccounted to the host. We use the asn * lpp usage would be misaccounted to the host. We use the asn
* value as a heuristic to detect most of these guest samples. * value as an addon heuristic to detect most of these guest samples.
* If the value differs from the host hpp value, we assume * If the value differs from the host hpp value, we assume to be a
* it to be a KVM guest. * KVM guest.
*/ */
if (sfr->basic.gpp || sfr->basic.prim_asn != (u16) sfr->basic.hpp) switch (sfr->basic.CL) {
case 1: /* logical partition */
sde_regs->in_guest = 0;
break;
case 2: /* virtual machine */
sde_regs->in_guest = 1; sde_regs->in_guest = 1;
break;
default: /* old machine, use heuristics */
if (sfr->basic.gpp ||
sfr->basic.prim_asn != (u16)sfr->basic.hpp)
sde_regs->in_guest = 1;
break;
}
overflow = 0; overflow = 0;
if (perf_exclude_event(event, &regs, sde_regs)) if (perf_exclude_event(event, &regs, sde_regs))
......
...@@ -103,7 +103,6 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) ...@@ -103,7 +103,6 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
int copy_thread(unsigned long clone_flags, unsigned long new_stackp, int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
unsigned long arg, struct task_struct *p) unsigned long arg, struct task_struct *p)
{ {
struct thread_info *ti;
struct fake_frame struct fake_frame
{ {
struct stack_frame sf; struct stack_frame sf;
...@@ -121,9 +120,8 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, ...@@ -121,9 +120,8 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
memset(&p->thread.per_event, 0, sizeof(p->thread.per_event)); memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
clear_tsk_thread_flag(p, TIF_SINGLE_STEP); clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
/* Initialize per thread user and system timer values */ /* Initialize per thread user and system timer values */
ti = task_thread_info(p); p->thread.user_timer = 0;
ti->user_timer = 0; p->thread.system_timer = 0;
ti->system_timer = 0;
frame->sf.back_chain = 0; frame->sf.back_chain = 0;
/* new return point is ret_from_fork */ /* new return point is ret_from_fork */
......
...@@ -461,7 +461,7 @@ long arch_ptrace(struct task_struct *child, long request, ...@@ -461,7 +461,7 @@ long arch_ptrace(struct task_struct *child, long request,
} }
return 0; return 0;
case PTRACE_GET_LAST_BREAK: case PTRACE_GET_LAST_BREAK:
put_user(task_thread_info(child)->last_break, put_user(child->thread.last_break,
(unsigned long __user *) data); (unsigned long __user *) data);
return 0; return 0;
case PTRACE_ENABLE_TE: case PTRACE_ENABLE_TE:
...@@ -811,7 +811,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, ...@@ -811,7 +811,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
} }
return 0; return 0;
case PTRACE_GET_LAST_BREAK: case PTRACE_GET_LAST_BREAK:
put_user(task_thread_info(child)->last_break, put_user(child->thread.last_break,
(unsigned int __user *) data); (unsigned int __user *) data);
return 0; return 0;
} }
...@@ -997,10 +997,10 @@ static int s390_last_break_get(struct task_struct *target, ...@@ -997,10 +997,10 @@ static int s390_last_break_get(struct task_struct *target,
if (count > 0) { if (count > 0) {
if (kbuf) { if (kbuf) {
unsigned long *k = kbuf; unsigned long *k = kbuf;
*k = task_thread_info(target)->last_break; *k = target->thread.last_break;
} else { } else {
unsigned long __user *u = ubuf; unsigned long __user *u = ubuf;
if (__put_user(task_thread_info(target)->last_break, u)) if (__put_user(target->thread.last_break, u))
return -EFAULT; return -EFAULT;
} }
} }
...@@ -1113,7 +1113,7 @@ static int s390_system_call_get(struct task_struct *target, ...@@ -1113,7 +1113,7 @@ static int s390_system_call_get(struct task_struct *target,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf) void *kbuf, void __user *ubuf)
{ {
unsigned int *data = &task_thread_info(target)->system_call; unsigned int *data = &target->thread.system_call;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
data, 0, sizeof(unsigned int)); data, 0, sizeof(unsigned int));
} }
...@@ -1123,7 +1123,7 @@ static int s390_system_call_set(struct task_struct *target, ...@@ -1123,7 +1123,7 @@ static int s390_system_call_set(struct task_struct *target,
unsigned int pos, unsigned int count, unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf) const void *kbuf, const void __user *ubuf)
{ {
unsigned int *data = &task_thread_info(target)->system_call; unsigned int *data = &target->thread.system_call;
return user_regset_copyin(&pos, &count, &kbuf, &ubuf, return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
data, 0, sizeof(unsigned int)); data, 0, sizeof(unsigned int));
} }
...@@ -1327,7 +1327,7 @@ static int s390_compat_last_break_get(struct task_struct *target, ...@@ -1327,7 +1327,7 @@ static int s390_compat_last_break_get(struct task_struct *target,
compat_ulong_t last_break; compat_ulong_t last_break;
if (count > 0) { if (count > 0) {
last_break = task_thread_info(target)->last_break; last_break = target->thread.last_break;
if (kbuf) { if (kbuf) {
unsigned long *k = kbuf; unsigned long *k = kbuf;
*k = last_break; *k = last_break;
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/root_dev.h> #include <linux/root_dev.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/dma-contiguous.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/pfn.h> #include <linux/pfn.h>
...@@ -303,7 +304,7 @@ static void __init setup_lowcore(void) ...@@ -303,7 +304,7 @@ static void __init setup_lowcore(void)
* Setup lowcore for boot cpu * Setup lowcore for boot cpu
*/ */
BUILD_BUG_ON(sizeof(struct lowcore) != LC_PAGES * 4096); BUILD_BUG_ON(sizeof(struct lowcore) != LC_PAGES * 4096);
lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0); lc = memblock_virt_alloc_low(sizeof(*lc), sizeof(*lc));
lc->restart_psw.mask = PSW_KERNEL_BITS; lc->restart_psw.mask = PSW_KERNEL_BITS;
lc->restart_psw.addr = (unsigned long) restart_int_handler; lc->restart_psw.addr = (unsigned long) restart_int_handler;
lc->external_new_psw.mask = PSW_KERNEL_BITS | lc->external_new_psw.mask = PSW_KERNEL_BITS |
...@@ -324,15 +325,15 @@ static void __init setup_lowcore(void) ...@@ -324,15 +325,15 @@ static void __init setup_lowcore(void)
lc->kernel_stack = ((unsigned long) &init_thread_union) lc->kernel_stack = ((unsigned long) &init_thread_union)
+ THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
lc->async_stack = (unsigned long) lc->async_stack = (unsigned long)
__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) memblock_virt_alloc(ASYNC_SIZE, ASYNC_SIZE)
+ ASYNC_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); + ASYNC_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
lc->panic_stack = (unsigned long) lc->panic_stack = (unsigned long)
__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE)
+ PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); + PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
lc->current_task = (unsigned long) init_thread_union.thread_info.task; lc->current_task = (unsigned long)&init_task;
lc->thread_info = (unsigned long) &init_thread_union;
lc->lpp = LPP_MAGIC; lc->lpp = LPP_MAGIC;
lc->machine_flags = S390_lowcore.machine_flags; lc->machine_flags = S390_lowcore.machine_flags;
lc->preempt_count = S390_lowcore.preempt_count;
lc->stfl_fac_list = S390_lowcore.stfl_fac_list; lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
MAX_FACILITY_BIT/8); MAX_FACILITY_BIT/8);
...@@ -349,7 +350,7 @@ static void __init setup_lowcore(void) ...@@ -349,7 +350,7 @@ static void __init setup_lowcore(void)
lc->last_update_timer = S390_lowcore.last_update_timer; lc->last_update_timer = S390_lowcore.last_update_timer;
lc->last_update_clock = S390_lowcore.last_update_clock; lc->last_update_clock = S390_lowcore.last_update_clock;
restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0); restart_stack = memblock_virt_alloc(ASYNC_SIZE, ASYNC_SIZE);
restart_stack += ASYNC_SIZE; restart_stack += ASYNC_SIZE;
/* /*
...@@ -412,7 +413,7 @@ static void __init setup_resources(void) ...@@ -412,7 +413,7 @@ static void __init setup_resources(void)
bss_resource.end = (unsigned long) &__bss_stop - 1; bss_resource.end = (unsigned long) &__bss_stop - 1;
for_each_memblock(memory, reg) { for_each_memblock(memory, reg) {
res = alloc_bootmem_low(sizeof(*res)); res = memblock_virt_alloc(sizeof(*res), 8);
res->flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM; res->flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM;
res->name = "System RAM"; res->name = "System RAM";
...@@ -426,7 +427,7 @@ static void __init setup_resources(void) ...@@ -426,7 +427,7 @@ static void __init setup_resources(void)
std_res->start > res->end) std_res->start > res->end)
continue; continue;
if (std_res->end > res->end) { if (std_res->end > res->end) {
sub_res = alloc_bootmem_low(sizeof(*sub_res)); sub_res = memblock_virt_alloc(sizeof(*sub_res), 8);
*sub_res = *std_res; *sub_res = *std_res;
sub_res->end = res->end; sub_res->end = res->end;
std_res->start = res->end + 1; std_res->start = res->end + 1;
...@@ -445,7 +446,7 @@ static void __init setup_resources(void) ...@@ -445,7 +446,7 @@ static void __init setup_resources(void)
* part of the System RAM resource. * part of the System RAM resource.
*/ */
if (crashk_res.end) { if (crashk_res.end) {
memblock_add(crashk_res.start, resource_size(&crashk_res)); memblock_add_node(crashk_res.start, resource_size(&crashk_res), 0);
memblock_reserve(crashk_res.start, resource_size(&crashk_res)); memblock_reserve(crashk_res.start, resource_size(&crashk_res));
insert_resource(&iomem_resource, &crashk_res); insert_resource(&iomem_resource, &crashk_res);
} }
...@@ -903,6 +904,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -903,6 +904,7 @@ void __init setup_arch(char **cmdline_p)
setup_memory_end(); setup_memory_end();
setup_memory(); setup_memory();
dma_contiguous_reserve(memory_end);
check_initrd(); check_initrd();
reserve_crashkernel(); reserve_crashkernel();
...@@ -921,6 +923,8 @@ void __init setup_arch(char **cmdline_p) ...@@ -921,6 +923,8 @@ void __init setup_arch(char **cmdline_p)
cpu_detect_mhz_feature(); cpu_detect_mhz_feature();
cpu_init(); cpu_init();
numa_setup(); numa_setup();
smp_detect_cpus();
topology_init_early();
/* /*
* Create kernel page tables and switch to virtual addressing. * Create kernel page tables and switch to virtual addressing.
......
...@@ -359,7 +359,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, ...@@ -359,7 +359,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,
/* set extra registers only for synchronous signals */ /* set extra registers only for synchronous signals */
regs->gprs[4] = regs->int_code & 127; regs->gprs[4] = regs->int_code & 127;
regs->gprs[5] = regs->int_parm_long; regs->gprs[5] = regs->int_parm_long;
regs->gprs[6] = task_thread_info(current)->last_break; regs->gprs[6] = current->thread.last_break;
} }
return 0; return 0;
} }
...@@ -430,7 +430,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, ...@@ -430,7 +430,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
regs->gprs[2] = ksig->sig; regs->gprs[2] = ksig->sig;
regs->gprs[3] = (unsigned long) &frame->info; regs->gprs[3] = (unsigned long) &frame->info;
regs->gprs[4] = (unsigned long) &frame->uc; regs->gprs[4] = (unsigned long) &frame->uc;
regs->gprs[5] = task_thread_info(current)->last_break; regs->gprs[5] = current->thread.last_break;
return 0; return 0;
} }
...@@ -467,13 +467,13 @@ void do_signal(struct pt_regs *regs) ...@@ -467,13 +467,13 @@ void do_signal(struct pt_regs *regs)
* the debugger may change all our registers, including the system * the debugger may change all our registers, including the system
* call information. * call information.
*/ */
current_thread_info()->system_call = current->thread.system_call =
test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0; test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0;
if (get_signal(&ksig)) { if (get_signal(&ksig)) {
/* Whee! Actually deliver the signal. */ /* Whee! Actually deliver the signal. */
if (current_thread_info()->system_call) { if (current->thread.system_call) {
regs->int_code = current_thread_info()->system_call; regs->int_code = current->thread.system_call;
/* Check for system call restarting. */ /* Check for system call restarting. */
switch (regs->gprs[2]) { switch (regs->gprs[2]) {
case -ERESTART_RESTARTBLOCK: case -ERESTART_RESTARTBLOCK:
...@@ -506,8 +506,8 @@ void do_signal(struct pt_regs *regs) ...@@ -506,8 +506,8 @@ void do_signal(struct pt_regs *regs)
/* No handlers present - check for system call restart */ /* No handlers present - check for system call restart */
clear_pt_regs_flag(regs, PIF_SYSCALL); clear_pt_regs_flag(regs, PIF_SYSCALL);
if (current_thread_info()->system_call) { if (current->thread.system_call) {
regs->int_code = current_thread_info()->system_call; regs->int_code = current->thread.system_call;
switch (regs->gprs[2]) { switch (regs->gprs[2]) {
case -ERESTART_RESTARTBLOCK: case -ERESTART_RESTARTBLOCK:
/* Restart with sys_restart_syscall */ /* Restart with sys_restart_syscall */
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/bootmem.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -259,16 +260,14 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) ...@@ -259,16 +260,14 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk) static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
{ {
struct lowcore *lc = pcpu->lowcore; struct lowcore *lc = pcpu->lowcore;
struct thread_info *ti = task_thread_info(tsk);
lc->kernel_stack = (unsigned long) task_stack_page(tsk) lc->kernel_stack = (unsigned long) task_stack_page(tsk)
+ THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
lc->thread_info = (unsigned long) task_thread_info(tsk);
lc->current_task = (unsigned long) tsk; lc->current_task = (unsigned long) tsk;
lc->lpp = LPP_MAGIC; lc->lpp = LPP_MAGIC;
lc->current_pid = tsk->pid; lc->current_pid = tsk->pid;
lc->user_timer = ti->user_timer; lc->user_timer = tsk->thread.user_timer;
lc->system_timer = ti->system_timer; lc->system_timer = tsk->thread.system_timer;
lc->steal_timer = 0; lc->steal_timer = 0;
} }
...@@ -662,14 +661,12 @@ int smp_cpu_get_polarization(int cpu) ...@@ -662,14 +661,12 @@ int smp_cpu_get_polarization(int cpu)
return pcpu_devices[cpu].polarization; return pcpu_devices[cpu].polarization;
} }
static struct sclp_core_info *smp_get_core_info(void) static void __ref smp_get_core_info(struct sclp_core_info *info, int early)
{ {
static int use_sigp_detection; static int use_sigp_detection;
struct sclp_core_info *info;
int address; int address;
info = kzalloc(sizeof(*info), GFP_KERNEL); if (use_sigp_detection || sclp_get_core_info(info, early)) {
if (info && (use_sigp_detection || sclp_get_core_info(info))) {
use_sigp_detection = 1; use_sigp_detection = 1;
for (address = 0; for (address = 0;
address < (SCLP_MAX_CORES << smp_cpu_mt_shift); address < (SCLP_MAX_CORES << smp_cpu_mt_shift);
...@@ -683,7 +680,6 @@ static struct sclp_core_info *smp_get_core_info(void) ...@@ -683,7 +680,6 @@ static struct sclp_core_info *smp_get_core_info(void)
} }
info->combined = info->configured; info->combined = info->configured;
} }
return info;
} }
static int smp_add_present_cpu(int cpu); static int smp_add_present_cpu(int cpu);
...@@ -724,17 +720,15 @@ static int __smp_rescan_cpus(struct sclp_core_info *info, int sysfs_add) ...@@ -724,17 +720,15 @@ static int __smp_rescan_cpus(struct sclp_core_info *info, int sysfs_add)
return nr; return nr;
} }
static void __init smp_detect_cpus(void) void __init smp_detect_cpus(void)
{ {
unsigned int cpu, mtid, c_cpus, s_cpus; unsigned int cpu, mtid, c_cpus, s_cpus;
struct sclp_core_info *info; struct sclp_core_info *info;
u16 address; u16 address;
/* Get CPU information */ /* Get CPU information */
info = smp_get_core_info(); info = memblock_virt_alloc(sizeof(*info), 8);
if (!info) smp_get_core_info(info, 1);
panic("smp_detect_cpus failed to allocate memory\n");
/* Find boot CPU type */ /* Find boot CPU type */
if (sclp.has_core_type) { if (sclp.has_core_type) {
address = stap(); address = stap();
...@@ -770,7 +764,7 @@ static void __init smp_detect_cpus(void) ...@@ -770,7 +764,7 @@ static void __init smp_detect_cpus(void)
get_online_cpus(); get_online_cpus();
__smp_rescan_cpus(info, 0); __smp_rescan_cpus(info, 0);
put_online_cpus(); put_online_cpus();
kfree(info); memblock_free_early((unsigned long)info, sizeof(*info));
} }
/* /*
...@@ -807,7 +801,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) ...@@ -807,7 +801,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
pcpu = pcpu_devices + cpu; pcpu = pcpu_devices + cpu;
if (pcpu->state != CPU_STATE_CONFIGURED) if (pcpu->state != CPU_STATE_CONFIGURED)
return -EIO; return -EIO;
base = cpu - (cpu % (smp_cpu_mtid + 1)); base = smp_get_base_cpu(cpu);
for (i = 0; i <= smp_cpu_mtid; i++) { for (i = 0; i <= smp_cpu_mtid; i++) {
if (base + i < nr_cpu_ids) if (base + i < nr_cpu_ids)
if (cpu_online(base + i)) if (cpu_online(base + i))
...@@ -907,7 +901,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) ...@@ -907,7 +901,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
/* request the 0x1202 external call external interrupt */ /* request the 0x1202 external call external interrupt */
if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt)) if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt))
panic("Couldn't request external interrupt 0x1202"); panic("Couldn't request external interrupt 0x1202");
smp_detect_cpus();
} }
void __init smp_prepare_boot_cpu(void) void __init smp_prepare_boot_cpu(void)
...@@ -973,7 +966,7 @@ static ssize_t cpu_configure_store(struct device *dev, ...@@ -973,7 +966,7 @@ static ssize_t cpu_configure_store(struct device *dev,
rc = -EBUSY; rc = -EBUSY;
/* disallow configuration changes of online cpus and cpu 0 */ /* disallow configuration changes of online cpus and cpu 0 */
cpu = dev->id; cpu = dev->id;
cpu -= cpu % (smp_cpu_mtid + 1); cpu = smp_get_base_cpu(cpu);
if (cpu == 0) if (cpu == 0)
goto out; goto out;
for (i = 0; i <= smp_cpu_mtid; i++) for (i = 0; i <= smp_cpu_mtid; i++)
...@@ -1106,9 +1099,10 @@ int __ref smp_rescan_cpus(void) ...@@ -1106,9 +1099,10 @@ int __ref smp_rescan_cpus(void)
struct sclp_core_info *info; struct sclp_core_info *info;
int nr; int nr;
info = smp_get_core_info(); info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
smp_get_core_info(info, 0);
get_online_cpus(); get_online_cpus();
mutex_lock(&smp_cpu_state_mutex); mutex_lock(&smp_cpu_state_mutex);
nr = __smp_rescan_cpus(info, 1); nr = __smp_rescan_cpus(info, 1);
......
...@@ -194,7 +194,7 @@ pgm_check_entry: ...@@ -194,7 +194,7 @@ pgm_check_entry:
/* Suspend CPU not available -> panic */ /* Suspend CPU not available -> panic */
larl %r15,init_thread_union larl %r15,init_thread_union
ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) ahi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER)
larl %r2,.Lpanic_string larl %r2,.Lpanic_string
larl %r3,_sclp_print_early larl %r3,_sclp_print_early
lghi %r1,0 lghi %r1,0
......
...@@ -56,6 +56,20 @@ int stsi(void *sysinfo, int fc, int sel1, int sel2) ...@@ -56,6 +56,20 @@ int stsi(void *sysinfo, int fc, int sel1, int sel2)
} }
EXPORT_SYMBOL(stsi); EXPORT_SYMBOL(stsi);
static bool convert_ext_name(unsigned char encoding, char *name, size_t len)
{
switch (encoding) {
case 1: /* EBCDIC */
EBCASC(name, len);
break;
case 2: /* UTF-8 */
break;
default:
return false;
}
return true;
}
static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info)
{ {
int i; int i;
...@@ -207,24 +221,19 @@ static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info) ...@@ -207,24 +221,19 @@ static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info)
seq_printf(m, "LPAR CPUs S-MTID: %d\n", info->mt_stid); seq_printf(m, "LPAR CPUs S-MTID: %d\n", info->mt_stid);
seq_printf(m, "LPAR CPUs PS-MTID: %d\n", info->mt_psmtid); seq_printf(m, "LPAR CPUs PS-MTID: %d\n", info->mt_psmtid);
} }
if (convert_ext_name(info->vsne, info->ext_name, sizeof(info->ext_name))) {
seq_printf(m, "LPAR Extended Name: %-.256s\n", info->ext_name);
seq_printf(m, "LPAR UUID: %pUb\n", &info->uuid);
}
} }
static void print_ext_name(struct seq_file *m, int lvl, static void print_ext_name(struct seq_file *m, int lvl,
struct sysinfo_3_2_2 *info) struct sysinfo_3_2_2 *info)
{ {
if (info->vm[lvl].ext_name_encoding == 0) size_t len = sizeof(info->ext_names[lvl]);
return;
if (info->ext_names[lvl][0] == 0) if (!convert_ext_name(info->vm[lvl].evmne, info->ext_names[lvl], len))
return;
switch (info->vm[lvl].ext_name_encoding) {
case 1: /* EBCDIC */
EBCASC(info->ext_names[lvl], sizeof(info->ext_names[lvl]));
break;
case 2: /* UTF-8 */
break;
default:
return; return;
}
seq_printf(m, "VM%02d Extended Name: %-.256s\n", lvl, seq_printf(m, "VM%02d Extended Name: %-.256s\n", lvl,
info->ext_names[lvl]); info->ext_names[lvl]);
} }
......
...@@ -59,19 +59,27 @@ ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier); ...@@ -59,19 +59,27 @@ ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier);
EXPORT_SYMBOL(s390_epoch_delta_notifier); EXPORT_SYMBOL(s390_epoch_delta_notifier);
unsigned char ptff_function_mask[16]; unsigned char ptff_function_mask[16];
unsigned long lpar_offset;
unsigned long initial_leap_seconds; static unsigned long long lpar_offset;
static unsigned long long initial_leap_seconds;
static unsigned long long tod_steering_end;
static long long tod_steering_delta;
/* /*
* Get time offsets with PTFF * Get time offsets with PTFF
*/ */
void __init ptff_init(void) void __init time_early_init(void)
{ {
struct ptff_qto qto; struct ptff_qto qto;
struct ptff_qui qui; struct ptff_qui qui;
/* Initialize TOD steering parameters */
tod_steering_end = sched_clock_base_cc;
vdso_data->ts_end = tod_steering_end;
if (!test_facility(28)) if (!test_facility(28))
return; return;
ptff(&ptff_function_mask, sizeof(ptff_function_mask), PTFF_QAF); ptff(&ptff_function_mask, sizeof(ptff_function_mask), PTFF_QAF);
/* get LPAR offset */ /* get LPAR offset */
...@@ -80,7 +88,7 @@ void __init ptff_init(void) ...@@ -80,7 +88,7 @@ void __init ptff_init(void)
/* get initial leap seconds */ /* get initial leap seconds */
if (ptff_query(PTFF_QUI) && ptff(&qui, sizeof(qui), PTFF_QUI) == 0) if (ptff_query(PTFF_QUI) && ptff(&qui, sizeof(qui), PTFF_QUI) == 0)
initial_leap_seconds = (unsigned long) initial_leap_seconds = (unsigned long long)
((long) qui.old_leap * 4096000000L); ((long) qui.old_leap * 4096000000L);
} }
...@@ -123,18 +131,6 @@ void clock_comparator_work(void) ...@@ -123,18 +131,6 @@ void clock_comparator_work(void)
cd->event_handler(cd); cd->event_handler(cd);
} }
/*
* Fixup the clock comparator.
*/
static void fixup_clock_comparator(unsigned long long delta)
{
/* If nobody is waiting there's nothing to fix. */
if (S390_lowcore.clock_comparator == -1ULL)
return;
S390_lowcore.clock_comparator += delta;
set_clock_comparator(S390_lowcore.clock_comparator);
}
static int s390_next_event(unsigned long delta, static int s390_next_event(unsigned long delta,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
...@@ -215,7 +211,21 @@ void read_boot_clock64(struct timespec64 *ts) ...@@ -215,7 +211,21 @@ void read_boot_clock64(struct timespec64 *ts)
static cycle_t read_tod_clock(struct clocksource *cs) static cycle_t read_tod_clock(struct clocksource *cs)
{ {
return get_tod_clock(); unsigned long long now, adj;
preempt_disable(); /* protect from changes to steering parameters */
now = get_tod_clock();
adj = tod_steering_end - now;
if (unlikely((s64) adj >= 0))
/*
* manually steer by 1 cycle every 2^16 cycles. This
* corresponds to shifting the tod delta by 15. 1s is
* therefore steered in ~9h. The adjust will decrease
* over time, until it finally reaches 0.
*/
now += (tod_steering_delta < 0) ? (adj >> 15) : -(adj >> 15);
preempt_enable();
return now;
} }
static struct clocksource clocksource_tod = { static struct clocksource clocksource_tod = {
...@@ -384,6 +394,55 @@ static inline int check_sync_clock(void) ...@@ -384,6 +394,55 @@ static inline int check_sync_clock(void)
return rc; return rc;
} }
/*
* Apply clock delta to the global data structures.
* This is called once on the CPU that performed the clock sync.
*/
static void clock_sync_global(unsigned long long delta)
{
unsigned long now, adj;
struct ptff_qto qto;
/* Fixup the monotonic sched clock. */
sched_clock_base_cc += delta;
/* Adjust TOD steering parameters. */
vdso_data->tb_update_count++;
now = get_tod_clock();
adj = tod_steering_end - now;
if (unlikely((s64) adj >= 0))
/* Calculate how much of the old adjustment is left. */
tod_steering_delta = (tod_steering_delta < 0) ?
-(adj >> 15) : (adj >> 15);
tod_steering_delta += delta;
if ((abs(tod_steering_delta) >> 48) != 0)
panic("TOD clock sync offset %lli is too large to drift\n",
tod_steering_delta);
tod_steering_end = now + (abs(tod_steering_delta) << 15);
vdso_data->ts_dir = (tod_steering_delta < 0) ? 0 : 1;
vdso_data->ts_end = tod_steering_end;
vdso_data->tb_update_count++;
/* Update LPAR offset. */
if (ptff_query(PTFF_QTO) && ptff(&qto, sizeof(qto), PTFF_QTO) == 0)
lpar_offset = qto.tod_epoch_difference;
/* Call the TOD clock change notifier. */
atomic_notifier_call_chain(&s390_epoch_delta_notifier, 0, &delta);
}
/*
* Apply clock delta to the per-CPU data structures of this CPU.
* This is called for each online CPU after the call to clock_sync_global.
*/
static void clock_sync_local(unsigned long long delta)
{
/* Add the delta to the clock comparator. */
if (S390_lowcore.clock_comparator != -1ULL) {
S390_lowcore.clock_comparator += delta;
set_clock_comparator(S390_lowcore.clock_comparator);
}
/* Adjust the last_update_clock time-stamp. */
S390_lowcore.last_update_clock += delta;
}
/* Single threaded workqueue used for stp sync events */ /* Single threaded workqueue used for stp sync events */
static struct workqueue_struct *time_sync_wq; static struct workqueue_struct *time_sync_wq;
...@@ -397,31 +456,9 @@ static void __init time_init_wq(void) ...@@ -397,31 +456,9 @@ static void __init time_init_wq(void)
struct clock_sync_data { struct clock_sync_data {
atomic_t cpus; atomic_t cpus;
int in_sync; int in_sync;
unsigned long long fixup_cc; unsigned long long clock_delta;
}; };
static void clock_sync_cpu(struct clock_sync_data *sync)
{
atomic_dec(&sync->cpus);
enable_sync_clock();
while (sync->in_sync == 0) {
__udelay(1);
/*
* A different cpu changes *in_sync. Therefore use
* barrier() to force memory access.
*/
barrier();
}
if (sync->in_sync != 1)
/* Didn't work. Clear per-cpu in sync bit again. */
disable_sync_clock(NULL);
/*
* This round of TOD syncing is done. Set the clock comparator
* to the next tick and let the processor continue.
*/
fixup_clock_comparator(sync->fixup_cc);
}
/* /*
* Server Time Protocol (STP) code. * Server Time Protocol (STP) code.
*/ */
...@@ -523,54 +560,46 @@ void stp_queue_work(void) ...@@ -523,54 +560,46 @@ void stp_queue_work(void)
static int stp_sync_clock(void *data) static int stp_sync_clock(void *data)
{ {
static int first; struct clock_sync_data *sync = data;
unsigned long long clock_delta; unsigned long long clock_delta;
struct clock_sync_data *stp_sync; static int first;
struct ptff_qto qto;
int rc; int rc;
stp_sync = data;
if (xchg(&first, 1) == 1) {
/* Slave */
clock_sync_cpu(stp_sync);
return 0;
}
/* Wait until all other cpus entered the sync function. */
while (atomic_read(&stp_sync->cpus) != 0)
cpu_relax();
enable_sync_clock(); enable_sync_clock();
if (xchg(&first, 1) == 0) {
rc = 0; /* Wait until all other cpus entered the sync function. */
if (stp_info.todoff[0] || stp_info.todoff[1] || while (atomic_read(&sync->cpus) != 0)
stp_info.todoff[2] || stp_info.todoff[3] || cpu_relax();
stp_info.tmd != 2) { rc = 0;
rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0, &clock_delta); if (stp_info.todoff[0] || stp_info.todoff[1] ||
if (rc == 0) { stp_info.todoff[2] || stp_info.todoff[3] ||
/* fixup the monotonic sched clock */ stp_info.tmd != 2) {
sched_clock_base_cc += clock_delta; rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0,
if (ptff_query(PTFF_QTO) && &clock_delta);
ptff(&qto, sizeof(qto), PTFF_QTO) == 0) if (rc == 0) {
/* Update LPAR offset */ sync->clock_delta = clock_delta;
lpar_offset = qto.tod_epoch_difference; clock_sync_global(clock_delta);
atomic_notifier_call_chain(&s390_epoch_delta_notifier, rc = chsc_sstpi(stp_page, &stp_info,
0, &clock_delta); sizeof(struct stp_sstpi));
stp_sync->fixup_cc = clock_delta; if (rc == 0 && stp_info.tmd != 2)
fixup_clock_comparator(clock_delta); rc = -EAGAIN;
rc = chsc_sstpi(stp_page, &stp_info, }
sizeof(struct stp_sstpi));
if (rc == 0 && stp_info.tmd != 2)
rc = -EAGAIN;
} }
sync->in_sync = rc ? -EAGAIN : 1;
xchg(&first, 0);
} else {
/* Slave */
atomic_dec(&sync->cpus);
/* Wait for in_sync to be set. */
while (READ_ONCE(sync->in_sync) == 0)
__udelay(1);
} }
if (rc) { if (sync->in_sync != 1)
/* Didn't work. Clear per-cpu in sync bit again. */
disable_sync_clock(NULL); disable_sync_clock(NULL);
stp_sync->in_sync = -EAGAIN; /* Apply clock delta to per-CPU fields of this CPU. */
} else clock_sync_local(sync->clock_delta);
stp_sync->in_sync = 1;
xchg(&first, 0);
return 0; return 0;
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/bootmem.h>
#include <linux/cpuset.h> #include <linux/cpuset.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/export.h> #include <linux/export.h>
...@@ -41,15 +42,17 @@ static bool topology_enabled = true; ...@@ -41,15 +42,17 @@ static bool topology_enabled = true;
static DECLARE_WORK(topology_work, topology_work_fn); static DECLARE_WORK(topology_work, topology_work_fn);
/* /*
* Socket/Book linked lists and per_cpu(cpu_topology) updates are * Socket/Book linked lists and cpu_topology updates are
* protected by "sched_domains_mutex". * protected by "sched_domains_mutex".
*/ */
static struct mask_info socket_info; static struct mask_info socket_info;
static struct mask_info book_info; static struct mask_info book_info;
static struct mask_info drawer_info; static struct mask_info drawer_info;
DEFINE_PER_CPU(struct cpu_topology_s390, cpu_topology); struct cpu_topology_s390 cpu_topology[NR_CPUS];
EXPORT_PER_CPU_SYMBOL_GPL(cpu_topology); EXPORT_SYMBOL_GPL(cpu_topology);
cpumask_t cpus_with_topology;
static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
{ {
...@@ -97,7 +100,7 @@ static void add_cpus_to_mask(struct topology_core *tl_core, ...@@ -97,7 +100,7 @@ static void add_cpus_to_mask(struct topology_core *tl_core,
if (lcpu < 0) if (lcpu < 0)
continue; continue;
for (i = 0; i <= smp_cpu_mtid; i++) { for (i = 0; i <= smp_cpu_mtid; i++) {
topo = &per_cpu(cpu_topology, lcpu + i); topo = &cpu_topology[lcpu + i];
topo->drawer_id = drawer->id; topo->drawer_id = drawer->id;
topo->book_id = book->id; topo->book_id = book->id;
topo->socket_id = socket->id; topo->socket_id = socket->id;
...@@ -106,6 +109,7 @@ static void add_cpus_to_mask(struct topology_core *tl_core, ...@@ -106,6 +109,7 @@ static void add_cpus_to_mask(struct topology_core *tl_core,
cpumask_set_cpu(lcpu + i, &drawer->mask); cpumask_set_cpu(lcpu + i, &drawer->mask);
cpumask_set_cpu(lcpu + i, &book->mask); cpumask_set_cpu(lcpu + i, &book->mask);
cpumask_set_cpu(lcpu + i, &socket->mask); cpumask_set_cpu(lcpu + i, &socket->mask);
cpumask_set_cpu(lcpu + i, &cpus_with_topology);
smp_cpu_set_polarization(lcpu + i, tl_core->pp); smp_cpu_set_polarization(lcpu + i, tl_core->pp);
} }
} }
...@@ -220,7 +224,7 @@ static void update_cpu_masks(void) ...@@ -220,7 +224,7 @@ static void update_cpu_masks(void)
int cpu; int cpu;
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
topo = &per_cpu(cpu_topology, cpu); topo = &cpu_topology[cpu];
topo->thread_mask = cpu_thread_map(cpu); topo->thread_mask = cpu_thread_map(cpu);
topo->core_mask = cpu_group_map(&socket_info, cpu); topo->core_mask = cpu_group_map(&socket_info, cpu);
topo->book_mask = cpu_group_map(&book_info, cpu); topo->book_mask = cpu_group_map(&book_info, cpu);
...@@ -231,6 +235,8 @@ static void update_cpu_masks(void) ...@@ -231,6 +235,8 @@ static void update_cpu_masks(void)
topo->socket_id = cpu; topo->socket_id = cpu;
topo->book_id = cpu; topo->book_id = cpu;
topo->drawer_id = cpu; topo->drawer_id = cpu;
if (cpu_present(cpu))
cpumask_set_cpu(cpu, &cpus_with_topology);
} }
} }
numa_update_cpu_topology(); numa_update_cpu_topology();
...@@ -241,12 +247,12 @@ void store_topology(struct sysinfo_15_1_x *info) ...@@ -241,12 +247,12 @@ void store_topology(struct sysinfo_15_1_x *info)
stsi(info, 15, 1, min(topology_max_mnest, 4)); stsi(info, 15, 1, min(topology_max_mnest, 4));
} }
int arch_update_cpu_topology(void) static int __arch_update_cpu_topology(void)
{ {
struct sysinfo_15_1_x *info = tl_info; struct sysinfo_15_1_x *info = tl_info;
struct device *dev; int rc = 0;
int cpu, rc = 0;
cpumask_clear(&cpus_with_topology);
if (MACHINE_HAS_TOPOLOGY) { if (MACHINE_HAS_TOPOLOGY) {
rc = 1; rc = 1;
store_topology(info); store_topology(info);
...@@ -255,6 +261,15 @@ int arch_update_cpu_topology(void) ...@@ -255,6 +261,15 @@ int arch_update_cpu_topology(void)
update_cpu_masks(); update_cpu_masks();
if (!MACHINE_HAS_TOPOLOGY) if (!MACHINE_HAS_TOPOLOGY)
topology_update_polarization_simple(); topology_update_polarization_simple();
return rc;
}
int arch_update_cpu_topology(void)
{
struct device *dev;
int cpu, rc;
rc = __arch_update_cpu_topology();
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
dev = get_cpu_device(cpu); dev = get_cpu_device(cpu);
kobject_uevent(&dev->kobj, KOBJ_CHANGE); kobject_uevent(&dev->kobj, KOBJ_CHANGE);
...@@ -394,23 +409,23 @@ int topology_cpu_init(struct cpu *cpu) ...@@ -394,23 +409,23 @@ int topology_cpu_init(struct cpu *cpu)
static const struct cpumask *cpu_thread_mask(int cpu) static const struct cpumask *cpu_thread_mask(int cpu)
{ {
return &per_cpu(cpu_topology, cpu).thread_mask; return &cpu_topology[cpu].thread_mask;
} }
const struct cpumask *cpu_coregroup_mask(int cpu) const struct cpumask *cpu_coregroup_mask(int cpu)
{ {
return &per_cpu(cpu_topology, cpu).core_mask; return &cpu_topology[cpu].core_mask;
} }
static const struct cpumask *cpu_book_mask(int cpu) static const struct cpumask *cpu_book_mask(int cpu)
{ {
return &per_cpu(cpu_topology, cpu).book_mask; return &cpu_topology[cpu].book_mask;
} }
static const struct cpumask *cpu_drawer_mask(int cpu) static const struct cpumask *cpu_drawer_mask(int cpu)
{ {
return &per_cpu(cpu_topology, cpu).drawer_mask; return &cpu_topology[cpu].drawer_mask;
} }
static int __init early_parse_topology(char *p) static int __init early_parse_topology(char *p)
...@@ -438,19 +453,20 @@ static void __init alloc_masks(struct sysinfo_15_1_x *info, ...@@ -438,19 +453,20 @@ static void __init alloc_masks(struct sysinfo_15_1_x *info,
nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i]; nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i];
nr_masks = max(nr_masks, 1); nr_masks = max(nr_masks, 1);
for (i = 0; i < nr_masks; i++) { for (i = 0; i < nr_masks; i++) {
mask->next = kzalloc(sizeof(*mask->next), GFP_KERNEL); mask->next = memblock_virt_alloc(sizeof(*mask->next), 8);
mask = mask->next; mask = mask->next;
} }
} }
static int __init s390_topology_init(void) void __init topology_init_early(void)
{ {
struct sysinfo_15_1_x *info; struct sysinfo_15_1_x *info;
int i; int i;
set_sched_topology(s390_topology);
if (!MACHINE_HAS_TOPOLOGY) if (!MACHINE_HAS_TOPOLOGY)
return 0; goto out;
tl_info = (struct sysinfo_15_1_x *)__get_free_page(GFP_KERNEL); tl_info = memblock_virt_alloc(sizeof(*tl_info), PAGE_SIZE);
info = tl_info; info = tl_info;
store_topology(info); store_topology(info);
pr_info("The CPU configuration topology of the machine is:"); pr_info("The CPU configuration topology of the machine is:");
...@@ -460,10 +476,9 @@ static int __init s390_topology_init(void) ...@@ -460,10 +476,9 @@ static int __init s390_topology_init(void)
alloc_masks(info, &socket_info, 1); alloc_masks(info, &socket_info, 1);
alloc_masks(info, &book_info, 2); alloc_masks(info, &book_info, 2);
alloc_masks(info, &drawer_info, 3); alloc_masks(info, &drawer_info, 3);
set_sched_topology(s390_topology); out:
return 0; __arch_update_cpu_topology();
} }
early_initcall(s390_topology_init);
static int __init topology_init(void) static int __init topology_init(void)
{ {
......
...@@ -99,8 +99,27 @@ __kernel_clock_gettime: ...@@ -99,8 +99,27 @@ __kernel_clock_gettime:
tml %r4,0x0001 /* pending update ? loop */ tml %r4,0x0001 /* pending update ? loop */
jnz 11b jnz 11b
stcke 0(%r15) /* Store TOD clock */ stcke 0(%r15) /* Store TOD clock */
lm %r0,%r1,1(%r15) lm %r0,%r1,__VDSO_TS_END(%r5) /* TOD steering end time */
s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ s %r0,1(%r15) /* no - ts_steering_end */
sl %r1,5(%r15)
brc 3,22f
ahi %r0,-1
22: ltr %r0,%r0 /* past end of steering? */
jm 24f
srdl %r0,15 /* 1 per 2^16 */
tm __VDSO_TS_DIR+3(%r5),0x01 /* steering direction? */
jz 23f
lcr %r0,%r0 /* negative TOD offset */
lcr %r1,%r1
je 23f
ahi %r0,-1
23: a %r0,1(%r15) /* add TOD timestamp */
al %r1,5(%r15)
brc 12,25f
ahi %r0,1
j 25f
24: lm %r0,%r1,1(%r15) /* load TOD timestamp */
25: s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
sl %r1,__VDSO_XTIME_STAMP+4(%r5) sl %r1,__VDSO_XTIME_STAMP+4(%r5)
brc 3,12f brc 3,12f
ahi %r0,-1 ahi %r0,-1
......
...@@ -31,8 +31,27 @@ __kernel_gettimeofday: ...@@ -31,8 +31,27 @@ __kernel_gettimeofday:
tml %r4,0x0001 /* pending update ? loop */ tml %r4,0x0001 /* pending update ? loop */
jnz 1b jnz 1b
stcke 0(%r15) /* Store TOD clock */ stcke 0(%r15) /* Store TOD clock */
lm %r0,%r1,1(%r15) lm %r0,%r1,__VDSO_TS_END(%r5) /* TOD steering end time */
s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ s %r0,1(%r15)
sl %r1,5(%r15)
brc 3,14f
ahi %r0,-1
14: ltr %r0,%r0 /* past end of steering? */
jm 16f
srdl %r0,15 /* 1 per 2^16 */
tm __VDSO_TS_DIR+3(%r5),0x01 /* steering direction? */
jz 15f
lcr %r0,%r0 /* negative TOD offset */
lcr %r1,%r1
je 15f
ahi %r0,-1
15: a %r0,1(%r15) /* add TOD timestamp */
al %r1,5(%r15)
brc 12,17f
ahi %r0,1
j 17f
16: lm %r0,%r1,1(%r15) /* load TOD timestamp */
17: s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
sl %r1,__VDSO_XTIME_STAMP+4(%r5) sl %r1,__VDSO_XTIME_STAMP+4(%r5)
brc 3,3f brc 3,3f
ahi %r0,-1 ahi %r0,-1
......
...@@ -83,8 +83,17 @@ __kernel_clock_gettime: ...@@ -83,8 +83,17 @@ __kernel_clock_gettime:
tmll %r4,0x0001 /* pending update ? loop */ tmll %r4,0x0001 /* pending update ? loop */
jnz 5b jnz 5b
stcke 0(%r15) /* Store TOD clock */ stcke 0(%r15) /* Store TOD clock */
lgf %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
lg %r1,1(%r15) lg %r1,1(%r15)
lg %r0,__VDSO_TS_END(%r5) /* TOD steering end time */
slgr %r0,%r1 /* now - ts_steering_end */
ltgr %r0,%r0 /* past end of steering ? */
jm 17f
srlg %r0,%r0,15 /* 1 per 2^16 */
tm __VDSO_TS_DIR+3(%r5),0x01 /* steering direction? */
jz 18f
lcgr %r0,%r0 /* negative TOD offset */
18: algr %r1,%r0 /* add steering offset */
17: lgf %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */ msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */
......
...@@ -31,7 +31,16 @@ __kernel_gettimeofday: ...@@ -31,7 +31,16 @@ __kernel_gettimeofday:
jnz 0b jnz 0b
stcke 0(%r15) /* Store TOD clock */ stcke 0(%r15) /* Store TOD clock */
lg %r1,1(%r15) lg %r1,1(%r15)
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ lg %r0,__VDSO_TS_END(%r5) /* TOD steering end time */
slgr %r0,%r1 /* now - ts_steering_end */
ltgr %r0,%r0 /* past end of steering ? */
jm 6f
srlg %r0,%r0,15 /* 1 per 2^16 */
tm __VDSO_TS_DIR+3(%r5),0x01 /* steering direction? */
jz 7f
lcgr %r0,%r0 /* negative TOD offset */
7: algr %r1,%r0 /* add steering offset */
6: sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */ msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */
lg %r0,__VDSO_XTIME_SEC(%r5) /* tk->xtime_sec */ lg %r0,__VDSO_XTIME_SEC(%r5) /* tk->xtime_sec */
......
...@@ -96,7 +96,6 @@ static void update_mt_scaling(void) ...@@ -96,7 +96,6 @@ static void update_mt_scaling(void)
*/ */
static int do_account_vtime(struct task_struct *tsk, int hardirq_offset) static int do_account_vtime(struct task_struct *tsk, int hardirq_offset)
{ {
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; u64 user_scaled, system_scaled;
...@@ -119,13 +118,13 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset) ...@@ -119,13 +118,13 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset)
time_after64(jiffies_64, this_cpu_read(mt_scaling_jiffies))) time_after64(jiffies_64, this_cpu_read(mt_scaling_jiffies)))
update_mt_scaling(); update_mt_scaling();
user = S390_lowcore.user_timer - ti->user_timer; user = S390_lowcore.user_timer - tsk->thread.user_timer;
S390_lowcore.steal_timer -= user; S390_lowcore.steal_timer -= user;
ti->user_timer = S390_lowcore.user_timer; tsk->thread.user_timer = S390_lowcore.user_timer;
system = S390_lowcore.system_timer - ti->system_timer; system = S390_lowcore.system_timer - tsk->thread.system_timer;
S390_lowcore.steal_timer -= system; S390_lowcore.steal_timer -= system;
ti->system_timer = S390_lowcore.system_timer; tsk->thread.system_timer = S390_lowcore.system_timer;
user_scaled = user; user_scaled = user;
system_scaled = system; system_scaled = system;
...@@ -153,15 +152,11 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset) ...@@ -153,15 +152,11 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset)
void vtime_task_switch(struct task_struct *prev) void vtime_task_switch(struct task_struct *prev)
{ {
struct thread_info *ti;
do_account_vtime(prev, 0); do_account_vtime(prev, 0);
ti = task_thread_info(prev); prev->thread.user_timer = S390_lowcore.user_timer;
ti->user_timer = S390_lowcore.user_timer; prev->thread.system_timer = S390_lowcore.system_timer;
ti->system_timer = S390_lowcore.system_timer; S390_lowcore.user_timer = current->thread.user_timer;
ti = task_thread_info(current); S390_lowcore.system_timer = current->thread.system_timer;
S390_lowcore.user_timer = ti->user_timer;
S390_lowcore.system_timer = ti->system_timer;
} }
/* /*
...@@ -181,7 +176,6 @@ void vtime_account_user(struct task_struct *tsk) ...@@ -181,7 +176,6 @@ 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);
u64 timer, system, system_scaled; u64 timer, system, system_scaled;
timer = S390_lowcore.last_update_timer; timer = S390_lowcore.last_update_timer;
...@@ -193,9 +187,9 @@ void vtime_account_irq_enter(struct task_struct *tsk) ...@@ -193,9 +187,9 @@ void vtime_account_irq_enter(struct task_struct *tsk)
time_after64(jiffies_64, this_cpu_read(mt_scaling_jiffies))) time_after64(jiffies_64, this_cpu_read(mt_scaling_jiffies)))
update_mt_scaling(); update_mt_scaling();
system = S390_lowcore.system_timer - ti->system_timer; system = S390_lowcore.system_timer - tsk->thread.system_timer;
S390_lowcore.steal_timer -= system; S390_lowcore.steal_timer -= system;
ti->system_timer = S390_lowcore.system_timer; tsk->thread.system_timer = S390_lowcore.system_timer;
system_scaled = system; system_scaled = system;
/* Do MT utilization scaling */ /* Do MT utilization scaling */
if (smp_cpu_mtid) { if (smp_cpu_mtid) {
......
...@@ -7,6 +7,45 @@ ...@@ -7,6 +7,45 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/export.h> #include <asm/export.h>
/*
* void *memmove(void *dest, const void *src, size_t n)
*/
ENTRY(memmove)
ltgr %r4,%r4
lgr %r1,%r2
bzr %r14
clgr %r2,%r3
jnh .Lmemmove_forward
la %r5,0(%r4,%r3)
clgr %r2,%r5
jl .Lmemmove_reverse
.Lmemmove_forward:
aghi %r4,-1
srlg %r0,%r4,8
ltgr %r0,%r0
jz .Lmemmove_rest
.Lmemmove_loop:
mvc 0(256,%r1),0(%r3)
la %r1,256(%r1)
la %r3,256(%r3)
brctg %r0,.Lmemmove_loop
.Lmemmove_rest:
larl %r5,.Lmemmove_mvc
ex %r4,0(%r5)
br %r14
.Lmemmove_reverse:
aghi %r4,-1
.Lmemmove_reverse_loop:
ic %r0,0(%r4,%r3)
stc %r0,0(%r4,%r1)
brctg %r4,.Lmemmove_reverse_loop
ic %r0,0(%r4,%r3)
stc %r0,0(%r4,%r1)
br %r14
.Lmemmove_mvc:
mvc 0(1,%r1),0(%r3)
EXPORT_SYMBOL(memmove)
/* /*
* memset implementation * memset implementation
* *
......
...@@ -733,6 +733,7 @@ static void pfault_interrupt(struct ext_code ext_code, ...@@ -733,6 +733,7 @@ static void pfault_interrupt(struct ext_code ext_code,
* return to userspace schedule() to block. */ * return to userspace schedule() to block. */
__set_current_state(TASK_UNINTERRUPTIBLE); __set_current_state(TASK_UNINTERRUPTIBLE);
set_tsk_need_resched(tsk); set_tsk_need_resched(tsk);
set_preempt_need_resched();
} }
} }
out: out:
......
...@@ -34,7 +34,7 @@ static void __ref *vmem_alloc_pages(unsigned int order) ...@@ -34,7 +34,7 @@ static void __ref *vmem_alloc_pages(unsigned int order)
if (slab_is_available()) if (slab_is_available())
return (void *)__get_free_pages(GFP_KERNEL, order); return (void *)__get_free_pages(GFP_KERNEL, order);
return alloc_bootmem_align(size, size); return (void *) memblock_alloc(size, size);
} }
static inline pud_t *vmem_pud_alloc(void) static inline pud_t *vmem_pud_alloc(void)
...@@ -61,17 +61,16 @@ pmd_t *vmem_pmd_alloc(void) ...@@ -61,17 +61,16 @@ pmd_t *vmem_pmd_alloc(void)
pte_t __ref *vmem_pte_alloc(void) pte_t __ref *vmem_pte_alloc(void)
{ {
unsigned long size = PTRS_PER_PTE * sizeof(pte_t);
pte_t *pte; pte_t *pte;
if (slab_is_available()) if (slab_is_available())
pte = (pte_t *) page_table_alloc(&init_mm); pte = (pte_t *) page_table_alloc(&init_mm);
else else
pte = alloc_bootmem_align(PTRS_PER_PTE * sizeof(pte_t), pte = (pte_t *) memblock_alloc(size, size);
PTRS_PER_PTE * sizeof(pte_t));
if (!pte) if (!pte)
return NULL; return NULL;
clear_table((unsigned long *) pte, _PAGE_INVALID, clear_table((unsigned long *) pte, _PAGE_INVALID, size);
PTRS_PER_PTE * sizeof(pte_t));
return pte; return pte;
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/bootmem.h>
#include <linux/node.h> #include <linux/node.h>
#include <linux/memory.h> #include <linux/memory.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -307,13 +308,11 @@ static struct toptree *toptree_new(int id, int nodes) ...@@ -307,13 +308,11 @@ static struct toptree *toptree_new(int id, int nodes)
/* /*
* Allocate and initialize core to node mapping * Allocate and initialize core to node mapping
*/ */
static void create_core_to_node_map(void) static void __ref create_core_to_node_map(void)
{ {
int i; int i;
emu_cores = kzalloc(sizeof(*emu_cores), GFP_KERNEL); emu_cores = memblock_virt_alloc(sizeof(*emu_cores), 8);
if (emu_cores == NULL)
panic("Could not allocate cores to node memory");
for (i = 0; i < ARRAY_SIZE(emu_cores->to_node_id); i++) for (i = 0; i < ARRAY_SIZE(emu_cores->to_node_id); i++)
emu_cores->to_node_id[i] = NODE_ID_FREE; emu_cores->to_node_id[i] = NODE_ID_FREE;
} }
...@@ -354,13 +353,13 @@ static struct toptree *toptree_from_topology(void) ...@@ -354,13 +353,13 @@ static struct toptree *toptree_from_topology(void)
phys = toptree_new(TOPTREE_ID_PHYS, 1); phys = toptree_new(TOPTREE_ID_PHYS, 1);
for_each_online_cpu(cpu) { for_each_cpu(cpu, &cpus_with_topology) {
top = &per_cpu(cpu_topology, cpu); top = &cpu_topology[cpu];
node = toptree_get_child(phys, 0); node = toptree_get_child(phys, 0);
drawer = toptree_get_child(node, top->drawer_id); drawer = toptree_get_child(node, top->drawer_id);
book = toptree_get_child(drawer, top->book_id); book = toptree_get_child(drawer, top->book_id);
mc = toptree_get_child(book, top->socket_id); mc = toptree_get_child(book, top->socket_id);
core = toptree_get_child(mc, top->core_id); core = toptree_get_child(mc, smp_get_base_cpu(cpu));
if (!drawer || !book || !mc || !core) if (!drawer || !book || !mc || !core)
panic("NUMA emulation could not allocate memory"); panic("NUMA emulation could not allocate memory");
cpumask_set_cpu(cpu, &core->mask); cpumask_set_cpu(cpu, &core->mask);
...@@ -378,7 +377,7 @@ static void topology_add_core(struct toptree *core) ...@@ -378,7 +377,7 @@ static void topology_add_core(struct toptree *core)
int cpu; int cpu;
for_each_cpu(cpu, &core->mask) { for_each_cpu(cpu, &core->mask) {
top = &per_cpu(cpu_topology, cpu); top = &cpu_topology[cpu];
cpumask_copy(&top->thread_mask, &core->mask); cpumask_copy(&top->thread_mask, &core->mask);
cpumask_copy(&top->core_mask, &core_mc(core)->mask); cpumask_copy(&top->core_mask, &core_mc(core)->mask);
cpumask_copy(&top->book_mask, &core_book(core)->mask); cpumask_copy(&top->book_mask, &core_book(core)->mask);
...@@ -425,6 +424,27 @@ static void print_node_to_core_map(void) ...@@ -425,6 +424,27 @@ static void print_node_to_core_map(void)
} }
} }
static void pin_all_possible_cpus(void)
{
int core_id, node_id, cpu;
static int initialized;
if (initialized)
return;
print_node_to_core_map();
node_id = 0;
for_each_possible_cpu(cpu) {
core_id = smp_get_base_cpu(cpu);
if (emu_cores->to_node_id[core_id] != NODE_ID_FREE)
continue;
pin_core_to_node(core_id, node_id);
cpu_topology[cpu].node_id = node_id;
node_id = (node_id + 1) % emu_nodes;
}
print_node_to_core_map();
initialized = 1;
}
/* /*
* Transfer physical topology into a NUMA topology and modify CPU masks * Transfer physical topology into a NUMA topology and modify CPU masks
* according to the NUMA topology. * according to the NUMA topology.
...@@ -442,7 +462,7 @@ static void emu_update_cpu_topology(void) ...@@ -442,7 +462,7 @@ static void emu_update_cpu_topology(void)
toptree_free(phys); toptree_free(phys);
toptree_to_topology(numa); toptree_to_topology(numa);
toptree_free(numa); toptree_free(numa);
print_node_to_core_map(); pin_all_possible_cpus();
} }
/* /*
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/bootmem.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/list_sort.h> #include <linux/list_sort.h>
...@@ -25,10 +26,14 @@ ...@@ -25,10 +26,14 @@
* RETURNS: * RETURNS:
* Pointer to the new tree node or NULL on error * Pointer to the new tree node or NULL on error
*/ */
struct toptree *toptree_alloc(int level, int id) struct toptree __ref *toptree_alloc(int level, int id)
{ {
struct toptree *res = kzalloc(sizeof(struct toptree), GFP_KERNEL); struct toptree *res;
if (slab_is_available())
res = kzalloc(sizeof(*res), GFP_KERNEL);
else
res = memblock_virt_alloc(sizeof(*res), 8);
if (!res) if (!res)
return res; return res;
...@@ -65,7 +70,7 @@ static void toptree_remove(struct toptree *cand) ...@@ -65,7 +70,7 @@ static void toptree_remove(struct toptree *cand)
* cleanly using toptree_remove. Possible children are freed * cleanly using toptree_remove. Possible children are freed
* recursively. In the end @cand itself is freed. * recursively. In the end @cand itself is freed.
*/ */
void toptree_free(struct toptree *cand) void __ref toptree_free(struct toptree *cand)
{ {
struct toptree *child, *tmp; struct toptree *child, *tmp;
...@@ -73,7 +78,10 @@ void toptree_free(struct toptree *cand) ...@@ -73,7 +78,10 @@ void toptree_free(struct toptree *cand)
toptree_remove(cand); toptree_remove(cand);
toptree_for_each_child_safe(child, tmp, cand) toptree_for_each_child_safe(child, tmp, cand)
toptree_free(child); toptree_free(child);
kfree(cand); if (slab_is_available())
kfree(cand);
else
memblock_free_early((unsigned long)cand, sizeof(*cand));
} }
/** /**
......
...@@ -722,6 +722,11 @@ struct dev_pm_ops pcibios_pm_ops = { ...@@ -722,6 +722,11 @@ struct dev_pm_ops pcibios_pm_ops = {
static int zpci_alloc_domain(struct zpci_dev *zdev) static int zpci_alloc_domain(struct zpci_dev *zdev)
{ {
if (zpci_unique_uid) {
zdev->domain = (u16) zdev->uid;
return 0;
}
spin_lock(&zpci_domain_lock); spin_lock(&zpci_domain_lock);
zdev->domain = find_first_zero_bit(zpci_domain, ZPCI_NR_DEVICES); zdev->domain = find_first_zero_bit(zpci_domain, ZPCI_NR_DEVICES);
if (zdev->domain == ZPCI_NR_DEVICES) { if (zdev->domain == ZPCI_NR_DEVICES) {
...@@ -735,6 +740,9 @@ static int zpci_alloc_domain(struct zpci_dev *zdev) ...@@ -735,6 +740,9 @@ static int zpci_alloc_domain(struct zpci_dev *zdev)
static void zpci_free_domain(struct zpci_dev *zdev) static void zpci_free_domain(struct zpci_dev *zdev)
{ {
if (zpci_unique_uid)
return;
spin_lock(&zpci_domain_lock); spin_lock(&zpci_domain_lock);
clear_bit(zdev->domain, zpci_domain); clear_bit(zdev->domain, zpci_domain);
spin_unlock(&zpci_domain_lock); spin_unlock(&zpci_domain_lock);
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <asm/clp.h> #include <asm/clp.h>
#include <uapi/asm/clp.h> #include <uapi/asm/clp.h>
bool zpci_unique_uid;
static inline void zpci_err_clp(unsigned int rsp, int rc) static inline void zpci_err_clp(unsigned int rsp, int rc)
{ {
struct { struct {
...@@ -315,6 +317,7 @@ static int clp_list_pci(struct clp_req_rsp_list_pci *rrb, ...@@ -315,6 +317,7 @@ static int clp_list_pci(struct clp_req_rsp_list_pci *rrb,
goto out; goto out;
} }
zpci_unique_uid = rrb->response.uid_checking;
WARN_ON_ONCE(rrb->response.entry_size != WARN_ON_ONCE(rrb->response.entry_size !=
sizeof(struct clp_fh_list_entry)); sizeof(struct clp_fh_list_entry));
......
...@@ -69,7 +69,7 @@ static void pci_sw_counter_show(struct seq_file *m) ...@@ -69,7 +69,7 @@ static void pci_sw_counter_show(struct seq_file *m)
int i; int i;
for (i = 0; i < ARRAY_SIZE(pci_sw_names); i++, counter++) for (i = 0; i < ARRAY_SIZE(pci_sw_names); i++, counter++)
seq_printf(m, "%26s:\t%llu\n", pci_sw_names[i], seq_printf(m, "%26s:\t%lu\n", pci_sw_names[i],
atomic64_read(counter)); atomic64_read(counter));
} }
......
...@@ -181,14 +181,17 @@ static int __dma_purge_tlb(struct zpci_dev *zdev, dma_addr_t dma_addr, ...@@ -181,14 +181,17 @@ static int __dma_purge_tlb(struct zpci_dev *zdev, dma_addr_t dma_addr,
/* /*
* With zdev->tlb_refresh == 0, rpcit is not required to establish new * With zdev->tlb_refresh == 0, rpcit is not required to establish new
* translations when previously invalid translation-table entries are * translations when previously invalid translation-table entries are
* validated. With lazy unmap, it also is skipped for previously valid * validated. With lazy unmap, rpcit is skipped for previously valid
* entries, but a global rpcit is then required before any address can * entries, but a global rpcit is then required before any address can
* be re-used, i.e. after each iommu bitmap wrap-around. * be re-used, i.e. after each iommu bitmap wrap-around.
*/ */
if (!zdev->tlb_refresh && if ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID) {
(!s390_iommu_strict || if (!zdev->tlb_refresh)
((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID))) return 0;
return 0; } else {
if (!s390_iommu_strict)
return 0;
}
return zpci_refresh_trans((u64) zdev->fh << 32, dma_addr, return zpci_refresh_trans((u64) zdev->fh << 32, dma_addr,
PAGE_ALIGN(size)); PAGE_ALIGN(size));
...@@ -257,7 +260,7 @@ static dma_addr_t dma_alloc_address(struct device *dev, int size) ...@@ -257,7 +260,7 @@ static dma_addr_t dma_alloc_address(struct device *dev, int size)
spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags);
offset = __dma_alloc_iommu(dev, zdev->next_bit, size); offset = __dma_alloc_iommu(dev, zdev->next_bit, size);
if (offset == -1) { if (offset == -1) {
if (!zdev->tlb_refresh && !s390_iommu_strict) { if (!s390_iommu_strict) {
/* global flush before DMA addresses are reused */ /* global flush before DMA addresses are reused */
if (zpci_refresh_global(zdev)) if (zpci_refresh_global(zdev))
goto out_error; goto out_error;
...@@ -292,7 +295,7 @@ static void dma_free_address(struct device *dev, dma_addr_t dma_addr, int size) ...@@ -292,7 +295,7 @@ static void dma_free_address(struct device *dev, dma_addr_t dma_addr, int size)
if (!zdev->iommu_bitmap) if (!zdev->iommu_bitmap)
goto out; goto out;
if (zdev->tlb_refresh || s390_iommu_strict) if (s390_iommu_strict)
bitmap_clear(zdev->iommu_bitmap, offset, size); bitmap_clear(zdev->iommu_bitmap, offset, size);
else else
bitmap_set(zdev->lazy_bitmap, offset, size); bitmap_set(zdev->lazy_bitmap, offset, size);
...@@ -388,8 +391,6 @@ static void *s390_dma_alloc(struct device *dev, size_t size, ...@@ -388,8 +391,6 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
return NULL; return NULL;
pa = page_to_phys(page); pa = page_to_phys(page);
memset((void *) pa, 0, size);
map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, 0); map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, 0);
if (dma_mapping_error(dev, map)) { if (dma_mapping_error(dev, map)) {
free_pages(pa, get_order(size)); free_pages(pa, get_order(size));
...@@ -419,6 +420,7 @@ static int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg, ...@@ -419,6 +420,7 @@ static int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg,
size_t size, dma_addr_t *handle, size_t size, dma_addr_t *handle,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
dma_addr_t dma_addr_base, dma_addr; dma_addr_t dma_addr_base, dma_addr;
int flags = ZPCI_PTE_VALID; int flags = ZPCI_PTE_VALID;
...@@ -426,8 +428,7 @@ static int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg, ...@@ -426,8 +428,7 @@ static int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg,
unsigned long pa = 0; unsigned long pa = 0;
int ret; int ret;
size = PAGE_ALIGN(size); dma_addr_base = dma_alloc_address(dev, nr_pages);
dma_addr_base = dma_alloc_address(dev, size >> PAGE_SHIFT);
if (dma_addr_base == DMA_ERROR_CODE) if (dma_addr_base == DMA_ERROR_CODE)
return -ENOMEM; return -ENOMEM;
...@@ -436,26 +437,27 @@ static int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg, ...@@ -436,26 +437,27 @@ static int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg,
flags |= ZPCI_TABLE_PROTECTED; flags |= ZPCI_TABLE_PROTECTED;
for (s = sg; dma_addr < dma_addr_base + size; s = sg_next(s)) { for (s = sg; dma_addr < dma_addr_base + size; s = sg_next(s)) {
pa = page_to_phys(sg_page(s)) + s->offset; pa = page_to_phys(sg_page(s));
ret = __dma_update_trans(zdev, pa, dma_addr, s->length, flags); ret = __dma_update_trans(zdev, pa, dma_addr,
s->offset + s->length, flags);
if (ret) if (ret)
goto unmap; goto unmap;
dma_addr += s->length; dma_addr += s->offset + s->length;
} }
ret = __dma_purge_tlb(zdev, dma_addr_base, size, flags); ret = __dma_purge_tlb(zdev, dma_addr_base, size, flags);
if (ret) if (ret)
goto unmap; goto unmap;
*handle = dma_addr_base; *handle = dma_addr_base;
atomic64_add(size >> PAGE_SHIFT, &zdev->mapped_pages); atomic64_add(nr_pages, &zdev->mapped_pages);
return ret; return ret;
unmap: unmap:
dma_update_trans(zdev, 0, dma_addr_base, dma_addr - dma_addr_base, dma_update_trans(zdev, 0, dma_addr_base, dma_addr - dma_addr_base,
ZPCI_PTE_INVALID); ZPCI_PTE_INVALID);
dma_free_address(dev, dma_addr_base, size >> PAGE_SHIFT); dma_free_address(dev, dma_addr_base, nr_pages);
zpci_err("map error:\n"); zpci_err("map error:\n");
zpci_err_dma(ret, pa); zpci_err_dma(ret, pa);
return ret; return ret;
...@@ -564,7 +566,7 @@ int zpci_dma_init_device(struct zpci_dev *zdev) ...@@ -564,7 +566,7 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
rc = -ENOMEM; rc = -ENOMEM;
goto free_dma_table; goto free_dma_table;
} }
if (!zdev->tlb_refresh && !s390_iommu_strict) { if (!s390_iommu_strict) {
zdev->lazy_bitmap = vzalloc(zdev->iommu_pages / 8); zdev->lazy_bitmap = vzalloc(zdev->iommu_pages / 8);
if (!zdev->lazy_bitmap) { if (!zdev->lazy_bitmap) {
rc = -ENOMEM; rc = -ENOMEM;
......
...@@ -9,7 +9,5 @@ define filechk_facilities.h ...@@ -9,7 +9,5 @@ define filechk_facilities.h
$(obj)/gen_facilities $(obj)/gen_facilities
endef endef
$(obj)/gen_facilities.o: $(srctree)/arch/s390/tools/gen_facilities.c
include/generated/facilities.h: $(obj)/gen_facilities FORCE include/generated/facilities.h: $(obj)/gen_facilities FORCE
$(call filechk,facilities.h) $(call filechk,facilities.h)
...@@ -7,13 +7,83 @@ ...@@ -7,13 +7,83 @@
* *
*/ */
#define S390_GEN_FACILITIES_C
#include <strings.h> #include <strings.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <asm/facilities_src.h>
struct facility_def {
char *name;
int *bits;
};
static struct facility_def facility_defs[] = {
{
/*
* FACILITIES_ALS contains the list of facilities that are
* required to run a kernel that is compiled e.g. with
* -march=<machine>.
*/
.name = "FACILITIES_ALS",
.bits = (int[]){
#ifdef CONFIG_HAVE_MARCH_Z900_FEATURES
0, /* N3 instructions */
1, /* z/Arch mode installed */
#endif
#ifdef CONFIG_HAVE_MARCH_Z990_FEATURES
18, /* long displacement facility */
#endif
#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
7, /* stfle */
17, /* message security assist */
21, /* extended-immediate facility */
25, /* store clock fast */
#endif
#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
27, /* mvcos */
32, /* compare and swap and store */
33, /* compare and swap and store 2 */
34, /* general extension facility */
35, /* execute extensions */
#endif
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
45, /* fast-BCR, etc. */
#endif
#ifdef CONFIG_HAVE_MARCH_ZEC12_FEATURES
49, /* misc-instruction-extensions */
52, /* interlocked facility 2 */
#endif
#ifdef CONFIG_HAVE_MARCH_Z13_FEATURES
53, /* load-and-zero-rightmost-byte, etc. */
#endif
-1 /* END */
}
},
{
.name = "FACILITIES_KVM",
.bits = (int[]){
0, /* N3 instructions */
1, /* z/Arch mode installed */
2, /* z/Arch mode active */
3, /* DAT-enhancement */
4, /* idte segment table */
5, /* idte region table */
6, /* ASN-and-LX reuse */
7, /* stfle */
8, /* enhanced-DAT 1 */
9, /* sense-running-status */
10, /* conditional sske */
13, /* ipte-range */
14, /* nonquiescing key-setting */
73, /* transactional execution */
75, /* access-exception-fetch/store indication */
76, /* msa extension 3 */
77, /* msa extension 4 */
78, /* enhanced-DAT 2 */
-1 /* END */
}
},
};
static void print_facility_list(struct facility_def *def) static void print_facility_list(struct facility_def *def)
{ {
......
...@@ -5,12 +5,13 @@ ...@@ -5,12 +5,13 @@
* *
* Author(s): * Author(s):
* Jan Glauber <jang@linux.vnet.ibm.com> * Jan Glauber <jang@linux.vnet.ibm.com>
*
* License: GPL
*/ */
#define KMSG_COMPONENT "zpci" #define KMSG_COMPONENT "zpci"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h> #include <linux/pci.h>
...@@ -21,10 +22,6 @@ ...@@ -21,10 +22,6 @@
#define SLOT_NAME_SIZE 10 #define SLOT_NAME_SIZE 10
static LIST_HEAD(s390_hotplug_slot_list); static LIST_HEAD(s390_hotplug_slot_list);
MODULE_AUTHOR("Jan Glauber <jang@linux.vnet.ibm.com");
MODULE_DESCRIPTION("Hot Plug PCI Controller for System z");
MODULE_LICENSE("GPL");
static int zpci_fn_configured(enum zpci_state state) static int zpci_fn_configured(enum zpci_state state)
{ {
return state == ZPCI_FN_STATE_CONFIGURED || return state == ZPCI_FN_STATE_CONFIGURED ||
......
...@@ -69,6 +69,7 @@ static void dasd_block_tasklet(struct dasd_block *); ...@@ -69,6 +69,7 @@ static void dasd_block_tasklet(struct dasd_block *);
static void do_kick_device(struct work_struct *); static void do_kick_device(struct work_struct *);
static void do_restore_device(struct work_struct *); static void do_restore_device(struct work_struct *);
static void do_reload_device(struct work_struct *); static void do_reload_device(struct work_struct *);
static void do_requeue_requests(struct work_struct *);
static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
static void dasd_device_timeout(unsigned long); static void dasd_device_timeout(unsigned long);
static void dasd_block_timeout(unsigned long); static void dasd_block_timeout(unsigned long);
...@@ -125,6 +126,7 @@ struct dasd_device *dasd_alloc_device(void) ...@@ -125,6 +126,7 @@ struct dasd_device *dasd_alloc_device(void)
INIT_WORK(&device->kick_work, do_kick_device); INIT_WORK(&device->kick_work, do_kick_device);
INIT_WORK(&device->restore_device, do_restore_device); INIT_WORK(&device->restore_device, do_restore_device);
INIT_WORK(&device->reload_device, do_reload_device); INIT_WORK(&device->reload_device, do_reload_device);
INIT_WORK(&device->requeue_requests, do_requeue_requests);
device->state = DASD_STATE_NEW; device->state = DASD_STATE_NEW;
device->target = DASD_STATE_NEW; device->target = DASD_STATE_NEW;
mutex_init(&device->state_mutex); mutex_init(&device->state_mutex);
...@@ -1448,9 +1450,9 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) ...@@ -1448,9 +1450,9 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
cqr->starttime = jiffies; cqr->starttime = jiffies;
cqr->retries--; cqr->retries--;
if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) {
cqr->lpm &= device->path_data.opm; cqr->lpm &= dasd_path_get_opm(device);
if (!cqr->lpm) if (!cqr->lpm)
cqr->lpm = device->path_data.opm; cqr->lpm = dasd_path_get_opm(device);
} }
if (cqr->cpmode == 1) { if (cqr->cpmode == 1) {
rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, rc = ccw_device_tm_start(device->cdev, cqr->cpaddr,
...@@ -1483,8 +1485,8 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) ...@@ -1483,8 +1485,8 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
DBF_DEV_EVENT(DBF_WARNING, device, DBF_DEV_EVENT(DBF_WARNING, device,
"start_IO: selected paths gone (%x)", "start_IO: selected paths gone (%x)",
cqr->lpm); cqr->lpm);
} else if (cqr->lpm != device->path_data.opm) { } else if (cqr->lpm != dasd_path_get_opm(device)) {
cqr->lpm = device->path_data.opm; cqr->lpm = dasd_path_get_opm(device);
DBF_DEV_EVENT(DBF_DEBUG, device, "%s", DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
"start_IO: selected paths gone," "start_IO: selected paths gone,"
" retry on all paths"); " retry on all paths");
...@@ -1493,11 +1495,10 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) ...@@ -1493,11 +1495,10 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
"start_IO: all paths in opm gone," "start_IO: all paths in opm gone,"
" do path verification"); " do path verification");
dasd_generic_last_path_gone(device); dasd_generic_last_path_gone(device);
device->path_data.opm = 0; dasd_path_no_path(device);
device->path_data.ppm = 0; dasd_path_set_tbvpm(device,
device->path_data.npm = 0; ccw_device_get_path_mask(
device->path_data.tbvpm = device->cdev));
ccw_device_get_path_mask(device->cdev);
} }
break; break;
case -ENODEV: case -ENODEV:
...@@ -1623,6 +1624,13 @@ void dasd_generic_handle_state_change(struct dasd_device *device) ...@@ -1623,6 +1624,13 @@ void dasd_generic_handle_state_change(struct dasd_device *device)
} }
EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change); EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change);
static int dasd_check_hpf_error(struct irb *irb)
{
return (scsw_tm_is_valid_schxs(&irb->scsw) &&
(irb->scsw.tm.sesq == SCSW_SESQ_DEV_NOFCX ||
irb->scsw.tm.sesq == SCSW_SESQ_PATH_NOFCX));
}
/* /*
* Interrupt handler for "normal" ssch-io based dasd devices. * Interrupt handler for "normal" ssch-io based dasd devices.
*/ */
...@@ -1642,7 +1650,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -1642,7 +1650,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
switch (PTR_ERR(irb)) { switch (PTR_ERR(irb)) {
case -EIO: case -EIO:
if (cqr && cqr->status == DASD_CQR_CLEAR_PENDING) { if (cqr && cqr->status == DASD_CQR_CLEAR_PENDING) {
device = (struct dasd_device *) cqr->startdev; device = cqr->startdev;
cqr->status = DASD_CQR_CLEARED; cqr->status = DASD_CQR_CLEARED;
dasd_device_clear_timer(device); dasd_device_clear_timer(device);
wake_up(&dasd_flush_wq); wake_up(&dasd_flush_wq);
...@@ -1749,19 +1757,26 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -1749,19 +1757,26 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
struct dasd_ccw_req, devlist); struct dasd_ccw_req, devlist);
} }
} else { /* error */ } else { /* error */
/* check for HPF error
* call discipline function to requeue all requests
* and disable HPF accordingly
*/
if (cqr->cpmode && dasd_check_hpf_error(irb) &&
device->discipline->handle_hpf_error)
device->discipline->handle_hpf_error(device, irb);
/* /*
* If we don't want complex ERP for this request, then just * If we don't want complex ERP for this request, then just
* reset this and retry it in the fastpath * reset this and retry it in the fastpath
*/ */
if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) &&
cqr->retries > 0) { cqr->retries > 0) {
if (cqr->lpm == device->path_data.opm) if (cqr->lpm == dasd_path_get_opm(device))
DBF_DEV_EVENT(DBF_DEBUG, device, DBF_DEV_EVENT(DBF_DEBUG, device,
"default ERP in fastpath " "default ERP in fastpath "
"(%i retries left)", "(%i retries left)",
cqr->retries); cqr->retries);
if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))
cqr->lpm = device->path_data.opm; cqr->lpm = dasd_path_get_opm(device);
cqr->status = DASD_CQR_QUEUED; cqr->status = DASD_CQR_QUEUED;
next = cqr; next = cqr;
} else } else
...@@ -2002,17 +2017,18 @@ static void __dasd_device_check_path_events(struct dasd_device *device) ...@@ -2002,17 +2017,18 @@ static void __dasd_device_check_path_events(struct dasd_device *device)
{ {
int rc; int rc;
if (device->path_data.tbvpm) { if (!dasd_path_get_tbvpm(device))
if (device->stopped & ~(DASD_STOPPED_DC_WAIT | return;
DASD_UNRESUMED_PM))
return; if (device->stopped &
rc = device->discipline->verify_path( ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM))
device, device->path_data.tbvpm); return;
if (rc) rc = device->discipline->verify_path(device,
dasd_device_set_timer(device, 50); dasd_path_get_tbvpm(device));
else if (rc)
device->path_data.tbvpm = 0; dasd_device_set_timer(device, 50);
} else
dasd_path_clear_all_verify(device);
}; };
/* /*
...@@ -2924,10 +2940,10 @@ static int _dasd_requeue_request(struct dasd_ccw_req *cqr) ...@@ -2924,10 +2940,10 @@ static int _dasd_requeue_request(struct dasd_ccw_req *cqr)
if (!block) if (!block)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&block->queue_lock, flags); spin_lock_irqsave(&block->request_queue_lock, flags);
req = (struct request *) cqr->callback_data; req = (struct request *) cqr->callback_data;
blk_requeue_request(block->request_queue, req); blk_requeue_request(block->request_queue, req);
spin_unlock_irqrestore(&block->queue_lock, flags); spin_unlock_irqrestore(&block->request_queue_lock, flags);
return 0; return 0;
} }
...@@ -3121,6 +3137,7 @@ static int dasd_alloc_queue(struct dasd_block *block) ...@@ -3121,6 +3137,7 @@ static int dasd_alloc_queue(struct dasd_block *block)
*/ */
static void dasd_setup_queue(struct dasd_block *block) static void dasd_setup_queue(struct dasd_block *block)
{ {
struct request_queue *q = block->request_queue;
int max; int max;
if (block->base->features & DASD_FEATURE_USERAW) { if (block->base->features & DASD_FEATURE_USERAW) {
...@@ -3135,17 +3152,16 @@ static void dasd_setup_queue(struct dasd_block *block) ...@@ -3135,17 +3152,16 @@ static void dasd_setup_queue(struct dasd_block *block)
} else { } else {
max = block->base->discipline->max_blocks << block->s2b_shift; max = block->base->discipline->max_blocks << block->s2b_shift;
} }
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, block->request_queue); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
block->request_queue->limits.max_dev_sectors = max; q->limits.max_dev_sectors = max;
blk_queue_logical_block_size(block->request_queue, blk_queue_logical_block_size(q, block->bp_block);
block->bp_block); blk_queue_max_hw_sectors(q, max);
blk_queue_max_hw_sectors(block->request_queue, max); blk_queue_max_segments(q, USHRT_MAX);
blk_queue_max_segments(block->request_queue, -1L);
/* with page sized segments we can translate each segement into /* with page sized segments we can translate each segement into
* one idaw/tidaw * one idaw/tidaw
*/ */
blk_queue_max_segment_size(block->request_queue, PAGE_SIZE); blk_queue_max_segment_size(q, PAGE_SIZE);
blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1); blk_queue_segment_boundary(q, PAGE_SIZE - 1);
} }
/* /*
...@@ -3517,11 +3533,15 @@ int dasd_generic_set_offline(struct ccw_device *cdev) ...@@ -3517,11 +3533,15 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
struct dasd_device *device; struct dasd_device *device;
struct dasd_block *block; struct dasd_block *block;
int max_count, open_count, rc; int max_count, open_count, rc;
unsigned long flags;
rc = 0; rc = 0;
device = dasd_device_from_cdev(cdev); spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
if (IS_ERR(device)) device = dasd_device_from_cdev_locked(cdev);
if (IS_ERR(device)) {
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
return PTR_ERR(device); return PTR_ERR(device);
}
/* /*
* We must make sure that this device is currently not in use. * We must make sure that this device is currently not in use.
...@@ -3540,8 +3560,7 @@ int dasd_generic_set_offline(struct ccw_device *cdev) ...@@ -3540,8 +3560,7 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
pr_warn("%s: The DASD cannot be set offline while it is in use\n", pr_warn("%s: The DASD cannot be set offline while it is in use\n",
dev_name(&cdev->dev)); dev_name(&cdev->dev));
clear_bit(DASD_FLAG_OFFLINE, &device->flags); clear_bit(DASD_FLAG_OFFLINE, &device->flags);
dasd_put_device(device); goto out_busy;
return -EBUSY;
} }
} }
...@@ -3551,19 +3570,19 @@ int dasd_generic_set_offline(struct ccw_device *cdev) ...@@ -3551,19 +3570,19 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
* could only be called by normal offline so safe_offline flag * could only be called by normal offline so safe_offline flag
* needs to be removed to run normal offline and kill all I/O * needs to be removed to run normal offline and kill all I/O
*/ */
if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags))
/* Already doing normal offline processing */ /* Already doing normal offline processing */
dasd_put_device(device); goto out_busy;
return -EBUSY; else
} else
clear_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags); clear_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags);
} else {
} else if (test_bit(DASD_FLAG_OFFLINE, &device->flags))
if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
/* Already doing offline processing */ /* Already doing offline processing */
dasd_put_device(device); goto out_busy;
return -EBUSY; }
}
set_bit(DASD_FLAG_OFFLINE, &device->flags);
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
/* /*
* if safe_offline called set safe_offline_running flag and * if safe_offline called set safe_offline_running flag and
...@@ -3591,7 +3610,6 @@ int dasd_generic_set_offline(struct ccw_device *cdev) ...@@ -3591,7 +3610,6 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
goto interrupted; goto interrupted;
} }
set_bit(DASD_FLAG_OFFLINE, &device->flags);
dasd_set_target_state(device, DASD_STATE_NEW); dasd_set_target_state(device, DASD_STATE_NEW);
/* dasd_delete_device destroys the device reference. */ /* dasd_delete_device destroys the device reference. */
block = device->block; block = device->block;
...@@ -3610,7 +3628,14 @@ int dasd_generic_set_offline(struct ccw_device *cdev) ...@@ -3610,7 +3628,14 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
clear_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags); clear_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags);
clear_bit(DASD_FLAG_OFFLINE, &device->flags); clear_bit(DASD_FLAG_OFFLINE, &device->flags);
dasd_put_device(device); dasd_put_device(device);
return rc; return rc;
out_busy:
dasd_put_device(device);
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
return -EBUSY;
} }
EXPORT_SYMBOL_GPL(dasd_generic_set_offline); EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
...@@ -3675,14 +3700,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) ...@@ -3675,14 +3700,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
case CIO_GONE: case CIO_GONE:
case CIO_BOXED: case CIO_BOXED:
case CIO_NO_PATH: case CIO_NO_PATH:
device->path_data.opm = 0; dasd_path_no_path(device);
device->path_data.ppm = 0;
device->path_data.npm = 0;
ret = dasd_generic_last_path_gone(device); ret = dasd_generic_last_path_gone(device);
break; break;
case CIO_OPER: case CIO_OPER:
ret = 1; ret = 1;
if (device->path_data.opm) if (dasd_path_get_opm(device))
ret = dasd_generic_path_operational(device); ret = dasd_generic_path_operational(device);
break; break;
} }
...@@ -3693,48 +3716,32 @@ EXPORT_SYMBOL_GPL(dasd_generic_notify); ...@@ -3693,48 +3716,32 @@ EXPORT_SYMBOL_GPL(dasd_generic_notify);
void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) void dasd_generic_path_event(struct ccw_device *cdev, int *path_event)
{ {
int chp;
__u8 oldopm, eventlpm;
struct dasd_device *device; struct dasd_device *device;
int chp, oldopm, hpfpm, ifccpm;
device = dasd_device_from_cdev_locked(cdev); device = dasd_device_from_cdev_locked(cdev);
if (IS_ERR(device)) if (IS_ERR(device))
return; return;
oldopm = dasd_path_get_opm(device);
for (chp = 0; chp < 8; chp++) { for (chp = 0; chp < 8; chp++) {
eventlpm = 0x80 >> chp;
if (path_event[chp] & PE_PATH_GONE) { if (path_event[chp] & PE_PATH_GONE) {
oldopm = device->path_data.opm; dasd_path_notoper(device, chp);
device->path_data.opm &= ~eventlpm;
device->path_data.ppm &= ~eventlpm;
device->path_data.npm &= ~eventlpm;
if (oldopm && !device->path_data.opm) {
dev_warn(&device->cdev->dev,
"No verified channel paths remain "
"for the device\n");
DBF_DEV_EVENT(DBF_WARNING, device,
"%s", "last verified path gone");
dasd_eer_write(device, NULL, DASD_EER_NOPATH);
dasd_device_set_stop_bits(device,
DASD_STOPPED_DC_WAIT);
}
} }
if (path_event[chp] & PE_PATH_AVAILABLE) { if (path_event[chp] & PE_PATH_AVAILABLE) {
device->path_data.opm &= ~eventlpm; dasd_path_available(device, chp);
device->path_data.ppm &= ~eventlpm;
device->path_data.npm &= ~eventlpm;
device->path_data.tbvpm |= eventlpm;
dasd_schedule_device_bh(device); dasd_schedule_device_bh(device);
} }
if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) { if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) {
if (!(device->path_data.opm & eventlpm) && if (!dasd_path_is_operational(device, chp) &&
!(device->path_data.tbvpm & eventlpm)) { !dasd_path_need_verify(device, chp)) {
/* /*
* we can not establish a pathgroup on an * we can not establish a pathgroup on an
* unavailable path, so trigger a path * unavailable path, so trigger a path
* verification first * verification first
*/ */
device->path_data.tbvpm |= eventlpm; dasd_path_available(device, chp);
dasd_schedule_device_bh(device); dasd_schedule_device_bh(device);
} }
DBF_DEV_EVENT(DBF_WARNING, device, "%s", DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"Pathgroup re-established\n"); "Pathgroup re-established\n");
...@@ -3742,45 +3749,65 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) ...@@ -3742,45 +3749,65 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event)
device->discipline->kick_validate(device); device->discipline->kick_validate(device);
} }
} }
hpfpm = dasd_path_get_hpfpm(device);
ifccpm = dasd_path_get_ifccpm(device);
if (!dasd_path_get_opm(device) && hpfpm) {
/*
* device has no operational paths but at least one path is
* disabled due to HPF errors
* disable HPF at all and use the path(s) again
*/
if (device->discipline->disable_hpf)
device->discipline->disable_hpf(device);
dasd_device_set_stop_bits(device, DASD_STOPPED_NOT_ACC);
dasd_path_set_tbvpm(device, hpfpm);
dasd_schedule_device_bh(device);
dasd_schedule_requeue(device);
} else if (!dasd_path_get_opm(device) && ifccpm) {
/*
* device has no operational paths but at least one path is
* disabled due to IFCC errors
* trigger path verification on paths with IFCC errors
*/
dasd_path_set_tbvpm(device, ifccpm);
dasd_schedule_device_bh(device);
}
if (oldopm && !dasd_path_get_opm(device) && !hpfpm && !ifccpm) {
dev_warn(&device->cdev->dev,
"No verified channel paths remain for the device\n");
DBF_DEV_EVENT(DBF_WARNING, device,
"%s", "last verified path gone");
dasd_eer_write(device, NULL, DASD_EER_NOPATH);
dasd_device_set_stop_bits(device,
DASD_STOPPED_DC_WAIT);
}
dasd_put_device(device); dasd_put_device(device);
} }
EXPORT_SYMBOL_GPL(dasd_generic_path_event); EXPORT_SYMBOL_GPL(dasd_generic_path_event);
int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm) int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm)
{ {
if (!device->path_data.opm && lpm) { if (!dasd_path_get_opm(device) && lpm) {
device->path_data.opm = lpm; dasd_path_set_opm(device, lpm);
dasd_generic_path_operational(device); dasd_generic_path_operational(device);
} else } else
device->path_data.opm |= lpm; dasd_path_add_opm(device, lpm);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(dasd_generic_verify_path); EXPORT_SYMBOL_GPL(dasd_generic_verify_path);
/*
int dasd_generic_pm_freeze(struct ccw_device *cdev) * clear active requests and requeue them to block layer if possible
*/
static int dasd_generic_requeue_all_requests(struct dasd_device *device)
{ {
struct dasd_device *device = dasd_device_from_cdev(cdev); struct list_head requeue_queue;
struct list_head freeze_queue;
struct dasd_ccw_req *cqr, *n; struct dasd_ccw_req *cqr, *n;
struct dasd_ccw_req *refers; struct dasd_ccw_req *refers;
int rc; int rc;
if (IS_ERR(device)) INIT_LIST_HEAD(&requeue_queue);
return PTR_ERR(device); spin_lock_irq(get_ccwdev_lock(device->cdev));
/* mark device as suspended */
set_bit(DASD_FLAG_SUSPENDED, &device->flags);
if (device->discipline->freeze)
rc = device->discipline->freeze(device);
/* disallow new I/O */
dasd_device_set_stop_bits(device, DASD_STOPPED_PM);
/* clear active requests and requeue them to block layer if possible */
INIT_LIST_HEAD(&freeze_queue);
spin_lock_irq(get_ccwdev_lock(cdev));
rc = 0; rc = 0;
list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) { list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
/* Check status and move request to flush_queue */ /* Check status and move request to flush_queue */
...@@ -3791,25 +3818,22 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) ...@@ -3791,25 +3818,22 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
dev_err(&device->cdev->dev, dev_err(&device->cdev->dev,
"Unable to terminate request %p " "Unable to terminate request %p "
"on suspend\n", cqr); "on suspend\n", cqr);
spin_unlock_irq(get_ccwdev_lock(cdev)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
dasd_put_device(device); dasd_put_device(device);
return rc; return rc;
} }
} }
list_move_tail(&cqr->devlist, &freeze_queue); list_move_tail(&cqr->devlist, &requeue_queue);
} }
spin_unlock_irq(get_ccwdev_lock(cdev)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) { list_for_each_entry_safe(cqr, n, &requeue_queue, devlist) {
wait_event(dasd_flush_wq, wait_event(dasd_flush_wq,
(cqr->status != DASD_CQR_CLEAR_PENDING)); (cqr->status != DASD_CQR_CLEAR_PENDING));
if (cqr->status == DASD_CQR_CLEARED)
cqr->status = DASD_CQR_QUEUED;
/* requeue requests to blocklayer will only work for /* mark sleepon requests as ended */
block device requests */ if (cqr->callback_data == DASD_SLEEPON_START_TAG)
if (_dasd_requeue_request(cqr)) cqr->callback_data = DASD_SLEEPON_END_TAG;
continue;
/* remove requests from device and block queue */ /* remove requests from device and block queue */
list_del_init(&cqr->devlist); list_del_init(&cqr->devlist);
...@@ -3821,6 +3845,14 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) ...@@ -3821,6 +3845,14 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
dasd_free_erp_request(cqr, cqr->memdev); dasd_free_erp_request(cqr, cqr->memdev);
cqr = refers; cqr = refers;
} }
/*
* requeue requests to blocklayer will only work
* for block device requests
*/
if (_dasd_requeue_request(cqr))
continue;
if (cqr->block) if (cqr->block)
list_del_init(&cqr->blocklist); list_del_init(&cqr->blocklist);
cqr->block->base->discipline->free_cp( cqr->block->base->discipline->free_cp(
...@@ -3831,15 +3863,56 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) ...@@ -3831,15 +3863,56 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
* if requests remain then they are internal request * if requests remain then they are internal request
* and go back to the device queue * and go back to the device queue
*/ */
if (!list_empty(&freeze_queue)) { if (!list_empty(&requeue_queue)) {
/* move freeze_queue to start of the ccw_queue */ /* move freeze_queue to start of the ccw_queue */
spin_lock_irq(get_ccwdev_lock(cdev)); spin_lock_irq(get_ccwdev_lock(device->cdev));
list_splice_tail(&freeze_queue, &device->ccw_queue); list_splice_tail(&requeue_queue, &device->ccw_queue);
spin_unlock_irq(get_ccwdev_lock(cdev)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
} }
dasd_put_device(device); /* wake up generic waitqueue for eventually ended sleepon requests */
wake_up(&generic_waitq);
return rc; return rc;
} }
static void do_requeue_requests(struct work_struct *work)
{
struct dasd_device *device = container_of(work, struct dasd_device,
requeue_requests);
dasd_generic_requeue_all_requests(device);
dasd_device_remove_stop_bits(device, DASD_STOPPED_NOT_ACC);
if (device->block)
dasd_schedule_block_bh(device->block);
dasd_put_device(device);
}
void dasd_schedule_requeue(struct dasd_device *device)
{
dasd_get_device(device);
/* queue call to dasd_reload_device to the kernel event daemon. */
if (!schedule_work(&device->requeue_requests))
dasd_put_device(device);
}
EXPORT_SYMBOL(dasd_schedule_requeue);
int dasd_generic_pm_freeze(struct ccw_device *cdev)
{
struct dasd_device *device = dasd_device_from_cdev(cdev);
int rc;
if (IS_ERR(device))
return PTR_ERR(device);
/* mark device as suspended */
set_bit(DASD_FLAG_SUSPENDED, &device->flags);
if (device->discipline->freeze)
rc = device->discipline->freeze(device);
/* disallow new I/O */
dasd_device_set_stop_bits(device, DASD_STOPPED_PM);
return dasd_generic_requeue_all_requests(device);
}
EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze); EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze);
int dasd_generic_restore_device(struct ccw_device *cdev) int dasd_generic_restore_device(struct ccw_device *cdev)
......
...@@ -152,7 +152,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) ...@@ -152,7 +152,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
opm = ccw_device_get_path_mask(device->cdev); opm = ccw_device_get_path_mask(device->cdev);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
if (erp->lpm == 0) if (erp->lpm == 0)
erp->lpm = device->path_data.opm & erp->lpm = dasd_path_get_opm(device) &
~(erp->irb.esw.esw0.sublog.lpum); ~(erp->irb.esw.esw0.sublog.lpum);
else else
erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum); erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum);
...@@ -273,7 +273,7 @@ static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp) ...@@ -273,7 +273,7 @@ static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp)
!test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) {
erp->status = DASD_CQR_FILLED; erp->status = DASD_CQR_FILLED;
erp->retries = 10; erp->retries = 10;
erp->lpm = erp->startdev->path_data.opm; erp->lpm = dasd_path_get_opm(erp->startdev);
erp->function = dasd_3990_erp_action_1_sec; erp->function = dasd_3990_erp_action_1_sec;
} }
return erp; return erp;
...@@ -1926,7 +1926,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense) ...@@ -1926,7 +1926,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
!test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) {
/* reset the lpm and the status to be able to /* reset the lpm and the status to be able to
* try further actions. */ * try further actions. */
erp->lpm = erp->startdev->path_data.opm; erp->lpm = dasd_path_get_opm(erp->startdev);
erp->status = DASD_CQR_NEED_ERP; erp->status = DASD_CQR_NEED_ERP;
} }
} }
...@@ -2208,6 +2208,51 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) ...@@ -2208,6 +2208,51 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
} /* end dasd_3990_erp_inspect_32 */ } /* end dasd_3990_erp_inspect_32 */
static void dasd_3990_erp_disable_path(struct dasd_device *device, __u8 lpum)
{
int pos = pathmask_to_pos(lpum);
/* no remaining path, cannot disable */
if (!(dasd_path_get_opm(device) & ~lpum))
return;
dev_err(&device->cdev->dev,
"Path %x.%02x (pathmask %02x) is disabled - IFCC threshold exceeded\n",
device->path[pos].cssid, device->path[pos].chpid, lpum);
dasd_path_remove_opm(device, lpum);
dasd_path_add_ifccpm(device, lpum);
device->path[pos].errorclk = 0;
atomic_set(&device->path[pos].error_count, 0);
}
static void dasd_3990_erp_account_error(struct dasd_ccw_req *erp)
{
struct dasd_device *device = erp->startdev;
__u8 lpum = erp->refers->irb.esw.esw1.lpum;
int pos = pathmask_to_pos(lpum);
unsigned long long clk;
if (!device->path_thrhld)
return;
clk = get_tod_clock();
/*
* check if the last error is longer ago than the timeout,
* if so reset error state
*/
if ((tod_to_ns(clk - device->path[pos].errorclk) / NSEC_PER_SEC)
>= device->path_interval) {
atomic_set(&device->path[pos].error_count, 0);
device->path[pos].errorclk = 0;
}
atomic_inc(&device->path[pos].error_count);
device->path[pos].errorclk = clk;
/* threshold exceeded disable path if possible */
if (atomic_read(&device->path[pos].error_count) >=
device->path_thrhld)
dasd_3990_erp_disable_path(device, lpum);
}
/* /*
***************************************************************************** *****************************************************************************
* main ERP control functions (24 and 32 byte sense) * main ERP control functions (24 and 32 byte sense)
...@@ -2237,6 +2282,7 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp) ...@@ -2237,6 +2282,7 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp)
| SCHN_STAT_CHN_CTRL_CHK)) { | SCHN_STAT_CHN_CTRL_CHK)) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s", DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"channel or interface control check"); "channel or interface control check");
dasd_3990_erp_account_error(erp);
erp = dasd_3990_erp_action_4(erp, NULL); erp = dasd_3990_erp_action_4(erp, NULL);
} }
return erp; return erp;
......
...@@ -725,27 +725,15 @@ static ssize_t dasd_ff_show(struct device *dev, struct device_attribute *attr, ...@@ -725,27 +725,15 @@ static ssize_t dasd_ff_show(struct device *dev, struct device_attribute *attr,
static ssize_t dasd_ff_store(struct device *dev, struct device_attribute *attr, static ssize_t dasd_ff_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dasd_devmap *devmap; unsigned int val;
int val; int rc;
char *endp;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
val = simple_strtoul(buf, &endp, 0); if (kstrtouint(buf, 0, &val) || val > 1)
if (((endp + 1) < (buf + count)) || (val > 1))
return -EINVAL; return -EINVAL;
spin_lock(&dasd_devmap_lock); rc = dasd_set_feature(to_ccwdev(dev), DASD_FEATURE_FAILFAST, val);
if (val)
devmap->features |= DASD_FEATURE_FAILFAST; return rc ? : count;
else
devmap->features &= ~DASD_FEATURE_FAILFAST;
if (devmap->device)
devmap->device->features = devmap->features;
spin_unlock(&dasd_devmap_lock);
return count;
} }
static DEVICE_ATTR(failfast, 0644, dasd_ff_show, dasd_ff_store); static DEVICE_ATTR(failfast, 0644, dasd_ff_show, dasd_ff_store);
...@@ -771,32 +759,41 @@ static ssize_t ...@@ -771,32 +759,41 @@ static ssize_t
dasd_ro_store(struct device *dev, struct device_attribute *attr, dasd_ro_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dasd_devmap *devmap; struct ccw_device *cdev = to_ccwdev(dev);
struct dasd_device *device; struct dasd_device *device;
int val; unsigned long flags;
char *endp; unsigned int val;
int rc;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
val = simple_strtoul(buf, &endp, 0); if (kstrtouint(buf, 0, &val) || val > 1)
if (((endp + 1) < (buf + count)) || (val > 1))
return -EINVAL; return -EINVAL;
spin_lock(&dasd_devmap_lock); rc = dasd_set_feature(cdev, DASD_FEATURE_READONLY, val);
if (val) if (rc)
devmap->features |= DASD_FEATURE_READONLY; return rc;
else
devmap->features &= ~DASD_FEATURE_READONLY; device = dasd_device_from_cdev(cdev);
device = devmap->device; if (IS_ERR(device))
if (device) { return PTR_ERR(device);
device->features = devmap->features;
val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags); spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags);
if (!device->block || !device->block->gdp ||
test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
goto out;
} }
spin_unlock(&dasd_devmap_lock); /* Increase open_count to avoid losing the block device */
if (device && device->block && device->block->gdp) atomic_inc(&device->block->open_count);
set_disk_ro(device->block->gdp, val); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
set_disk_ro(device->block->gdp, val);
atomic_dec(&device->block->open_count);
out:
dasd_put_device(device);
return count; return count;
} }
...@@ -823,27 +820,15 @@ static ssize_t ...@@ -823,27 +820,15 @@ static ssize_t
dasd_erplog_store(struct device *dev, struct device_attribute *attr, dasd_erplog_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dasd_devmap *devmap; unsigned int val;
int val; int rc;
char *endp;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
val = simple_strtoul(buf, &endp, 0); if (kstrtouint(buf, 0, &val) || val > 1)
if (((endp + 1) < (buf + count)) || (val > 1))
return -EINVAL; return -EINVAL;
spin_lock(&dasd_devmap_lock); rc = dasd_set_feature(to_ccwdev(dev), DASD_FEATURE_ERPLOG, val);
if (val)
devmap->features |= DASD_FEATURE_ERPLOG; return rc ? : count;
else
devmap->features &= ~DASD_FEATURE_ERPLOG;
if (devmap->device)
devmap->device->features = devmap->features;
spin_unlock(&dasd_devmap_lock);
return count;
} }
static DEVICE_ATTR(erplog, 0644, dasd_erplog_show, dasd_erplog_store); static DEVICE_ATTR(erplog, 0644, dasd_erplog_show, dasd_erplog_store);
...@@ -871,16 +856,14 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, ...@@ -871,16 +856,14 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dasd_devmap *devmap; struct dasd_devmap *devmap;
unsigned int val;
ssize_t rc; ssize_t rc;
int val;
char *endp;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
if (IS_ERR(devmap)) if (IS_ERR(devmap))
return PTR_ERR(devmap); return PTR_ERR(devmap);
val = simple_strtoul(buf, &endp, 0); if (kstrtouint(buf, 0, &val) || val > 1)
if (((endp + 1) < (buf + count)) || (val > 1))
return -EINVAL; return -EINVAL;
spin_lock(&dasd_devmap_lock); spin_lock(&dasd_devmap_lock);
...@@ -994,10 +977,12 @@ dasd_access_show(struct device *dev, struct device_attribute *attr, ...@@ -994,10 +977,12 @@ dasd_access_show(struct device *dev, struct device_attribute *attr,
if (IS_ERR(device)) if (IS_ERR(device))
return PTR_ERR(device); return PTR_ERR(device);
if (device->discipline->host_access_count) if (!device->discipline)
count = device->discipline->host_access_count(device); count = -ENODEV;
else else if (!device->discipline->host_access_count)
count = -EOPNOTSUPP; count = -EOPNOTSUPP;
else
count = device->discipline->host_access_count(device);
dasd_put_device(device); dasd_put_device(device);
if (count < 0) if (count < 0)
...@@ -1197,27 +1182,25 @@ static ssize_t ...@@ -1197,27 +1182,25 @@ static ssize_t
dasd_eer_store(struct device *dev, struct device_attribute *attr, dasd_eer_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dasd_devmap *devmap; struct dasd_device *device;
int val, rc; unsigned int val;
char *endp; int rc = 0;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); device = dasd_device_from_cdev(to_ccwdev(dev));
if (IS_ERR(devmap)) if (IS_ERR(device))
return PTR_ERR(devmap); return PTR_ERR(device);
if (!devmap->device)
return -ENODEV;
val = simple_strtoul(buf, &endp, 0); if (kstrtouint(buf, 0, &val) || val > 1)
if (((endp + 1) < (buf + count)) || (val > 1))
return -EINVAL; return -EINVAL;
if (val) { if (val)
rc = dasd_eer_enable(devmap->device); rc = dasd_eer_enable(device);
if (rc) else
return rc; dasd_eer_disable(device);
} else
dasd_eer_disable(devmap->device); dasd_put_device(device);
return count;
return rc ? : count;
} }
static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store); static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);
...@@ -1360,6 +1343,50 @@ dasd_timeout_store(struct device *dev, struct device_attribute *attr, ...@@ -1360,6 +1343,50 @@ dasd_timeout_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(timeout, 0644, static DEVICE_ATTR(timeout, 0644,
dasd_timeout_show, dasd_timeout_store); dasd_timeout_show, dasd_timeout_store);
static ssize_t
dasd_path_reset_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dasd_device *device;
unsigned int val;
device = dasd_device_from_cdev(to_ccwdev(dev));
if (IS_ERR(device))
return -ENODEV;
if ((kstrtouint(buf, 16, &val) != 0) || val > 0xff)
val = 0;
if (device->discipline && device->discipline->reset_path)
device->discipline->reset_path(device, (__u8) val);
dasd_put_device(device);
return count;
}
static DEVICE_ATTR(path_reset, 0200, NULL, dasd_path_reset_store);
static ssize_t dasd_hpf_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct dasd_device *device;
int hpf;
device = dasd_device_from_cdev(to_ccwdev(dev));
if (IS_ERR(device))
return -ENODEV;
if (!device->discipline || !device->discipline->hpf_enabled) {
dasd_put_device(device);
return snprintf(buf, PAGE_SIZE, "%d\n", dasd_nofcx);
}
hpf = device->discipline->hpf_enabled(device);
dasd_put_device(device);
return snprintf(buf, PAGE_SIZE, "%d\n", hpf);
}
static DEVICE_ATTR(hpf, 0444, dasd_hpf_show, NULL);
static ssize_t dasd_reservation_policy_show(struct device *dev, static ssize_t dasd_reservation_policy_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
...@@ -1385,27 +1412,17 @@ static ssize_t dasd_reservation_policy_store(struct device *dev, ...@@ -1385,27 +1412,17 @@ static ssize_t dasd_reservation_policy_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct dasd_devmap *devmap; struct ccw_device *cdev = to_ccwdev(dev);
int rc; int rc;
devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
if (IS_ERR(devmap))
return PTR_ERR(devmap);
rc = 0;
spin_lock(&dasd_devmap_lock);
if (sysfs_streq("ignore", buf)) if (sysfs_streq("ignore", buf))
devmap->features &= ~DASD_FEATURE_FAILONSLCK; rc = dasd_set_feature(cdev, DASD_FEATURE_FAILONSLCK, 0);
else if (sysfs_streq("fail", buf)) else if (sysfs_streq("fail", buf))
devmap->features |= DASD_FEATURE_FAILONSLCK; rc = dasd_set_feature(cdev, DASD_FEATURE_FAILONSLCK, 1);
else else
rc = -EINVAL; rc = -EINVAL;
if (devmap->device)
devmap->device->features = devmap->features; return rc ? : count;
spin_unlock(&dasd_devmap_lock);
if (rc)
return rc;
else
return count;
} }
static DEVICE_ATTR(reservation_policy, 0644, static DEVICE_ATTR(reservation_policy, 0644,
...@@ -1461,25 +1478,120 @@ static ssize_t dasd_pm_show(struct device *dev, ...@@ -1461,25 +1478,120 @@ static ssize_t dasd_pm_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct dasd_device *device; struct dasd_device *device;
u8 opm, nppm, cablepm, cuirpm, hpfpm; u8 opm, nppm, cablepm, cuirpm, hpfpm, ifccpm;
device = dasd_device_from_cdev(to_ccwdev(dev)); device = dasd_device_from_cdev(to_ccwdev(dev));
if (IS_ERR(device)) if (IS_ERR(device))
return sprintf(buf, "0\n"); return sprintf(buf, "0\n");
opm = device->path_data.opm; opm = dasd_path_get_opm(device);
nppm = device->path_data.npm; nppm = dasd_path_get_nppm(device);
cablepm = device->path_data.cablepm; cablepm = dasd_path_get_cablepm(device);
cuirpm = device->path_data.cuirpm; cuirpm = dasd_path_get_cuirpm(device);
hpfpm = device->path_data.hpfpm; hpfpm = dasd_path_get_hpfpm(device);
ifccpm = dasd_path_get_ifccpm(device);
dasd_put_device(device); dasd_put_device(device);
return sprintf(buf, "%02x %02x %02x %02x %02x\n", opm, nppm, return sprintf(buf, "%02x %02x %02x %02x %02x %02x\n", opm, nppm,
cablepm, cuirpm, hpfpm); cablepm, cuirpm, hpfpm, ifccpm);
} }
static DEVICE_ATTR(path_masks, 0444, dasd_pm_show, NULL); static DEVICE_ATTR(path_masks, 0444, dasd_pm_show, NULL);
/*
* threshold value for IFCC/CCC errors
*/
static ssize_t
dasd_path_threshold_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct dasd_device *device;
int len;
device = dasd_device_from_cdev(to_ccwdev(dev));
if (IS_ERR(device))
return -ENODEV;
len = snprintf(buf, PAGE_SIZE, "%lu\n", device->path_thrhld);
dasd_put_device(device);
return len;
}
static ssize_t
dasd_path_threshold_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dasd_device *device;
unsigned long flags;
unsigned long val;
device = dasd_device_from_cdev(to_ccwdev(dev));
if (IS_ERR(device))
return -ENODEV;
if ((kstrtoul(buf, 10, &val) != 0) ||
(val > DASD_THRHLD_MAX) || val == 0) {
dasd_put_device(device);
return -EINVAL;
}
spin_lock_irqsave(get_ccwdev_lock(to_ccwdev(dev)), flags);
if (val)
device->path_thrhld = val;
spin_unlock_irqrestore(get_ccwdev_lock(to_ccwdev(dev)), flags);
dasd_put_device(device);
return count;
}
static DEVICE_ATTR(path_threshold, 0644, dasd_path_threshold_show,
dasd_path_threshold_store);
/*
* interval for IFCC/CCC checks
* meaning time with no IFCC/CCC error before the error counter
* gets reset
*/
static ssize_t
dasd_path_interval_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct dasd_device *device;
int len;
device = dasd_device_from_cdev(to_ccwdev(dev));
if (IS_ERR(device))
return -ENODEV;
len = snprintf(buf, PAGE_SIZE, "%lu\n", device->path_interval);
dasd_put_device(device);
return len;
}
static ssize_t
dasd_path_interval_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dasd_device *device;
unsigned long flags;
unsigned long val;
device = dasd_device_from_cdev(to_ccwdev(dev));
if (IS_ERR(device))
return -ENODEV;
if ((kstrtoul(buf, 10, &val) != 0) ||
(val > DASD_INTERVAL_MAX) || val == 0) {
dasd_put_device(device);
return -EINVAL;
}
spin_lock_irqsave(get_ccwdev_lock(to_ccwdev(dev)), flags);
if (val)
device->path_interval = val;
spin_unlock_irqrestore(get_ccwdev_lock(to_ccwdev(dev)), flags);
dasd_put_device(device);
return count;
}
static DEVICE_ATTR(path_interval, 0644, dasd_path_interval_show,
dasd_path_interval_store);
static struct attribute * dasd_attrs[] = { static struct attribute * dasd_attrs[] = {
&dev_attr_readonly.attr, &dev_attr_readonly.attr,
&dev_attr_discipline.attr, &dev_attr_discipline.attr,
...@@ -1500,6 +1612,10 @@ static struct attribute * dasd_attrs[] = { ...@@ -1500,6 +1612,10 @@ static struct attribute * dasd_attrs[] = {
&dev_attr_safe_offline.attr, &dev_attr_safe_offline.attr,
&dev_attr_host_access_count.attr, &dev_attr_host_access_count.attr,
&dev_attr_path_masks.attr, &dev_attr_path_masks.attr,
&dev_attr_path_threshold.attr,
&dev_attr_path_interval.attr,
&dev_attr_path_reset.attr,
&dev_attr_hpf.attr,
NULL, NULL,
}; };
...@@ -1531,7 +1647,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag) ...@@ -1531,7 +1647,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
{ {
struct dasd_devmap *devmap; struct dasd_devmap *devmap;
devmap = dasd_find_busid(dev_name(&cdev->dev)); devmap = dasd_devmap_from_cdev(cdev);
if (IS_ERR(devmap)) if (IS_ERR(devmap))
return PTR_ERR(devmap); return PTR_ERR(devmap);
......
此差异已折叠。
...@@ -94,6 +94,8 @@ ...@@ -94,6 +94,8 @@
#define FCX_MAX_DATA_FACTOR 65536 #define FCX_MAX_DATA_FACTOR 65536
#define DASD_ECKD_RCD_DATA_SIZE 256 #define DASD_ECKD_RCD_DATA_SIZE 256
#define DASD_ECKD_PATH_THRHLD 256
#define DASD_ECKD_PATH_INTERVAL 300
/***************************************************************************** /*****************************************************************************
* SECTION: Type Definitions * SECTION: Type Definitions
...@@ -535,8 +537,7 @@ struct dasd_eckd_private { ...@@ -535,8 +537,7 @@ struct dasd_eckd_private {
struct dasd_eckd_characteristics rdc_data; struct dasd_eckd_characteristics rdc_data;
u8 *conf_data; u8 *conf_data;
int conf_len; int conf_len;
/* per path configuration data */
struct dasd_conf_data *path_conf_data[8];
/* pointers to specific parts in the conf_data */ /* pointers to specific parts in the conf_data */
struct dasd_ned *ned; struct dasd_ned *ned;
struct dasd_sneq *sneq; struct dasd_sneq *sneq;
......
此差异已折叠。
...@@ -96,7 +96,7 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr) ...@@ -96,7 +96,7 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr)
"default ERP called (%i retries left)", "default ERP called (%i retries left)",
cqr->retries); cqr->retries);
if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))
cqr->lpm = device->path_data.opm; cqr->lpm = dasd_path_get_opm(device);
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
} else { } else {
pr_err("%s: default ERP has run out of retries and failed\n", pr_err("%s: default ERP has run out of retries and failed\n",
......
...@@ -168,7 +168,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) ...@@ -168,7 +168,7 @@ dasd_fba_check_characteristics(struct dasd_device *device)
device->default_expires = DASD_EXPIRES; device->default_expires = DASD_EXPIRES;
device->default_retries = FBA_DEFAULT_RETRIES; device->default_retries = FBA_DEFAULT_RETRIES;
device->path_data.opm = LPM_ANYPATH; dasd_path_set_opm(device, LPM_ANYPATH);
readonly = dasd_device_is_ro(device); readonly = dasd_device_is_ro(device);
if (readonly) if (readonly)
......
此差异已折叠。
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
* Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu> * Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu>
*/ */
#include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#include <linux/tty.h> #include <linux/tty.h>
...@@ -1215,13 +1214,4 @@ static int __init tty3215_init(void) ...@@ -1215,13 +1214,4 @@ static int __init tty3215_init(void)
tty3215_driver = driver; tty3215_driver = driver;
return 0; return 0;
} }
device_initcall(tty3215_init);
static void __exit tty3215_exit(void)
{
tty_unregister_driver(tty3215_driver);
put_tty_driver(tty3215_driver);
ccw_driver_unregister(&raw3215_ccw_driver);
}
module_init(tty3215_init);
module_exit(tty3215_exit);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -870,7 +870,7 @@ static int __init vmlogrdr_init(void) ...@@ -870,7 +870,7 @@ static int __init vmlogrdr_init(void)
goto cleanup; goto cleanup;
for (i=0; i < MAXMINOR; ++i ) { for (i=0; i < MAXMINOR; ++i ) {
sys_ser[i].buffer = (char *) get_zeroed_page(GFP_KERNEL); sys_ser[i].buffer = (char *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!sys_ser[i].buffer) { if (!sys_ser[i].buffer) {
rc = -ENOMEM; rc = -ENOMEM;
break; break;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册