Commit cc106eb3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6

* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6:
  [S390] fill out file list in s390 MAINTAINERS entry
  [S390] Add support for LZO-compressed kernels.
  [S390] cmm: get rid of CMM_PROC config option
  [S390] cmm: remove superfluous EXPORT_SYMBOLs plus cleanups
  [S390] dasd: unit check handling during internal cio I/O
  [S390] cio: unit check handling during internal I/O
  [S390] ccwgroup: add locking around drvdata access
  [S390] cio: remove stsch
  [S390] spp: remove KVM_AWARE_CMF config option
  [S390] kprobes: forbid probing of stnsm/stosm/epsw
  [S390] spp: fix compilation for CONFIG_32BIT
  [S390] atomic: implement atomic64_dec_if_positive
  [S390] cmm: fix crash on module unload
parents 4e455c67 3bfe6858
...@@ -4836,6 +4836,9 @@ W: http://www.ibm.com/developerworks/linux/linux390/ ...@@ -4836,6 +4836,9 @@ W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported S: Supported
F: arch/s390/ F: arch/s390/
F: drivers/s390/ F: drivers/s390/
F: fs/partitions/ibm.c
F: Documentation/s390/
F: Documentation/DocBook/s390*
S390 NETWORK DRIVERS S390 NETWORK DRIVERS
M: Ursula Braun <ursula.braun@de.ibm.com> M: Ursula Braun <ursula.braun@de.ibm.com>
......
...@@ -102,6 +102,7 @@ config S390 ...@@ -102,6 +102,7 @@ config S390
select HAVE_KERNEL_GZIP select HAVE_KERNEL_GZIP
select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
select ARCH_INLINE_SPIN_TRYLOCK select ARCH_INLINE_SPIN_TRYLOCK
select ARCH_INLINE_SPIN_TRYLOCK_BH select ARCH_INLINE_SPIN_TRYLOCK_BH
select ARCH_INLINE_SPIN_LOCK select ARCH_INLINE_SPIN_LOCK
...@@ -479,13 +480,6 @@ config CMM ...@@ -479,13 +480,6 @@ config CMM
Everybody who wants to run Linux under VM should select this Everybody who wants to run Linux under VM should select this
option. option.
config CMM_PROC
bool "/proc interface to cooperative memory management"
depends on CMM
help
Select this option to enable the /proc interface to the
cooperative memory management.
config CMM_IUCV config CMM_IUCV
bool "IUCV special message interface to cooperative memory management" bool "IUCV special message interface to cooperative memory management"
depends on CMM && (SMSGIUCV=y || CMM=SMSGIUCV) depends on CMM && (SMSGIUCV=y || CMM=SMSGIUCV)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
BITS := $(if $(CONFIG_64BIT),64,31) BITS := $(if $(CONFIG_64BIT),64,31)
targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \ targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \
vmlinux.bin.lzma misc.o piggy.o sizes.h head$(BITS).o vmlinux.bin.lzma vmlinux.bin.lzo misc.o piggy.o sizes.h head$(BITS).o
KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
KBUILD_CFLAGS += $(cflags-y) KBUILD_CFLAGS += $(cflags-y)
...@@ -47,6 +47,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin ...@@ -47,6 +47,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin
suffix-$(CONFIG_KERNEL_GZIP) := gz suffix-$(CONFIG_KERNEL_GZIP) := gz
suffix-$(CONFIG_KERNEL_BZIP2) := bz2 suffix-$(CONFIG_KERNEL_BZIP2) := bz2
suffix-$(CONFIG_KERNEL_LZMA) := lzma suffix-$(CONFIG_KERNEL_LZMA) := lzma
suffix-$(CONFIG_KERNEL_LZO) := lzo
$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y)
$(call if_changed,gzip) $(call if_changed,gzip)
...@@ -54,6 +55,8 @@ $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) ...@@ -54,6 +55,8 @@ $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y)
$(call if_changed,bzip2) $(call if_changed,bzip2)
$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y)
$(call if_changed,lzma) $(call if_changed,lzma)
$(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y)
$(call if_changed,lzo)
LDFLAGS_piggy.o := -r --format binary --oformat $(LD_BFD) -T LDFLAGS_piggy.o := -r --format binary --oformat $(LD_BFD) -T
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y)
......
...@@ -50,6 +50,10 @@ static unsigned long free_mem_end_ptr; ...@@ -50,6 +50,10 @@ static unsigned long free_mem_end_ptr;
#include "../../../../lib/decompress_unlzma.c" #include "../../../../lib/decompress_unlzma.c"
#endif #endif
#ifdef CONFIG_KERNEL_LZO
#include "../../../../lib/decompress_unlzo.c"
#endif
extern _sclp_print_early(const char *); extern _sclp_print_early(const char *);
int puts(const char *s) int puts(const char *s)
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/system.h>
#define ATOMIC_INIT(i) { (i) } #define ATOMIC_INIT(i) { (i) }
...@@ -274,6 +275,7 @@ static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v) ...@@ -274,6 +275,7 @@ static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v)
static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
{ {
long long c, old; long long c, old;
c = atomic64_read(v); c = atomic64_read(v);
for (;;) { for (;;) {
if (unlikely(c == u)) if (unlikely(c == u))
...@@ -286,6 +288,23 @@ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) ...@@ -286,6 +288,23 @@ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
return c != u; return c != u;
} }
static inline long long atomic64_dec_if_positive(atomic64_t *v)
{
long long c, old, dec;
c = atomic64_read(v);
for (;;) {
dec = c - 1;
if (unlikely(dec < 0))
break;
old = atomic64_cmpxchg((v), c, dec);
if (likely(old == c))
break;
c = old;
}
return dec;
}
#define atomic64_add(_i, _v) atomic64_add_return(_i, _v) #define atomic64_add(_i, _v) atomic64_add_return(_i, _v)
#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0) #define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0)
#define atomic64_inc(_v) atomic64_add_return(1, _v) #define atomic64_inc(_v) atomic64_add_return(1, _v)
......
...@@ -91,6 +91,14 @@ struct ccw_device { ...@@ -91,6 +91,14 @@ struct ccw_device {
void (*handler) (struct ccw_device *, unsigned long, struct irb *); void (*handler) (struct ccw_device *, unsigned long, struct irb *);
}; };
/*
* Possible CIO actions triggered by the unit check handler.
*/
enum uc_todo {
UC_TODO_RETRY,
UC_TODO_RETRY_ON_NEW_PATH,
UC_TODO_STOP
};
/** /**
* struct ccw driver - device driver for channel attached devices * struct ccw driver - device driver for channel attached devices
...@@ -107,6 +115,7 @@ struct ccw_device { ...@@ -107,6 +115,7 @@ struct ccw_device {
* @freeze: callback for freezing during hibernation snapshotting * @freeze: callback for freezing during hibernation snapshotting
* @thaw: undo work done in @freeze * @thaw: undo work done in @freeze
* @restore: callback for restoring after hibernation * @restore: callback for restoring after hibernation
* @uc_handler: callback for unit check handler
* @driver: embedded device driver structure * @driver: embedded device driver structure
* @name: device driver name * @name: device driver name
*/ */
...@@ -124,6 +133,7 @@ struct ccw_driver { ...@@ -124,6 +133,7 @@ struct ccw_driver {
int (*freeze)(struct ccw_device *); int (*freeze)(struct ccw_device *);
int (*thaw) (struct ccw_device *); int (*thaw) (struct ccw_device *);
int (*restore)(struct ccw_device *); int (*restore)(struct ccw_device *);
enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *);
struct device_driver driver; struct device_driver driver;
char *name; char *name;
}; };
......
...@@ -132,8 +132,6 @@ int main(void) ...@@ -132,8 +132,6 @@ int main(void)
DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func));
DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook));
DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));
DEFINE(__LC_IRB, offsetof(struct _lowcore, irb)); DEFINE(__LC_IRB, offsetof(struct _lowcore, irb));
DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area));
DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area)); DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area));
...@@ -154,6 +152,8 @@ int main(void) ...@@ -154,6 +152,8 @@ int main(void)
DEFINE(__LC_FP_CREG_SAVE_AREA, offsetof(struct _lowcore, fpt_creg_save_area)); DEFINE(__LC_FP_CREG_SAVE_AREA, offsetof(struct _lowcore, fpt_creg_save_area));
DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr)); DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr));
DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data)); DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook));
DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));
#endif /* CONFIG_32BIT */ #endif /* CONFIG_32BIT */
return 0; return 0;
} }
...@@ -65,7 +65,7 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ ...@@ -65,7 +65,7 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \
ltgr %r3,%r3 ltgr %r3,%r3
jz 0f jz 0f
basr %r14,%r3 basr %r14,%r3
0: 0:
#endif #endif
.endm .endm
......
...@@ -63,6 +63,8 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction) ...@@ -63,6 +63,8 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
case 0x0b: /* bsm */ case 0x0b: /* bsm */
case 0x83: /* diag */ case 0x83: /* diag */
case 0x44: /* ex */ case 0x44: /* ex */
case 0xac: /* stnsm */
case 0xad: /* stosm */
return -EINVAL; return -EINVAL;
} }
switch (*(__u16 *) instruction) { switch (*(__u16 *) instruction) {
...@@ -72,6 +74,7 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction) ...@@ -72,6 +74,7 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
case 0xb258: /* bsg */ case 0xb258: /* bsg */
case 0xb218: /* pc */ case 0xb218: /* pc */
case 0xb228: /* pt */ case 0xb228: /* pt */
case 0xb98d: /* epsw */
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
......
...@@ -401,7 +401,6 @@ setup_lowcore(void) ...@@ -401,7 +401,6 @@ setup_lowcore(void)
lc->io_new_psw.mask = psw_kernel_bits; lc->io_new_psw.mask = psw_kernel_bits;
lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
lc->clock_comparator = -1ULL; lc->clock_comparator = -1ULL;
lc->cmf_hpp = -1ULL;
lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
lc->async_stack = (unsigned long) lc->async_stack = (unsigned long)
__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
...@@ -418,6 +417,7 @@ setup_lowcore(void) ...@@ -418,6 +417,7 @@ setup_lowcore(void)
__ctl_set_bit(14, 29); __ctl_set_bit(14, 29);
} }
#else #else
lc->cmf_hpp = -1ULL;
lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0];
#endif #endif
lc->sync_enter_timer = S390_lowcore.sync_enter_timer; lc->sync_enter_timer = S390_lowcore.sync_enter_timer;
......
...@@ -33,17 +33,6 @@ config KVM ...@@ -33,17 +33,6 @@ config KVM
If unsure, say N. If unsure, say N.
config KVM_AWARE_CMF
depends on KVM
bool "KVM aware sampling"
---help---
This option enhances the sampling data from the CPU Measurement
Facility with additional information, that allows to distinguish
guest(s) and host when using the kernel based virtual machine
functionality.
If unsure, say N.
# OK, it's a little counter-intuitive to do this, but it puts it neatly under # OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu. # the virtualization menu.
source drivers/vhost/Kconfig source drivers/vhost/Kconfig
......
...@@ -32,12 +32,10 @@ SPI_PSW = STACK_FRAME_OVERHEAD + __PT_PSW ...@@ -32,12 +32,10 @@ SPI_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
.macro SPP newpp .macro SPP newpp
#ifdef CONFIG_KVM_AWARE_CMF
tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP
jz 0f jz 0f
.insn s,0xb2800000,\newpp .insn s,0xb2800000,\newpp
0: 0:
#endif
.endm .endm
sie_irq_handler: sie_irq_handler:
......
/* /*
* arch/s390/mm/cmm.c * Collaborative memory management interface.
* *
* S390 version * Copyright IBM Corp 2003,2010
* Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
* *
* Collaborative memory management interface.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
...@@ -20,9 +18,9 @@ ...@@ -20,9 +18,9 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/uaccess.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <asm/diag.h> #include <asm/diag.h>
static char *sender = "VMRMSVM"; static char *sender = "VMRMSVM";
...@@ -53,14 +51,14 @@ static struct cmm_page_array *cmm_timed_page_list; ...@@ -53,14 +51,14 @@ static struct cmm_page_array *cmm_timed_page_list;
static DEFINE_SPINLOCK(cmm_lock); static DEFINE_SPINLOCK(cmm_lock);
static struct task_struct *cmm_thread_ptr; static struct task_struct *cmm_thread_ptr;
static wait_queue_head_t cmm_thread_wait; static DECLARE_WAIT_QUEUE_HEAD(cmm_thread_wait);
static struct timer_list cmm_timer; static DEFINE_TIMER(cmm_timer, NULL, 0, 0);
static void cmm_timer_fn(unsigned long); static void cmm_timer_fn(unsigned long);
static void cmm_set_timer(void); static void cmm_set_timer(void);
static long static long cmm_alloc_pages(long nr, long *counter,
cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list) struct cmm_page_array **list)
{ {
struct cmm_page_array *pa, *npa; struct cmm_page_array *pa, *npa;
unsigned long addr; unsigned long addr;
...@@ -99,8 +97,7 @@ cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list) ...@@ -99,8 +97,7 @@ cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list)
return nr; return nr;
} }
static long static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
{ {
struct cmm_page_array *pa; struct cmm_page_array *pa;
unsigned long addr; unsigned long addr;
...@@ -140,11 +137,10 @@ static int cmm_oom_notify(struct notifier_block *self, ...@@ -140,11 +137,10 @@ static int cmm_oom_notify(struct notifier_block *self,
} }
static struct notifier_block cmm_oom_nb = { static struct notifier_block cmm_oom_nb = {
.notifier_call = cmm_oom_notify .notifier_call = cmm_oom_notify,
}; };
static int static int cmm_thread(void *dummy)
cmm_thread(void *dummy)
{ {
int rc; int rc;
...@@ -170,7 +166,7 @@ cmm_thread(void *dummy) ...@@ -170,7 +166,7 @@ cmm_thread(void *dummy)
cmm_timed_pages_target = cmm_timed_pages; cmm_timed_pages_target = cmm_timed_pages;
} else if (cmm_timed_pages_target < cmm_timed_pages) { } else if (cmm_timed_pages_target < cmm_timed_pages) {
cmm_free_pages(1, &cmm_timed_pages, cmm_free_pages(1, &cmm_timed_pages,
&cmm_timed_page_list); &cmm_timed_page_list);
} }
if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer)) if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer))
cmm_set_timer(); cmm_set_timer();
...@@ -178,14 +174,12 @@ cmm_thread(void *dummy) ...@@ -178,14 +174,12 @@ cmm_thread(void *dummy)
return 0; return 0;
} }
static void static void cmm_kick_thread(void)
cmm_kick_thread(void)
{ {
wake_up(&cmm_thread_wait); wake_up(&cmm_thread_wait);
} }
static void static void cmm_set_timer(void)
cmm_set_timer(void)
{ {
if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) { if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) {
if (timer_pending(&cmm_timer)) if (timer_pending(&cmm_timer))
...@@ -202,8 +196,7 @@ cmm_set_timer(void) ...@@ -202,8 +196,7 @@ cmm_set_timer(void)
add_timer(&cmm_timer); add_timer(&cmm_timer);
} }
static void static void cmm_timer_fn(unsigned long ignored)
cmm_timer_fn(unsigned long ignored)
{ {
long nr; long nr;
...@@ -216,57 +209,49 @@ cmm_timer_fn(unsigned long ignored) ...@@ -216,57 +209,49 @@ cmm_timer_fn(unsigned long ignored)
cmm_set_timer(); cmm_set_timer();
} }
void static void cmm_set_pages(long nr)
cmm_set_pages(long nr)
{ {
cmm_pages_target = nr; cmm_pages_target = nr;
cmm_kick_thread(); cmm_kick_thread();
} }
long static long cmm_get_pages(void)
cmm_get_pages(void)
{ {
return cmm_pages; return cmm_pages;
} }
void static void cmm_add_timed_pages(long nr)
cmm_add_timed_pages(long nr)
{ {
cmm_timed_pages_target += nr; cmm_timed_pages_target += nr;
cmm_kick_thread(); cmm_kick_thread();
} }
long static long cmm_get_timed_pages(void)
cmm_get_timed_pages(void)
{ {
return cmm_timed_pages; return cmm_timed_pages;
} }
void static void cmm_set_timeout(long nr, long seconds)
cmm_set_timeout(long nr, long seconds)
{ {
cmm_timeout_pages = nr; cmm_timeout_pages = nr;
cmm_timeout_seconds = seconds; cmm_timeout_seconds = seconds;
cmm_set_timer(); cmm_set_timer();
} }
static int static int cmm_skip_blanks(char *cp, char **endp)
cmm_skip_blanks(char *cp, char **endp)
{ {
char *str; char *str;
for (str = cp; *str == ' ' || *str == '\t'; str++); for (str = cp; *str == ' ' || *str == '\t'; str++)
;
*endp = str; *endp = str;
return str != cp; return str != cp;
} }
#ifdef CONFIG_CMM_PROC
static struct ctl_table cmm_table[]; static struct ctl_table cmm_table[];
static int static int cmm_pages_handler(ctl_table *ctl, int write, void __user *buffer,
cmm_pages_handler(ctl_table *ctl, int write, size_t *lenp, loff_t *ppos)
void __user *buffer, size_t *lenp, loff_t *ppos)
{ {
char buf[16], *p; char buf[16], *p;
long nr; long nr;
...@@ -305,9 +290,8 @@ cmm_pages_handler(ctl_table *ctl, int write, ...@@ -305,9 +290,8 @@ cmm_pages_handler(ctl_table *ctl, int write,
return 0; return 0;
} }
static int static int cmm_timeout_handler(ctl_table *ctl, int write, void __user *buffer,
cmm_timeout_handler(ctl_table *ctl, int write, size_t *lenp, loff_t *ppos)
void __user *buffer, size_t *lenp, loff_t *ppos)
{ {
char buf[64], *p; char buf[64], *p;
long nr, seconds; long nr, seconds;
...@@ -370,12 +354,10 @@ static struct ctl_table cmm_dir_table[] = { ...@@ -370,12 +354,10 @@ static struct ctl_table cmm_dir_table[] = {
}, },
{ } { }
}; };
#endif
#ifdef CONFIG_CMM_IUCV #ifdef CONFIG_CMM_IUCV
#define SMSG_PREFIX "CMM" #define SMSG_PREFIX "CMM"
static void static void cmm_smsg_target(const char *from, char *msg)
cmm_smsg_target(const char *from, char *msg)
{ {
long nr, seconds; long nr, seconds;
...@@ -445,16 +427,13 @@ static struct notifier_block cmm_power_notifier = { ...@@ -445,16 +427,13 @@ static struct notifier_block cmm_power_notifier = {
.notifier_call = cmm_power_event, .notifier_call = cmm_power_event,
}; };
static int static int cmm_init(void)
cmm_init (void)
{ {
int rc = -ENOMEM; int rc = -ENOMEM;
#ifdef CONFIG_CMM_PROC
cmm_sysctl_header = register_sysctl_table(cmm_dir_table); cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
if (!cmm_sysctl_header) if (!cmm_sysctl_header)
goto out_sysctl; goto out_sysctl;
#endif
#ifdef CONFIG_CMM_IUCV #ifdef CONFIG_CMM_IUCV
rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
if (rc < 0) if (rc < 0)
...@@ -466,8 +445,6 @@ cmm_init (void) ...@@ -466,8 +445,6 @@ cmm_init (void)
rc = register_pm_notifier(&cmm_power_notifier); rc = register_pm_notifier(&cmm_power_notifier);
if (rc) if (rc)
goto out_pm; goto out_pm;
init_waitqueue_head(&cmm_thread_wait);
init_timer(&cmm_timer);
cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0; rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
if (rc) if (rc)
...@@ -483,36 +460,26 @@ cmm_init (void) ...@@ -483,36 +460,26 @@ cmm_init (void)
smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
out_smsg: out_smsg:
#endif #endif
#ifdef CONFIG_CMM_PROC
unregister_sysctl_table(cmm_sysctl_header); unregister_sysctl_table(cmm_sysctl_header);
out_sysctl: out_sysctl:
#endif del_timer_sync(&cmm_timer);
return rc; return rc;
} }
module_init(cmm_init);
static void static void cmm_exit(void)
cmm_exit(void)
{ {
kthread_stop(cmm_thread_ptr);
unregister_pm_notifier(&cmm_power_notifier);
unregister_oom_notifier(&cmm_oom_nb);
cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
#ifdef CONFIG_CMM_PROC
unregister_sysctl_table(cmm_sysctl_header); unregister_sysctl_table(cmm_sysctl_header);
#endif
#ifdef CONFIG_CMM_IUCV #ifdef CONFIG_CMM_IUCV
smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
#endif #endif
unregister_pm_notifier(&cmm_power_notifier);
unregister_oom_notifier(&cmm_oom_nb);
kthread_stop(cmm_thread_ptr);
del_timer_sync(&cmm_timer);
cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
} }
module_init(cmm_init);
module_exit(cmm_exit); module_exit(cmm_exit);
EXPORT_SYMBOL(cmm_set_pages);
EXPORT_SYMBOL(cmm_get_pages);
EXPORT_SYMBOL(cmm_add_timed_pages);
EXPORT_SYMBOL(cmm_get_timed_pages);
EXPORT_SYMBOL(cmm_set_timeout);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -1186,6 +1186,29 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -1186,6 +1186,29 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
dasd_schedule_device_bh(device); dasd_schedule_device_bh(device);
} }
enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb)
{
struct dasd_device *device;
device = dasd_device_from_cdev_locked(cdev);
if (IS_ERR(device))
goto out;
if (test_bit(DASD_FLAG_OFFLINE, &device->flags) ||
device->state != device->target ||
!device->discipline->handle_unsolicited_interrupt){
dasd_put_device(device);
goto out;
}
dasd_device_clear_timer(device);
device->discipline->handle_unsolicited_interrupt(device, irb);
dasd_put_device(device);
out:
return UC_TODO_RETRY;
}
EXPORT_SYMBOL_GPL(dasd_generic_uc_handler);
/* /*
* If we have an error on a dasd_block layer request then we cancel * If we have an error on a dasd_block layer request then we cancel
* and return all further requests from the same dasd_block as well. * and return all further requests from the same dasd_block as well.
......
...@@ -3436,6 +3436,7 @@ static struct ccw_driver dasd_eckd_driver = { ...@@ -3436,6 +3436,7 @@ static struct ccw_driver dasd_eckd_driver = {
.freeze = dasd_generic_pm_freeze, .freeze = dasd_generic_pm_freeze,
.thaw = dasd_generic_restore_device, .thaw = dasd_generic_restore_device,
.restore = dasd_generic_restore_device, .restore = dasd_generic_restore_device,
.uc_handler = dasd_generic_uc_handler,
}; };
/* /*
......
...@@ -617,6 +617,7 @@ int dasd_generic_notify(struct ccw_device *, int); ...@@ -617,6 +617,7 @@ int dasd_generic_notify(struct ccw_device *, int);
void dasd_generic_handle_state_change(struct dasd_device *); void dasd_generic_handle_state_change(struct dasd_device *);
int dasd_generic_pm_freeze(struct ccw_device *); int dasd_generic_pm_freeze(struct ccw_device *);
int dasd_generic_restore_device(struct ccw_device *); int dasd_generic_restore_device(struct ccw_device *);
enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *);
int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
char *dasd_get_sense(struct irb *); char *dasd_get_sense(struct irb *);
......
...@@ -123,8 +123,10 @@ ccwgroup_release (struct device *dev) ...@@ -123,8 +123,10 @@ ccwgroup_release (struct device *dev)
for (i = 0; i < gdev->count; i++) { for (i = 0; i < gdev->count; i++) {
if (gdev->cdev[i]) { if (gdev->cdev[i]) {
spin_lock_irq(gdev->cdev[i]->ccwlock);
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL); dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
spin_unlock_irq(gdev->cdev[i]->ccwlock);
put_device(&gdev->cdev[i]->dev); put_device(&gdev->cdev[i]->dev);
} }
} }
...@@ -262,11 +264,14 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, ...@@ -262,11 +264,14 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
goto error; goto error;
} }
/* Don't allow a device to belong to more than one group. */ /* Don't allow a device to belong to more than one group. */
spin_lock_irq(gdev->cdev[i]->ccwlock);
if (dev_get_drvdata(&gdev->cdev[i]->dev)) { if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
spin_unlock_irq(gdev->cdev[i]->ccwlock);
rc = -EINVAL; rc = -EINVAL;
goto error; goto error;
} }
dev_set_drvdata(&gdev->cdev[i]->dev, gdev); dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
spin_unlock_irq(gdev->cdev[i]->ccwlock);
} }
/* Check for sufficient number of bus ids. */ /* Check for sufficient number of bus ids. */
if (i < num_devices && !curr_buf) { if (i < num_devices && !curr_buf) {
...@@ -303,8 +308,10 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, ...@@ -303,8 +308,10 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
error: error:
for (i = 0; i < num_devices; i++) for (i = 0; i < num_devices; i++)
if (gdev->cdev[i]) { if (gdev->cdev[i]) {
spin_lock_irq(gdev->cdev[i]->ccwlock);
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL); dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
spin_unlock_irq(gdev->cdev[i]->ccwlock);
put_device(&gdev->cdev[i]->dev); put_device(&gdev->cdev[i]->dev);
gdev->cdev[i] = NULL; gdev->cdev[i] = NULL;
} }
......
...@@ -159,6 +159,7 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) ...@@ -159,6 +159,7 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
{ {
struct irb *irb = &cdev->private->irb; struct irb *irb = &cdev->private->irb;
struct cmd_scsw *scsw = &irb->scsw.cmd; struct cmd_scsw *scsw = &irb->scsw.cmd;
enum uc_todo todo;
/* Perform BASIC SENSE if needed. */ /* Perform BASIC SENSE if needed. */
if (ccw_device_accumulate_and_sense(cdev, lcirb)) if (ccw_device_accumulate_and_sense(cdev, lcirb))
...@@ -178,6 +179,20 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) ...@@ -178,6 +179,20 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
/* Check for command reject. */ /* Check for command reject. */
if (irb->ecw[0] & SNS0_CMD_REJECT) if (irb->ecw[0] & SNS0_CMD_REJECT)
return IO_REJECTED; return IO_REJECTED;
/* Ask the driver what to do */
if (cdev->drv && cdev->drv->uc_handler) {
todo = cdev->drv->uc_handler(cdev, lcirb);
switch (todo) {
case UC_TODO_RETRY:
return IO_STATUS_ERROR;
case UC_TODO_RETRY_ON_NEW_PATH:
return IO_PATH_ERROR;
case UC_TODO_STOP:
return IO_REJECTED;
default:
return IO_STATUS_ERROR;
}
}
/* Assume that unexpected SENSE data implies an error. */ /* Assume that unexpected SENSE data implies an error. */
return IO_STATUS_ERROR; return IO_STATUS_ERROR;
} }
......
...@@ -23,21 +23,6 @@ struct tpi_info { ...@@ -23,21 +23,6 @@ struct tpi_info {
* Some S390 specific IO instructions as inline * Some S390 specific IO instructions as inline
*/ */
static inline int stsch(struct subchannel_id schid, struct schib *addr)
{
register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
asm volatile(
" stsch 0(%3)\n"
" ipm %0\n"
" srl %0,28"
: "=d" (ccode), "=m" (*addr)
: "d" (reg1), "a" (addr)
: "cc");
return ccode;
}
static inline int stsch_err(struct subchannel_id schid, struct schib *addr) static inline int stsch_err(struct subchannel_id schid, struct schib *addr)
{ {
register struct subchannel_id reg1 asm ("1") = schid; register struct subchannel_id reg1 asm ("1") = schid;
......
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