diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-06-24 04:30:41 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-06-26 15:10:28 -0400 |
commit | f4eae94f71372ea5ec1ba17a85f3aebedc516ca8 (patch) | |
tree | ec3d6a527bf276a92e8befd559d9a0f0866ab7bd /drivers/s390 | |
parent | 386aa051fb4b6298c23996e68b7c92f186e484b6 (diff) |
s390/airq: simplify adapter interrupt code
There are three users of adapter interrupts: AP, QDIO and PCI. Each
registers a single adapter interrupt with independent ISCs. Define
a "struct airq" with the interrupt handler, a pointer and a mask for
the local summary indicator and the ISC for the adapter interrupt
source. Convert the indicator array with its fixed number of adapter
interrupt sources per ISE to an array of hlists. This removes the
limitation to 32 adapter interrupts per ISC and allows for arbitrary
memory locations for the local summary indicator.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/airq.c | 167 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_thinint.c | 33 | ||||
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 60 |
3 files changed, 107 insertions, 153 deletions
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index bc10220f6847..91edbd7ee806 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c | |||
@@ -9,142 +9,87 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/irq.h> | ||
13 | #include <linux/kernel_stat.h> | ||
12 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/mutex.h> | ||
16 | #include <linux/rculist.h> | ||
13 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
14 | #include <linux/rcupdate.h> | ||
15 | 18 | ||
16 | #include <asm/airq.h> | 19 | #include <asm/airq.h> |
17 | #include <asm/isc.h> | 20 | #include <asm/isc.h> |
18 | 21 | ||
19 | #include "cio.h" | 22 | #include "cio.h" |
20 | #include "cio_debug.h" | 23 | #include "cio_debug.h" |
24 | #include "ioasm.h" | ||
21 | 25 | ||
22 | #define NR_AIRQS 32 | 26 | static DEFINE_SPINLOCK(airq_lists_lock); |
23 | #define NR_AIRQS_PER_WORD sizeof(unsigned long) | 27 | static struct hlist_head airq_lists[MAX_ISC+1]; |
24 | #define NR_AIRQ_WORDS (NR_AIRQS / NR_AIRQS_PER_WORD) | ||
25 | |||
26 | union indicator_t { | ||
27 | unsigned long word[NR_AIRQ_WORDS]; | ||
28 | unsigned char byte[NR_AIRQS]; | ||
29 | } __attribute__((packed)); | ||
30 | |||
31 | struct airq_t { | ||
32 | adapter_int_handler_t handler; | ||
33 | void *drv_data; | ||
34 | }; | ||
35 | |||
36 | static union indicator_t indicators[MAX_ISC+1]; | ||
37 | static struct airq_t *airqs[MAX_ISC+1][NR_AIRQS]; | ||
38 | |||
39 | static int register_airq(struct airq_t *airq, u8 isc) | ||
40 | { | ||
41 | int i; | ||
42 | |||
43 | for (i = 0; i < NR_AIRQS; i++) | ||
44 | if (!cmpxchg(&airqs[isc][i], NULL, airq)) | ||
45 | return i; | ||
46 | return -ENOMEM; | ||
47 | } | ||
48 | 28 | ||
49 | /** | 29 | /** |
50 | * s390_register_adapter_interrupt() - register adapter interrupt handler | 30 | * register_adapter_interrupt() - register adapter interrupt handler |
51 | * @handler: adapter handler to be registered | 31 | * @airq: pointer to adapter interrupt descriptor |
52 | * @drv_data: driver data passed with each call to the handler | ||
53 | * @isc: isc for which the handler should be called | ||
54 | * | 32 | * |
55 | * Returns: | 33 | * Returns 0 on success, or -EINVAL. |
56 | * Pointer to the indicator to be used on success | ||
57 | * ERR_PTR() if registration failed | ||
58 | */ | 34 | */ |
59 | void *s390_register_adapter_interrupt(adapter_int_handler_t handler, | 35 | int register_adapter_interrupt(struct airq_struct *airq) |
60 | void *drv_data, u8 isc) | ||
61 | { | 36 | { |
62 | struct airq_t *airq; | 37 | char dbf_txt[32]; |
63 | char dbf_txt[16]; | 38 | |
64 | int ret; | 39 | if (!airq->handler || airq->isc > MAX_ISC) |
65 | 40 | return -EINVAL; | |
66 | if (isc > MAX_ISC) | 41 | if (!airq->lsi_ptr) { |
67 | return ERR_PTR(-EINVAL); | 42 | airq->lsi_ptr = kzalloc(1, GFP_KERNEL); |
68 | airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL); | 43 | if (!airq->lsi_ptr) |
69 | if (!airq) { | 44 | return -ENOMEM; |
70 | ret = -ENOMEM; | 45 | airq->flags |= AIRQ_PTR_ALLOCATED; |
71 | goto out; | ||
72 | } | 46 | } |
73 | airq->handler = handler; | 47 | if (!airq->lsi_mask) |
74 | airq->drv_data = drv_data; | 48 | airq->lsi_mask = 0xff; |
75 | 49 | snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%p", airq); | |
76 | ret = register_airq(airq, isc); | ||
77 | out: | ||
78 | snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); | ||
79 | CIO_TRACE_EVENT(4, dbf_txt); | 50 | CIO_TRACE_EVENT(4, dbf_txt); |
80 | if (ret < 0) { | 51 | isc_register(airq->isc); |
81 | kfree(airq); | 52 | spin_lock(&airq_lists_lock); |
82 | return ERR_PTR(ret); | 53 | hlist_add_head_rcu(&airq->list, &airq_lists[airq->isc]); |
83 | } else | 54 | spin_unlock(&airq_lists_lock); |
84 | return &indicators[isc].byte[ret]; | 55 | return 0; |
85 | } | 56 | } |
86 | EXPORT_SYMBOL(s390_register_adapter_interrupt); | 57 | EXPORT_SYMBOL(register_adapter_interrupt); |
87 | 58 | ||
88 | /** | 59 | /** |
89 | * s390_unregister_adapter_interrupt - unregister adapter interrupt handler | 60 | * unregister_adapter_interrupt - unregister adapter interrupt handler |
90 | * @ind: indicator for which the handler is to be unregistered | 61 | * @airq: pointer to adapter interrupt descriptor |
91 | * @isc: interruption subclass | ||
92 | */ | 62 | */ |
93 | void s390_unregister_adapter_interrupt(void *ind, u8 isc) | 63 | void unregister_adapter_interrupt(struct airq_struct *airq) |
94 | { | 64 | { |
95 | struct airq_t *airq; | 65 | char dbf_txt[32]; |
96 | char dbf_txt[16]; | ||
97 | int i; | ||
98 | 66 | ||
99 | i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]); | 67 | if (hlist_unhashed(&airq->list)) |
100 | snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i); | 68 | return; |
69 | snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%p", airq); | ||
101 | CIO_TRACE_EVENT(4, dbf_txt); | 70 | CIO_TRACE_EVENT(4, dbf_txt); |
102 | indicators[isc].byte[i] = 0; | 71 | spin_lock(&airq_lists_lock); |
103 | airq = xchg(&airqs[isc][i], NULL); | 72 | hlist_del_rcu(&airq->list); |
104 | /* | 73 | spin_unlock(&airq_lists_lock); |
105 | * Allow interrupts to complete. This will ensure that the airq handle | 74 | synchronize_rcu(); |
106 | * is no longer referenced by any interrupt handler. | 75 | isc_unregister(airq->isc); |
107 | */ | 76 | if (airq->flags & AIRQ_PTR_ALLOCATED) { |
108 | synchronize_sched(); | 77 | kfree(airq->lsi_ptr); |
109 | kfree(airq); | 78 | airq->lsi_ptr = NULL; |
79 | airq->flags &= ~AIRQ_PTR_ALLOCATED; | ||
80 | } | ||
110 | } | 81 | } |
111 | EXPORT_SYMBOL(s390_unregister_adapter_interrupt); | 82 | EXPORT_SYMBOL(unregister_adapter_interrupt); |
112 | |||
113 | #define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8)) | ||
114 | 83 | ||
115 | void do_adapter_IO(u8 isc) | 84 | void do_adapter_IO(u8 isc) |
116 | { | 85 | { |
117 | int w; | 86 | struct airq_struct *airq; |
118 | int i; | 87 | struct hlist_head *head; |
119 | unsigned long word; | 88 | |
120 | struct airq_t *airq; | 89 | head = &airq_lists[isc]; |
121 | 90 | rcu_read_lock(); | |
122 | /* | 91 | hlist_for_each_entry_rcu(airq, head, list) |
123 | * Access indicator array in word-sized chunks to minimize storage | 92 | if ((*airq->lsi_ptr & airq->lsi_mask) != 0) |
124 | * fetch operations. | 93 | airq->handler(airq); |
125 | */ | 94 | rcu_read_unlock(); |
126 | for (w = 0; w < NR_AIRQ_WORDS; w++) { | ||
127 | word = indicators[isc].word[w]; | ||
128 | i = w * NR_AIRQS_PER_WORD; | ||
129 | /* | ||
130 | * Check bytes within word for active indicators. | ||
131 | */ | ||
132 | while (word) { | ||
133 | if (word & INDICATOR_MASK) { | ||
134 | airq = airqs[isc][i]; | ||
135 | /* Make sure gcc reads from airqs only once. */ | ||
136 | barrier(); | ||
137 | if (likely(airq)) | ||
138 | airq->handler(&indicators[isc].byte[i], | ||
139 | airq->drv_data); | ||
140 | else | ||
141 | /* | ||
142 | * Reset ill-behaved indicator. | ||
143 | */ | ||
144 | indicators[isc].byte[i] = 0; | ||
145 | } | ||
146 | word <<= 8; | ||
147 | i++; | ||
148 | } | ||
149 | } | ||
150 | } | 95 | } |
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 417b2557d83e..5d06253c2a7a 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c | |||
@@ -36,8 +36,13 @@ struct indicator_t { | |||
36 | static LIST_HEAD(tiq_list); | 36 | static LIST_HEAD(tiq_list); |
37 | static DEFINE_MUTEX(tiq_list_lock); | 37 | static DEFINE_MUTEX(tiq_list_lock); |
38 | 38 | ||
39 | /* adapter local summary indicator */ | 39 | /* Adapter interrupt definitions */ |
40 | static u8 *tiqdio_alsi; | 40 | static void tiqdio_thinint_handler(struct airq_struct *airq); |
41 | |||
42 | static struct airq_struct tiqdio_airq = { | ||
43 | .handler = tiqdio_thinint_handler, | ||
44 | .isc = QDIO_AIRQ_ISC, | ||
45 | }; | ||
41 | 46 | ||
42 | static struct indicator_t *q_indicators; | 47 | static struct indicator_t *q_indicators; |
43 | 48 | ||
@@ -176,7 +181,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) | |||
176 | * @alsi: pointer to adapter local summary indicator | 181 | * @alsi: pointer to adapter local summary indicator |
177 | * @data: NULL | 182 | * @data: NULL |
178 | */ | 183 | */ |
179 | static void tiqdio_thinint_handler(void *alsi, void *data) | 184 | static void tiqdio_thinint_handler(struct airq_struct *airq) |
180 | { | 185 | { |
181 | u32 si_used = clear_shared_ind(); | 186 | u32 si_used = clear_shared_ind(); |
182 | struct qdio_q *q; | 187 | struct qdio_q *q; |
@@ -216,7 +221,7 @@ static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) | |||
216 | summary_indicator_addr = 0; | 221 | summary_indicator_addr = 0; |
217 | subchannel_indicator_addr = 0; | 222 | subchannel_indicator_addr = 0; |
218 | } else { | 223 | } else { |
219 | summary_indicator_addr = virt_to_phys(tiqdio_alsi); | 224 | summary_indicator_addr = virt_to_phys(tiqdio_airq.lsi_ptr); |
220 | subchannel_indicator_addr = virt_to_phys(irq_ptr->dsci); | 225 | subchannel_indicator_addr = virt_to_phys(irq_ptr->dsci); |
221 | } | 226 | } |
222 | 227 | ||
@@ -252,14 +257,12 @@ void tiqdio_free_memory(void) | |||
252 | 257 | ||
253 | int __init tiqdio_register_thinints(void) | 258 | int __init tiqdio_register_thinints(void) |
254 | { | 259 | { |
255 | isc_register(QDIO_AIRQ_ISC); | 260 | int rc; |
256 | tiqdio_alsi = s390_register_adapter_interrupt(&tiqdio_thinint_handler, | 261 | |
257 | NULL, QDIO_AIRQ_ISC); | 262 | rc = register_adapter_interrupt(&tiqdio_airq); |
258 | if (IS_ERR(tiqdio_alsi)) { | 263 | if (rc) { |
259 | DBF_EVENT("RTI:%lx", PTR_ERR(tiqdio_alsi)); | 264 | DBF_EVENT("RTI:%x", rc); |
260 | tiqdio_alsi = NULL; | 265 | return rc; |
261 | isc_unregister(QDIO_AIRQ_ISC); | ||
262 | return -ENOMEM; | ||
263 | } | 266 | } |
264 | return 0; | 267 | return 0; |
265 | } | 268 | } |
@@ -292,9 +295,5 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr) | |||
292 | void __exit tiqdio_unregister_thinints(void) | 295 | void __exit tiqdio_unregister_thinints(void) |
293 | { | 296 | { |
294 | WARN_ON(!list_empty(&tiq_list)); | 297 | WARN_ON(!list_empty(&tiq_list)); |
295 | 298 | unregister_adapter_interrupt(&tiqdio_airq); | |
296 | if (tiqdio_alsi) { | ||
297 | s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC); | ||
298 | isc_unregister(QDIO_AIRQ_ISC); | ||
299 | } | ||
300 | } | 299 | } |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 0b116a49ee53..f446a7705c3b 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -58,7 +58,7 @@ static inline void ap_schedule_poll_timer(void); | |||
58 | static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags); | 58 | static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags); |
59 | static int ap_device_remove(struct device *dev); | 59 | static int ap_device_remove(struct device *dev); |
60 | static int ap_device_probe(struct device *dev); | 60 | static int ap_device_probe(struct device *dev); |
61 | static void ap_interrupt_handler(void *unused1, void *unused2); | 61 | static void ap_interrupt_handler(struct airq_struct *airq); |
62 | static void ap_reset(struct ap_device *ap_dev); | 62 | static void ap_reset(struct ap_device *ap_dev); |
63 | static void ap_config_timeout(unsigned long ptr); | 63 | static void ap_config_timeout(unsigned long ptr); |
64 | static int ap_select_domain(void); | 64 | static int ap_select_domain(void); |
@@ -106,7 +106,6 @@ static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); | |||
106 | static struct task_struct *ap_poll_kthread = NULL; | 106 | static struct task_struct *ap_poll_kthread = NULL; |
107 | static DEFINE_MUTEX(ap_poll_thread_mutex); | 107 | static DEFINE_MUTEX(ap_poll_thread_mutex); |
108 | static DEFINE_SPINLOCK(ap_poll_timer_lock); | 108 | static DEFINE_SPINLOCK(ap_poll_timer_lock); |
109 | static void *ap_interrupt_indicator; | ||
110 | static struct hrtimer ap_poll_timer; | 109 | static struct hrtimer ap_poll_timer; |
111 | /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. | 110 | /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. |
112 | * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ | 111 | * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ |
@@ -120,13 +119,21 @@ static int ap_suspend_flag; | |||
120 | static int user_set_domain = 0; | 119 | static int user_set_domain = 0; |
121 | static struct bus_type ap_bus_type; | 120 | static struct bus_type ap_bus_type; |
122 | 121 | ||
122 | /* Adapter interrupt definitions */ | ||
123 | static int ap_airq_flag; | ||
124 | |||
125 | static struct airq_struct ap_airq = { | ||
126 | .handler = ap_interrupt_handler, | ||
127 | .isc = AP_ISC, | ||
128 | }; | ||
129 | |||
123 | /** | 130 | /** |
124 | * ap_using_interrupts() - Returns non-zero if interrupt support is | 131 | * ap_using_interrupts() - Returns non-zero if interrupt support is |
125 | * available. | 132 | * available. |
126 | */ | 133 | */ |
127 | static inline int ap_using_interrupts(void) | 134 | static inline int ap_using_interrupts(void) |
128 | { | 135 | { |
129 | return ap_interrupt_indicator != NULL; | 136 | return ap_airq_flag; |
130 | } | 137 | } |
131 | 138 | ||
132 | /** | 139 | /** |
@@ -588,7 +595,7 @@ static int ap_init_queue(ap_qid_t qid) | |||
588 | } | 595 | } |
589 | } | 596 | } |
590 | if (rc == 0 && ap_using_interrupts()) { | 597 | if (rc == 0 && ap_using_interrupts()) { |
591 | rc = ap_queue_enable_interruption(qid, ap_interrupt_indicator); | 598 | rc = ap_queue_enable_interruption(qid, ap_airq.lsi_ptr); |
592 | /* If interruption mode is supported by the machine, | 599 | /* If interruption mode is supported by the machine, |
593 | * but an AP can not be enabled for interruption then | 600 | * but an AP can not be enabled for interruption then |
594 | * the AP will be discarded. */ | 601 | * the AP will be discarded. */ |
@@ -821,13 +828,22 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) | |||
821 | 828 | ||
822 | static int ap_bus_resume(struct device *dev) | 829 | static int ap_bus_resume(struct device *dev) |
823 | { | 830 | { |
824 | int rc = 0; | ||
825 | struct ap_device *ap_dev = to_ap_dev(dev); | 831 | struct ap_device *ap_dev = to_ap_dev(dev); |
832 | int rc; | ||
826 | 833 | ||
827 | if (ap_suspend_flag) { | 834 | if (ap_suspend_flag) { |
828 | ap_suspend_flag = 0; | 835 | ap_suspend_flag = 0; |
829 | if (!ap_interrupts_available()) | 836 | if (ap_interrupts_available()) { |
830 | ap_interrupt_indicator = NULL; | 837 | if (!ap_using_interrupts()) { |
838 | rc = register_adapter_interrupt(&ap_airq); | ||
839 | ap_airq_flag = (rc == 0); | ||
840 | } | ||
841 | } else { | ||
842 | if (ap_using_interrupts()) { | ||
843 | unregister_adapter_interrupt(&ap_airq); | ||
844 | ap_airq_flag = 0; | ||
845 | } | ||
846 | } | ||
831 | ap_query_configuration(); | 847 | ap_query_configuration(); |
832 | if (!user_set_domain) { | 848 | if (!user_set_domain) { |
833 | ap_domain_index = -1; | 849 | ap_domain_index = -1; |
@@ -848,7 +864,10 @@ static int ap_bus_resume(struct device *dev) | |||
848 | tasklet_schedule(&ap_tasklet); | 864 | tasklet_schedule(&ap_tasklet); |
849 | if (ap_thread_flag) | 865 | if (ap_thread_flag) |
850 | rc = ap_poll_thread_start(); | 866 | rc = ap_poll_thread_start(); |
851 | } | 867 | else |
868 | rc = 0; | ||
869 | } else | ||
870 | rc = 0; | ||
852 | if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) { | 871 | if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) { |
853 | spin_lock_bh(&ap_dev->lock); | 872 | spin_lock_bh(&ap_dev->lock); |
854 | ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid), | 873 | ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid), |
@@ -1266,7 +1285,7 @@ out: | |||
1266 | return rc; | 1285 | return rc; |
1267 | } | 1286 | } |
1268 | 1287 | ||
1269 | static void ap_interrupt_handler(void *unused1, void *unused2) | 1288 | static void ap_interrupt_handler(struct airq_struct *airq) |
1270 | { | 1289 | { |
1271 | inc_irq_stat(IRQIO_APB); | 1290 | inc_irq_stat(IRQIO_APB); |
1272 | tasklet_schedule(&ap_tasklet); | 1291 | tasklet_schedule(&ap_tasklet); |
@@ -1722,7 +1741,7 @@ static void ap_poll_all(unsigned long dummy) | |||
1722 | * important that no requests on any AP get lost. | 1741 | * important that no requests on any AP get lost. |
1723 | */ | 1742 | */ |
1724 | if (ap_using_interrupts()) | 1743 | if (ap_using_interrupts()) |
1725 | xchg((u8 *)ap_interrupt_indicator, 0); | 1744 | xchg(ap_airq.lsi_ptr, 0); |
1726 | do { | 1745 | do { |
1727 | flags = 0; | 1746 | flags = 0; |
1728 | spin_lock(&ap_device_list_lock); | 1747 | spin_lock(&ap_device_list_lock); |
@@ -1881,13 +1900,8 @@ int __init ap_module_init(void) | |||
1881 | return -ENODEV; | 1900 | return -ENODEV; |
1882 | } | 1901 | } |
1883 | if (ap_interrupts_available()) { | 1902 | if (ap_interrupts_available()) { |
1884 | isc_register(AP_ISC); | 1903 | rc = register_adapter_interrupt(&ap_airq); |
1885 | ap_interrupt_indicator = s390_register_adapter_interrupt( | 1904 | ap_airq_flag = (rc == 0); |
1886 | &ap_interrupt_handler, NULL, AP_ISC); | ||
1887 | if (IS_ERR(ap_interrupt_indicator)) { | ||
1888 | ap_interrupt_indicator = NULL; | ||
1889 | isc_unregister(AP_ISC); | ||
1890 | } | ||
1891 | } | 1905 | } |
1892 | 1906 | ||
1893 | register_reset_call(&ap_reset_call); | 1907 | register_reset_call(&ap_reset_call); |
@@ -1955,10 +1969,8 @@ out_bus: | |||
1955 | bus_unregister(&ap_bus_type); | 1969 | bus_unregister(&ap_bus_type); |
1956 | out: | 1970 | out: |
1957 | unregister_reset_call(&ap_reset_call); | 1971 | unregister_reset_call(&ap_reset_call); |
1958 | if (ap_using_interrupts()) { | 1972 | if (ap_using_interrupts()) |
1959 | s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC); | 1973 | unregister_adapter_interrupt(&ap_airq); |
1960 | isc_unregister(AP_ISC); | ||
1961 | } | ||
1962 | return rc; | 1974 | return rc; |
1963 | } | 1975 | } |
1964 | 1976 | ||
@@ -1994,10 +2006,8 @@ void ap_module_exit(void) | |||
1994 | bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); | 2006 | bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); |
1995 | bus_unregister(&ap_bus_type); | 2007 | bus_unregister(&ap_bus_type); |
1996 | unregister_reset_call(&ap_reset_call); | 2008 | unregister_reset_call(&ap_reset_call); |
1997 | if (ap_using_interrupts()) { | 2009 | if (ap_using_interrupts()) |
1998 | s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC); | 2010 | unregister_adapter_interrupt(&ap_airq); |
1999 | isc_unregister(AP_ISC); | ||
2000 | } | ||
2001 | } | 2011 | } |
2002 | 2012 | ||
2003 | module_init(ap_module_init); | 2013 | module_init(ap_module_init); |