aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2011-05-26 03:48:23 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2011-05-26 03:48:24 -0400
commitdf7997ab1ca82ae3c37a2f5eb98613fc24527f95 (patch)
tree51794f46cb7fc7fa4db8fbadb8feb265fc8ef499 /arch/s390/kernel
parent902050bcdece6191565c055539e82c5cc534feed (diff)
[S390] irq: fix service signal external interrupt handling
Interrupt sources like pfault, sclp, dasd_diag and virtio all use the service signal external interrupt subclass mask in control register 0 to enable and disable the corresponding interrupt. Because no reference counting is implemented each subsystem thinks it is the only user of subclass and sets and clears the bit like it wants. This leads to case that unloading the dasd diag module under z/VM causes both sclp and pfault interrupts to be masked. The result will be locked up system sooner or later. Fix this by introducing a new way to set (register) and clear (unregister) the service signal subclass mask bit in cr0. Also convert all drivers. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/s390_ext.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
index 185029919c4d..87b5c532abf1 100644
--- a/arch/s390/kernel/s390_ext.c
+++ b/arch/s390/kernel/s390_ext.c
@@ -106,3 +106,26 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
106 irq_exit(); 106 irq_exit();
107 set_irq_regs(old_regs); 107 set_irq_regs(old_regs);
108} 108}
109
110static DEFINE_SPINLOCK(sc_irq_lock);
111static int sc_irq_refcount;
112
113void service_subclass_irq_register(void)
114{
115 spin_lock(&sc_irq_lock);
116 if (!sc_irq_refcount)
117 ctl_set_bit(0, 9);
118 sc_irq_refcount++;
119 spin_unlock(&sc_irq_lock);
120}
121EXPORT_SYMBOL(service_subclass_irq_register);
122
123void service_subclass_irq_unregister(void)
124{
125 spin_lock(&sc_irq_lock);
126 sc_irq_refcount--;
127 if (!sc_irq_refcount)
128 ctl_clear_bit(0, 9);
129 spin_unlock(&sc_irq_lock);
130}
131EXPORT_SYMBOL(service_subclass_irq_unregister);