aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/s390/include/asm/s390_ext.h2
-rw-r--r--arch/s390/kernel/s390_ext.c23
-rw-r--r--arch/s390/mm/fault.c2
-rw-r--r--drivers/s390/block/dasd_diag.c4
-rw-r--r--drivers/s390/char/sclp.c6
-rw-r--r--drivers/s390/kvm/kvm_virtio.c2
6 files changed, 32 insertions, 7 deletions
diff --git a/arch/s390/include/asm/s390_ext.h b/arch/s390/include/asm/s390_ext.h
index 080876d5f196..85b2154b899f 100644
--- a/arch/s390/include/asm/s390_ext.h
+++ b/arch/s390/include/asm/s390_ext.h
@@ -13,5 +13,7 @@ typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
13 13
14int register_external_interrupt(__u16 code, ext_int_handler_t handler); 14int register_external_interrupt(__u16 code, ext_int_handler_t handler);
15int unregister_external_interrupt(__u16 code, ext_int_handler_t handler); 15int unregister_external_interrupt(__u16 code, ext_int_handler_t handler);
16void service_subclass_irq_register(void);
17void service_subclass_irq_unregister(void);
16 18
17#endif /* _S390_EXTINT_H */ 19#endif /* _S390_EXTINT_H */
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);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index e46ba2927424..6e922b50efa4 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -613,7 +613,7 @@ static int __init pfault_irq_init(void)
613 rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP; 613 rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP;
614 if (rc) 614 if (rc)
615 goto out_pfault; 615 goto out_pfault;
616 ctl_set_bit(0, 9); 616 service_subclass_irq_register();
617 hotcpu_notifier(pfault_cpu_notify, 0); 617 hotcpu_notifier(pfault_cpu_notify, 0);
618 return 0; 618 return 0;
619 619
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 85dddb1e4126..5e8e82db1886 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -642,7 +642,7 @@ dasd_diag_init(void)
642 } 642 }
643 ASCEBC(dasd_diag_discipline.ebcname, 4); 643 ASCEBC(dasd_diag_discipline.ebcname, 4);
644 644
645 ctl_set_bit(0, 9); 645 service_subclass_irq_register();
646 register_external_interrupt(0x2603, dasd_ext_handler); 646 register_external_interrupt(0x2603, dasd_ext_handler);
647 dasd_diag_discipline_pointer = &dasd_diag_discipline; 647 dasd_diag_discipline_pointer = &dasd_diag_discipline;
648 return 0; 648 return 0;
@@ -652,7 +652,7 @@ static void __exit
652dasd_diag_cleanup(void) 652dasd_diag_cleanup(void)
653{ 653{
654 unregister_external_interrupt(0x2603, dasd_ext_handler); 654 unregister_external_interrupt(0x2603, dasd_ext_handler);
655 ctl_clear_bit(0, 9); 655 service_subclass_irq_unregister();
656 dasd_diag_discipline_pointer = NULL; 656 dasd_diag_discipline_pointer = NULL;
657} 657}
658 658
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index b76c61f82485..b37b98cbbd00 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -885,12 +885,12 @@ sclp_check_interface(void)
885 spin_unlock_irqrestore(&sclp_lock, flags); 885 spin_unlock_irqrestore(&sclp_lock, flags);
886 /* Enable service-signal interruption - needs to happen 886 /* Enable service-signal interruption - needs to happen
887 * with IRQs enabled. */ 887 * with IRQs enabled. */
888 ctl_set_bit(0, 9); 888 service_subclass_irq_register();
889 /* Wait for signal from interrupt or timeout */ 889 /* Wait for signal from interrupt or timeout */
890 sclp_sync_wait(); 890 sclp_sync_wait();
891 /* Disable service-signal interruption - needs to happen 891 /* Disable service-signal interruption - needs to happen
892 * with IRQs enabled. */ 892 * with IRQs enabled. */
893 ctl_clear_bit(0,9); 893 service_subclass_irq_unregister();
894 spin_lock_irqsave(&sclp_lock, flags); 894 spin_lock_irqsave(&sclp_lock, flags);
895 del_timer(&sclp_request_timer); 895 del_timer(&sclp_request_timer);
896 if (sclp_init_req.status == SCLP_REQ_DONE && 896 if (sclp_init_req.status == SCLP_REQ_DONE &&
@@ -1070,7 +1070,7 @@ sclp_init(void)
1070 spin_unlock_irqrestore(&sclp_lock, flags); 1070 spin_unlock_irqrestore(&sclp_lock, flags);
1071 /* Enable service-signal external interruption - needs to happen with 1071 /* Enable service-signal external interruption - needs to happen with
1072 * IRQs enabled. */ 1072 * IRQs enabled. */
1073 ctl_set_bit(0, 9); 1073 service_subclass_irq_register();
1074 sclp_init_mask(1); 1074 sclp_init_mask(1);
1075 return 0; 1075 return 0;
1076 1076
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 607998f0b7d8..724b5923b6e2 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -441,7 +441,7 @@ static int __init kvm_devices_init(void)
441 441
442 INIT_WORK(&hotplug_work, hotplug_devices); 442 INIT_WORK(&hotplug_work, hotplug_devices);
443 443
444 ctl_set_bit(0, 9); 444 service_subclass_irq_register();
445 register_external_interrupt(0x2603, kvm_extint_handler); 445 register_external_interrupt(0x2603, kvm_extint_handler);
446 446
447 scan_devices(); 447 scan_devices();