Commit 6daa755f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 's390-5.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Heiko Carstens:

 - fix buffer size for in-kernel disassembler for ebpf programs.

 - fix two memory leaks in zcrypt driver.

 - expose PCI device UID as index, including an indicator if the uid is
   unique.

 - remove some oprofile leftovers.

 - improve stack unwinder tests.

 - don't use gcc atomic builtins anymore, just like all other
   architectures. Even though I'm sure the current code is ok, I totally
   dislike that s390 is the only architecture being special here;
   especially considering that there was a lengthly discussion about
   this topic and the outcome was not to use the builtins. Therefore
   open-code atomic ops again with inline assembly and switch to gcc
   builtins as soon as other architectures are doing.

 - couple of other changes to atomic and cmpxchg, and use
   atomic-instrumented.h for KASAN.

 - separate zbus creation, registration, and scanning in our PCI code
   which allows for cleaner and easier handling.

 - a rather large change to the vfio-ap code to fix circular locking
   dependencies when updating crypto masks.

 - move QAOB handling from qdio layer down to drivers.

 - add CRW inject facility to common I/O layer. This adds debugs files
   which allow to generate artificial events from user space for testing
   purposes.

 - increase SCLP console line length from 80 to 320 characters to avoid
   odd wrapped lines.

 - add protected virtualization guest and host indication files, which
   indicate either that a guest is running in pv mode or if the
   hypervisor is capable of starting pv guests.

 - various other small fixes and improvements all over the place.

* tag 's390-5.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (53 commits)
  s390/disassembler: increase ebpf disasm buffer size
  s390/archrandom: add parameter check for s390_arch_random_generate
  s390/zcrypt: fix zcard and zqueue hot-unplug memleak
  s390/pci: expose a PCI device's UID as its index
  s390/atomic,cmpxchg: always inline __xchg/__cmpxchg
  s390/smp: fix do_restart() prototype
  s390: get rid of oprofile leftovers
  s390/atomic,cmpxchg: make constraints work with old compilers
  s390/test_unwind: print test suite start/end info
  s390/cmpxchg: use unsigned long values instead of void pointers
  s390/test_unwind: add WARN if tests failed
  s390/test_unwind: unify error handling paths
  s390: update defconfigs
  s390/spinlock: use R constraint in inline assembly
  s390/atomic,cmpxchg: switch to use atomic-instrumented.h
  s390/cmpxchg: get rid of gcc atomic builtins
  s390/atomic: get rid of gcc atomic builtins
  s390/atomic: use proper constraints
  s390/atomic: move remaining inline assemblies to atomic_ops.h
  s390/bitops: make bitops only work on longs
  ...
parents c6536676 6f3353c2
......@@ -195,10 +195,13 @@ What: /sys/bus/pci/devices/.../index
Date: July 2010
Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
Description:
Reading this attribute will provide the firmware
given instance (SMBIOS type 41 device type instance) of the
PCI device. The attribute will be created only if the firmware
has given an instance number to the PCI device.
Reading this attribute will provide the firmware given instance
number of the PCI device. Depending on the platform this can
be for example the SMBIOS type 41 device type instance or the
user-defined ID (UID) on s390. The attribute will be created
only if the firmware has given an instance number to the PCI
device and that number is guaranteed to uniquely identify the
device in the system.
Users:
Userspace applications interested in knowing the
firmware assigned device type instance of the PCI
......
......@@ -50,7 +50,8 @@ Entries specific to zPCI functions and entries that hold zPCI information.
* /sys/bus/pci/slots/XXXXXXXX
The slot entries are set up using the function identifier (FID) of the
PCI function.
PCI function. The format depicted as XXXXXXXX above is 8 hexadecimal digits
with 0 padding and lower case hexadecimal digitis.
- /sys/bus/pci/slots/XXXXXXXX/power
......@@ -88,8 +89,15 @@ Entries specific to zPCI functions and entries that hold zPCI information.
is attached to.
- uid
The unique identifier (UID) is defined when configuring an LPAR and is
unique in the LPAR.
The user identifier (UID) may be defined as part of the machine
configuration or the z/VM or KVM guest configuration. If the accompanying
uid_is_unique attribute is 1 the platform guarantees that the UID is unique
within that instance and no devices with the same UID can be attached
during the lifetime of the system.
- uid_is_unique
Indicates whether the user identifier (UID) is guaranteed to be and remain
unique within this Linux instance.
- pfip/segmentX
The segments determine the isolation of a function.
......
......@@ -15,3 +15,11 @@ config DEBUG_ENTRY
exits or otherwise impact performance.
If unsure, say N.
config CIO_INJECT
bool "CIO Inject interfaces"
depends on DEBUG_KERNEL && DEBUG_FS
help
This option provides a debugging facility to inject certain artificial events
and instruction responses to the CIO layer of Linux kernel. The newly created
debugfs user-interfaces will be at /sys/kernel/debug/s390/cio/*
......@@ -771,7 +771,6 @@ CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_GDB_SCRIPTS=y
CONFIG_FRAME_WARN=1024
CONFIG_HEADERS_INSTALL=y
CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_MAGIC_SYSRQ=y
......@@ -829,6 +828,7 @@ CONFIG_HIST_TRIGGERS=y
CONFIG_FTRACE_STARTUP_TEST=y
# CONFIG_EVENT_TRACE_STARTUP_TEST is not set
CONFIG_DEBUG_ENTRY=y
CONFIG_CIO_INJECT=y
CONFIG_NOTIFIER_ERROR_INJECTION=m
CONFIG_NETDEV_NOTIFIER_ERROR_INJECT=m
CONFIG_FAULT_INJECTION=y
......
......@@ -756,7 +756,6 @@ CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_GDB_SCRIPTS=y
CONFIG_FRAME_WARN=1024
CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_WX=y
......
......@@ -54,6 +54,10 @@ static DECLARE_DELAYED_WORK(arch_rng_work, arch_rng_refill_buffer);
bool s390_arch_random_generate(u8 *buf, unsigned int nbytes)
{
/* max hunk is ARCH_RNG_BUF_SIZE */
if (nbytes > ARCH_RNG_BUF_SIZE)
return false;
/* lock rng buffer */
if (!spin_trylock(&arch_rng_lock))
return false;
......
......@@ -32,7 +32,7 @@
* process particular chunks of the input data stream in parallel.
*
* For the CRC-32 variants, the constants are precomputed according to
* these defintions:
* these definitions:
*
* R1 = x4*128+64 mod P(x)
* R2 = x4*128 mod P(x)
......@@ -189,7 +189,7 @@ ENTRY(crc32_be_vgfm_16)
* Note: To compensate the division by x^32, use the vector unpack
* instruction to move the leftmost word into the leftmost doubleword
* of the vector register. The rightmost doubleword is multiplied
* with zero to not contribute to the intermedate results.
* with zero to not contribute to the intermediate results.
*/
/* T1(x) = floor( R(x) / x^32 ) GF2MUL u */
......
......@@ -15,48 +15,46 @@
#include <asm/barrier.h>
#include <asm/cmpxchg.h>
static inline int atomic_read(const atomic_t *v)
static inline int arch_atomic_read(const atomic_t *v)
{
int c;
asm volatile(
" l %0,%1\n"
: "=d" (c) : "Q" (v->counter));
return c;
return __atomic_read(v);
}
#define arch_atomic_read arch_atomic_read
static inline void atomic_set(atomic_t *v, int i)
static inline void arch_atomic_set(atomic_t *v, int i)
{
asm volatile(
" st %1,%0\n"
: "=Q" (v->counter) : "d" (i));
__atomic_set(v, i);
}
#define arch_atomic_set arch_atomic_set
static inline int atomic_add_return(int i, atomic_t *v)
static inline int arch_atomic_add_return(int i, atomic_t *v)
{
return __atomic_add_barrier(i, &v->counter) + i;
}
#define arch_atomic_add_return arch_atomic_add_return
static inline int atomic_fetch_add(int i, atomic_t *v)
static inline int arch_atomic_fetch_add(int i, atomic_t *v)
{
return __atomic_add_barrier(i, &v->counter);
}
#define arch_atomic_fetch_add arch_atomic_fetch_add
static inline void atomic_add(int i, atomic_t *v)
static inline void arch_atomic_add(int i, atomic_t *v)
{
__atomic_add(i, &v->counter);
}
#define arch_atomic_add arch_atomic_add
#define atomic_sub(_i, _v) atomic_add(-(int)(_i), _v)
#define atomic_sub_return(_i, _v) atomic_add_return(-(int)(_i), _v)
#define atomic_fetch_sub(_i, _v) atomic_fetch_add(-(int)(_i), _v)
#define arch_atomic_sub(_i, _v) arch_atomic_add(-(int)(_i), _v)
#define arch_atomic_sub_return(_i, _v) arch_atomic_add_return(-(int)(_i), _v)
#define arch_atomic_fetch_sub(_i, _v) arch_atomic_fetch_add(-(int)(_i), _v)
#define ATOMIC_OPS(op) \
static inline void atomic_##op(int i, atomic_t *v) \
static inline void arch_atomic_##op(int i, atomic_t *v) \
{ \
__atomic_##op(i, &v->counter); \
} \
static inline int atomic_fetch_##op(int i, atomic_t *v) \
static inline int arch_atomic_fetch_##op(int i, atomic_t *v) \
{ \
return __atomic_##op##_barrier(i, &v->counter); \
}
......@@ -67,60 +65,67 @@ ATOMIC_OPS(xor)
#undef ATOMIC_OPS
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
#define arch_atomic_and arch_atomic_and
#define arch_atomic_or arch_atomic_or
#define arch_atomic_xor arch_atomic_xor
#define arch_atomic_fetch_and arch_atomic_fetch_and
#define arch_atomic_fetch_or arch_atomic_fetch_or
#define arch_atomic_fetch_xor arch_atomic_fetch_xor
#define arch_atomic_xchg(v, new) (arch_xchg(&((v)->counter), new))
static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
static inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
{
return __atomic_cmpxchg(&v->counter, old, new);
}
#define arch_atomic_cmpxchg arch_atomic_cmpxchg
#define ATOMIC64_INIT(i) { (i) }
static inline s64 atomic64_read(const atomic64_t *v)
static inline s64 arch_atomic64_read(const atomic64_t *v)
{
s64 c;
asm volatile(
" lg %0,%1\n"
: "=d" (c) : "Q" (v->counter));
return c;
return __atomic64_read(v);
}
#define arch_atomic64_read arch_atomic64_read
static inline void atomic64_set(atomic64_t *v, s64 i)
static inline void arch_atomic64_set(atomic64_t *v, s64 i)
{
asm volatile(
" stg %1,%0\n"
: "=Q" (v->counter) : "d" (i));
__atomic64_set(v, i);
}
#define arch_atomic64_set arch_atomic64_set
static inline s64 atomic64_add_return(s64 i, atomic64_t *v)
static inline s64 arch_atomic64_add_return(s64 i, atomic64_t *v)
{
return __atomic64_add_barrier(i, (long *)&v->counter) + i;
}
#define arch_atomic64_add_return arch_atomic64_add_return
static inline s64 atomic64_fetch_add(s64 i, atomic64_t *v)
static inline s64 arch_atomic64_fetch_add(s64 i, atomic64_t *v)
{
return __atomic64_add_barrier(i, (long *)&v->counter);
}
#define arch_atomic64_fetch_add arch_atomic64_fetch_add
static inline void atomic64_add(s64 i, atomic64_t *v)
static inline void arch_atomic64_add(s64 i, atomic64_t *v)
{
__atomic64_add(i, (long *)&v->counter);
}
#define arch_atomic64_add arch_atomic64_add
#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
#define arch_atomic64_xchg(v, new) (arch_xchg(&((v)->counter), new))
static inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
static inline s64 arch_atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
{
return __atomic64_cmpxchg((long *)&v->counter, old, new);
}
#define arch_atomic64_cmpxchg arch_atomic64_cmpxchg
#define ATOMIC64_OPS(op) \
static inline void atomic64_##op(s64 i, atomic64_t *v) \
static inline void arch_atomic64_##op(s64 i, atomic64_t *v) \
{ \
__atomic64_##op(i, (long *)&v->counter); \
} \
static inline long atomic64_fetch_##op(s64 i, atomic64_t *v) \
static inline long arch_atomic64_fetch_##op(s64 i, atomic64_t *v) \
{ \
return __atomic64_##op##_barrier(i, (long *)&v->counter); \
}
......@@ -131,8 +136,17 @@ ATOMIC64_OPS(xor)
#undef ATOMIC64_OPS
#define atomic64_sub_return(_i, _v) atomic64_add_return(-(s64)(_i), _v)
#define atomic64_fetch_sub(_i, _v) atomic64_fetch_add(-(s64)(_i), _v)
#define atomic64_sub(_i, _v) atomic64_add(-(s64)(_i), _v)
#define arch_atomic64_and arch_atomic64_and
#define arch_atomic64_or arch_atomic64_or
#define arch_atomic64_xor arch_atomic64_xor
#define arch_atomic64_fetch_and arch_atomic64_fetch_and
#define arch_atomic64_fetch_or arch_atomic64_fetch_or
#define arch_atomic64_fetch_xor arch_atomic64_fetch_xor
#define arch_atomic64_sub_return(_i, _v) arch_atomic64_add_return(-(s64)(_i), _v)
#define arch_atomic64_fetch_sub(_i, _v) arch_atomic64_fetch_add(-(s64)(_i), _v)
#define arch_atomic64_sub(_i, _v) arch_atomic64_add(-(s64)(_i), _v)
#define ARCH_ATOMIC
#endif /* __ARCH_S390_ATOMIC__ */
......@@ -8,6 +8,40 @@
#ifndef __ARCH_S390_ATOMIC_OPS__
#define __ARCH_S390_ATOMIC_OPS__
static inline int __atomic_read(const atomic_t *v)
{
int c;
asm volatile(
" l %0,%1\n"
: "=d" (c) : "R" (v->counter));
return c;
}
static inline void __atomic_set(atomic_t *v, int i)
{
asm volatile(
" st %1,%0\n"
: "=R" (v->counter) : "d" (i));
}
static inline s64 __atomic64_read(const atomic64_t *v)
{
s64 c;
asm volatile(
" lg %0,%1\n"
: "=d" (c) : "RT" (v->counter));
return c;
}
static inline void __atomic64_set(atomic64_t *v, s64 i)
{
asm volatile(
" stg %1,%0\n"
: "=RT" (v->counter) : "d" (i));
}
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
#define __ATOMIC_OP(op_name, op_type, op_string, op_barrier) \
......@@ -18,7 +52,7 @@ static inline op_type op_name(op_type val, op_type *ptr) \
asm volatile( \
op_string " %[old],%[val],%[ptr]\n" \
op_barrier \
: [old] "=d" (old), [ptr] "+Q" (*ptr) \
: [old] "=d" (old), [ptr] "+QS" (*ptr) \
: [val] "d" (val) : "cc", "memory"); \
return old; \
} \
......@@ -46,7 +80,7 @@ static __always_inline void op_name(op_type val, op_type *ptr) \
asm volatile( \
op_string " %[ptr],%[val]\n" \
op_barrier \
: [ptr] "+Q" (*ptr) : [val] "i" (val) : "cc", "memory");\
: [ptr] "+QS" (*ptr) : [val] "i" (val) : "cc", "memory");\
}
#define __ATOMIC_CONST_OPS(op_name, op_type, op_string) \
......@@ -97,7 +131,7 @@ static inline long op_name(long val, long *ptr) \
op_string " %[new],%[val]\n" \
" csg %[old],%[new],%[ptr]\n" \
" jl 0b" \
: [old] "=d" (old), [new] "=&d" (new), [ptr] "+Q" (*ptr)\
: [old] "=d" (old), [new] "=&d" (new), [ptr] "+QS" (*ptr)\
: [val] "d" (val), "0" (*ptr) : "cc", "memory"); \
return old; \
}
......@@ -122,22 +156,46 @@ __ATOMIC64_OPS(__atomic64_xor, "xgr")
static inline int __atomic_cmpxchg(int *ptr, int old, int new)
{
return __sync_val_compare_and_swap(ptr, old, new);
asm volatile(
" cs %[old],%[new],%[ptr]"
: [old] "+d" (old), [ptr] "+Q" (*ptr)
: [new] "d" (new)
: "cc", "memory");
return old;
}
static inline int __atomic_cmpxchg_bool(int *ptr, int old, int new)
static inline bool __atomic_cmpxchg_bool(int *ptr, int old, int new)
{
return __sync_bool_compare_and_swap(ptr, old, new);
int old_expected = old;
asm volatile(
" cs %[old],%[new],%[ptr]"
: [old] "+d" (old), [ptr] "+Q" (*ptr)
: [new] "d" (new)
: "cc", "memory");
return old == old_expected;
}
static inline long __atomic64_cmpxchg(long *ptr, long old, long new)
{
return __sync_val_compare_and_swap(ptr, old, new);
asm volatile(
" csg %[old],%[new],%[ptr]"
: [old] "+d" (old), [ptr] "+QS" (*ptr)
: [new] "d" (new)
: "cc", "memory");
return old;
}
static inline long __atomic64_cmpxchg_bool(long *ptr, long old, long new)
static inline bool __atomic64_cmpxchg_bool(long *ptr, long old, long new)
{
return __sync_bool_compare_and_swap(ptr, old, new);
long old_expected = old;
asm volatile(
" csg %[old],%[new],%[ptr]"
: [old] "+d" (old), [ptr] "+QS" (*ptr)
: [new] "d" (new)
: "cc", "memory");
return old == old_expected;
}
#endif /* __ARCH_S390_ATOMIC_OPS__ */
......@@ -42,7 +42,7 @@
#define __BITOPS_WORDS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
static inline unsigned long *
__bitops_word(unsigned long nr, volatile unsigned long *ptr)
__bitops_word(unsigned long nr, const volatile unsigned long *ptr)
{
unsigned long addr;
......@@ -50,37 +50,33 @@ __bitops_word(unsigned long nr, volatile unsigned long *ptr)
return (unsigned long *)addr;
}
static inline unsigned char *
__bitops_byte(unsigned long nr, volatile unsigned long *ptr)
static inline unsigned long __bitops_mask(unsigned long nr)
{
return ((unsigned char *)ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
return 1UL << (nr & (BITS_PER_LONG - 1));
}
static __always_inline void arch_set_bit(unsigned long nr, volatile unsigned long *ptr)
{
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask;
unsigned long mask = __bitops_mask(nr);
mask = 1UL << (nr & (BITS_PER_LONG - 1));
__atomic64_or(mask, (long *)addr);
}
static __always_inline void arch_clear_bit(unsigned long nr, volatile unsigned long *ptr)
{
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask;
unsigned long mask = __bitops_mask(nr);
mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
__atomic64_and(mask, (long *)addr);
__atomic64_and(~mask, (long *)addr);
}
static __always_inline void arch_change_bit(unsigned long nr,
volatile unsigned long *ptr)
{
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask;
unsigned long mask = __bitops_mask(nr);
mask = 1UL << (nr & (BITS_PER_LONG - 1));
__atomic64_xor(mask, (long *)addr);
}
......@@ -88,99 +84,104 @@ static inline bool arch_test_and_set_bit(unsigned long nr,
volatile unsigned long *ptr)
{
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long old, mask;
unsigned long mask = __bitops_mask(nr);
unsigned long old;
mask = 1UL << (nr & (BITS_PER_LONG - 1));
old = __atomic64_or_barrier(mask, (long *)addr);
return (old & mask) != 0;
return old & mask;
}
static inline bool arch_test_and_clear_bit(unsigned long nr,
volatile unsigned long *ptr)
{
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long old, mask;
unsigned long mask = __bitops_mask(nr);
unsigned long old;
mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
old = __atomic64_and_barrier(mask, (long *)addr);
return (old & ~mask) != 0;
old = __atomic64_and_barrier(~mask, (long *)addr);
return old & mask;
}
static inline bool arch_test_and_change_bit(unsigned long nr,
volatile unsigned long *ptr)
{
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long old, mask;
unsigned long mask = __bitops_mask(nr);
unsigned long old;
mask = 1UL << (nr & (BITS_PER_LONG - 1));
old = __atomic64_xor_barrier(mask, (long *)addr);
return (old & mask) != 0;
return old & mask;
}
static inline void arch___set_bit(unsigned long nr, volatile unsigned long *ptr)
{
unsigned char *addr = __bitops_byte(nr, ptr);
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask = __bitops_mask(nr);
*addr |= 1 << (nr & 7);
*addr |= mask;
}
static inline void arch___clear_bit(unsigned long nr,
volatile unsigned long *ptr)
{
unsigned char *addr = __bitops_byte(nr, ptr);
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask = __bitops_mask(nr);
*addr &= ~(1 << (nr & 7));
*addr &= ~mask;
}
static inline void arch___change_bit(unsigned long nr,
volatile unsigned long *ptr)
{
unsigned char *addr = __bitops_byte(nr, ptr);
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask = __bitops_mask(nr);
*addr ^= 1 << (nr & 7);
*addr ^= mask;
}
static inline bool arch___test_and_set_bit(unsigned long nr,
volatile unsigned long *ptr)
{
unsigned char *addr = __bitops_byte(nr, ptr);
unsigned char ch;
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask = __bitops_mask(nr);
unsigned long old;
ch = *addr;
*addr |= 1 << (nr & 7);
return (ch >> (nr & 7)) & 1;
old = *addr;
*addr |= mask;
return old & mask;
}
static inline bool arch___test_and_clear_bit(unsigned long nr,
volatile unsigned long *ptr)
{
unsigned char *addr = __bitops_byte(nr, ptr);
unsigned char ch;
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask = __bitops_mask(nr);
unsigned long old;
ch = *addr;
*addr &= ~(1 << (nr & 7));
return (ch >> (nr & 7)) & 1;
old = *addr;
*addr &= ~mask;
return old & mask;
}
static inline bool arch___test_and_change_bit(unsigned long nr,
volatile unsigned long *ptr)
{
unsigned char *addr = __bitops_byte(nr, ptr);
unsigned char ch;
unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask = __bitops_mask(nr);
unsigned long old;
ch = *addr;
*addr ^= 1 << (nr & 7);
return (ch >> (nr & 7)) & 1;
old = *addr;
*addr ^= mask;
return old & mask;
}
static inline bool arch_test_bit(unsigned long nr,
const volatile unsigned long *ptr)
{
const volatile unsigned char *addr;
const volatile unsigned long *addr = __bitops_word(nr, ptr);
unsigned long mask = __bitops_mask(nr);
addr = ((const volatile unsigned char *)ptr);
addr += (nr ^ (BITS_PER_LONG - 8)) >> 3;
return (*addr >> (nr & 7)) & 1;
return *addr & mask;
}
static inline bool arch_test_and_set_bit_lock(unsigned long nr,
......
......@@ -152,9 +152,6 @@ extern struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
* when new devices for its type pop up */
extern int ccw_driver_register (struct ccw_driver *driver);
extern void ccw_driver_unregister (struct ccw_driver *driver);
struct ccw1;
extern int ccw_device_set_options_mask(struct ccw_device *, unsigned long);
extern int ccw_device_set_options(struct ccw_device *, unsigned long);
extern void ccw_device_clear_options(struct ccw_device *, unsigned long);
......
......@@ -12,27 +12,163 @@
#include <linux/types.h>
#include <linux/bug.h>
#define cmpxchg(ptr, o, n) \
void __xchg_called_with_bad_pointer(void);
static __always_inline unsigned long __xchg(unsigned long x,
unsigned long address, int size)
{
unsigned long old;
int shift;
switch (size) {
case 1:
shift = (3 ^ (address & 3)) << 3;
address ^= address & 3;
asm volatile(
" l %0,%1\n"
"0: lr 0,%0\n"
" nr 0,%3\n"
" or 0,%2\n"
" cs %0,0,%1\n"
" jl 0b\n"
: "=&d" (old), "+Q" (*(int *) address)
: "d" ((x & 0xff) << shift), "d" (~(0xff << shift))
: "memory", "cc", "0");
return old >> shift;
case 2:
shift = (2 ^ (address & 2)) << 3;
address ^= address & 2;
asm volatile(
" l %0,%1\n"
"0: lr 0,%0\n"
" nr 0,%3\n"
" or 0,%2\n"
" cs %0,0,%1\n"
" jl 0b\n"
: "=&d" (old), "+Q" (*(int *) address)
: "d" ((x & 0xffff) << shift), "d" (~(0xffff << shift))
: "memory", "cc", "0");
return old >> shift;
case 4:
asm volatile(
" l %0,%1\n"
"0: cs %0,%2,%1\n"
" jl 0b\n"
: "=&d" (old), "+Q" (*(int *) address)
: "d" (x)
: "memory", "cc");
return old;
case 8:
asm volatile(
" lg %0,%1\n"
"0: csg %0,%2,%1\n"
" jl 0b\n"
: "=&d" (old), "+QS" (*(long *) address)
: "d" (x)
: "memory", "cc");
return old;
}
__xchg_called_with_bad_pointer();
return x;
}
#define arch_xchg(ptr, x) \
({ \
__typeof__(*(ptr)) __o = (o); \
__typeof__(*(ptr)) __n = (n); \
(__typeof__(*(ptr))) __sync_val_compare_and_swap((ptr),__o,__n);\
__typeof__(*(ptr)) __ret; \
\
__ret = (__typeof__(*(ptr))) \
__xchg((unsigned long)(x), (unsigned long)(ptr), \
sizeof(*(ptr))); \
__ret; \
})
#define cmpxchg64 cmpxchg
#define cmpxchg_local cmpxchg
#define cmpxchg64_local cmpxchg
void __cmpxchg_called_with_bad_pointer(void);
static __always_inline unsigned long __cmpxchg(unsigned long address,
unsigned long old,
unsigned long new, int size)
{
unsigned long prev, tmp;
int shift;
switch (size) {
case 1:
shift = (3 ^ (address & 3)) << 3;
address ^= address & 3;
asm volatile(
" l %0,%2\n"
"0: nr %0,%5\n"
" lr %1,%0\n"
" or %0,%3\n"
" or %1,%4\n"
" cs %0,%1,%2\n"
" jnl 1f\n"
" xr %1,%0\n"
" nr %1,%5\n"
" jnz 0b\n"
"1:"
: "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) address)
: "d" ((old & 0xff) << shift),
"d" ((new & 0xff) << shift),
"d" (~(0xff << shift))
: "memory", "cc");
return prev >> shift;
case 2:
shift = (2 ^ (address & 2)) << 3;
address ^= address & 2;
asm volatile(
" l %0,%2\n"
"0: nr %0,%5\n"
" lr %1,%0\n"
" or %0,%3\n"
" or %1,%4\n"
" cs %0,%1,%2\n"
" jnl 1f\n"
" xr %1,%0\n"
" nr %1,%5\n"
" jnz 0b\n"
"1:"
: "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) address)
: "d" ((old & 0xffff) << shift),
"d" ((new & 0xffff) << shift),
"d" (~(0xffff << shift))
: "memory", "cc");
return prev >> shift;
case 4:
asm volatile(
" cs %0,%3,%1\n"
: "=&d" (prev), "+Q" (*(int *) address)
: "0" (old), "d" (new)
: "memory", "cc");
return prev;
case 8:
asm volatile(
" csg %0,%3,%1\n"
: "=&d" (prev), "+QS" (*(long *) address)
: "0" (old), "d" (new)
: "memory", "cc");
return prev;
}
__cmpxchg_called_with_bad_pointer();
return old;
}
#define xchg(ptr, x) \
#define arch_cmpxchg(ptr, o, n) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __old; \
do { \
__old = *__ptr; \
} while (!__sync_bool_compare_and_swap(__ptr, __old, x)); \
__old; \
__typeof__(*(ptr)) __ret; \
\
__ret = (__typeof__(*(ptr))) \
__cmpxchg((unsigned long)(ptr), (unsigned long)(o), \
(unsigned long)(n), sizeof(*(ptr))); \
__ret; \
})
#define arch_cmpxchg64 arch_cmpxchg
#define arch_cmpxchg_local arch_cmpxchg
#define arch_cmpxchg64_local arch_cmpxchg
#define system_has_cmpxchg_double() 1
#define __cmpxchg_double(p1, p2, o1, o2, n1, n2) \
({ \
register __typeof__(*(p1)) __old1 asm("2") = (o1); \
......@@ -51,7 +187,7 @@
!cc; \
})
#define cmpxchg_double(p1, p2, o1, o2, n1, n2) \
#define arch_cmpxchg_double(p1, p2, o1, o2, n1, n2) \
({ \
__typeof__(p1) __p1 = (p1); \
__typeof__(p2) __p2 = (p2); \
......@@ -61,6 +197,4 @@
__cmpxchg_double(__p1, __p2, o1, o2, n1, n2); \
})
#define system_has_cmpxchg_double() 1
#endif /* __ASM_CMPXCHG_H */
......@@ -14,10 +14,6 @@
void do_per_trap(struct pt_regs *regs);
void do_syscall(struct pt_regs *regs);
typedef void (*pgm_check_func)(struct pt_regs *regs);
extern pgm_check_func pgm_check_table[128];
#ifdef CONFIG_DEBUG_ENTRY
static __always_inline void arch_check_user_regs(struct pt_regs *regs)
{
......
......@@ -85,7 +85,6 @@ enum zpci_state {
ZPCI_FN_STATE_STANDBY = 0,
ZPCI_FN_STATE_CONFIGURED = 1,
ZPCI_FN_STATE_RESERVED = 2,
ZPCI_FN_STATE_ONLINE = 3,
};
struct zpci_bar_struct {
......@@ -131,9 +130,10 @@ struct zpci_dev {
u8 port;
u8 rid_available : 1;
u8 has_hp_slot : 1;
u8 has_resources : 1;
u8 is_physfn : 1;
u8 util_str_avail : 1;
u8 reserved : 4;
u8 reserved : 3;
unsigned int devfn; /* DEVFN part of the RID*/
struct mutex lock;
......@@ -201,10 +201,12 @@ extern unsigned int s390_pci_no_rid;
Prototypes
----------------------------------------------------------------------------- */
/* Base stuff */
int zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
void zpci_remove_device(struct zpci_dev *zdev, bool set_error);
struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
int zpci_enable_device(struct zpci_dev *);
int zpci_disable_device(struct zpci_dev *);
int zpci_configure_device(struct zpci_dev *zdev, u32 fh);
int zpci_deconfigure_device(struct zpci_dev *zdev);
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
int zpci_unregister_ioat(struct zpci_dev *, u8);
void zpci_remove_reserved_devices(void);
......
......@@ -246,21 +246,8 @@ struct slsb {
u8 val[QDIO_MAX_BUFFERS_PER_Q];
} __attribute__ ((packed, aligned(256)));
/**
* struct qdio_outbuf_state - SBAL related asynchronous operation information
* (for communication with upper layer programs)
* (only required for use with completion queues)
* @user: pointer to upper layer program's state information related to SBAL
* (stored in user1 data of QAOB)
*/
struct qdio_outbuf_state {
void *user;
};
#define CHSC_AC1_INITIATE_INPUTQ 0x80
/* qdio adapter-characteristics-1 flag */
#define CHSC_AC1_INITIATE_INPUTQ 0x80
#define AC1_SIGA_INPUT_NEEDED 0x40 /* process input queues */
#define AC1_SIGA_OUTPUT_NEEDED 0x20 /* process output queues */
#define AC1_SIGA_SYNC_NEEDED 0x10 /* ask hypervisor to sync */
......@@ -338,7 +325,6 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
* @int_parm: interruption parameter
* @input_sbal_addr_array: per-queue array, each element points to 128 SBALs
* @output_sbal_addr_array: per-queue array, each element points to 128 SBALs
* @output_sbal_state_array: no_output_qs * 128 state info (for CQ or NULL)
*/
struct qdio_initialize {
unsigned char q_format;
......@@ -357,7 +343,6 @@ struct qdio_initialize {
unsigned long int_parm;
struct qdio_buffer ***input_sbal_addr_array;
struct qdio_buffer ***output_sbal_addr_array;
struct qdio_outbuf_state *output_sbal_state_array;
};
#define QDIO_STATE_INACTIVE 0x00000002 /* after qdio_cleanup */
......@@ -378,9 +363,10 @@ extern int qdio_allocate(struct ccw_device *cdev, unsigned int no_input_qs,
extern int qdio_establish(struct ccw_device *cdev,
struct qdio_initialize *init_data);
extern int qdio_activate(struct ccw_device *);
extern struct qaob *qdio_allocate_aob(void);
extern void qdio_release_aob(struct qaob *);
extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int,
unsigned int);
extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, int q_nr,
unsigned int bufnr, unsigned int count, struct qaob *aob);
extern int qdio_start_irq(struct ccw_device *cdev);
extern int qdio_stop_irq(struct ccw_device *cdev);
extern int qdio_get_next_buffers(struct ccw_device *, int, int *, int *);
......
......@@ -88,7 +88,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp)
asm_inline volatile(
ALTERNATIVE("", ".long 0xb2fa0070", 49) /* NIAI 7 */
" sth %1,%0\n"
: "=Q" (((unsigned short *) &lp->lock)[1])
: "=R" (((unsigned short *) &lp->lock)[1])
: "d" (0) : "cc", "memory");
}
......
......@@ -8,7 +8,7 @@
typedef struct {
int lock;
} __attribute__ ((aligned (4))) arch_spinlock_t;
} arch_spinlock_t;
#define __ARCH_SPIN_LOCK_UNLOCKED { .lock = 0, }
......
......@@ -36,7 +36,7 @@ CFLAGS_unwind_bc.o += -fno-optimize-sibling-calls
obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
obj-y += processor.o syscall.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o
obj-y += sysinfo.o lgr.o os_info.o machine_kexec.o pgm_check.o
obj-y += sysinfo.o lgr.o os_info.o machine_kexec.o
obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o
obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o
obj-y += nospec-branch.o ipl_vmparm.o machine_kexec_reloc.o unwind_bc.o
......
......@@ -563,7 +563,7 @@ void show_code(struct pt_regs *regs)
void print_fn_code(unsigned char *code, unsigned long len)
{
char buffer[64], *ptr;
char buffer[128], *ptr;
int opsize, i;
while (len) {
......
......@@ -26,29 +26,6 @@ void do_dat_exception(struct pt_regs *regs);
void do_secure_storage_access(struct pt_regs *regs);
void do_non_secure_storage_access(struct pt_regs *regs);
void do_secure_storage_violation(struct pt_regs *regs);
void addressing_exception(struct pt_regs *regs);
void data_exception(struct pt_regs *regs);
void default_trap_handler(struct pt_regs *regs);
void divide_exception(struct pt_regs *regs);
void execute_exception(struct pt_regs *regs);
void hfp_divide_exception(struct pt_regs *regs);
void hfp_overflow_exception(struct pt_regs *regs);
void hfp_significance_exception(struct pt_regs *regs);
void hfp_sqrt_exception(struct pt_regs *regs);
void hfp_underflow_exception(struct pt_regs *regs);
void illegal_op(struct pt_regs *regs);
void operand_exception(struct pt_regs *regs);
void overflow_exception(struct pt_regs *regs);
void privileged_op(struct pt_regs *regs);
void space_switch_exception(struct pt_regs *regs);
void special_op_exception(struct pt_regs *regs);
void specification_exception(struct pt_regs *regs);
void transaction_exception(struct pt_regs *regs);
void translation_exception(struct pt_regs *regs);
void vector_exception(struct pt_regs *regs);
void monitor_event_exception(struct pt_regs *regs);
void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str);
void kernel_stack_overflow(struct pt_regs * regs);
void do_signal(struct pt_regs *regs);
......@@ -59,7 +36,7 @@ void do_notify_resume(struct pt_regs *regs);
void __init init_IRQ(void);
void do_io_irq(struct pt_regs *regs);
void do_ext_irq(struct pt_regs *regs);
void do_restart(void);
void do_restart(void *arg);
void __init startup_init(void);
void die(struct pt_regs *regs, const char *str);
int setup_profiling_timer(unsigned int multiplier);
......
......@@ -1849,12 +1849,12 @@ static void __do_restart(void *ignore)
stop_run(&on_restart_trigger);
}
void do_restart(void)
void do_restart(void *arg)
{
tracing_off();
debug_locks_off();
lgr_info_log();
smp_call_online_cpu(__do_restart, NULL);
smp_call_online_cpu(__do_restart, arg);
}
/* on halt */
......
......@@ -52,7 +52,7 @@ void os_info_entry_add(int nr, void *ptr, u64 size)
}
/*
* Initialize OS info struture and set lowcore pointer
* Initialize OS info structure and set lowcore pointer
*/
void __init os_info_init(void)
{
......
......@@ -23,27 +23,6 @@
#include <asm/sysinfo.h>
#include <asm/unwind.h>
const char *perf_pmu_name(void)
{
if (cpum_cf_avail() || cpum_sf_avail())
return "CPU-Measurement Facilities (CPU-MF)";
return "pmu";
}
EXPORT_SYMBOL(perf_pmu_name);
int perf_num_counters(void)
{
int num = 0;
if (cpum_cf_avail())
num += PERF_CPUM_CF_MAX_CTR;
if (cpum_sf_avail())
num += PERF_CPUM_SF_MAX_CTR;
return num;
}
EXPORT_SYMBOL(perf_num_counters);
static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs)
{
struct stack_frame *stack = (struct stack_frame *) regs->gprs[15];
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Program check table.
*
* Copyright IBM Corp. 2012
*/
#include <linux/linkage.h>
#define PGM_CHECK(handler) .quad handler
#define PGM_CHECK_DEFAULT PGM_CHECK(default_trap_handler)
/*
* The program check table contains exactly 128 (0x00-0x7f) entries. Each
* line defines the function to be called corresponding to the program check
* interruption code.
*/
.section .rodata, "a"
ENTRY(pgm_check_table)
PGM_CHECK_DEFAULT /* 00 */
PGM_CHECK(illegal_op) /* 01 */
PGM_CHECK(privileged_op) /* 02 */
PGM_CHECK(execute_exception) /* 03 */
PGM_CHECK(do_protection_exception) /* 04 */
PGM_CHECK(addressing_exception) /* 05 */
PGM_CHECK(specification_exception) /* 06 */
PGM_CHECK(data_exception) /* 07 */
PGM_CHECK(overflow_exception) /* 08 */
PGM_CHECK(divide_exception) /* 09 */
PGM_CHECK(overflow_exception) /* 0a */
PGM_CHECK(divide_exception) /* 0b */
PGM_CHECK(hfp_overflow_exception) /* 0c */
PGM_CHECK(hfp_underflow_exception) /* 0d */
PGM_CHECK(hfp_significance_exception) /* 0e */
PGM_CHECK(hfp_divide_exception) /* 0f */
PGM_CHECK(do_dat_exception) /* 10 */
PGM_CHECK(do_dat_exception) /* 11 */
PGM_CHECK(translation_exception) /* 12 */
PGM_CHECK(special_op_exception) /* 13 */
PGM_CHECK_DEFAULT /* 14 */
PGM_CHECK(operand_exception) /* 15 */
PGM_CHECK_DEFAULT /* 16 */
PGM_CHECK_DEFAULT /* 17 */
PGM_CHECK(transaction_exception) /* 18 */
PGM_CHECK_DEFAULT /* 19 */
PGM_CHECK_DEFAULT /* 1a */
PGM_CHECK(vector_exception) /* 1b */
PGM_CHECK(space_switch_exception) /* 1c */
PGM_CHECK(hfp_sqrt_exception) /* 1d */
PGM_CHECK_DEFAULT /* 1e */
PGM_CHECK_DEFAULT /* 1f */
PGM_CHECK_DEFAULT /* 20 */
PGM_CHECK_DEFAULT /* 21 */
PGM_CHECK_DEFAULT /* 22 */
PGM_CHECK_DEFAULT /* 23 */
PGM_CHECK_DEFAULT /* 24 */
PGM_CHECK_DEFAULT /* 25 */
PGM_CHECK_DEFAULT /* 26 */
PGM_CHECK_DEFAULT /* 27 */
PGM_CHECK_DEFAULT /* 28 */
PGM_CHECK_DEFAULT /* 29 */
PGM_CHECK_DEFAULT /* 2a */
PGM_CHECK_DEFAULT /* 2b */
PGM_CHECK_DEFAULT /* 2c */
PGM_CHECK_DEFAULT /* 2d */
PGM_CHECK_DEFAULT /* 2e */
PGM_CHECK_DEFAULT /* 2f */
PGM_CHECK_DEFAULT /* 30 */
PGM_CHECK_DEFAULT /* 31 */
PGM_CHECK_DEFAULT /* 32 */
PGM_CHECK_DEFAULT /* 33 */
PGM_CHECK_DEFAULT /* 34 */
PGM_CHECK_DEFAULT /* 35 */
PGM_CHECK_DEFAULT /* 36 */
PGM_CHECK_DEFAULT /* 37 */
PGM_CHECK(do_dat_exception) /* 38 */
PGM_CHECK(do_dat_exception) /* 39 */
PGM_CHECK(do_dat_exception) /* 3a */
PGM_CHECK(do_dat_exception) /* 3b */
PGM_CHECK_DEFAULT /* 3c */
PGM_CHECK(do_secure_storage_access) /* 3d */
PGM_CHECK(do_non_secure_storage_access) /* 3e */
PGM_CHECK(do_secure_storage_violation) /* 3f */
PGM_CHECK(monitor_event_exception) /* 40 */
PGM_CHECK_DEFAULT /* 41 */
PGM_CHECK_DEFAULT /* 42 */
PGM_CHECK_DEFAULT /* 43 */
PGM_CHECK_DEFAULT /* 44 */
PGM_CHECK_DEFAULT /* 45 */
PGM_CHECK_DEFAULT /* 46 */
PGM_CHECK_DEFAULT /* 47 */
PGM_CHECK_DEFAULT /* 48 */
PGM_CHECK_DEFAULT /* 49 */
PGM_CHECK_DEFAULT /* 4a */
PGM_CHECK_DEFAULT /* 4b */
PGM_CHECK_DEFAULT /* 4c */
PGM_CHECK_DEFAULT /* 4d */
PGM_CHECK_DEFAULT /* 4e */
PGM_CHECK_DEFAULT /* 4f */
PGM_CHECK_DEFAULT /* 50 */
PGM_CHECK_DEFAULT /* 51 */
PGM_CHECK_DEFAULT /* 52 */
PGM_CHECK_DEFAULT /* 53 */
PGM_CHECK_DEFAULT /* 54 */
PGM_CHECK_DEFAULT /* 55 */
PGM_CHECK_DEFAULT /* 56 */
PGM_CHECK_DEFAULT /* 57 */
PGM_CHECK_DEFAULT /* 58 */
PGM_CHECK_DEFAULT /* 59 */
PGM_CHECK_DEFAULT /* 5a */
PGM_CHECK_DEFAULT /* 5b */
PGM_CHECK_DEFAULT /* 5c */
PGM_CHECK_DEFAULT /* 5d */
PGM_CHECK_DEFAULT /* 5e */
PGM_CHECK_DEFAULT /* 5f */
PGM_CHECK_DEFAULT /* 60 */
PGM_CHECK_DEFAULT /* 61 */
PGM_CHECK_DEFAULT /* 62 */
PGM_CHECK_DEFAULT /* 63 */
PGM_CHECK_DEFAULT /* 64 */
PGM_CHECK_DEFAULT /* 65 */
PGM_CHECK_DEFAULT /* 66 */
PGM_CHECK_DEFAULT /* 67 */
PGM_CHECK_DEFAULT /* 68 */
PGM_CHECK_DEFAULT /* 69 */
PGM_CHECK_DEFAULT /* 6a */
PGM_CHECK_DEFAULT /* 6b */
PGM_CHECK_DEFAULT /* 6c */
PGM_CHECK_DEFAULT /* 6d */
PGM_CHECK_DEFAULT /* 6e */
PGM_CHECK_DEFAULT /* 6f */
PGM_CHECK_DEFAULT /* 70 */
PGM_CHECK_DEFAULT /* 71 */
PGM_CHECK_DEFAULT /* 72 */
PGM_CHECK_DEFAULT /* 73 */
PGM_CHECK_DEFAULT /* 74 */
PGM_CHECK_DEFAULT /* 75 */
PGM_CHECK_DEFAULT /* 76 */
PGM_CHECK_DEFAULT /* 77 */
PGM_CHECK_DEFAULT /* 78 */
PGM_CHECK_DEFAULT /* 79 */
PGM_CHECK_DEFAULT /* 7a */
PGM_CHECK_DEFAULT /* 7b */
PGM_CHECK_DEFAULT /* 7c */
PGM_CHECK_DEFAULT /* 7d */
PGM_CHECK_DEFAULT /* 7e */
PGM_CHECK_DEFAULT /* 7f */
......@@ -79,7 +79,7 @@ void do_per_trap(struct pt_regs *regs)
}
NOKPROBE_SYMBOL(do_per_trap);
void default_trap_handler(struct pt_regs *regs)
static void default_trap_handler(struct pt_regs *regs)
{
if (user_mode(regs)) {
report_user_fault(regs, SIGSEGV, 0);
......@@ -89,7 +89,7 @@ void default_trap_handler(struct pt_regs *regs)
}
#define DO_ERROR_INFO(name, signr, sicode, str) \
void name(struct pt_regs *regs) \
static void name(struct pt_regs *regs) \
{ \
do_trap(regs, signr, sicode, str); \
}
......@@ -141,13 +141,13 @@ static inline void do_fp_trap(struct pt_regs *regs, __u32 fpc)
do_trap(regs, SIGFPE, si_code, "floating point exception");
}
void translation_exception(struct pt_regs *regs)
static void translation_exception(struct pt_regs *regs)
{
/* May never happen. */
panic("Translation exception");
}
void illegal_op(struct pt_regs *regs)
static void illegal_op(struct pt_regs *regs)
{
__u8 opcode[6];
__u16 __user *location;
......@@ -189,7 +189,7 @@ NOKPROBE_SYMBOL(illegal_op);
DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
"specification exception");
void vector_exception(struct pt_regs *regs)
static void vector_exception(struct pt_regs *regs)
{
int si_code, vic;
......@@ -223,7 +223,7 @@ void vector_exception(struct pt_regs *regs)
do_trap(regs, SIGFPE, si_code, "vector exception");
}
void data_exception(struct pt_regs *regs)
static void data_exception(struct pt_regs *regs)
{
save_fpu_regs();
if (current->thread.fpu.fpc & FPC_DXC_MASK)
......@@ -232,7 +232,7 @@ void data_exception(struct pt_regs *regs)
do_trap(regs, SIGILL, ILL_ILLOPN, "data exception");
}
void space_switch_exception(struct pt_regs *regs)
static void space_switch_exception(struct pt_regs *regs)
{
/* Set user psw back to home space mode. */
if (user_mode(regs))
......@@ -241,7 +241,7 @@ void space_switch_exception(struct pt_regs *regs)
do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
}
void monitor_event_exception(struct pt_regs *regs)
static void monitor_event_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
......@@ -293,6 +293,8 @@ void __init trap_init(void)
test_monitor_call();
}
static void (*pgm_check_table[128])(struct pt_regs *regs);
void noinstr __do_pgm_check(struct pt_regs *regs)
{
unsigned long last_break = S390_lowcore.breaking_event_addr;
......@@ -353,3 +355,61 @@ void noinstr __do_pgm_check(struct pt_regs *regs)
exit_to_user_mode();
}
}
/*
* The program check table contains exactly 128 (0x00-0x7f) entries. Each
* line defines the function to be called corresponding to the program check
* interruption code.
*/
static void (*pgm_check_table[128])(struct pt_regs *regs) = {
[0x00] = default_trap_handler,
[0x01] = illegal_op,
[0x02] = privileged_op,
[0x03] = execute_exception,
[0x04] = do_protection_exception,
[0x05] = addressing_exception,
[0x06] = specification_exception,
[0x07] = data_exception,
[0x08] = overflow_exception,
[0x09] = divide_exception,
[0x0a] = overflow_exception,
[0x0b] = divide_exception,
[0x0c] = hfp_overflow_exception,
[0x0d] = hfp_underflow_exception,
[0x0e] = hfp_significance_exception,
[0x0f] = hfp_divide_exception,
[0x10] = do_dat_exception,
[0x11] = do_dat_exception,
[0x12] = translation_exception,
[0x13] = special_op_exception,
[0x14] = default_trap_handler,
[0x15] = operand_exception,
[0x16] = default_trap_handler,
[0x17] = default_trap_handler,
[0x18] = transaction_exception,
[0x19] = default_trap_handler,
[0x1a] = default_trap_handler,
[0x1b] = vector_exception,
[0x1c] = space_switch_exception,
[0x1d] = hfp_sqrt_exception,
[0x1e ... 0x37] = default_trap_handler,
[0x38] = do_dat_exception,
[0x39] = do_dat_exception,
[0x3a] = do_dat_exception,
[0x3b] = do_dat_exception,
[0x3c] = default_trap_handler,
[0x3d] = do_secure_storage_access,
[0x3e] = do_non_secure_storage_access,
[0x3f] = do_secure_storage_violation,
[0x40] = monitor_event_exception,
[0x41 ... 0x7f] = default_trap_handler,
};
#define COND_TRAP(x) asm( \
".weak " __stringify(x) "\n\t" \
".set " __stringify(x) "," \
__stringify(default_trap_handler))
COND_TRAP(do_secure_storage_access);
COND_TRAP(do_non_secure_storage_access);
COND_TRAP(do_secure_storage_violation);
......@@ -406,6 +406,41 @@ static struct attribute_group uv_query_attr_group = {
.attrs = uv_query_attrs,
};
static ssize_t uv_is_prot_virt_guest(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{
int val = 0;
#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
val = prot_virt_guest;
#endif
return scnprintf(page, PAGE_SIZE, "%d\n", val);
}
static ssize_t uv_is_prot_virt_host(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{
int val = 0;
#if IS_ENABLED(CONFIG_KVM)
val = prot_virt_host;
#endif
return scnprintf(page, PAGE_SIZE, "%d\n", val);
}
static struct kobj_attribute uv_prot_virt_guest =
__ATTR(prot_virt_guest, 0444, uv_is_prot_virt_guest, NULL);
static struct kobj_attribute uv_prot_virt_host =
__ATTR(prot_virt_host, 0444, uv_is_prot_virt_host, NULL);
static const struct attribute *uv_prot_virt_attrs[] = {
&uv_prot_virt_guest.attr,
&uv_prot_virt_host.attr,
NULL,
};
static struct kset *uv_query_kset;
static struct kobject *uv_kobj;
......@@ -420,15 +455,23 @@ static int __init uv_info_init(void)
if (!uv_kobj)
return -ENOMEM;
uv_query_kset = kset_create_and_add("query", NULL, uv_kobj);
if (!uv_query_kset)
rc = sysfs_create_files(uv_kobj, uv_prot_virt_attrs);
if (rc)
goto out_kobj;
uv_query_kset = kset_create_and_add("query", NULL, uv_kobj);
if (!uv_query_kset) {
rc = -ENOMEM;
goto out_ind_files;
}
rc = sysfs_create_group(&uv_query_kset->kobj, &uv_query_attr_group);
if (!rc)
return 0;
kset_unregister(uv_query_kset);
out_ind_files:
sysfs_remove_files(uv_kobj, uv_prot_virt_attrs);
out_kobj:
kobject_del(uv_kobj);
kobject_put(uv_kobj);
......
......@@ -64,8 +64,8 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs,
break;
if (state.reliable && !addr) {
pr_err("unwind state reliable but addr is 0\n");
kfree(bt);
return -EINVAL;
ret = -EINVAL;
break;
}
sprint_symbol(sym, addr);
if (bt_pos < BT_BUF_SIZE) {
......@@ -296,19 +296,22 @@ static int test_unwind_flags(int flags)
static int test_unwind_init(void)
{
int ret = 0;
int failed = 0;
int total = 0;
#define TEST(flags) \
do { \
pr_info("[ RUN ] " #flags "\n"); \
total++; \
if (!test_unwind_flags((flags))) { \
pr_info("[ OK ] " #flags "\n"); \
} else { \
pr_err("[ FAILED ] " #flags "\n"); \
ret = -EINVAL; \
failed++; \
} \
} while (0)
pr_info("running stack unwinder tests");
TEST(UWM_DEFAULT);
TEST(UWM_SP);
TEST(UWM_REGS);
......@@ -335,8 +338,14 @@ do { \
TEST(UWM_PGM | UWM_SP | UWM_REGS);
#endif
#undef TEST
if (failed) {
pr_err("%d of %d stack unwinder tests failed", failed, total);
WARN(1, "%d of %d stack unwinder tests failed", failed, total);
} else {
pr_info("all %d stack unwinder tests passed", total);
}
return ret;
return failed ? -EINVAL : 0;
}
static void test_unwind_exit(void)
......
......@@ -783,6 +783,7 @@ early_initcall(pfault_irq_init);
#endif /* CONFIG_PFAULT */
#if IS_ENABLED(CONFIG_PGSTE)
void do_secure_storage_access(struct pt_regs *regs)
{
unsigned long addr = regs->int_parm_long & __FAIL_ADDR_MASK;
......@@ -859,19 +860,4 @@ void do_secure_storage_violation(struct pt_regs *regs)
send_sig(SIGSEGV, current, 0);
}
#else
void do_secure_storage_access(struct pt_regs *regs)
{
default_trap_handler(regs);
}
void do_non_secure_storage_access(struct pt_regs *regs)
{
default_trap_handler(regs);
}
void do_secure_storage_violation(struct pt_regs *regs)
{
default_trap_handler(regs);
}
#endif
#endif /* CONFIG_PGSTE */
......@@ -112,7 +112,7 @@ static void mark_kernel_pmd(pud_t *pud, unsigned long addr, unsigned long end)
next = pmd_addr_end(addr, end);
if (pmd_none(*pmd) || pmd_large(*pmd))
continue;
page = virt_to_page(pmd_val(*pmd));
page = phys_to_page(pmd_val(*pmd));
set_bit(PG_arch_1, &page->flags);
} while (pmd++, addr = next, addr != end);
}
......@@ -130,7 +130,7 @@ static void mark_kernel_pud(p4d_t *p4d, unsigned long addr, unsigned long end)
if (pud_none(*pud) || pud_large(*pud))
continue;
if (!pud_folded(*pud)) {
page = virt_to_page(pud_val(*pud));
page = phys_to_page(pud_val(*pud));
for (i = 0; i < 3; i++)
set_bit(PG_arch_1, &page[i].flags);
}
......@@ -151,7 +151,7 @@ static void mark_kernel_p4d(pgd_t *pgd, unsigned long addr, unsigned long end)
if (p4d_none(*p4d))
continue;
if (!p4d_folded(*p4d)) {
page = virt_to_page(p4d_val(*p4d));
page = phys_to_page(p4d_val(*p4d));
for (i = 0; i < 3; i++)
set_bit(PG_arch_1, &page[i].flags);
}
......@@ -173,7 +173,7 @@ static void mark_kernel_pgd(void)
if (pgd_none(*pgd))
continue;
if (!pgd_folded(*pgd)) {
page = virt_to_page(pgd_val(*pgd));
page = phys_to_page(pgd_val(*pgd));
for (i = 0; i < 3; i++)
set_bit(PG_arch_1, &page[i].flags);
}
......
......@@ -538,6 +538,7 @@ int zpci_setup_bus_resources(struct zpci_dev *zdev,
zdev->bars[i].res = res;
pci_add_resource(resources, res);
}
zdev->has_resources = 1;
return 0;
}
......@@ -554,6 +555,7 @@ static void zpci_cleanup_bus_resources(struct zpci_dev *zdev)
release_resource(zdev->bars[i].res);
kfree(zdev->bars[i].res);
}
zdev->has_resources = 0;
}
int pcibios_add_device(struct pci_dev *pdev)
......@@ -661,7 +663,6 @@ int zpci_enable_device(struct zpci_dev *zdev)
if (rc)
goto out_dma;
zdev->state = ZPCI_FN_STATE_ONLINE;
return 0;
out_dma:
......@@ -669,7 +670,6 @@ int zpci_enable_device(struct zpci_dev *zdev)
out:
return rc;
}
EXPORT_SYMBOL_GPL(zpci_enable_device);
int zpci_disable_device(struct zpci_dev *zdev)
{
......@@ -680,40 +680,6 @@ int zpci_disable_device(struct zpci_dev *zdev)
*/
return clp_disable_fh(zdev);
}
EXPORT_SYMBOL_GPL(zpci_disable_device);
/* zpci_remove_device - Removes the given zdev from the PCI core
* @zdev: the zdev to be removed from the PCI core
* @set_error: if true the device's error state is set to permanent failure
*
* Sets a zPCI device to a configured but offline state; the zPCI
* device is still accessible through its hotplug slot and the zPCI
* API but is removed from the common code PCI bus, making it
* no longer available to drivers.
*/
void zpci_remove_device(struct zpci_dev *zdev, bool set_error)
{
struct zpci_bus *zbus = zdev->zbus;
struct pci_dev *pdev;
if (!zdev->zbus->bus)
return;
pdev = pci_get_slot(zbus->bus, zdev->devfn);
if (pdev) {
if (set_error)
pdev->error_state = pci_channel_io_perm_failure;
if (pdev->is_virtfn) {
zpci_iov_remove_virtfn(pdev, zdev->vfn);
/* balance pci_get_slot */
pci_dev_put(pdev);
return;
}
pci_stop_and_remove_bus_device_locked(pdev);
/* balance pci_get_slot */
pci_dev_put(pdev);
}
}
/**
* zpci_create_device() - Create a new zpci_dev and add it to the zbus
......@@ -724,9 +690,9 @@ void zpci_remove_device(struct zpci_dev *zdev, bool set_error)
* Creates a new zpci device and adds it to its, possibly newly created, zbus
* as well as zpci_list.
*
* Returns: 0 on success, an error value otherwise
* Returns: the zdev on success or an error pointer otherwise
*/
int zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
{
struct zpci_dev *zdev;
int rc;
......@@ -734,7 +700,7 @@ int zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
zpci_dbg(3, "add fid:%x, fh:%x, c:%d\n", fid, fh, state);
zdev = kzalloc(sizeof(*zdev), GFP_KERNEL);
if (!zdev)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
/* FID and Function Handle are the static/dynamic identifiers */
zdev->fid = fid;
......@@ -753,44 +719,103 @@ int zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
if (rc)
goto error;
if (zdev->state == ZPCI_FN_STATE_CONFIGURED) {
rc = zpci_enable_device(zdev);
if (rc)
goto error_destroy_iommu;
}
rc = zpci_bus_device_register(zdev, &pci_root_ops);
if (rc)
goto error_disable;
goto error_destroy_iommu;
spin_lock(&zpci_list_lock);
list_add_tail(&zdev->entry, &zpci_list);
spin_unlock(&zpci_list_lock);
return 0;
return zdev;
error_disable:
if (zdev->state == ZPCI_FN_STATE_ONLINE)
zpci_disable_device(zdev);
error_destroy_iommu:
zpci_destroy_iommu(zdev);
error:
zpci_dbg(0, "add fid:%x, rc:%d\n", fid, rc);
kfree(zdev);
return ERR_PTR(rc);
}
/**
* zpci_configure_device() - Configure a zpci_dev
* @zdev: The zpci_dev to be configured
* @fh: The general function handle supplied by the platform
*
* Given a device in the configuration state Configured, enables, scans and
* adds it to the common code PCI subsystem. If any failure occurs, the
* zpci_dev is left disabled.
*
* Return: 0 on success, or an error code otherwise
*/
int zpci_configure_device(struct zpci_dev *zdev, u32 fh)
{
int rc;
zdev->fh = fh;
/* the PCI function will be scanned once function 0 appears */
if (!zdev->zbus->bus)
return 0;
/* For function 0 on a multi-function bus scan whole bus as we might
* have to pick up existing functions waiting for it to allow creating
* the PCI bus
*/
if (zdev->devfn == 0 && zdev->zbus->multifunction)
rc = zpci_bus_scan_bus(zdev->zbus);
else
rc = zpci_bus_scan_device(zdev);
return rc;
}
/**
* zpci_deconfigure_device() - Deconfigure a zpci_dev
* @zdev: The zpci_dev to configure
*
* Deconfigure a zPCI function that is currently configured and possibly known
* to the common code PCI subsystem.
* If any failure occurs the device is left as is.
*
* Return: 0 on success, or an error code otherwise
*/
int zpci_deconfigure_device(struct zpci_dev *zdev)
{
int rc;
if (zdev->zbus->bus)
zpci_bus_remove_device(zdev, false);
if (zdev_enabled(zdev)) {
rc = zpci_disable_device(zdev);
if (rc)
return rc;
}
rc = sclp_pci_deconfigure(zdev->fid);
zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, rc);
if (rc)
return rc;
zdev->state = ZPCI_FN_STATE_STANDBY;
return 0;
}
void zpci_release_device(struct kref *kref)
{
struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
int ret;
if (zdev->zbus->bus)
zpci_remove_device(zdev, false);
zpci_bus_remove_device(zdev, false);
if (zdev_enabled(zdev))
zpci_disable_device(zdev);
switch (zdev->state) {
case ZPCI_FN_STATE_ONLINE:
case ZPCI_FN_STATE_CONFIGURED:
zpci_disable_device(zdev);
ret = sclp_pci_deconfigure(zdev->fid);
zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret);
fallthrough;
case ZPCI_FN_STATE_STANDBY:
if (zdev->has_hp_slot)
......@@ -925,6 +950,7 @@ static int __init pci_base_init(void)
rc = clp_scan_pci_devices();
if (rc)
goto out_find;
zpci_bus_scan_busses();
s390_pci_initialized = 1;
return 0;
......
This diff is collapsed.
......@@ -10,6 +10,12 @@
int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops);
void zpci_bus_device_unregister(struct zpci_dev *zdev);
int zpci_bus_scan_bus(struct zpci_bus *zbus);
void zpci_bus_scan_busses(void);
int zpci_bus_scan_device(struct zpci_dev *zdev);
void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error);
void zpci_release_device(struct kref *kref);
static inline void zpci_zdev_put(struct zpci_dev *zdev)
{
......
......@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <asm/pci_debug.h>
#include <asm/pci_dma.h>
#include <asm/sclp.h>
#include "pci_bus.h"
......@@ -73,12 +74,29 @@ void zpci_event_error(void *data)
__zpci_event_error(data);
}
static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
{
enum zpci_state state;
zdev->fh = fh;
/* Give the driver a hint that the function is
* already unusable.
*/
zpci_bus_remove_device(zdev, true);
/* Even though the device is already gone we still
* need to free zPCI resources as part of the disable.
*/
zpci_disable_device(zdev);
zdev->state = ZPCI_FN_STATE_STANDBY;
if (!clp_get_state(zdev->fid, &state) &&
state == ZPCI_FN_STATE_RESERVED) {
zpci_zdev_put(zdev);
}
}
static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
{
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
enum zpci_state state;
struct pci_dev *pdev;
int ret;
zpci_err("avail CCDF:\n");
zpci_err_hex(ccdf, sizeof(*ccdf));
......@@ -86,68 +104,32 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
switch (ccdf->pec) {
case 0x0301: /* Reserved|Standby -> Configured */
if (!zdev) {
zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED);
break;
zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED);
if (IS_ERR(zdev))
break;
} else {
/* the configuration request may be stale */
if (zdev->state != ZPCI_FN_STATE_STANDBY)
break;
zdev->state = ZPCI_FN_STATE_CONFIGURED;
}
/* the configuration request may be stale */
if (zdev->state != ZPCI_FN_STATE_STANDBY)
break;
zdev->fh = ccdf->fh;
zdev->state = ZPCI_FN_STATE_CONFIGURED;
ret = zpci_enable_device(zdev);
if (ret)
break;
/* the PCI function will be scanned once function 0 appears */
if (!zdev->zbus->bus)
break;
pdev = pci_scan_single_device(zdev->zbus->bus, zdev->devfn);
if (!pdev)
break;
pci_bus_add_device(pdev);
pci_lock_rescan_remove();
pci_bus_add_devices(zdev->zbus->bus);
pci_unlock_rescan_remove();
zpci_configure_device(zdev, ccdf->fh);
break;
case 0x0302: /* Reserved -> Standby */
if (!zdev) {
if (!zdev)
zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY);
break;
}
zdev->fh = ccdf->fh;
else
zdev->fh = ccdf->fh;
break;
case 0x0303: /* Deconfiguration requested */
if (!zdev)
break;
zpci_remove_device(zdev, false);
ret = zpci_disable_device(zdev);
if (ret)
break;
ret = sclp_pci_deconfigure(zdev->fid);
zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret);
if (!ret)
zdev->state = ZPCI_FN_STATE_STANDBY;
if (zdev) {
zdev->fh = ccdf->fh;
zpci_deconfigure_device(zdev);
}
break;
case 0x0304: /* Configured -> Standby|Reserved */
if (!zdev)
break;
/* Give the driver a hint that the function is
* already unusable.
*/
zpci_remove_device(zdev, true);
zdev->fh = ccdf->fh;
zpci_disable_device(zdev);
zdev->state = ZPCI_FN_STATE_STANDBY;
if (!clp_get_state(ccdf->fid, &state) &&
state == ZPCI_FN_STATE_RESERVED) {
zpci_zdev_put(zdev);
}
if (zdev)
zpci_event_hard_deconfigured(zdev, ccdf->fh);
break;
case 0x0306: /* 0x308 or 0x302 for multiple devices */
zpci_remove_reserved_devices();
......
......@@ -131,6 +131,45 @@ static ssize_t report_error_write(struct file *filp, struct kobject *kobj,
}
static BIN_ATTR(report_error, S_IWUSR, NULL, report_error_write, PAGE_SIZE);
static ssize_t uid_is_unique_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sysfs_emit(buf, "%d\n", zpci_unique_uid ? 1 : 0);
}
static DEVICE_ATTR_RO(uid_is_unique);
#ifndef CONFIG_DMI
/* analogous to smbios index */
static ssize_t index_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
u32 index = ~0;
if (zpci_unique_uid)
index = zdev->uid;
return sysfs_emit(buf, "%u\n", index);
}
static DEVICE_ATTR_RO(index);
static umode_t zpci_index_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
return zpci_unique_uid ? attr->mode : 0;
}
static struct attribute *zpci_ident_attrs[] = {
&dev_attr_index.attr,
NULL,
};
static struct attribute_group zpci_ident_attr_group = {
.attrs = zpci_ident_attrs,
.is_visible = zpci_index_is_visible,
};
#endif
static struct bin_attribute *zpci_bin_attrs[] = {
&bin_attr_util_string,
&bin_attr_report_error,
......@@ -148,8 +187,10 @@ static struct attribute *zpci_dev_attrs[] = {
&dev_attr_uid.attr,
&dev_attr_recover.attr,
&dev_attr_mio_enabled.attr,
&dev_attr_uid_is_unique.attr,
NULL,
};
static struct attribute_group zpci_attr_group = {
.attrs = zpci_dev_attrs,
.bin_attrs = zpci_bin_attrs,
......@@ -170,5 +211,8 @@ static struct attribute_group pfip_attr_group = {
const struct attribute_group *zpci_attr_groups[] = {
&zpci_attr_group,
&pfip_attr_group,
#ifndef CONFIG_DMI
&zpci_ident_attr_group,
#endif
NULL,
};
......@@ -20,62 +20,22 @@
#define SLOT_NAME_SIZE 10
static int zpci_fn_configured(enum zpci_state state)
{
return state == ZPCI_FN_STATE_CONFIGURED ||
state == ZPCI_FN_STATE_ONLINE;
}
static inline int zdev_configure(struct zpci_dev *zdev)
{
int ret = sclp_pci_configure(zdev->fid);
zpci_dbg(3, "conf fid:%x, rc:%d\n", zdev->fid, ret);
if (!ret)
zdev->state = ZPCI_FN_STATE_CONFIGURED;
return ret;
}
static inline int zdev_deconfigure(struct zpci_dev *zdev)
{
int ret = sclp_pci_deconfigure(zdev->fid);
zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret);
if (!ret)
zdev->state = ZPCI_FN_STATE_STANDBY;
return ret;
}
static int enable_slot(struct hotplug_slot *hotplug_slot)
{
struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev,
hotplug_slot);
struct zpci_bus *zbus = zdev->zbus;
int rc;
if (zdev->state != ZPCI_FN_STATE_STANDBY)
return -EIO;
rc = zdev_configure(zdev);
rc = sclp_pci_configure(zdev->fid);
zpci_dbg(3, "conf fid:%x, rc:%d\n", zdev->fid, rc);
if (rc)
return rc;
zdev->state = ZPCI_FN_STATE_CONFIGURED;
rc = zpci_enable_device(zdev);
if (rc)
goto out_deconfigure;
pci_scan_slot(zbus->bus, zdev->devfn);
pci_lock_rescan_remove();
pci_bus_add_devices(zbus->bus);
pci_unlock_rescan_remove();
return rc;
out_deconfigure:
zdev_deconfigure(zdev);
return rc;
return zpci_configure_device(zdev, zdev->fh);
}
static int disable_slot(struct hotplug_slot *hotplug_slot)
......@@ -83,9 +43,8 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev,
hotplug_slot);
struct pci_dev *pdev;
int rc;
if (!zpci_fn_configured(zdev->state))
if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
return -EIO;
pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
......@@ -95,13 +54,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
}
pci_dev_put(pdev);
zpci_remove_device(zdev, false);
rc = zpci_disable_device(zdev);
if (rc)
return rc;
return zdev_deconfigure(zdev);
return zpci_deconfigure_device(zdev);
}
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
......
......@@ -98,7 +98,7 @@ static DEFINE_SPINLOCK(raw3215_device_lock);
/* list of free request structures */
static struct raw3215_req *raw3215_freelist;
/* spinlock to protect free list */
static spinlock_t raw3215_freelist_lock;
static DEFINE_SPINLOCK(raw3215_freelist_lock);
static struct tty_driver *tty3215_driver;
......@@ -833,7 +833,6 @@ static int __init con3215_init(void)
/* allocate 3215 request structures */
raw3215_freelist = NULL;
spin_lock_init(&raw3215_freelist_lock);
for (i = 0; i < NR_3215_REQ; i++) {
req = kzalloc(sizeof(struct raw3215_req), GFP_KERNEL | GFP_DMA);
if (!req)
......
......@@ -37,10 +37,10 @@ static sccb_mask_t sclp_receive_mask;
static sccb_mask_t sclp_send_mask;
/* List of registered event listeners and senders. */
static struct list_head sclp_reg_list;
static LIST_HEAD(sclp_reg_list);
/* List of queued requests. */
static struct list_head sclp_req_queue;
static LIST_HEAD(sclp_req_queue);
/* Data for read and and init requests. */
static struct sclp_req sclp_read_req;
......@@ -1178,8 +1178,6 @@ sclp_init(void)
sclp_init_sccb = (void *) __get_free_page(GFP_ATOMIC | GFP_DMA);
BUG_ON(!sclp_read_sccb || !sclp_init_sccb);
/* Set up variables */
INIT_LIST_HEAD(&sclp_req_queue);
INIT_LIST_HEAD(&sclp_reg_list);
list_add(&sclp_state_change_event.list, &sclp_reg_list);
timer_setup(&sclp_request_timer, NULL, 0);
timer_setup(&sclp_queue_timer, sclp_req_queue_timeout, 0);
......
......@@ -26,11 +26,11 @@
#define sclp_console_name "ttyS"
/* Lock to guard over changes to global variables */
static spinlock_t sclp_con_lock;
static DEFINE_SPINLOCK(sclp_con_lock);
/* List of free pages that can be used for console output buffering */
static struct list_head sclp_con_pages;
static LIST_HEAD(sclp_con_pages);
/* List of full struct sclp_buffer structures ready for output */
static struct list_head sclp_con_outqueue;
static LIST_HEAD(sclp_con_outqueue);
/* Pointer to current console buffer */
static struct sclp_buffer *sclp_conbuf;
/* Timer for delayed output of console messages */
......@@ -41,8 +41,8 @@ static int sclp_con_suspended;
static int sclp_con_queue_running;
/* Output format for console messages */
static unsigned short sclp_con_columns;
static unsigned short sclp_con_width_htab;
#define SCLP_CON_COLUMNS 320
#define SPACES_PER_TAB 8
static void
sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
......@@ -189,8 +189,8 @@ sclp_console_write(struct console *console, const char *message,
}
page = sclp_con_pages.next;
list_del((struct list_head *) page);
sclp_conbuf = sclp_make_buffer(page, sclp_con_columns,
sclp_con_width_htab);
sclp_conbuf = sclp_make_buffer(page, SCLP_CON_COLUMNS,
SPACES_PER_TAB);
}
/* try to write the string to the current output buffer */
written = sclp_write(sclp_conbuf, (const unsigned char *)
......@@ -323,27 +323,13 @@ sclp_console_init(void)
if (rc)
return rc;
/* Allocate pages for output buffering */
INIT_LIST_HEAD(&sclp_con_pages);
for (i = 0; i < sclp_console_pages; i++) {
page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
list_add_tail(page, &sclp_con_pages);
}
INIT_LIST_HEAD(&sclp_con_outqueue);
spin_lock_init(&sclp_con_lock);
sclp_conbuf = NULL;
timer_setup(&sclp_con_timer, sclp_console_timeout, 0);
/* Set output format */
if (MACHINE_IS_VM)
/*
* save 4 characters for the CPU number
* written at start of each line by VM/CP
*/
sclp_con_columns = 76;
else
sclp_con_columns = 80;
sclp_con_width_htab = 8;
/* enable printk-access to this driver */
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
register_reboot_notifier(&on_reboot_nb);
......
......@@ -35,11 +35,11 @@
*/
/* Lock to guard over changes to global variables. */
static spinlock_t sclp_tty_lock;
static DEFINE_SPINLOCK(sclp_tty_lock);
/* List of free pages that can be used for console output buffering. */
static struct list_head sclp_tty_pages;
static LIST_HEAD(sclp_tty_pages);
/* List of full struct sclp_buffer structures ready for output. */
static struct list_head sclp_tty_outqueue;
static LIST_HEAD(sclp_tty_outqueue);
/* Counter how many buffers are emitted. */
static int sclp_tty_buffer_count;
/* Pointer to current console buffer. */
......@@ -54,8 +54,8 @@ static unsigned short int sclp_tty_chars_count;
struct tty_driver *sclp_tty_driver;
static int sclp_tty_tolower;
static int sclp_tty_columns = 80;
#define SCLP_TTY_COLUMNS 320
#define SPACES_PER_TAB 8
#define CASE_DELIMITER 0x6c /* to separate upper and lower case (% in EBCDIC) */
......@@ -193,7 +193,7 @@ static int sclp_tty_write_string(const unsigned char *str, int count, int may_fa
}
page = sclp_tty_pages.next;
list_del((struct list_head *) page);
sclp_ttybuf = sclp_make_buffer(page, sclp_tty_columns,
sclp_ttybuf = sclp_make_buffer(page, SCLP_TTY_COLUMNS,
SPACES_PER_TAB);
}
/* try to write the string to the current output buffer */
......@@ -516,7 +516,6 @@ sclp_tty_init(void)
return rc;
}
/* Allocate pages for output buffering */
INIT_LIST_HEAD(&sclp_tty_pages);
for (i = 0; i < MAX_KMEM_PAGES; i++) {
page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (page == NULL) {
......@@ -525,17 +524,10 @@ sclp_tty_init(void)
}
list_add_tail((struct list_head *) page, &sclp_tty_pages);
}
INIT_LIST_HEAD(&sclp_tty_outqueue);
spin_lock_init(&sclp_tty_lock);
timer_setup(&sclp_tty_timer, sclp_tty_timeout, 0);
sclp_ttybuf = NULL;
sclp_tty_buffer_count = 0;
if (MACHINE_IS_VM) {
/*
* save 4 characters for the CPU number
* written at start of each line by VM/CP
*/
sclp_tty_columns = 76;
/* case input lines to lowercase */
sclp_tty_tolower = 1;
}
......
......@@ -61,13 +61,13 @@ static struct tty_driver *sclp_vt220_driver;
static struct tty_port sclp_vt220_port;
/* Lock to protect internal data from concurrent access */
static spinlock_t sclp_vt220_lock;
static DEFINE_SPINLOCK(sclp_vt220_lock);
/* List of empty pages to be used as write request buffers */
static struct list_head sclp_vt220_empty;
static LIST_HEAD(sclp_vt220_empty);
/* List of pending requests */
static struct list_head sclp_vt220_outqueue;
static LIST_HEAD(sclp_vt220_outqueue);
/* Suspend mode flag */
static int sclp_vt220_suspended;
......@@ -693,9 +693,6 @@ static int __init __sclp_vt220_init(int num_pages)
sclp_vt220_init_count++;
if (sclp_vt220_init_count != 1)
return 0;
spin_lock_init(&sclp_vt220_lock);
INIT_LIST_HEAD(&sclp_vt220_empty);
INIT_LIST_HEAD(&sclp_vt220_outqueue);
timer_setup(&sclp_vt220_timer, sclp_vt220_timeout, 0);
tty_port_init(&sclp_vt220_port);
sclp_vt220_current_request = NULL;
......
......@@ -8,7 +8,7 @@ CFLAGS_trace.o := -I$(src)
CFLAGS_vfio_ccw_trace.o := -I$(src)
obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
fcx.o itcw.o crw.o ccwreq.o trace.o ioasm.o
fcx.o itcw.o crw.o ccwreq.o trace.o ioasm.o cio_debugfs.o
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
obj-y += ccw_device.o cmf.o
......@@ -23,3 +23,5 @@ obj-$(CONFIG_QDIO) += qdio.o
vfio_ccw-objs += vfio_ccw_drv.o vfio_ccw_cp.o vfio_ccw_ops.o vfio_ccw_fsm.o \
vfio_ccw_async.o vfio_ccw_trace.o vfio_ccw_chp.o
obj-$(CONFIG_VFIO_CCW) += vfio_ccw.o
obj-$(CONFIG_CIO_INJECT) += cio_inject.o
......@@ -50,7 +50,7 @@ static unsigned long chp_info_expires;
static struct work_struct cfg_work;
/* Wait queue for configure completion events. */
static wait_queue_head_t cfg_wait_queue;
static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_queue);
/* Set vary state for given chpid. */
static void set_chp_logically_online(struct chp_id chpid, int onoff)
......@@ -829,7 +829,6 @@ static int __init chp_init(void)
if (ret)
return ret;
INIT_WORK(&cfg_work, cfg_func);
init_waitqueue_head(&cfg_wait_queue);
if (info_update())
return 0;
/* Register available channel-paths. */
......
......@@ -26,4 +26,7 @@ static inline void CIO_HEX_EVENT(int level, void *data, int length)
debug_event(cio_debug_trace_id, level, data, length);
}
/* For the CIO debugfs related features */
extern struct dentry *cio_debugfs_dir;
#endif
// SPDX-License-Identifier: GPL-2.0
/*
* S/390 common I/O debugfs interface
*
* Copyright IBM Corp. 2021
* Author(s): Vineeth Vijayan <vneethv@linux.ibm.com>
*/
#include <linux/debugfs.h>
#include "cio_debug.h"
struct dentry *cio_debugfs_dir;
/* Create the debugfs directory for CIO under the arch_debugfs_dir
* i.e /sys/kernel/debug/s390/cio
*/
static int __init cio_debugfs_init(void)
{
cio_debugfs_dir = debugfs_create_dir("cio", arch_debugfs_dir);
return 0;
}
subsys_initcall(cio_debugfs_init);
// SPDX-License-Identifier: GPL-2.0
/*
* CIO inject interface
*
* Copyright IBM Corp. 2021
* Author(s): Vineeth Vijayan <vneethv@linux.ibm.com>
*/
#define KMSG_COMPONENT "cio"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/debugfs.h>
#include <asm/chpid.h>
#include "cio_inject.h"
#include "cio_debug.h"
static DEFINE_SPINLOCK(crw_inject_lock);
DEFINE_STATIC_KEY_FALSE(cio_inject_enabled);
static struct crw *crw_inject_data;
/**
* crw_inject : Initiate the artificial CRW inject
* @crw: The data which needs to be injected as new CRW.
*
* The CRW handler is called, which will use the provided artificial
* data instead of the CRW from the underlying hardware.
*
* Return: 0 on success
*/
static int crw_inject(struct crw *crw)
{
int rc = 0;
struct crw *copy;
unsigned long flags;
copy = kmemdup(crw, sizeof(*crw), GFP_KERNEL);
if (!copy)
return -ENOMEM;
spin_lock_irqsave(&crw_inject_lock, flags);
if (crw_inject_data) {
kfree(copy);
rc = -EBUSY;
} else {
crw_inject_data = copy;
}
spin_unlock_irqrestore(&crw_inject_lock, flags);
if (!rc)
crw_handle_channel_report();
return rc;
}
/**
* stcrw_get_injected: Copy the artificial CRW data to CRW struct.
* @crw: The target CRW pointer.
*
* Retrieve an injected CRW data. Return 0 on success, 1 if no
* injected-CRW is available. The function reproduces the return
* code of the actual STCRW function.
*/
int stcrw_get_injected(struct crw *crw)
{
int rc = 1;
unsigned long flags;
spin_lock_irqsave(&crw_inject_lock, flags);
if (crw_inject_data) {
memcpy(crw, crw_inject_data, sizeof(*crw));
kfree(crw_inject_data);
crw_inject_data = NULL;
rc = 0;
}
spin_unlock_irqrestore(&crw_inject_lock, flags);
return rc;
}
/* The debugfs write handler for crw_inject nodes operation */
static ssize_t crw_inject_write(struct file *file, const char __user *buf,
size_t lbuf, loff_t *ppos)
{
u32 slct, oflw, chn, rsc, anc, erc, rsid;
struct crw crw;
char *buffer;
int rc;
if (!static_branch_likely(&cio_inject_enabled)) {
pr_warn("CIO inject is not enabled - ignoring CRW inject\n");
return -EINVAL;
}
buffer = vmemdup_user(buf, lbuf);
if (IS_ERR(buffer))
return -ENOMEM;
rc = sscanf(buffer, "%x %x %x %x %x %x %x", &slct, &oflw, &chn, &rsc, &anc,
&erc, &rsid);
kvfree(buffer);
if (rc != 7) {
pr_warn("crw_inject: Invalid format (need <solicited> <overflow> <chaining> <rsc> <ancillary> <erc> <rsid>)\n");
return -EINVAL;
}
memset(&crw, 0, sizeof(crw));
crw.slct = slct;
crw.oflw = oflw;
crw.chn = chn;
crw.rsc = rsc;
crw.anc = anc;
crw.erc = erc;
crw.rsid = rsid;
rc = crw_inject(&crw);
if (rc)
return rc;
return lbuf;
}
/* Debugfs write handler for inject_enable node*/
static ssize_t enable_inject_write(struct file *file, const char __user *buf,
size_t lbuf, loff_t *ppos)
{
unsigned long en = 0;
int rc;
rc = kstrtoul_from_user(buf, lbuf, 10, &en);
if (rc)
return rc;
switch (en) {
case 0:
static_branch_disable(&cio_inject_enabled);
break;
case 1:
static_branch_enable(&cio_inject_enabled);
break;
}
return lbuf;
}
static const struct file_operations crw_fops = {
.owner = THIS_MODULE,
.write = crw_inject_write,
};
static const struct file_operations cio_en_fops = {
.owner = THIS_MODULE,
.write = enable_inject_write,
};
static int __init cio_inject_init(void)
{
/* enable_inject node enables the static branching */
debugfs_create_file("enable_inject", 0200, cio_debugfs_dir,
NULL, &cio_en_fops);
debugfs_create_file("crw_inject", 0200, cio_debugfs_dir,
NULL, &crw_fops);
return 0;
}
device_initcall(cio_inject_init);
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright IBM Corp. 2021
* Author(s): Vineeth Vijayan <vneethv@linux.ibm.com>
*/
#ifndef CIO_CRW_INJECT_H
#define CIO_CRW_INJECT_H
#ifdef CONFIG_CIO_INJECT
#include <asm/crw.h>
DECLARE_STATIC_KEY_FALSE(cio_inject_enabled);
int stcrw_get_injected(struct crw *crw);
#endif
#endif
......@@ -651,15 +651,13 @@ static void css_sch_todo(struct work_struct *work)
}
static struct idset *slow_subchannel_set;
static spinlock_t slow_subchannel_lock;
static wait_queue_head_t css_eval_wq;
static DEFINE_SPINLOCK(slow_subchannel_lock);
static DECLARE_WAIT_QUEUE_HEAD(css_eval_wq);
static atomic_t css_eval_scheduled;
static int __init slow_subchannel_init(void)
{
spin_lock_init(&slow_subchannel_lock);
atomic_set(&css_eval_scheduled, 0);
init_waitqueue_head(&css_eval_wq);
slow_subchannel_set = idset_sch_new();
if (!slow_subchannel_set) {
CIO_MSG_EVENT(0, "could not allocate slow subchannel set\n");
......
......@@ -12,6 +12,7 @@
#include "ioasm.h"
#include "orb.h"
#include "cio.h"
#include "cio_inject.h"
static inline int __stsch(struct subchannel_id schid, struct schib *addr)
{
......@@ -260,7 +261,7 @@ int xsch(struct subchannel_id schid)
return ccode;
}
int stcrw(struct crw *crw)
static inline int __stcrw(struct crw *crw)
{
int ccode;
......@@ -271,6 +272,26 @@ int stcrw(struct crw *crw)
: "=d" (ccode), "=m" (*crw)
: "a" (crw)
: "cc");
return ccode;
}
static inline int _stcrw(struct crw *crw)
{
#ifdef CONFIG_CIO_INJECT
if (static_branch_unlikely(&cio_inject_enabled)) {
if (stcrw_get_injected(crw) == 0)
return 0;
}
#endif
return __stcrw(crw);
}
int stcrw(struct crw *crw)
{
int ccode;
ccode = _stcrw(crw);
trace_s390_cio_stcrw(crw, ccode);
return ccode;
......
......@@ -181,12 +181,6 @@ struct qdio_input_q {
struct qdio_output_q {
/* PCIs are enabled for the queue */
int pci_out_enabled;
/* cq: use asynchronous output buffers */
int use_cq;
/* cq: aobs used for particual SBAL */
struct qaob **aobs;
/* cq: sbal state related to asynchronous operation */
struct qdio_outbuf_state *sbal_state;
/* timer to check for more outbound work */
struct timer_list timer;
/* tasklet to check for completions */
......@@ -379,12 +373,8 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data);
void qdio_shutdown_irq(struct qdio_irq *irq);
void qdio_print_subchannel_info(struct qdio_irq *irq_ptr);
void qdio_free_queues(struct qdio_irq *irq_ptr);
void qdio_free_async_data(struct qdio_irq *irq_ptr);
int qdio_setup_init(void);
void qdio_setup_exit(void);
int qdio_enable_async_operation(struct qdio_output_q *q);
void qdio_disable_async_operation(struct qdio_output_q *q);
struct qaob *qdio_allocate_aob(void);
int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr,
unsigned char *state);
......
......@@ -517,24 +517,6 @@ static inline int qdio_inbound_q_done(struct qdio_q *q, unsigned int start)
return 1;
}
static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q,
int bufnr)
{
unsigned long phys_aob = 0;
if (!q->aobs[bufnr]) {
struct qaob *aob = qdio_allocate_aob();
q->aobs[bufnr] = aob;
}
if (q->aobs[bufnr]) {
q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user;
phys_aob = virt_to_phys(q->aobs[bufnr]);
WARN_ON_ONCE(phys_aob & 0xFF);
}
return phys_aob;
}
static inline int qdio_tasklet_schedule(struct qdio_q *q)
{
if (likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE)) {
......@@ -548,7 +530,6 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start,
unsigned int *error)
{
unsigned char state = 0;
unsigned int i;
int count;
q->timestamp = get_tod_clock_fast();
......@@ -570,10 +551,6 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start,
switch (state) {
case SLSB_P_OUTPUT_PENDING:
/* detach the utilized QAOBs: */
for (i = 0; i < count; i++)
q->u.out.aobs[QDIO_BUFNR(start + i)] = NULL;
*error = QDIO_ERROR_SLSB_PENDING;
fallthrough;
case SLSB_P_OUTPUT_EMPTY:
......@@ -999,7 +976,6 @@ int qdio_free(struct ccw_device *cdev)
cdev->private->qdio_data = NULL;
mutex_unlock(&irq_ptr->setup_mutex);
qdio_free_async_data(irq_ptr);
qdio_free_queues(irq_ptr);
free_page((unsigned long) irq_ptr->qdr);
free_page(irq_ptr->chsc_page);
......@@ -1075,28 +1051,6 @@ int qdio_allocate(struct ccw_device *cdev, unsigned int no_input_qs,
}
EXPORT_SYMBOL_GPL(qdio_allocate);
static void qdio_detect_hsicq(struct qdio_irq *irq_ptr)
{
struct qdio_q *q = irq_ptr->input_qs[0];
int i, use_cq = 0;
if (irq_ptr->nr_input_qs > 1 && queue_type(q) == QDIO_IQDIO_QFMT)
use_cq = 1;
for_each_output_queue(irq_ptr, q, i) {
if (use_cq) {
if (multicast_outbound(q))
continue;
if (qdio_enable_async_operation(&q->u.out) < 0) {
use_cq = 0;
continue;
}
} else
qdio_disable_async_operation(&q->u.out);
}
DBF_EVENT("use_cq:%d", use_cq);
}
static void qdio_trace_init_data(struct qdio_irq *irq,
struct qdio_initialize *data)
{
......@@ -1191,8 +1145,6 @@ int qdio_establish(struct ccw_device *cdev,
qdio_setup_ssqd_info(irq_ptr);
qdio_detect_hsicq(irq_ptr);
/* qebsm is now setup if available, initialize buffer states */
qdio_init_buf_states(irq_ptr);
......@@ -1297,9 +1249,11 @@ static int handle_inbound(struct qdio_q *q, unsigned int callflags,
* @callflags: flags
* @bufnr: first buffer to process
* @count: how many buffers are filled
* @aob: asynchronous operation block
*/
static int handle_outbound(struct qdio_q *q, unsigned int callflags,
unsigned int bufnr, unsigned int count)
unsigned int bufnr, unsigned int count,
struct qaob *aob)
{
const unsigned int scan_threshold = q->irq_ptr->scan_threshold;
unsigned char state = 0;
......@@ -1320,11 +1274,9 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
q->u.out.pci_out_enabled = 0;
if (queue_type(q) == QDIO_IQDIO_QFMT) {
unsigned long phys_aob = 0;
if (q->u.out.use_cq && count == 1)
phys_aob = qdio_aob_for_buffer(&q->u.out, bufnr);
unsigned long phys_aob = aob ? virt_to_phys(aob) : 0;
WARN_ON_ONCE(!IS_ALIGNED(phys_aob, 256));
rc = qdio_kick_outbound_q(q, count, phys_aob);
} else if (need_siga_sync(q)) {
rc = qdio_siga_sync_q(q);
......@@ -1359,9 +1311,10 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
* @q_nr: queue number
* @bufnr: buffer number
* @count: how many buffers to process
* @aob: asynchronous operation block (outbound only)
*/
int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
int q_nr, unsigned int bufnr, unsigned int count)
int q_nr, unsigned int bufnr, unsigned int count, struct qaob *aob)
{
struct qdio_irq *irq_ptr = cdev->private->qdio_data;
......@@ -1383,7 +1336,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
callflags, bufnr, count);
else if (callflags & QDIO_FLAG_SYNC_OUTPUT)
return handle_outbound(irq_ptr->output_qs[q_nr],
callflags, bufnr, count);
callflags, bufnr, count, aob);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(do_QDIO);
......
......@@ -30,6 +30,7 @@ struct qaob *qdio_allocate_aob(void)
{
return kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(qdio_allocate_aob);
void qdio_release_aob(struct qaob *aob)
{
......@@ -247,8 +248,6 @@ static void setup_queues(struct qdio_irq *irq_ptr,
struct qdio_initialize *qdio_init)
{
struct qdio_q *q;
struct qdio_outbuf_state *output_sbal_state_array =
qdio_init->output_sbal_state_array;
int i;
for_each_input_queue(irq_ptr, q, i) {
......@@ -265,9 +264,6 @@ static void setup_queues(struct qdio_irq *irq_ptr,
DBF_EVENT("outq:%1d", i);
setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i);
q->u.out.sbal_state = output_sbal_state_array;
output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q;
q->is_input_q = 0;
setup_storage_lists(q, irq_ptr,
qdio_init->output_sbal_addr_array[i], i);
......@@ -372,30 +368,6 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr)
DBF_EVENT("3:%4x qib:%4x", irq_ptr->ssqd_desc.qdioac3, irq_ptr->qib.ac);
}
void qdio_free_async_data(struct qdio_irq *irq_ptr)
{
struct qdio_q *q;
int i;
for (i = 0; i < irq_ptr->max_output_qs; i++) {
q = irq_ptr->output_qs[i];
if (q->u.out.use_cq) {
unsigned int n;
for (n = 0; n < QDIO_MAX_BUFFERS_PER_Q; n++) {
struct qaob *aob = q->u.out.aobs[n];
if (aob) {
qdio_release_aob(aob);
q->u.out.aobs[n] = NULL;
}
}
qdio_disable_async_operation(&q->u.out);
}
}
}
static void qdio_fill_qdr_desc(struct qdesfmt0 *desc, struct qdio_q *queue)
{
desc->sliba = virt_to_phys(queue->slib);
......@@ -545,25 +517,6 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr)
printk(KERN_INFO "%s", s);
}
int qdio_enable_async_operation(struct qdio_output_q *outq)
{
outq->aobs = kcalloc(QDIO_MAX_BUFFERS_PER_Q, sizeof(struct qaob *),
GFP_KERNEL);
if (!outq->aobs) {
outq->use_cq = 0;
return -ENOMEM;
}
outq->use_cq = 1;
return 0;
}
void qdio_disable_async_operation(struct qdio_output_q *q)
{
kfree(q->aobs);
q->aobs = NULL;
q->use_cq = 0;
}
int __init qdio_setup_init(void)
{
int rc;
......
This diff is collapsed.
......@@ -83,6 +83,8 @@ struct ap_matrix_mdev {
struct ap_matrix matrix;
struct notifier_block group_notifier;
struct notifier_block iommu_notifier;
bool kvm_busy;
wait_queue_head_t wait_for_kvm;
struct kvm *kvm;
struct kvm_s390_module_hook pqap_hook;
struct mdev_device *mdev;
......
......@@ -192,5 +192,6 @@ void zcrypt_card_unregister(struct zcrypt_card *zc)
spin_unlock(&zcrypt_list_lock);
sysfs_remove_group(&zc->card->ap_dev.device.kobj,
&zcrypt_card_attr_group);
zcrypt_card_put(zc);
}
EXPORT_SYMBOL(zcrypt_card_unregister);
......@@ -223,5 +223,6 @@ void zcrypt_queue_unregister(struct zcrypt_queue *zq)
sysfs_remove_group(&zq->queue->ap_dev.device.kobj,
&zcrypt_queue_attr_group);
zcrypt_card_put(zc);
zcrypt_queue_put(zq);
}
EXPORT_SYMBOL(zcrypt_queue_unregister);
......@@ -437,6 +437,7 @@ struct qeth_qdio_out_buffer {
struct qeth_qdio_out_q *q;
struct list_head list_entry;
struct qaob *aob;
};
struct qeth_card;
......@@ -499,7 +500,6 @@ struct qeth_out_q_stats {
struct qeth_qdio_out_q {
struct qdio_buffer *qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qdio_outbuf_state *bufstates; /* convenience pointer */
struct list_head pending_bufs;
struct qeth_out_q_stats stats;
spinlock_t lock;
......@@ -563,7 +563,6 @@ struct qeth_qdio_info {
/* output */
unsigned int no_out_queues;
struct qeth_qdio_out_q *out_qs[QETH_MAX_OUT_QUEUES];
struct qdio_outbuf_state *out_bufstates;
/* priority queueing */
int do_prio_queueing;
......
......@@ -369,8 +369,7 @@ static int qeth_cq_init(struct qeth_card *card)
QDIO_MAX_BUFFERS_PER_Q);
card->qdio.c_q->next_buf_to_init = 127;
rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT,
card->qdio.no_in_queues - 1, 0,
127);
card->qdio.no_in_queues - 1, 0, 127, NULL);
if (rc) {
QETH_CARD_TEXT_(card, 2, "1err%d", rc);
goto out;
......@@ -383,48 +382,22 @@ static int qeth_cq_init(struct qeth_card *card)
static int qeth_alloc_cq(struct qeth_card *card)
{
int rc;
if (card->options.cq == QETH_CQ_ENABLED) {
int i;
struct qdio_outbuf_state *outbuf_states;
QETH_CARD_TEXT(card, 2, "cqon");
card->qdio.c_q = qeth_alloc_qdio_queue();
if (!card->qdio.c_q) {
rc = -1;
goto kmsg_out;
dev_err(&card->gdev->dev, "Failed to create completion queue\n");
return -ENOMEM;
}
card->qdio.no_in_queues = 2;
card->qdio.out_bufstates =
kcalloc(card->qdio.no_out_queues *
QDIO_MAX_BUFFERS_PER_Q,
sizeof(struct qdio_outbuf_state),
GFP_KERNEL);
outbuf_states = card->qdio.out_bufstates;
if (outbuf_states == NULL) {
rc = -1;
goto free_cq_out;
}
for (i = 0; i < card->qdio.no_out_queues; ++i) {
card->qdio.out_qs[i]->bufstates = outbuf_states;
outbuf_states += QDIO_MAX_BUFFERS_PER_Q;
}
} else {
QETH_CARD_TEXT(card, 2, "nocq");
card->qdio.c_q = NULL;
card->qdio.no_in_queues = 1;
}
QETH_CARD_TEXT_(card, 2, "iqc%d", card->qdio.no_in_queues);
rc = 0;
out:
return rc;
free_cq_out:
qeth_free_qdio_queue(card->qdio.c_q);
card->qdio.c_q = NULL;
kmsg_out:
dev_err(&card->gdev->dev, "Failed to create completion queue\n");
goto out;
return 0;
}
static void qeth_free_cq(struct qeth_card *card)
......@@ -434,8 +407,6 @@ static void qeth_free_cq(struct qeth_card *card)
qeth_free_qdio_queue(card->qdio.c_q);
card->qdio.c_q = NULL;
}
kfree(card->qdio.out_bufstates);
card->qdio.out_bufstates = NULL;
}
static enum iucv_tx_notify qeth_compute_cq_notification(int sbalf15,
......@@ -487,12 +458,12 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
switch (atomic_xchg(&buffer->state, new_state)) {
case QETH_QDIO_BUF_PRIMED:
/* Faster than TX completion code, let it handle the async
* completion for us.
* completion for us. It will also recycle the QAOB.
*/
break;
case QETH_QDIO_BUF_PENDING:
/* TX completion code is active and will handle the async
* completion for us.
* completion for us. It will also recycle the QAOB.
*/
break;
case QETH_QDIO_BUF_NEED_QAOB:
......@@ -501,7 +472,7 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
qeth_notify_skbs(buffer->q, buffer, notification);
/* Free dangling allocations. The attached skbs are handled by
* qeth_tx_complete_pending_bufs().
* qeth_tx_complete_pending_bufs(), and so is the QAOB.
*/
for (i = 0;
i < aob->sb_count && i < QETH_MAX_BUFFER_ELEMENTS(card);
......@@ -520,8 +491,6 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
default:
WARN_ON_ONCE(1);
}
qdio_release_aob(aob);
}
static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len,
......@@ -1451,6 +1420,13 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
}
static void qeth_free_out_buf(struct qeth_qdio_out_buffer *buf)
{
if (buf->aob)
qdio_release_aob(buf->aob);
kmem_cache_free(qeth_qdio_outbuf_cache, buf);
}
static void qeth_tx_complete_pending_bufs(struct qeth_card *card,
struct qeth_qdio_out_q *queue,
bool drain)
......@@ -1468,7 +1444,7 @@ static void qeth_tx_complete_pending_bufs(struct qeth_card *card,
qeth_tx_complete_buf(buf, drain, 0);
list_del(&buf->list_entry);
kmem_cache_free(qeth_qdio_outbuf_cache, buf);
qeth_free_out_buf(buf);
}
}
}
......@@ -1485,7 +1461,7 @@ static void qeth_drain_output_queue(struct qeth_qdio_out_q *q, bool free)
qeth_clear_output_buffer(q, q->bufs[j], true, 0);
if (free) {
kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[j]);
qeth_free_out_buf(q->bufs[j]);
q->bufs[j] = NULL;
}
}
......@@ -2637,7 +2613,7 @@ static struct qeth_qdio_out_q *qeth_alloc_output_queue(void)
err_out_bufs:
while (i > 0)
kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[--i]);
qeth_free_out_buf(q->bufs[--i]);
qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q);
err_qdio_bufs:
kfree(q);
......@@ -3024,7 +3000,8 @@ static int qeth_init_qdio_queues(struct qeth_card *card)
}
card->qdio.in_q->next_buf_to_init = QDIO_BUFNR(rx_bufs);
rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0, rx_bufs);
rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0, rx_bufs,
NULL);
if (rc) {
QETH_CARD_TEXT_(card, 2, "1err%d", rc);
return rc;
......@@ -3516,7 +3493,7 @@ static unsigned int qeth_rx_refill_queue(struct qeth_card *card,
}
rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0,
queue->next_buf_to_init, count);
queue->next_buf_to_init, count, NULL);
if (rc) {
QETH_CARD_TEXT(card, 2, "qinberr");
}
......@@ -3625,6 +3602,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
struct qeth_qdio_out_buffer *buf = queue->bufs[index];
unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
struct qeth_card *card = queue->card;
struct qaob *aob = NULL;
int rc;
int i;
......@@ -3637,16 +3615,24 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
SBAL_EFLAGS_LAST_ENTRY;
queue->coalesced_frames += buf->frames;
if (queue->bufstates)
queue->bufstates[bidx].user = buf;
if (IS_IQD(card)) {
skb_queue_walk(&buf->skb_list, skb)
skb_tx_timestamp(skb);
}
}
if (!IS_IQD(card)) {
if (IS_IQD(card)) {
if (card->options.cq == QETH_CQ_ENABLED &&
!qeth_iqd_is_mcast_queue(card, queue) &&
count == 1) {
if (!buf->aob)
buf->aob = qdio_allocate_aob();
if (buf->aob) {
aob = buf->aob;
aob->user1 = (u64) buf;
}
}
} else {
if (!queue->do_pack) {
if ((atomic_read(&queue->used_buffers) >=
(QETH_HIGH_WATERMARK_PACK -
......@@ -3677,8 +3663,8 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
}
QETH_TXQ_STAT_INC(queue, doorbell);
rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags,
queue->queue_no, index, count);
rc = do_QDIO(CARD_DDEV(card), qdio_flags, queue->queue_no, index, count,
aob);
switch (rc) {
case 0:
......@@ -3814,8 +3800,7 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err,
qeth_scrub_qdio_buffer(buffer, QDIO_MAX_ELEMENTS_PER_BUFFER);
}
rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, queue,
card->qdio.c_q->next_buf_to_init,
count);
cq->next_buf_to_init, count, NULL);
if (rc) {
dev_warn(&card->gdev->dev,
"QDIO reported an error, rc=%i\n", rc);
......@@ -5270,7 +5255,6 @@ static int qeth_qdio_establish(struct qeth_card *card)
init_data.int_parm = (unsigned long) card;
init_data.input_sbal_addr_array = in_sbal_ptrs;
init_data.output_sbal_addr_array = out_sbal_ptrs;
init_data.output_sbal_state_array = card->qdio.out_bufstates;
init_data.scan_threshold = IS_IQD(card) ? 0 : 32;
if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED,
......@@ -6069,7 +6053,15 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
bool error = !!qdio_error;
if (qdio_error == QDIO_ERROR_SLSB_PENDING) {
WARN_ON_ONCE(card->options.cq != QETH_CQ_ENABLED);
struct qaob *aob = buffer->aob;
if (!aob) {
netdev_WARN_ONCE(card->dev,
"Pending TX buffer %#x without QAOB on TX queue %u\n",
bidx, queue->queue_no);
qeth_schedule_recovery(card);
return;
}
QETH_CARD_TEXT_(card, 5, "pel%u", bidx);
......@@ -6125,6 +6117,8 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
default:
WARN_ON_ONCE(1);
}
memset(aob, 0, sizeof(*aob));
} else if (card->options.cq == QETH_CQ_ENABLED) {
qeth_notify_skbs(queue, buffer,
qeth_compute_cq_notification(sflags, 0));
......
......@@ -128,7 +128,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
/*
* put SBALs back to response queue
*/
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count))
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count, NULL))
zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2");
}
......@@ -298,7 +298,7 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
atomic_sub(sbal_number, &qdio->req_q_free);
retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0,
q_req->sbal_first, sbal_number);
q_req->sbal_first, sbal_number, NULL);
if (unlikely(retval)) {
/* Failed to submit the IO, roll back our modifications. */
......@@ -463,7 +463,8 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
sbale->addr = 0;
}
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q))
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q,
NULL))
goto failed_qdio;
/* set index of first available SBALS / number of available SBALS */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment